<commit_before>package ledis

import (
	"bytes"
	"encoding/binary"
	"errors"
	"github.com/siddontang/golib/hack"
	"github.com/siddontang/golib/leveldb"
	"strconv"
)

var errZSizeKey = errors.New("invalid zsize key")
var errZSetKey = errors.New("invalid zset key")
var errZScoreKey = errors.New("invalid zscore key")

const (
	zsetNScoreSep    byte = '<'
	zsetPScoreSep    byte = zsetNScoreSep + 1
	zsetStopScoreSep byte = zsetPScoreSep + 1

	zsetStartMemSep byte = ':'
	zsetStopMemSep  byte = zsetStartMemSep + 1
)

func encode_zsize_key(key []byte) []byte {
	buf := make([]byte, len(key)+1)
	buf[0] = ZSIZE_TYPE

	copy(buf[1:], key)
	return buf
}

func decode_zsize_key(ek []byte) ([]byte, error) {
	if len(ek) == 0 || ek[0] != ZSIZE_TYPE {
		return nil, errZSizeKey
	}

	return ek[1:], nil
}

func encode_zset_key(key []byte, member []byte) []byte {
	buf := make([]byte, len(key)+len(member)+5)

	pos := 0
	buf[pos] = ZSET_TYPE
	pos++

	binary.BigEndian.PutUint32(buf[pos:], uint32(len(key)))
	pos += 4

	copy(buf[pos:], key)
	pos += len(key)

	copy(buf[pos:], member)

	return buf
}

func decode_zset_key(ek []byte) ([]byte, []byte, error) {
	if len(ek) < 5 || ek[0] != ZSET_TYPE {
		return nil, nil, errZSetKey
	}

	keyLen := int(binary.BigEndian.Uint32(ek[1:]))
	if keyLen+5 > len(ek) {
		return nil, nil, errZSetKey
	}

	key := ek[5 : 5+keyLen]
	member := ek[5+keyLen:]
	return key, member, nil
}

func encode_zscore_key(key []byte, member []byte, score int64) []byte {
	buf := make([]byte, len(key)+len(member)+15)

	pos := 0
	buf[pos] = ZSCORE_TYPE
	pos++

	binary.BigEndian.PutUint32(buf[pos:], uint32(len(key)))
	pos += 4

	copy(buf[pos:], key)
	pos += len(key)

	if score < 0 {
		buf[pos] = zsetNScoreSep
	} else {
		buf[pos] = zsetPScoreSep
	}

	pos++
	binary.BigEndian.PutUint64(buf[pos:], uint64(score))
	pos += 8

	buf[pos] = zsetStartMemSep
	pos++

	copy(buf[pos:], member)
	return buf
}

func encode_start_zscore_key(key []byte, score int64) []byte {
	k := encode_zscore_key(key, nil, score)
	return k
}

func encode_stop_zscore_key(key []byte, score int64) []byte {
	k := encode_zscore_key(key, nil, score)
	k[len(k)-1] = zsetStopMemSep
	return k
}

func decode_zscore_key(ek []byte) (key []byte, member []byte, score int64, err error) {
	if len(ek) < 15 || ek[0] != ZSCORE_TYPE {
		err = errZScoreKey
		return
	}

	keyLen := int(binary.BigEndian.Uint32(ek[1:]))
	if keyLen+14 > len(ek) {
		err = errZScoreKey
		return
	}

	key = ek[5 : 5+keyLen]
	pos := 5 + keyLen

	if (ek[pos] != zsetNScoreSep) && (ek[pos] != zsetPScoreSep) {
		err = errZScoreKey
		return
	}
	pos++

	score = int64(binary.BigEndian.Uint64(ek[pos:]))
	pos += 8

	if ek[pos] != zsetStartMemSep {
		err = errZScoreKey
		return
	}

	pos++

	member = ek[pos:]
	return
}

func (a *App) zset_setItem(key []byte, score int64, member []byte) (int64, error) {
	if score <= MinScore || score >= MaxScore {
		return 0, errScoreOverflow
	}

	t := a.zsetTx

	var exists int64 = 0
	ek := encode_zset_key(key, member)
	if v, err := a.db.Get(ek); err != nil {
		return 0, err
	} else if v != nil {
		exists = 1

		if s, err := Int64(v, err); err != nil {
			return 0, err
		} else {
			sk := encode_zscore_key(key, member, s)
			t.Delete(sk)
		}
	}

	t.Put(ek, PutInt64(score))

	sk := encode_zscore_key(key, member, score)
	t.Put(sk, []byte{})

	return exists, nil
}

func (a *App) zset_delItem(key []byte, member []byte, skipDelScore bool) (int64, error) {
	t := a.zsetTx

	ek := encode_zset_key(key, member)
	if v, err := a.db.Get(ek); err != nil {
		return 0, err
	} else if v == nil {
		//not exists
		return 0, nil
	} else {
		//exists
		if !skipDelScore {
			//we must del score
			if s, err := Int64(v, err); err != nil {
				return 0, err
			} else {
				sk := encode_zscore_key(key, member, s)
				t.Delete(sk)
			}
		}
	}

	t.Delete(ek)
	return 1, nil
}

func (a *App) zset_add(key []byte, args []interface{}) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	var num int64 = 0
	for i := 0; i < len(args); i += 2 {
		score := args[i].(int64)
		member := args[i+1].([]byte)

		if n, err := a.zset_setItem(key, score, member); err != nil {
			return 0, err
		} else if n == 0 {
			//add new
			num++
		}
	}

	if _, err := a.zset_incrSize(key, num); err != nil {
		return 0, err
	}

	//todo add binlog
	err := t.Commit()
	return num, err
}

func (a *App) zset_incrSize(key []byte, delta int64) (int64, error) {
	t := a.zsetTx
	sk := encode_zsize_key(key)
	size, err := Int64(a.db.Get(sk))
	if err != nil {
		return 0, err
	} else {
		size += delta
		if size <= 0 {
			size = 0
			t.Delete(sk)
		} else {
			t.Put(sk, PutInt64(size))
		}
	}

	return size, nil
}

func (a *App) zset_card(key []byte) (int64, error) {
	sk := encode_zsize_key(key)
	size, err := Int64(a.db.Get(sk))
	return size, err
}

func (a *App) zset_score(key []byte, member []byte) ([]byte, error) {
	k := encode_zset_key(key, member)
	score, err := Int64(a.db.Get(k))
	if err != nil {
		return nil, err
	}

	return hack.Slice(strconv.FormatInt(score, 10)), nil
}

func (a *App) zset_rem(key []byte, args [][]byte) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	var num int64 = 0
	for i := 0; i < len(args); i++ {
		if n, err := a.zset_delItem(key, args[i], false); err != nil {
			return 0, err
		} else if n == 1 {
			num++
		}
	}

	if _, err := a.zset_incrSize(key, -num); err != nil {
		return 0, err
	}

	err := t.Commit()
	return num, err
}

func (a *App) zset_incrby(key []byte, delta int64, member []byte) ([]byte, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	ek := encode_zset_key(key, member)
	var score int64 = delta
	v, err := a.db.Get(ek)
	if err != nil {
		return nil, err
	} else if v != nil {
		if s, err := Int64(v, err); err != nil {
			return nil, err
		} else {
			sk := encode_zscore_key(key, member, s)
			t.Delete(sk)

			score = s + delta

			if score >= MaxScore || score <= MinScore {
				return nil, errScoreOverflow
			}
		}
	} else {
		a.zset_incrSize(key, 1)
	}

	t.Put(ek, PutInt64(score))

	t.Put(encode_zscore_key(key, member, score), []byte{})

	err = t.Commit()
	return hack.Slice(strconv.FormatInt(score, 10)), err
}

func (a *App) zset_count(key []byte, min int64, max int64) (int64, error) {
	minKey := encode_start_zscore_key(key, min)
	maxKey := encode_stop_zscore_key(key, max)

	rangeType := leveldb.RangeROpen

	it := a.db.Iterator(minKey, maxKey, rangeType, 0, -1)
	var n int64 = 0
	for ; it.Valid(); it.Next() {
		n++
	}
	it.Close()

	return n, nil
}

func (a *App) zset_rank(key []byte, member []byte, reverse bool) (int64, error) {
	k := encode_zset_key(key, member)

	if v, err := a.db.Get(k); err != nil {
		return 0, err
	} else if v == nil {
		return -1, nil
	} else {
		if s, err := Int64(v, err); err != nil {
			return 0, err
		} else {
			var it *leveldb.Iterator

			sk := encode_zscore_key(key, member, s)

			if !reverse {
				minKey := encode_start_zscore_key(key, MinScore)
				it = a.db.Iterator(minKey, sk, leveldb.RangeClose, 0, -1)
			} else {
				maxKey := encode_stop_zscore_key(key, MaxScore)
				it = a.db.RevIterator(sk, maxKey, leveldb.RangeClose, 0, -1)
			}

			var lastKey []byte = nil
			var n int64 = 0

			for ; it.Valid(); it.Next() {
				n++

				lastKey = it.Key()
			}

			it.Close()

			if _, m, _, err := decode_zscore_key(lastKey); err == nil && bytes.Equal(m, member) {
				n--
				return n, nil
			}
		}
	}

	return -1, nil
}

func (a *App) zset_iterator(key []byte, min int64, max int64, offset int, limit int, reverse bool) *leveldb.Iterator {
	minKey := encode_start_zscore_key(key, min)
	maxKey := encode_stop_zscore_key(key, max)

	if !reverse {
		return a.db.Iterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
	} else {
		return a.db.RevIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
	}
}

func (a *App) zset_remRange(key []byte, min int64, max int64, offset int, limit int) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	it := a.zset_iterator(key, min, max, offset, limit, false)
	var num int64 = 0
	for ; it.Valid(); it.Next() {
		k := it.Key()
		_, m, _, err := decode_zscore_key(k)
		if err != nil {
			continue
		}

		if n, err := a.zset_delItem(key, m, true); err != nil {
			return 0, err
		} else if n == 1 {
			num++
		}

		t.Delete(k)
	}

	if _, err := a.zset_incrSize(key, -num); err != nil {
		return 0, err
	}

	//todo add binlog

	err := t.Commit()
	return num, err
}

func (a *App) zset_range(key []byte, min int64, max int64, withScores bool, offset int, limit int, reverse bool) ([]interface{}, error) {
	v := make([]interface{}, 0, 16)
	it := a.zset_iterator(key, min, max, offset, limit, reverse)
	for ; it.Valid(); it.Next() {
		_, m, s, err := decode_zscore_key(it.Key())
		//may be we will check key equal?
		if err != nil {
			continue
		}

		v = append(v, m)

		if withScores {
			v = append(v, hack.Slice(strconv.FormatInt(s, 10)))
		}
	}

	return v, nil
}

func (a *App) zset_clear(key []byte) (int64, error) {
	return a.zset_remRange(key, MinScore, MaxScore, 0, -1)
}
<commit_msg>optimize reverse range with no limit<commit_after>package ledis

import (
	"bytes"
	"encoding/binary"
	"errors"
	"github.com/siddontang/golib/hack"
	"github.com/siddontang/golib/leveldb"
	"strconv"
)

var errZSizeKey = errors.New("invalid zsize key")
var errZSetKey = errors.New("invalid zset key")
var errZScoreKey = errors.New("invalid zscore key")

const (
	zsetNScoreSep    byte = '<'
	zsetPScoreSep    byte = zsetNScoreSep + 1
	zsetStopScoreSep byte = zsetPScoreSep + 1

	zsetStartMemSep byte = ':'
	zsetStopMemSep  byte = zsetStartMemSep + 1
)

func encode_zsize_key(key []byte) []byte {
	buf := make([]byte, len(key)+1)
	buf[0] = ZSIZE_TYPE

	copy(buf[1:], key)
	return buf
}

func decode_zsize_key(ek []byte) ([]byte, error) {
	if len(ek) == 0 || ek[0] != ZSIZE_TYPE {
		return nil, errZSizeKey
	}

	return ek[1:], nil
}

func encode_zset_key(key []byte, member []byte) []byte {
	buf := make([]byte, len(key)+len(member)+5)

	pos := 0
	buf[pos] = ZSET_TYPE
	pos++

	binary.BigEndian.PutUint32(buf[pos:], uint32(len(key)))
	pos += 4

	copy(buf[pos:], key)
	pos += len(key)

	copy(buf[pos:], member)

	return buf
}

func decode_zset_key(ek []byte) ([]byte, []byte, error) {
	if len(ek) < 5 || ek[0] != ZSET_TYPE {
		return nil, nil, errZSetKey
	}

	keyLen := int(binary.BigEndian.Uint32(ek[1:]))
	if keyLen+5 > len(ek) {
		return nil, nil, errZSetKey
	}

	key := ek[5 : 5+keyLen]
	member := ek[5+keyLen:]
	return key, member, nil
}

func encode_zscore_key(key []byte, member []byte, score int64) []byte {
	buf := make([]byte, len(key)+len(member)+15)

	pos := 0
	buf[pos] = ZSCORE_TYPE
	pos++

	binary.BigEndian.PutUint32(buf[pos:], uint32(len(key)))
	pos += 4

	copy(buf[pos:], key)
	pos += len(key)

	if score < 0 {
		buf[pos] = zsetNScoreSep
	} else {
		buf[pos] = zsetPScoreSep
	}

	pos++
	binary.BigEndian.PutUint64(buf[pos:], uint64(score))
	pos += 8

	buf[pos] = zsetStartMemSep
	pos++

	copy(buf[pos:], member)
	return buf
}

func encode_start_zscore_key(key []byte, score int64) []byte {
	k := encode_zscore_key(key, nil, score)
	return k
}

func encode_stop_zscore_key(key []byte, score int64) []byte {
	k := encode_zscore_key(key, nil, score)
	k[len(k)-1] = zsetStopMemSep
	return k
}

func decode_zscore_key(ek []byte) (key []byte, member []byte, score int64, err error) {
	if len(ek) < 15 || ek[0] != ZSCORE_TYPE {
		err = errZScoreKey
		return
	}

	keyLen := int(binary.BigEndian.Uint32(ek[1:]))
	if keyLen+14 > len(ek) {
		err = errZScoreKey
		return
	}

	key = ek[5 : 5+keyLen]
	pos := 5 + keyLen

	if (ek[pos] != zsetNScoreSep) && (ek[pos] != zsetPScoreSep) {
		err = errZScoreKey
		return
	}
	pos++

	score = int64(binary.BigEndian.Uint64(ek[pos:]))
	pos += 8

	if ek[pos] != zsetStartMemSep {
		err = errZScoreKey
		return
	}

	pos++

	member = ek[pos:]
	return
}

func (a *App) zset_setItem(key []byte, score int64, member []byte) (int64, error) {
	if score <= MinScore || score >= MaxScore {
		return 0, errScoreOverflow
	}

	t := a.zsetTx

	var exists int64 = 0
	ek := encode_zset_key(key, member)
	if v, err := a.db.Get(ek); err != nil {
		return 0, err
	} else if v != nil {
		exists = 1

		if s, err := Int64(v, err); err != nil {
			return 0, err
		} else {
			sk := encode_zscore_key(key, member, s)
			t.Delete(sk)
		}
	}

	t.Put(ek, PutInt64(score))

	sk := encode_zscore_key(key, member, score)
	t.Put(sk, []byte{})

	return exists, nil
}

func (a *App) zset_delItem(key []byte, member []byte, skipDelScore bool) (int64, error) {
	t := a.zsetTx

	ek := encode_zset_key(key, member)
	if v, err := a.db.Get(ek); err != nil {
		return 0, err
	} else if v == nil {
		//not exists
		return 0, nil
	} else {
		//exists
		if !skipDelScore {
			//we must del score
			if s, err := Int64(v, err); err != nil {
				return 0, err
			} else {
				sk := encode_zscore_key(key, member, s)
				t.Delete(sk)
			}
		}
	}

	t.Delete(ek)
	return 1, nil
}

func (a *App) zset_add(key []byte, args []interface{}) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	var num int64 = 0
	for i := 0; i < len(args); i += 2 {
		score := args[i].(int64)
		member := args[i+1].([]byte)

		if n, err := a.zset_setItem(key, score, member); err != nil {
			return 0, err
		} else if n == 0 {
			//add new
			num++
		}
	}

	if _, err := a.zset_incrSize(key, num); err != nil {
		return 0, err
	}

	//todo add binlog
	err := t.Commit()
	return num, err
}

func (a *App) zset_incrSize(key []byte, delta int64) (int64, error) {
	t := a.zsetTx
	sk := encode_zsize_key(key)
	size, err := Int64(a.db.Get(sk))
	if err != nil {
		return 0, err
	} else {
		size += delta
		if size <= 0 {
			size = 0
			t.Delete(sk)
		} else {
			t.Put(sk, PutInt64(size))
		}
	}

	return size, nil
}

func (a *App) zset_card(key []byte) (int64, error) {
	sk := encode_zsize_key(key)
	size, err := Int64(a.db.Get(sk))
	return size, err
}

func (a *App) zset_score(key []byte, member []byte) ([]byte, error) {
	k := encode_zset_key(key, member)
	score, err := Int64(a.db.Get(k))
	if err != nil {
		return nil, err
	}

	return hack.Slice(strconv.FormatInt(score, 10)), nil
}

func (a *App) zset_rem(key []byte, args [][]byte) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	var num int64 = 0
	for i := 0; i < len(args); i++ {
		if n, err := a.zset_delItem(key, args[i], false); err != nil {
			return 0, err
		} else if n == 1 {
			num++
		}
	}

	if _, err := a.zset_incrSize(key, -num); err != nil {
		return 0, err
	}

	err := t.Commit()
	return num, err
}

func (a *App) zset_incrby(key []byte, delta int64, member []byte) ([]byte, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	ek := encode_zset_key(key, member)
	var score int64 = delta
	v, err := a.db.Get(ek)
	if err != nil {
		return nil, err
	} else if v != nil {
		if s, err := Int64(v, err); err != nil {
			return nil, err
		} else {
			sk := encode_zscore_key(key, member, s)
			t.Delete(sk)

			score = s + delta

			if score >= MaxScore || score <= MinScore {
				return nil, errScoreOverflow
			}
		}
	} else {
		a.zset_incrSize(key, 1)
	}

	t.Put(ek, PutInt64(score))

	t.Put(encode_zscore_key(key, member, score), []byte{})

	err = t.Commit()
	return hack.Slice(strconv.FormatInt(score, 10)), err
}

func (a *App) zset_count(key []byte, min int64, max int64) (int64, error) {
	minKey := encode_start_zscore_key(key, min)
	maxKey := encode_stop_zscore_key(key, max)

	rangeType := leveldb.RangeROpen

	it := a.db.Iterator(minKey, maxKey, rangeType, 0, -1)
	var n int64 = 0
	for ; it.Valid(); it.Next() {
		n++
	}
	it.Close()

	return n, nil
}

func (a *App) zset_rank(key []byte, member []byte, reverse bool) (int64, error) {
	k := encode_zset_key(key, member)

	if v, err := a.db.Get(k); err != nil {
		return 0, err
	} else if v == nil {
		return -1, nil
	} else {
		if s, err := Int64(v, err); err != nil {
			return 0, err
		} else {
			var it *leveldb.Iterator

			sk := encode_zscore_key(key, member, s)

			if !reverse {
				minKey := encode_start_zscore_key(key, MinScore)
				it = a.db.Iterator(minKey, sk, leveldb.RangeClose, 0, -1)
			} else {
				maxKey := encode_stop_zscore_key(key, MaxScore)
				it = a.db.RevIterator(sk, maxKey, leveldb.RangeClose, 0, -1)
			}

			var lastKey []byte = nil
			var n int64 = 0

			for ; it.Valid(); it.Next() {
				n++

				lastKey = it.Key()
			}

			it.Close()

			if _, m, _, err := decode_zscore_key(lastKey); err == nil && bytes.Equal(m, member) {
				n--
				return n, nil
			}
		}
	}

	return -1, nil
}

func (a *App) zset_iterator(key []byte, min int64, max int64, offset int, limit int, reverse bool) *leveldb.Iterator {
	minKey := encode_start_zscore_key(key, min)
	maxKey := encode_stop_zscore_key(key, max)

	if !reverse {
		return a.db.Iterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
	} else {
		return a.db.RevIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
	}
}

func (a *App) zset_remRange(key []byte, min int64, max int64, offset int, limit int) (int64, error) {
	t := a.zsetTx
	t.Lock()
	defer t.Unlock()

	it := a.zset_iterator(key, min, max, offset, limit, false)
	var num int64 = 0
	for ; it.Valid(); it.Next() {
		k := it.Key()
		_, m, _, err := decode_zscore_key(k)
		if err != nil {
			continue
		}

		if n, err := a.zset_delItem(key, m, true); err != nil {
			return 0, err
		} else if n == 1 {
			num++
		}

		t.Delete(k)
	}

	if _, err := a.zset_incrSize(key, -num); err != nil {
		return 0, err
	}

	//todo add binlog

	err := t.Commit()
	return num, err
}

func (a *App) zset_reverse(s []interface{}, withScores bool) []interface{} {
	if withScores {
		for i, j := 0, len(s)-2; i < j; i, j = i+2, j-2 {
			s[i], s[j] = s[j], s[i]
			s[i+1], s[j+1] = s[j+1], s[i+1]
		}
	} else {
		for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
			s[i], s[j] = s[j], s[i]
		}
	}

	return s
}

func (a *App) zset_range(key []byte, min int64, max int64, withScores bool, offset int, limit int, reverse bool) ([]interface{}, error) {
	nv := 64
	if limit > 0 {
		nv = limit
	}
	if withScores {
		nv = 2 * nv
	}
	v := make([]interface{}, 0, nv)

	var it *leveldb.Iterator

	//if reverse and offset is 0, limit < 0, we may use forward iterator then reverse
	//because leveldb iterator prev is slower than next
	if !reverse || (offset == 0 && limit < 0) {
		it = a.zset_iterator(key, min, max, offset, limit, false)
	} else {
		it = a.zset_iterator(key, min, max, offset, limit, true)
	}

	for ; it.Valid(); it.Next() {
		_, m, s, err := decode_zscore_key(it.Key())
		//may be we will check key equal?
		if err != nil {
			continue
		}

		v = append(v, m)

		if withScores {
			v = append(v, hack.Slice(strconv.FormatInt(s, 10)))
		}
	}

	if reverse && (offset == 0 && limit < 0) {
		v = a.zset_reverse(v, withScores)
	}

	return v, nil
}

func (a *App) zset_clear(key []byte) (int64, error) {
	return a.zset_remRange(key, MinScore, MaxScore, 0, -1)
}
<|endoftext|>


<commit_before>package kloud

import (
	"errors"
	"strconv"
	"time"

	"github.com/koding/kite"
)

type BuildResponse struct {
	MachineName string `json:"machineName" mapstructure:"machineName"`
	MachineId   int    `json:"machineId" mapstructure:"machineId"`
	KiteId      string `json:"kiteId" mapstructure:"kiteId"`
	IpAddress   string `json:"ipAddress" mapstructure:"ipAddress"`
}

type BuildArgs struct {
	MachineId    string
	SnapshotName string
	MachineName  string
}

func (k *Kloud) build(r *kite.Request) (interface{}, error) {
	args := &BuildArgs{}
	if err := r.Args.One().Unmarshal(args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, errors.New("machineId is missing.")
	}

	// this locks are important to prevent consecutive calls from the same user
	k.idlock.Get(r.Username).Lock()
	defer k.idlock.Get(r.Username).Unlock()

	snapshotName := defaultSnapshotName
	if args.SnapshotName != "" {
		snapshotName = args.SnapshotName
	}

	signFunc := func() (string, string, error) {
		return createKey(r.Username, k.KontrolURL, k.KontrolPrivateKey, k.KontrolPublicKey)
	}

	machineName := r.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
	if args.MachineName != "" {
		machineName = args.MachineName
	}

	provider, err := k.provider(args.MachineId)
	if err != nil {
		return nil, err
	}

	artifact, err := provider.Build(snapshotName, machineName, signFunc)
	if err != nil {
		return nil, err
	}

	if err := k.Storage.Update(args.MachineId, artifact); err != nil {
		return nil, err
	}

	return artifact, nil
}
<commit_msg>kloud: add states of several commands<commit_after>package kloud

import (
	"errors"
	"strconv"
	"time"

	"github.com/koding/kite"
)

type MachineState int

const (
	NotInitialized MachineState = iota
	Building
	Starting
	Running
	Stopping
	Stopped
	Rebooting
	Terminating
	Terminated
)

type BuildResponse struct {
	MachineName string `json:"machineName" mapstructure:"machineName"`
	MachineId   int    `json:"machineId" mapstructure:"machineId"`
	KiteId      string `json:"kiteId" mapstructure:"kiteId"`
	IpAddress   string `json:"ipAddress" mapstructure:"ipAddress"`
}

type BuildArgs struct {
	MachineId    string
	SnapshotName string
	MachineName  string
}

func (k *Kloud) build(r *kite.Request) (interface{}, error) {
	args := &BuildArgs{}
	if err := r.Args.One().Unmarshal(args); err != nil {
		return nil, err
	}

	if args.MachineId == "" {
		return nil, errors.New("machineId is missing.")
	}

	// this locks are important to prevent consecutive calls from the same user
	k.idlock.Get(r.Username).Lock()
	defer k.idlock.Get(r.Username).Unlock()

	snapshotName := defaultSnapshotName
	if args.SnapshotName != "" {
		snapshotName = args.SnapshotName
	}

	signFunc := func() (string, string, error) {
		return createKey(r.Username, k.KontrolURL, k.KontrolPrivateKey, k.KontrolPublicKey)
	}

	machineName := r.Username + "-" + strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
	if args.MachineName != "" {
		machineName = args.MachineName
	}

	provider, err := k.provider(args.MachineId)
	if err != nil {
		return nil, err
	}

	artifact, err := provider.Build(snapshotName, machineName, signFunc)
	if err != nil {
		return nil, err
	}

	if err := k.Storage.Update(args.MachineId, artifact); err != nil {
		return nil, err
	}

	return artifact, nil
}
<|endoftext|>


<commit_before>// Copyright 2019 xgfone
//
// 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 execution executes a command line program in a new process and returns a output.
package execution

import "context"

// DefaultCmd is the global default cmd executor.
var DefaultCmd = NewCmd()

// AppendHooks is equal to DefaultCmd.AppendHook(hooks...).
func AppendHooks(hooks ...Hook) {
	DefaultCmd.AppendHooks(hooks...)
}

// RunCmd is equal to DefaultCmd.RunCmd(ctx, name, args...).
func RunCmd(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.RunCmd(ctx, name, args...)
}

// Run is the alias of RunCmd.
func Run(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.Run(ctx, name, args...)
}

// RetryRunCmd is equal to DefaultCmd.RetryRunCmd(ctx, name, args...).
func RetryRunCmd(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.RetryRunCmd(ctx, name, args...)
}

// Execute is equal to DefaultCmd.Execute(cxt, name, args...).
func Execute(cxt context.Context, name string, args ...string) error {
	return DefaultCmd.Execute(cxt, name, args...)
}

// Output is equal to DefaultCmd.Output(cxt, name, args...).
func Output(cxt context.Context, name string, args ...string) (string, error) {
	return DefaultCmd.Output(cxt, name, args...)
}

// Executes is equal to DefaultCmd.Executes(cxt, cmds).
func Executes(cxt context.Context, cmds []string) error {
	return DefaultCmd.Executes(cxt, cmds)
}

// Outputs is equal to DefaultCmd.Outputs(cxt, cmds).
func Outputs(cxt context.Context, cmds []string) (string, error) {
	return DefaultCmd.Outputs(cxt, cmds)
}
<commit_msg>add the global function AppendResultHooks<commit_after>// Copyright 2019 xgfone
//
// 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 execution executes a command line program in a new process and returns a output.
package execution

import "context"

// DefaultCmd is the global default cmd executor.
var DefaultCmd = NewCmd()

// AppendHooks is equal to DefaultCmd.AppendHook(hooks...).
func AppendHooks(hooks ...Hook) {
	DefaultCmd.AppendHooks(hooks...)
}

// AppendResultHooks is equal to DefaultCmd.AppendResultHooks(hooks...).
func AppendResultHooks(hooks ...ResultHook) {
	DefaultCmd.AppendResultHooks(hooks...)
}

// RunCmd is equal to DefaultCmd.RunCmd(ctx, name, args...).
func RunCmd(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.RunCmd(ctx, name, args...)
}

// Run is the alias of RunCmd.
func Run(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.Run(ctx, name, args...)
}

// RetryRunCmd is equal to DefaultCmd.RetryRunCmd(ctx, name, args...).
func RetryRunCmd(ctx context.Context, name string, args ...string) (stdout, stderr []byte, err error) {
	return DefaultCmd.RetryRunCmd(ctx, name, args...)
}

// Execute is equal to DefaultCmd.Execute(cxt, name, args...).
func Execute(cxt context.Context, name string, args ...string) error {
	return DefaultCmd.Execute(cxt, name, args...)
}

// Output is equal to DefaultCmd.Output(cxt, name, args...).
func Output(cxt context.Context, name string, args ...string) (string, error) {
	return DefaultCmd.Output(cxt, name, args...)
}

// Executes is equal to DefaultCmd.Executes(cxt, cmds).
func Executes(cxt context.Context, cmds []string) error {
	return DefaultCmd.Executes(cxt, cmds)
}

// Outputs is equal to DefaultCmd.Outputs(cxt, cmds).
func Outputs(cxt context.Context, cmds []string) (string, error) {
	return DefaultCmd.Outputs(cxt, cmds)
}
<|endoftext|>


<commit_before>package contract

import "fmt"

var SuppressPanic bool = false

func shoutAndPanic(descr string) {
	err := fmt.Errorf(descr)
	if SuppressPanic {
		fmt.Println(err)
	} else {
		panic(err)
	}
}

func shoutAndPanicIf(orly bool, descr string) {
	if orly {
		shoutAndPanic(descr)
	}
}

func Require(success bool, descr string) {
	if !success {
		descr := fmt.Sprintf("Input contract not met: %s", descr)
		shoutAndPanic(descr)
	}
}

func MustBeTrue(success bool, descr string) {
	shoutAndPanicIf(success == true, descr)
}

func MustNotBeNil(v interface{}, descr string) {
	shoutAndPanicIf(v == nil, descr)
}

func MustBeNil(v interface{}, descr string) {
	shoutAndPanicIf(v != nil, descr)
}

func RequireArg(v interface{}) {
	MustNotBeNil(v, "nil passed instead of real value")
}

func MustBeFalse(success bool, descr string) {
	shoutAndPanicIf(success == false, descr)
}

func RequireNoError(err error, intent string) {
	if err != nil {
		descr := fmt.Sprintf("Required no error to do: %s, but got: %s", intent, err.Error())
		shoutAndPanic(descr)
	}
}

func Guarantee(success bool, descr string) {
	if !success {
		descr := fmt.Sprintf("Output contract not met: %s", descr)
		shoutAndPanic(descr)
	}
}
<commit_msg>add error formatting<commit_after>package contract

import "fmt"

var SuppressPanic bool = false

func shoutAndPanic(descrf ...string) {
	var err error
	if len(descrf) == 0 {
		err = fmt.Errorf("failed to meet the contract")
	} else {
		if len(descrf) == 1 {
			err = fmt.Errorf(descrf[0])
		} else {
			fmtargs := make([]interface{}, len(descrf[1:]))
			for i, v := range descrf[1:] {
				fmtargs[i] = interface{}(v)
			}
			err = fmt.Errorf(descrf[0], fmtargs...)
		}
	}
	if SuppressPanic {
		fmt.Println(err)
	} else {
		panic(err)
	}
}

func shoutAndPanicIf(orly bool, descrf ...string) {
	if orly {
		shoutAndPanic(descrf...)
	}
}

func Require(success bool, descrf ...string) {
	shoutAndPanicIf(!success, descrf...)
}

func MustBeTrue(success bool, descrf ...string) {
	shoutAndPanicIf(success == true, descrf...)
}

func MustNotBeNil(v interface{}, descrf ...string) {
	shoutAndPanicIf(v == nil, descrf...)
}

func MustBeNil(v interface{}, descrf ...string) {
	shoutAndPanicIf(v != nil, descrf...)
}

func RequireArg(v interface{}, descrf ...string) {
	if len(descrf) == 0 {
		descrf = []string{"nil passed instead of real value"}
	}
	MustNotBeNil(v, descrf...)
}

func MustBeFalse(success bool, descrf ...string) {
	shoutAndPanicIf(success == false, descrf...)
}

func RequireNoError(err error, descrf ...string) {
	shoutAndPanicIf(err != nil, descrf...)
}

func Guarantee(success bool, descrf ...string) {
	shoutAndPanicIf(!success, descrf...)
}
<|endoftext|>


<commit_before>// package wfilter provides facilities for adding filtering to io.Writer.
package wfilter

import (
	"bytes"
	"io"
)

type Prepend func(w io.Writer) (int, error)

// lines creates a filtering writer that filters on a line by line basis using
// the given filterFunc. FilterFunc is given the string for the current line
// along with the original writer, and it can write whatever it wants. It should
// return the bytes written and any error encountered.
func LinePrepender(w io.Writer, prepend Prepend) io.Writer {
	return &lp{w, prepend}
}

type lp struct {
	io.Writer
	prepend Prepend
}

func (w *lp) Write(buf []byte) (int, error) {
	totalN := 0
	for {
		_, err := w.prepend(w.Writer)
		if err != nil {
			return totalN, err
		}
		i := bytes.IndexRune(buf, '\n') + 1
		isLastLine := (i == len(buf))
		n, err := w.Writer.Write(buf[:i])
		totalN += n
		if err != nil || isLastLine {
			return totalN, err
		}
		buf = buf[i:]
	}
}
<commit_msg>Revert "do...while() version of wfilter Write()"<commit_after>// package wfilter provides facilities for adding filtering to io.Writer.
package wfilter

import (
	"bytes"
	"io"
)

type Prepend func(w io.Writer) (int, error)

// lines creates a filtering writer that filters on a line by line basis using
// the given filterFunc. FilterFunc is given the string for the current line
// along with the original writer, and it can write whatever it wants. It should
// return the bytes written and any error encountered.
func LinePrepender(w io.Writer, prepend Prepend) io.Writer {
	return &lp{w, prepend, true}
}

type lp struct {
	io.Writer
	prepend       Prepend
	prependNeeded bool
}

func (w *lp) Write(buf []byte) (int, error) {
	if w.prependNeeded {
		_, err := w.prepend(w.Writer)
		if err != nil {
			return 0, err
		}
		w.prependNeeded = false
	}

	// Prepend before every newline in the buffer
	totalN := 0

	for {
		i := bytes.IndexRune(buf, '\n') + 1
		if i > 0 {
			if i < len(buf) {
				// Newline is in middle of buffer
				// Write up to newline
				n, err := w.Writer.Write(buf[:i])
				totalN += n
				if err != nil {
					return totalN, err
				}
				// Add prepend
				_, err = w.prepend(w.Writer)
				if err != nil {
					return totalN, err
				}
				// Remove processed portion of buffer
				buf = buf[i:]
				continue
			}
			// Newline is at end of buffer, mark prependNeeded for next write
			w.prependNeeded = true
		}
		break
	}

	n, err := w.Writer.Write(buf)
	totalN += n
	return totalN, err
}
<|endoftext|>


<commit_before>package main

import (
	"strings"
	"time"

	"github.com/ninjasphere/go-hue"
	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/logger"
)

var log = logger.GetLogger("hue")

func getBridge() *hue.Bridge {
	nobridge := true
	var allbridges []*hue.Bridge
	var err error
	for nobridge {
		allbridges, err = hue.FindBridgesUsingCloud()
		if err != nil {
			//log.Infof("Warning: Failed finding bridges using cloud (%s). Falling back to ssdp.", err)
			allbridges, _ = hue.FindBridges()
		}
		if len(allbridges) == 0 {
			time.Sleep(time.Second * 5) //this sucks
		} else {
			nobridge = false
			log.Infof("Found %d bridges: %s", len(allbridges), allbridges)
		}
	}
	return allbridges[0]
}

var pushButtonNotification = channels.Notification{
	Title:    "Please press the pairing button on your Philips Hue base-station",
	Subtitle: "New Hue base-station found",
	Priority: channels.NotificationPriorityDefault,
	Category: channels.NotificationCategorySuggestion,
}

func getUser(driver *HueDriver, bridge *hue.Bridge) *hue.User {
	var user *hue.User
	var err error
	noUser := true
	retries := 0
	serial := config.Serial()
	username := serial + serial //username must be long 10-40 characters
	isvaliduser, err := bridge.IsValidUser(username)
	if err != nil {
		log.Warningf("Problem determining if hue user is valid")
	}

	var notificationTime time.Time

	if isvaliduser {
		user = hue.NewUserWithBridge(username, bridge)
	} else {
		for noUser {
			user, err = bridge.CreateUser("ninjadevice", username)
			if err != nil {
				if strings.Contains(err.Error(), "101") { // there's probably a nicer way to check this
					retries++
					log.Infof("Couldn't make user, push link button. Retry: %d", retries)

					if time.Since(notificationTime) < time.Minute*5 {
						notificationTime = time.Now()
						driver.sendEvent("notification", pushButtonNotification)
					}

					time.Sleep(time.Second * 2) //this sucks

				} else {
					log.Debugf("Error creating user %s", err)
					time.Sleep(time.Second * 20)
				}
			}

			if user != nil {
				noUser = false
			}
		}
	}
	return user
}
<commit_msg>< != ><commit_after>package main

import (
	"strings"
	"time"

	"github.com/ninjasphere/go-hue"
	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/go-ninja/logger"
)

var log = logger.GetLogger("hue")

func getBridge() *hue.Bridge {
	nobridge := true
	var allbridges []*hue.Bridge
	var err error
	for nobridge {
		allbridges, err = hue.FindBridgesUsingCloud()
		if err != nil {
			//log.Infof("Warning: Failed finding bridges using cloud (%s). Falling back to ssdp.", err)
			allbridges, _ = hue.FindBridges()
		}
		if len(allbridges) == 0 {
			time.Sleep(time.Second * 5) //this sucks
		} else {
			nobridge = false
			log.Infof("Found %d bridges: %s", len(allbridges), allbridges)
		}
	}
	return allbridges[0]
}

var pushButtonNotification = channels.Notification{
	Title:    "Please press the pairing button on your Philips Hue base-station",
	Subtitle: "New Hue base-station found",
	Priority: channels.NotificationPriorityDefault,
	Category: channels.NotificationCategorySuggestion,
}

func getUser(driver *HueDriver, bridge *hue.Bridge) *hue.User {
	var user *hue.User
	var err error
	noUser := true
	retries := 0
	serial := config.Serial()
	username := serial + serial //username must be long 10-40 characters
	isvaliduser, err := bridge.IsValidUser(username)
	if err != nil {
		log.Warningf("Problem determining if hue user is valid")
	}

	var notificationTime time.Time

	if isvaliduser {
		user = hue.NewUserWithBridge(username, bridge)
	} else {
		for noUser {
			user, err = bridge.CreateUser("ninjadevice", username)
			if err != nil {
				if strings.Contains(err.Error(), "101") { // there's probably a nicer way to check this
					retries++
					log.Infof("Couldn't make user, push link button. Retry: %d", retries)

					if time.Since(notificationTime) > time.Minute*5 {
						notificationTime = time.Now()
						driver.sendEvent("notification", pushButtonNotification)
					}

					time.Sleep(time.Second * 2) //this sucks

				} else {
					log.Debugf("Error creating user %s", err)
					time.Sleep(time.Second * 20)
				}
			}

			if user != nil {
				noUser = false
			}
		}
	}
	return user
}
<|endoftext|>


<commit_before>package influxdb

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/influxdb/influxdb/messaging"
)

const (
	// DefaultContinuousQueryCheckTime is how frequently the broker will ask a data node
	// in the cluster to run any continuous queries that should be run.
	DefaultContinuousQueryCheckTime = 1 * time.Second

	// DefaultDataNodeTimeout is how long the broker will wait before timing out on a data node
	// that it has requested process continuous queries.
	DefaultDataNodeTimeout = 1 * time.Second

	// DefaultFailureSleep is how long the broker will sleep before trying the next data node in
	// the cluster if the current data node failed to respond
	DefaultFailureSleep = 100 * time.Millisecond
)

// Broker represents an InfluxDB specific messaging broker.
type Broker struct {
	*messaging.Broker

	done chan struct{}

	// send CQ processing requests to the same data node
	currentCQProcessingNode *url.URL

	// variables to control when to trigger processing and when to timeout
	TriggerInterval     time.Duration
	TriggerTimeout      time.Duration
	TriggerFailurePause time.Duration
}

// NewBroker returns a new instance of a Broker with default values.
func NewBroker() *Broker {
	return &Broker{
		Broker:              messaging.NewBroker(),
		TriggerInterval:     5 * time.Second,
		TriggerTimeout:      20 * time.Second,
		TriggerFailurePause: 1 * time.Second,
	}
}

// RunContinuousQueryLoop starts running continuous queries on a background goroutine.
func (b *Broker) RunContinuousQueryLoop() {
	log.Println("and...")
	b.done = make(chan struct{})
	log.Println("boom!")
	go b.continuousQueryLoop(b.done)
}

// Close closes the broker.
func (b *Broker) Close() error {
	if b.done != nil {
		close(b.done)
		b.done = nil
	}
	return b.Broker.Close()
}

func (b *Broker) continuousQueryLoop(done chan struct{}) {
	for {
		// Check if broker is currently leader.
		if b.Broker.IsLeader() {
			b.runContinuousQueries()
		}

		// Sleep until either the broker is closed or we need to run continuous queries again
		select {
		case <-done:
			return
		case <-time.After(DefaultContinuousQueryCheckTime):
		}
	}
}

func (b *Broker) runContinuousQueries() {
	next := 0
	for {
		// if the current node hasn't been set it's our first time or we're reset. move to the next one
		if b.currentCQProcessingNode == nil {
			topic := b.Broker.Topic(BroadcastTopicID)
			if topic == nil {
				log.Println("broker cq: no topics currently available.")
				return // don't have any nodes to try, give it up
			}
			dataURLs := topic.DataURLs()
			if len(dataURLs) == 0 {
				log.Println("broker cq: no data nodes currently available.")
				return // don't have any nodes to try, give it up
			}
			next = next % len(dataURLs)
			u := dataURLs[next]
			b.currentCQProcessingNode = &u
			next++
		}

		// if no error, we're all good
		err := b.requestContinuousQueryProcessing()
		if err == nil {
			return
		}
		log.Printf("broker cq: error hitting data node: %s: %s\n", b.currentCQProcessingNode, err.Error())

		// reset and let the loop try the next data node in the cluster
		b.currentCQProcessingNode = nil
		<-time.After(DefaultFailureSleep)
	}
}

func (b *Broker) requestContinuousQueryProcessing() error {
	// Send request.
	cqURL := copyURL(b.currentCQProcessingNode)
	cqURL.Path = "/process_continuous_queries"
	cqURL.Scheme = "http"
	client := &http.Client{
		Timeout: DefaultDataNodeTimeout,
	}
	resp, err := client.Post(cqURL.String(), "application/octet-stream", nil)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Check if created.
	if resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("request returned status %s", resp.Status)
	}

	return nil
}
<commit_msg>remove debugging<commit_after>package influxdb

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"time"

	"github.com/influxdb/influxdb/messaging"
)

const (
	// DefaultContinuousQueryCheckTime is how frequently the broker will ask a data node
	// in the cluster to run any continuous queries that should be run.
	DefaultContinuousQueryCheckTime = 1 * time.Second

	// DefaultDataNodeTimeout is how long the broker will wait before timing out on a data node
	// that it has requested process continuous queries.
	DefaultDataNodeTimeout = 1 * time.Second

	// DefaultFailureSleep is how long the broker will sleep before trying the next data node in
	// the cluster if the current data node failed to respond
	DefaultFailureSleep = 100 * time.Millisecond
)

// Broker represents an InfluxDB specific messaging broker.
type Broker struct {
	*messaging.Broker

	done chan struct{}

	// send CQ processing requests to the same data node
	currentCQProcessingNode *url.URL

	// variables to control when to trigger processing and when to timeout
	TriggerInterval     time.Duration
	TriggerTimeout      time.Duration
	TriggerFailurePause time.Duration
}

// NewBroker returns a new instance of a Broker with default values.
func NewBroker() *Broker {
	return &Broker{
		Broker:              messaging.NewBroker(),
		TriggerInterval:     5 * time.Second,
		TriggerTimeout:      20 * time.Second,
		TriggerFailurePause: 1 * time.Second,
	}
}

// RunContinuousQueryLoop starts running continuous queries on a background goroutine.
func (b *Broker) RunContinuousQueryLoop() {
	b.done = make(chan struct{})
	go b.continuousQueryLoop(b.done)
}

// Close closes the broker.
func (b *Broker) Close() error {
	if b.done != nil {
		close(b.done)
		b.done = nil
	}
	return b.Broker.Close()
}

func (b *Broker) continuousQueryLoop(done chan struct{}) {
	for {
		// Check if broker is currently leader.
		if b.Broker.IsLeader() {
			b.runContinuousQueries()
		}

		// Sleep until either the broker is closed or we need to run continuous queries again
		select {
		case <-done:
			return
		case <-time.After(DefaultContinuousQueryCheckTime):
		}
	}
}

func (b *Broker) runContinuousQueries() {
	next := 0
	for {
		// if the current node hasn't been set it's our first time or we're reset. move to the next one
		if b.currentCQProcessingNode == nil {
			topic := b.Broker.Topic(BroadcastTopicID)
			if topic == nil {
				log.Println("broker cq: no topics currently available.")
				return // don't have any nodes to try, give it up
			}
			dataURLs := topic.DataURLs()
			if len(dataURLs) == 0 {
				log.Println("broker cq: no data nodes currently available.")
				return // don't have any nodes to try, give it up
			}
			next = next % len(dataURLs)
			u := dataURLs[next]
			b.currentCQProcessingNode = &u
			next++
		}

		// if no error, we're all good
		err := b.requestContinuousQueryProcessing()
		if err == nil {
			return
		}
		log.Printf("broker cq: error hitting data node: %s: %s\n", b.currentCQProcessingNode, err.Error())

		// reset and let the loop try the next data node in the cluster
		b.currentCQProcessingNode = nil
		<-time.After(DefaultFailureSleep)
	}
}

func (b *Broker) requestContinuousQueryProcessing() error {
	// Send request.
	cqURL := copyURL(b.currentCQProcessingNode)
	cqURL.Path = "/process_continuous_queries"
	cqURL.Scheme = "http"
	client := &http.Client{
		Timeout: DefaultDataNodeTimeout,
	}
	resp, err := client.Post(cqURL.String(), "application/octet-stream", nil)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// Check if created.
	if resp.StatusCode != http.StatusAccepted {
		return fmt.Errorf("request returned status %s", resp.Status)
	}

	return nil
}
<|endoftext|>


<commit_before>// Package client handles calls from the CLI calls
package client

import (
	"context"
	"fmt"
	"os"
	"time"

	ccli "github.com/micro/cli/v2"
	"github.com/micro/go-micro/v2/auth"
	srvAuth "github.com/micro/go-micro/v2/auth/service"
	"github.com/micro/go-micro/v2/client"
	"github.com/micro/go-micro/v2/client/grpc"
	"github.com/micro/go-micro/v2/config/cmd"
	"github.com/micro/go-micro/v2/metadata"
	"github.com/micro/micro/v2/client/cli/namespace"
	clitoken "github.com/micro/micro/v2/client/cli/token"
	cliutil "github.com/micro/micro/v2/client/cli/util"
)

// New returns a wrapped grpc client which will inject the
// token found in config into each request
func New(ctx *ccli.Context) client.Client {
	env := cliutil.GetEnv(ctx)
	ns, _ := namespace.Get(env.Name)
	client := &wrapper{
		Client:       grpc.NewClient(),
		token:        "",
		ns:           ns,
		proxyAddress: env.ProxyAddress,
		envName:      env.Name,
		context:      ctx,
	}
	err := client.getAccessToken(env.Name, ctx)
	if err != nil {
		// @todo this is veeery ugly being here
		fmt.Println("Error getting auth token:", err)
		os.Exit(1)
	}
	return client
}

type wrapper struct {
	client.Client
	token        string
	ns           string
	proxyAddress string
	envName      string
	context      *ccli.Context
}

func (a *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	if len(a.token) > 0 {
		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+a.token)
	}
	if len(a.proxyAddress) > 0 {
		opts = append(opts, client.WithAddress(a.proxyAddress))
	}
	ctx = metadata.Set(ctx, "Micro-Namespace", a.ns)
	return a.Client.Call(ctx, req, rsp, opts...)
}

func (a *wrapper) authFromContext(ctx *ccli.Context) auth.Auth {
	if cliutil.IsLocal(ctx) {
		return *cmd.DefaultCmd.Options().Auth
	}
	return srvAuth.NewAuth(
		auth.WithClient(a),
	)
}

// getAccessToken handles exchanging refresh tokens to access tokens
// The structure of the local micro userconfig file is the following:
// micro.auth.[envName].token: temporary access token
// micro.auth.[envName].refresh-token: long lived refresh token
// micro.auth.[envName].expiry: expiration time of the access token, seconds since Unix epoch.
func (a *wrapper) getAccessToken(envName string, ctx *ccli.Context) error {
	tok, err := clitoken.Get(envName)
	if err != nil {
		return err
	}

	// Save the access token so it's usable for calls
	a.token = tok.AccessToken

	// If there is no refresh token, do not try to refresh it
	if len(tok.RefreshToken) == 0 {
		return nil
	}

	// Check if token must be refreshed
	if time.Now().Before(tok.Expiry.Add(-15 * time.Second)) {
		return nil
	}

	// Get new access token from refresh token if it's close to expiry
	tok, err = a.authFromContext(a.context).Token(auth.WithToken(tok.RefreshToken))
	if err != nil {
		return err
	}

	// Save the new access token
	a.token = tok.AccessToken

	// Save the token to user config file
	return clitoken.Save(envName, tok)
}
<commit_msg>internal/client: fix stream without auth (#1059)<commit_after>// Package client handles calls from the CLI calls
package client

import (
	"context"
	"fmt"
	"os"
	"time"

	ccli "github.com/micro/cli/v2"
	"github.com/micro/go-micro/v2/auth"
	srvAuth "github.com/micro/go-micro/v2/auth/service"
	"github.com/micro/go-micro/v2/client"
	"github.com/micro/go-micro/v2/client/grpc"
	"github.com/micro/go-micro/v2/config/cmd"
	"github.com/micro/go-micro/v2/metadata"
	"github.com/micro/micro/v2/client/cli/namespace"
	clitoken "github.com/micro/micro/v2/client/cli/token"
	cliutil "github.com/micro/micro/v2/client/cli/util"
)

// New returns a wrapped grpc client which will inject the
// token found in config into each request
func New(ctx *ccli.Context) client.Client {
	env := cliutil.GetEnv(ctx)
	ns, _ := namespace.Get(env.Name)
	client := &wrapper{
		Client:       grpc.NewClient(),
		token:        "",
		ns:           ns,
		proxyAddress: env.ProxyAddress,
		envName:      env.Name,
		context:      ctx,
	}
	err := client.getAccessToken(env.Name, ctx)
	if err != nil {
		// @todo this is veeery ugly being here
		fmt.Println("Error getting auth token:", err)
		os.Exit(1)
	}
	return client
}

type wrapper struct {
	client.Client
	token        string
	ns           string
	proxyAddress string
	envName      string
	context      *ccli.Context
}

func (a *wrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
	if len(a.token) > 0 {
		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+a.token)
	}
	if len(a.proxyAddress) > 0 {
		opts = append(opts, client.WithAddress(a.proxyAddress))
	}
	ctx = metadata.Set(ctx, "Micro-Namespace", a.ns)
	return a.Client.Stream(ctx, req, opts...)
}

func (a *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	if len(a.token) > 0 {
		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+a.token)
	}
	if len(a.proxyAddress) > 0 {
		opts = append(opts, client.WithAddress(a.proxyAddress))
	}
	ctx = metadata.Set(ctx, "Micro-Namespace", a.ns)
	return a.Client.Call(ctx, req, rsp, opts...)
}

func (a *wrapper) authFromContext(ctx *ccli.Context) auth.Auth {
	if cliutil.IsLocal(ctx) {
		return *cmd.DefaultCmd.Options().Auth
	}
	return srvAuth.NewAuth(
		auth.WithClient(a),
	)
}

// getAccessToken handles exchanging refresh tokens to access tokens
// The structure of the local micro userconfig file is the following:
// micro.auth.[envName].token: temporary access token
// micro.auth.[envName].refresh-token: long lived refresh token
// micro.auth.[envName].expiry: expiration time of the access token, seconds since Unix epoch.
func (a *wrapper) getAccessToken(envName string, ctx *ccli.Context) error {
	tok, err := clitoken.Get(envName)
	if err != nil {
		return err
	}

	// Save the access token so it's usable for calls
	a.token = tok.AccessToken

	// If there is no refresh token, do not try to refresh it
	if len(tok.RefreshToken) == 0 {
		return nil
	}

	// Check if token must be refreshed
	if time.Now().Before(tok.Expiry.Add(-15 * time.Second)) {
		return nil
	}

	// Get new access token from refresh token if it's close to expiry
	tok, err = a.authFromContext(a.context).Token(auth.WithToken(tok.RefreshToken))
	if err != nil {
		return err
	}

	// Save the new access token
	a.token = tok.AccessToken

	// Save the token to user config file
	return clitoken.Save(envName, tok)
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"net/url"
	"os"

	"github.com/apex/log"
	"github.com/google/go-github/github"
	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"golang.org/x/oauth2"
)

type githubClient struct {
	client *github.Client
}

// NewGitHub returns a github client implementation
func NewGitHub(ctx *context.Context) (Client, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: ctx.Token},
	)
	client := github.NewClient(oauth2.NewClient(ctx, ts))
	if ctx.Config.GitHubURLs.API != "" {
		api, err := url.Parse(ctx.Config.GitHubURLs.API)
		if err != nil {
			return &githubClient{}, err
		}
		upload, err := url.Parse(ctx.Config.GitHubURLs.Upload)
		if err != nil {
			return &githubClient{}, err
		}
		client.BaseURL = api
		client.UploadURL = upload
	}

	return &githubClient{client}, nil
}

func (c *githubClient) CreateFile(
	ctx *context.Context,
	commitAuthor config.CommitAuthor,
	repo config.Repo,
	content bytes.Buffer,
	path string,
	message string,
) error {
	options := &github.RepositoryContentFileOptions{
		Committer: &github.CommitAuthor{
			Name:  github.String(commitAuthor.Name),
			Email: github.String(commitAuthor.Email),
		},
		Content: content.Bytes(),
		Message: github.String(message),
	}

	file, _, res, err := c.client.Repositories.GetContents(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		&github.RepositoryContentGetOptions{},
	)
	if err != nil && res.StatusCode != 404 {
		return err
	}

	if res.StatusCode == 404 {
		_, _, err = c.client.Repositories.CreateFile(
			ctx,
			repo.Owner,
			repo.Name,
			path,
			options,
		)
		return err
	}
	options.SHA = file.SHA
	_, _, err = c.client.Repositories.UpdateFile(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		options,
	)
	return err
}

func (c *githubClient) CreateRelease(ctx *context.Context, body string) (int64, error) {
	var release *github.RepositoryRelease
	title, err := releaseTitle(ctx)
	if err != nil {
		return 0, err
	}
	var data = &github.RepositoryRelease{
		Name:       github.String(title),
		TagName:    github.String(ctx.Git.CurrentTag),
		Body:       github.String(body),
		Draft:      github.Bool(ctx.Config.Release.Draft),
		Prerelease: github.Bool(ctx.Config.Release.Prerelease),
	}
	release, _, err = c.client.Repositories.GetReleaseByTag(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		ctx.Git.CurrentTag,
	)
	if err != nil {
		release, _, err = c.client.Repositories.CreateRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			data,
		)
	} else {
		release, _, err = c.client.Repositories.EditRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			release.GetID(),
			data,
		)
	}
	log.WithField("url", release.GetHTMLURL()).Info("release updated")
	return release.GetID(), err
}

func (c *githubClient) Upload(
	ctx *context.Context,
	releaseID int64,
	name string,
	file *os.File,
) error {
	_, _, err := c.client.Repositories.UploadReleaseAsset(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		releaseID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	return err
}
<commit_msg>feat: Create new tags for GitHub release (#643)<commit_after>package client

import (
	"bytes"
	"net/url"
	"os"

	"github.com/apex/log"
	"github.com/google/go-github/github"
	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"golang.org/x/oauth2"
)

type githubClient struct {
	client *github.Client
}

// NewGitHub returns a github client implementation
func NewGitHub(ctx *context.Context) (Client, error) {
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: ctx.Token},
	)
	client := github.NewClient(oauth2.NewClient(ctx, ts))
	if ctx.Config.GitHubURLs.API != "" {
		api, err := url.Parse(ctx.Config.GitHubURLs.API)
		if err != nil {
			return &githubClient{}, err
		}
		upload, err := url.Parse(ctx.Config.GitHubURLs.Upload)
		if err != nil {
			return &githubClient{}, err
		}
		client.BaseURL = api
		client.UploadURL = upload
	}

	return &githubClient{client}, nil
}

func (c *githubClient) CreateFile(
	ctx *context.Context,
	commitAuthor config.CommitAuthor,
	repo config.Repo,
	content bytes.Buffer,
	path string,
	message string,
) error {
	options := &github.RepositoryContentFileOptions{
		Committer: &github.CommitAuthor{
			Name:  github.String(commitAuthor.Name),
			Email: github.String(commitAuthor.Email),
		},
		Content: content.Bytes(),
		Message: github.String(message),
	}

	file, _, res, err := c.client.Repositories.GetContents(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		&github.RepositoryContentGetOptions{},
	)
	if err != nil && res.StatusCode != 404 {
		return err
	}

	if res.StatusCode == 404 {
		_, _, err = c.client.Repositories.CreateFile(
			ctx,
			repo.Owner,
			repo.Name,
			path,
			options,
		)
		return err
	}
	options.SHA = file.SHA
	_, _, err = c.client.Repositories.UpdateFile(
		ctx,
		repo.Owner,
		repo.Name,
		path,
		options,
	)
	return err
}

func (c *githubClient) CreateRelease(ctx *context.Context, body string) (int64, error) {
	var release *github.RepositoryRelease
	title, err := releaseTitle(ctx)
	if err != nil {
		return 0, err
	}
	var data = &github.RepositoryRelease{
		Name:            github.String(title),
		TagName:         github.String(ctx.Git.CurrentTag),
		TargetCommitish: github.String(ctx.Git.Commit),
		Body:            github.String(body),
		Draft:           github.Bool(ctx.Config.Release.Draft),
		Prerelease:      github.Bool(ctx.Config.Release.Prerelease),
	}
	release, _, err = c.client.Repositories.GetReleaseByTag(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		ctx.Git.CurrentTag,
	)
	if err != nil {
		release, _, err = c.client.Repositories.CreateRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			data,
		)
	} else {
		release, _, err = c.client.Repositories.EditRelease(
			ctx,
			ctx.Config.Release.GitHub.Owner,
			ctx.Config.Release.GitHub.Name,
			release.GetID(),
			data,
		)
	}
	log.WithField("url", release.GetHTMLURL()).Info("release updated")
	return release.GetID(), err
}

func (c *githubClient) Upload(
	ctx *context.Context,
	releaseID int64,
	name string,
	file *os.File,
) error {
	_, _, err := c.client.Repositories.UploadReleaseAsset(
		ctx,
		ctx.Config.Release.GitHub.Owner,
		ctx.Config.Release.GitHub.Name,
		releaseID,
		&github.UploadOptions{
			Name: name,
		},
		file,
	)
	return err
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"time"

	"github.com/juju/fslock"
	conf "github.com/micro/go-micro/v3/config"
	"github.com/micro/go-micro/v3/config/source/file"
)

var (
	// FileName for global micro config
	FileName = ".micro/config.json"

	path, _ = filePath()

	// a global lock for the config
	lock = fslock.New(path)
)

// config is a singleton which is required to ensure
// each function call doesn't load the .micro file
// from disk

// Get a value from the .micro file
func Get(path ...string) (string, error) {
	config, err := newConfig()
	if err != nil {
		return "", err
	}

	// acquire lock
	if err := lock.LockWithTimeout(time.Second); err != nil {
		return "", err
	}
	defer lock.Unlock()

	val := config.Get(path...)
	v := strings.TrimSpace(val.String(""))
	if len(v) > 0 {
		return v, nil
	}

	// try as bytes
	v = string(val.Bytes())
	v = strings.TrimSpace(v)

	// don't return nil decoded value
	if v == "null" {
		return "", nil
	}

	return v, nil
}

// Set a value in the .micro file
func Set(value string, path ...string) error {
	// get the filepath
	fp, err := filePath()
	if err != nil {
		return err
	}

	config, err := newConfig()
	if err != nil {
		return err
	}

	// acquire lock
	if err := lock.LockWithTimeout(time.Second); err != nil {
		return err
	}
	defer lock.Unlock()

	// set the value
	config.Set(value, path...)

	// write to the file
	return ioutil.WriteFile(fp, config.Bytes(), 0644)
}

func filePath() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return filepath.Join(usr.HomeDir, FileName), nil
}

func moveConfig(from, to string) error {
	// read the config
	b, err := ioutil.ReadFile(from)
	if err != nil {
		return fmt.Errorf("Failed to read config file %s: %v", from, err)
	}
	// remove the file
	os.Remove(from)

	// create new directory
	dir := filepath.Dir(to)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
	}
	// write the file to new location
	return ioutil.WriteFile(to, b, 0644)
}

// newConfig returns a loaded config
func newConfig() (conf.Config, error) {
	// get the filepath
	fp, err := filePath()
	if err != nil {
		return nil, err
	}

	// check if the directory exists, otherwise create it
	dir := filepath.Dir(fp)

	// for legacy purposes check if .micro is a file or directory
	if f, err := os.Stat(dir); err != nil {
		// check the error to see if the directory exists
		if os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				return nil, fmt.Errorf("Failed to create dir %s: %v", dir, err)
			}
		} else {
			return nil, fmt.Errorf("Failed to create config dir %s: %v", dir, err)
		}
	} else {
		// if not a directory, copy and move the config
		if !f.IsDir() {
			if err := moveConfig(dir, fp); err != nil {
				return nil, fmt.Errorf("Failed to move config from %s to %s: %v", dir, fp, err)
			}
		}
	}

	// now write the file if it does not exist
	if _, err := os.Stat(fp); os.IsNotExist(err) {
		ioutil.WriteFile(fp, []byte(`{}`), 0644)
	} else if err != nil {
		return nil, fmt.Errorf("Failed to write config file %s: %v", fp, err)
	}

	// create a new config
	c, err := conf.NewConfig(
		conf.WithSource(
			file.NewSource(
				file.WithPath(fp),
			),
		),
	)
	if err != nil {
		return nil, err
	}

	// load the config
	if err := c.Load(); err != nil {
		return nil, err
	}

	// return the conf
	return c, nil
}
<commit_msg>single threaded locking for config<commit_after>package config

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/juju/fslock"
	conf "github.com/micro/go-micro/v3/config"
	"github.com/micro/go-micro/v3/config/source/file"
)

var (
	// FileName for global micro config
	FileName = ".micro/config.json"

	path, _ = filePath()

	// a global lock for the config
	lock = fslock.New(path)

	// lock in single process
	mtx sync.Mutex
)

// config is a singleton which is required to ensure
// each function call doesn't load the .micro file
// from disk

// Get a value from the .micro file
func Get(path ...string) (string, error) {
	mtx.Lock()
	defer mtx.Unlock()

	config, err := newConfig()
	if err != nil {
		return "", err
	}

	// acquire lock
	if err := lock.LockWithTimeout(time.Second); err != nil {
		return "", err
	}
	defer lock.Unlock()

	val := config.Get(path...)
	v := strings.TrimSpace(val.String(""))
	if len(v) > 0 {
		return v, nil
	}

	// try as bytes
	v = string(val.Bytes())
	v = strings.TrimSpace(v)

	// don't return nil decoded value
	if v == "null" {
		return "", nil
	}

	return v, nil
}

// Set a value in the .micro file
func Set(value string, path ...string) error {
	mtx.Lock()
	defer mtx.Unlock()

	// get the filepath
	fp, err := filePath()
	if err != nil {
		return err
	}

	config, err := newConfig()
	if err != nil {
		return err
	}

	// acquire lock
	if err := lock.LockWithTimeout(time.Second); err != nil {
		return err
	}
	defer lock.Unlock()

	// set the value
	config.Set(value, path...)

	// write to the file
	return ioutil.WriteFile(fp, config.Bytes(), 0644)
}

func filePath() (string, error) {
	usr, err := user.Current()
	if err != nil {
		return "", err
	}
	return filepath.Join(usr.HomeDir, FileName), nil
}

func moveConfig(from, to string) error {
	// read the config
	b, err := ioutil.ReadFile(from)
	if err != nil {
		return fmt.Errorf("Failed to read config file %s: %v", from, err)
	}
	// remove the file
	os.Remove(from)

	// create new directory
	dir := filepath.Dir(to)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
	}
	// write the file to new location
	return ioutil.WriteFile(to, b, 0644)
}

// newConfig returns a loaded config
func newConfig() (conf.Config, error) {
	// get the filepath
	fp, err := filePath()
	if err != nil {
		return nil, err
	}

	// check if the directory exists, otherwise create it
	dir := filepath.Dir(fp)

	// for legacy purposes check if .micro is a file or directory
	if f, err := os.Stat(dir); err != nil {
		// check the error to see if the directory exists
		if os.IsNotExist(err) {
			if err := os.MkdirAll(dir, 0755); err != nil {
				return nil, fmt.Errorf("Failed to create dir %s: %v", dir, err)
			}
		} else {
			return nil, fmt.Errorf("Failed to create config dir %s: %v", dir, err)
		}
	} else {
		// if not a directory, copy and move the config
		if !f.IsDir() {
			if err := moveConfig(dir, fp); err != nil {
				return nil, fmt.Errorf("Failed to move config from %s to %s: %v", dir, fp, err)
			}
		}
	}

	// now write the file if it does not exist
	if _, err := os.Stat(fp); os.IsNotExist(err) {
		ioutil.WriteFile(fp, []byte(`{}`), 0644)
	} else if err != nil {
		return nil, fmt.Errorf("Failed to write config file %s: %v", fp, err)
	}

	// create a new config
	c, err := conf.NewConfig(
		conf.WithSource(
			file.NewSource(
				file.WithPath(fp),
			),
		),
	)
	if err != nil {
		return nil, err
	}

	// load the config
	if err := c.Load(); err != nil {
		return nil, err
	}

	// return the conf
	return c, nil
}
<|endoftext|>


<commit_before>package core

import (
	"context"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/scaleway/scaleway-cli/v2/internal/args"
	"github.com/scaleway/scaleway-sdk-go/logger"
	"github.com/scaleway/scaleway-sdk-go/strcase"
	"github.com/scaleway/scaleway-sdk-go/validation"
)

// CommandValidateFunc validates en entire command.
// Used in core.cobraRun().
type CommandValidateFunc func(ctx context.Context, cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error

// ArgSpecValidateFunc validates one argument of a command.
type ArgSpecValidateFunc func(argSpec *ArgSpec, value interface{}) error

// DefaultCommandValidateFunc is the default validation function for commands.
func DefaultCommandValidateFunc() CommandValidateFunc {
	return func(ctx context.Context, cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error {
		err := validateArgValues(cmd, cmdArgs)
		if err != nil {
			return err
		}
		err = validateRequiredArgs(cmd, cmdArgs, rawArgs)
		if err != nil {
			return err
		}
		err = validateNoConflict(cmd, rawArgs)
		if err != nil {
			return err
		}

		validateDeprecated(ctx, cmd)
		return nil
	}
}

// validateArgValues validates values passed to the different args of a Command.
func validateArgValues(cmd *Command, cmdArgs interface{}) error {
	for _, argSpec := range cmd.ArgSpecs {
		fieldName := strcase.ToPublicGoName(argSpec.Name)
		fieldValues, err := getValuesForFieldByName(reflect.ValueOf(cmdArgs), strings.Split(fieldName, "."))
		if err != nil {
			logger.Infof("could not validate arg value for '%v': invalid fieldName: %v: %v", argSpec.Name, fieldName, err.Error())
			continue
		}
		validateFunc := DefaultArgSpecValidateFunc()
		if argSpec.ValidateFunc != nil {
			validateFunc = argSpec.ValidateFunc
		}
		for _, fieldValue := range fieldValues {
			err := validateFunc(argSpec, fieldValue.Interface())
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// validateRequiredArgs checks for missing required args with no default value.
// Returns an error for the first missing required arg.
// Returns nil otherwise.
// TODO refactor this method which uses a mix of reflect and string arrays
func validateRequiredArgs(cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error {
	for _, arg := range cmd.ArgSpecs {
		if !arg.Required {
			continue
		}

		fieldName := strcase.ToPublicGoName(arg.Name)
		fieldValues, err := getValuesForFieldByName(reflect.ValueOf(cmdArgs), strings.Split(fieldName, "."))
		if err != nil {
			validationErr := fmt.Errorf("could not validate arg value for '%v': invalid field name '%v': %v", arg.Name, fieldName, err.Error())
			if !arg.Required {
				logger.Infof(validationErr.Error())
				continue
			}
			panic(validationErr)
		}

		// Either fieldsValues have a length for 1 and we check for existence in the rawArgs
		// or it has multiple values and we loop through each one to get the right element in
		// the corresponding rawArgs array and replace {index} by the element's index.
		// TODO handle required maps
		for i := range fieldValues {
			if !rawArgs.ExistsArgByName(strings.Replace(arg.Name, "{index}", strconv.Itoa(i), 1)) {
				return MissingRequiredArgumentError(strings.Replace(arg.Name, "{index}", strconv.Itoa(i), 1))
			}
		}
	}
	return nil
}

func validateNoConflict(cmd *Command, rawArgs args.RawArgs) error {
	for _, arg1 := range cmd.ArgSpecs {
		for _, arg2 := range cmd.ArgSpecs {
			if !arg1.ConflictWith(arg2) || arg1 == arg2 {
				continue
			}
			if rawArgs.Has(arg1.Name) && rawArgs.Has(arg2.Name) {
				return ArgumentConflictError(arg1.Name, arg2.Name)
			}
		}
	}
	return nil
}

// validateDeprecated print a warning message if a deprecated argument is used
func validateDeprecated(ctx context.Context, cmd *Command) {
	deprecatedArgs := cmd.ArgSpecs.GetDeprecated(true)
	for _, argSpec := range deprecatedArgs {
		helpCmd := cmd.GetCommandLine(extractMeta(ctx).BinaryName) + " --help"
		ExtractLogger(ctx).Warningf("The argument '%s' is deprecated, more info with: %s\n", argSpec.Name, helpCmd)
	}
}

// DefaultArgSpecValidateFunc validates a value passed for an ArgSpec
// Uses ArgSpec.EnumValues
func DefaultArgSpecValidateFunc() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, value interface{}) error {
		if len(argSpec.EnumValues) < 1 {
			return nil
		}

		strValue, err := args.MarshalValue(value)
		if err != nil {
			return err
		}

		// When an enum is not provided as an argument args.MarshalValue will in most cases return "" (go default value)
		// In those cases we ignore validation. This is not ideal but covers most of the use cases.
		// The only caveat would be that `my-enum=""` would not trigger an error, which is acceptable.
		if strValue == "" {
			return nil
		}

		if !stringExists(argSpec.EnumValues, strValue) {
			return InvalidValueForEnumError(argSpec.Name, argSpec.EnumValues, strValue)
		}
		return nil
	}
}

func stringExists(strs []string, s string) bool {
	for _, s2 := range strs {
		if s == s2 {
			return true
		}
	}
	return false
}

func ValidateSecretKey() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value := valueI.(string)
		err := DefaultArgSpecValidateFunc()(argSpec, value)
		if err != nil {
			return err
		}
		if !validation.IsSecretKey(value) {
			return InvalidSecretKeyError(value)
		}
		return nil
	}
}

// ValidateOrganizationID validates a non-required organization ID.
// By default, for most command, the organization ID is not required.
// In that case, we allow the empty-string value "".
func ValidateOrganizationID() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value, isStr := valueI.(string)
		valuePtr, isPtr := valueI.(*string)
		if !isStr && isPtr && valuePtr != nil {
			value = *valuePtr
		}

		if value == "" && !argSpec.Required {
			return nil
		}
		if !validation.IsOrganizationID(value) {
			return InvalidOrganizationIDError(value)
		}
		return nil
	}
}

// ValidateProjectID validates a non-required project ID.
// By default, for most command, the project ID is not required.
// In that case, we allow the empty-string value "".
func ValidateProjectID() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value, isStr := valueI.(string)
		valuePtr, isPtr := valueI.(*string)
		if !isStr && isPtr && valuePtr != nil {
			value = *valuePtr
		}

		if value == "" && !argSpec.Required {
			return nil
		}
		if !validation.IsProjectID(value) {
			return InvalidProjectIDError(value)
		}
		return nil
	}
}
<commit_msg>fix(core/validate): log deprecated arg only when used (#2509)<commit_after>package core

import (
	"context"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/scaleway/scaleway-cli/v2/internal/args"
	"github.com/scaleway/scaleway-sdk-go/logger"
	"github.com/scaleway/scaleway-sdk-go/strcase"
	"github.com/scaleway/scaleway-sdk-go/validation"
)

// CommandValidateFunc validates en entire command.
// Used in core.cobraRun().
type CommandValidateFunc func(ctx context.Context, cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error

// ArgSpecValidateFunc validates one argument of a command.
type ArgSpecValidateFunc func(argSpec *ArgSpec, value interface{}) error

// DefaultCommandValidateFunc is the default validation function for commands.
func DefaultCommandValidateFunc() CommandValidateFunc {
	return func(ctx context.Context, cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error {
		err := validateArgValues(cmd, cmdArgs)
		if err != nil {
			return err
		}
		err = validateRequiredArgs(cmd, cmdArgs, rawArgs)
		if err != nil {
			return err
		}
		err = validateNoConflict(cmd, rawArgs)
		if err != nil {
			return err
		}

		validateDeprecated(ctx, cmd, cmdArgs, rawArgs)
		return nil
	}
}

// validateArgValues validates values passed to the different args of a Command.
func validateArgValues(cmd *Command, cmdArgs interface{}) error {
	for _, argSpec := range cmd.ArgSpecs {
		fieldName := strcase.ToPublicGoName(argSpec.Name)
		fieldValues, err := getValuesForFieldByName(reflect.ValueOf(cmdArgs), strings.Split(fieldName, "."))
		if err != nil {
			logger.Infof("could not validate arg value for '%v': invalid fieldName: %v: %v", argSpec.Name, fieldName, err.Error())
			continue
		}
		validateFunc := DefaultArgSpecValidateFunc()
		if argSpec.ValidateFunc != nil {
			validateFunc = argSpec.ValidateFunc
		}
		for _, fieldValue := range fieldValues {
			err := validateFunc(argSpec, fieldValue.Interface())
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// validateRequiredArgs checks for missing required args with no default value.
// Returns an error for the first missing required arg.
// Returns nil otherwise.
// TODO refactor this method which uses a mix of reflect and string arrays
func validateRequiredArgs(cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) error {
	for _, arg := range cmd.ArgSpecs {
		if !arg.Required {
			continue
		}

		fieldName := strcase.ToPublicGoName(arg.Name)
		fieldValues, err := getValuesForFieldByName(reflect.ValueOf(cmdArgs), strings.Split(fieldName, "."))
		if err != nil {
			validationErr := fmt.Errorf("could not validate arg value for '%v': invalid field name '%v': %v", arg.Name, fieldName, err.Error())
			if !arg.Required {
				logger.Infof(validationErr.Error())
				continue
			}
			panic(validationErr)
		}

		// Either fieldsValues have a length for 1 and we check for existence in the rawArgs
		// or it has multiple values and we loop through each one to get the right element in
		// the corresponding rawArgs array and replace {index} by the element's index.
		// TODO handle required maps
		for i := range fieldValues {
			if !rawArgs.ExistsArgByName(strings.Replace(arg.Name, "{index}", strconv.Itoa(i), 1)) {
				return MissingRequiredArgumentError(strings.Replace(arg.Name, "{index}", strconv.Itoa(i), 1))
			}
		}
	}
	return nil
}

func validateNoConflict(cmd *Command, rawArgs args.RawArgs) error {
	for _, arg1 := range cmd.ArgSpecs {
		for _, arg2 := range cmd.ArgSpecs {
			if !arg1.ConflictWith(arg2) || arg1 == arg2 {
				continue
			}
			if rawArgs.Has(arg1.Name) && rawArgs.Has(arg2.Name) {
				return ArgumentConflictError(arg1.Name, arg2.Name)
			}
		}
	}
	return nil
}

// validateDeprecated print a warning message if a deprecated argument is used
func validateDeprecated(ctx context.Context, cmd *Command, cmdArgs interface{}, rawArgs args.RawArgs) {
	deprecatedArgs := cmd.ArgSpecs.GetDeprecated(true)
	for _, arg := range deprecatedArgs {
		fieldName := strcase.ToPublicGoName(arg.Name)
		fieldValues, err := getValuesForFieldByName(reflect.ValueOf(cmdArgs), strings.Split(fieldName, "."))
		if err != nil {
			validationErr := fmt.Errorf("could not validate arg value for '%v': invalid field name '%v': %v", arg.Name, fieldName, err.Error())
			if !arg.Required {
				logger.Infof(validationErr.Error())
				continue
			}
			panic(validationErr)
		}

		for i := range fieldValues {
			if rawArgs.ExistsArgByName(strings.Replace(arg.Name, "{index}", strconv.Itoa(i), 1)) {
				helpCmd := cmd.GetCommandLine(extractMeta(ctx).BinaryName) + " --help"
				ExtractLogger(ctx).Warningf("The argument '%s' is deprecated, more info with: %s\n", arg.Name, helpCmd)
			}
		}
	}
}

// DefaultArgSpecValidateFunc validates a value passed for an ArgSpec
// Uses ArgSpec.EnumValues
func DefaultArgSpecValidateFunc() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, value interface{}) error {
		if len(argSpec.EnumValues) < 1 {
			return nil
		}

		strValue, err := args.MarshalValue(value)
		if err != nil {
			return err
		}

		// When an enum is not provided as an argument args.MarshalValue will in most cases return "" (go default value)
		// In those cases we ignore validation. This is not ideal but covers most of the use cases.
		// The only caveat would be that `my-enum=""` would not trigger an error, which is acceptable.
		if strValue == "" {
			return nil
		}

		if !stringExists(argSpec.EnumValues, strValue) {
			return InvalidValueForEnumError(argSpec.Name, argSpec.EnumValues, strValue)
		}
		return nil
	}
}

func stringExists(strs []string, s string) bool {
	for _, s2 := range strs {
		if s == s2 {
			return true
		}
	}
	return false
}

func ValidateSecretKey() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value := valueI.(string)
		err := DefaultArgSpecValidateFunc()(argSpec, value)
		if err != nil {
			return err
		}
		if !validation.IsSecretKey(value) {
			return InvalidSecretKeyError(value)
		}
		return nil
	}
}

// ValidateOrganizationID validates a non-required organization ID.
// By default, for most command, the organization ID is not required.
// In that case, we allow the empty-string value "".
func ValidateOrganizationID() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value, isStr := valueI.(string)
		valuePtr, isPtr := valueI.(*string)
		if !isStr && isPtr && valuePtr != nil {
			value = *valuePtr
		}

		if value == "" && !argSpec.Required {
			return nil
		}
		if !validation.IsOrganizationID(value) {
			return InvalidOrganizationIDError(value)
		}
		return nil
	}
}

// ValidateProjectID validates a non-required project ID.
// By default, for most command, the project ID is not required.
// In that case, we allow the empty-string value "".
func ValidateProjectID() ArgSpecValidateFunc {
	return func(argSpec *ArgSpec, valueI interface{}) error {
		value, isStr := valueI.(string)
		valuePtr, isPtr := valueI.(*string)
		if !isStr && isPtr && valuePtr != nil {
			value = *valuePtr
		}

		if value == "" && !argSpec.Required {
			return nil
		}
		if !validation.IsProjectID(value) {
			return InvalidProjectIDError(value)
		}
		return nil
	}
}
<|endoftext|>


<commit_before>package dockerignore // import "github.com/docker/docker/builder/dockerignore"

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestReadAll(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "dockerignore-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	di, err := ReadAll(nil)
	if err != nil {
		t.Fatalf("Expected not to have error, got %v", err)
	}

	if diLen := len(di); diLen != 0 {
		t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen)
	}

	diName := filepath.Join(tmpDir, ".dockerignore")
	content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n")
	err = ioutil.WriteFile(diName, []byte(content), 0777)
	if err != nil {
		t.Fatal(err)
	}

	diFd, err := os.Open(diName)
	if err != nil {
		t.Fatal(err)
	}
	defer diFd.Close()

	di, err = ReadAll(diFd)
	if err != nil {
		t.Fatal(err)
	}

	if len(di) != 7 {
		t.Fatalf("Expected 5 entries, got %v", len(di))
	}
	if di[0] != "test1" {
		t.Fatal("First element is not test1")
	}
	if di[1] != "test2" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
		t.Fatal("Second element is not test2")
	}
	if di[2] != "a/file/here" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
		t.Fatal("Third element is not a/file/here")
	}
	if di[3] != "lastfile" {
		t.Fatal("Fourth element is not lastfile")
	}
	if di[4] != "!inverted/abs/path" {
		t.Fatal("Fifth element is not !inverted/abs/path")
	}
	if di[5] != "!" {
		t.Fatalf("Sixth element is not !, but %s", di[5])
	}
	if di[6] != "!" {
		t.Fatalf("Sixth element is not !, but %s", di[6])
	}
}
<commit_msg>Fix typos<commit_after>package dockerignore // import "github.com/docker/docker/builder/dockerignore"

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

func TestReadAll(t *testing.T) {
	tmpDir, err := ioutil.TempDir("", "dockerignore-test")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmpDir)

	di, err := ReadAll(nil)
	if err != nil {
		t.Fatalf("Expected not to have error, got %v", err)
	}

	if diLen := len(di); diLen != 0 {
		t.Fatalf("Expected to have zero dockerignore entry, got %d", diLen)
	}

	diName := filepath.Join(tmpDir, ".dockerignore")
	content := fmt.Sprintf("test1\n/test2\n/a/file/here\n\nlastfile\n# this is a comment\n! /inverted/abs/path\n!\n! \n")
	err = ioutil.WriteFile(diName, []byte(content), 0777)
	if err != nil {
		t.Fatal(err)
	}

	diFd, err := os.Open(diName)
	if err != nil {
		t.Fatal(err)
	}
	defer diFd.Close()

	di, err = ReadAll(diFd)
	if err != nil {
		t.Fatal(err)
	}

	if len(di) != 7 {
		t.Fatalf("Expected 7 entries, got %v", len(di))
	}
	if di[0] != "test1" {
		t.Fatal("First element is not test1")
	}
	if di[1] != "test2" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
		t.Fatal("Second element is not test2")
	}
	if di[2] != "a/file/here" { // according to https://docs.docker.com/engine/reference/builder/#dockerignore-file, /foo/bar should be treated as foo/bar
		t.Fatal("Third element is not a/file/here")
	}
	if di[3] != "lastfile" {
		t.Fatal("Fourth element is not lastfile")
	}
	if di[4] != "!inverted/abs/path" {
		t.Fatal("Fifth element is not !inverted/abs/path")
	}
	if di[5] != "!" {
		t.Fatalf("Sixth element is not !, but %s", di[5])
	}
	if di[6] != "!" {
		t.Fatalf("Seventh element is not !, but %s", di[6])
	}
}
<|endoftext|>


<commit_before>package common

import (
	"bytes"
	"errors"
	"os"
	"os/exec"
	"regexp"
)

// IfconfigIPFinder finds the host IP based on the output of `ifconfig`.
type IfconfigIPFinder struct {
	Device string
}

func (f *IfconfigIPFinder) HostIP() (string, error) {
	var ifconfigPath string

	// On some systems, ifconfig is in /sbin which is generally not
	// on the PATH for a standard user, so we just check that first.
	if _, err := os.Stat("/sbin/ifconfig"); err == nil {
		ifconfigPath = "/sbin/ifconfig"
	}

	if ifconfigPath == "" {
		var err error
		ifconfigPath, err = exec.LookPath("ifconfig")
		if err != nil {
			return "", err
		}
	}

	stdout := new(bytes.Buffer)

	cmd := exec.Command(ifconfigPath, f.Device)
	// Force LANG=C so that the output is what we expect it to be
	// despite the locale.
	cmd.Env = append(cmd.Env, "LANG=C")
	cmd.Env = append(cmd.Env, os.Environ()...)

	cmd.Stdout = stdout
	cmd.Stderr = new(bytes.Buffer)
	if err := cmd.Run(); err != nil {
		return "", err
	}

	re := regexp.MustCompile(`inet[^\d]+([\d\.]+)\s`)
	matches := re.FindStringSubmatch(stdout.String())
	if matches == nil {
		return "", errors.New("IP not found in ifconfig output...")
	}

	return matches[1], nil
}
<commit_msg>builder/vmware: Try to use `ip address` to find host IP<commit_after>package common

import (
	"bytes"
	"errors"
	"os"
	"os/exec"
	"regexp"
)

// IfconfigIPFinder finds the host IP based on the output of `ip address` or `ifconfig`.
type IfconfigIPFinder struct {
	Device string
}

func (f *IfconfigIPFinder) HostIP() (string, error) {
	ip, err := ipaddress(f.Device)
	if err != nil || ip == "" {
		return ifconfig(f.Device)
	}
	return ip, err
}

func ipaddress(device string) (string, error) {
	var ipPath string

	// On some systems, ip is in /sbin which is generally not
	// on the PATH for a standard user, so we just check that first.
	if _, err := os.Stat("/sbin/ip"); err == nil {
		ipPath = "/sbin/ip"
	}

	if ipPath == "" {
		var err error
		ipPath, err = exec.LookPath("ip")
		if err != nil {
			return "", err
		}
	}

	stdout := new(bytes.Buffer)
	cmd := exec.Command(ipPath, "address", "show", "dev", device)
	// Force LANG=C so that the output is what we expect it to be
	// despite the locale.
	cmd.Env = append(cmd.Env, "LANG=C")
	cmd.Env = append(cmd.Env, os.Environ()...)

	cmd.Stdout = stdout
	cmd.Stderr = new(bytes.Buffer)
	if err := cmd.Run(); err != nil {
		return "", err
	}

	re := regexp.MustCompile(`inet[^\d]+([\d\.]+)/`)
	matches := re.FindStringSubmatch(stdout.String())
	if matches == nil {
		return "", errors.New("IP not found in ip a output...")
	}

	return matches[1], nil
}

func ifconfig(device string) (string, error) {
	var ifconfigPath string

	// On some systems, ifconfig is in /sbin which is generally not
	// on the PATH for a standard user, so we just check that first.
	if _, err := os.Stat("/sbin/ifconfig"); err == nil {
		ifconfigPath = "/sbin/ifconfig"
	}

	if ifconfigPath == "" {
		var err error
		ifconfigPath, err = exec.LookPath("ifconfig")
		if err != nil {
			return "", err
		}
	}

	stdout := new(bytes.Buffer)

	cmd := exec.Command(ifconfigPath, device)
	// Force LANG=C so that the output is what we expect it to be
	// despite the locale.
	cmd.Env = append(cmd.Env, "LANG=C")
	cmd.Env = append(cmd.Env, os.Environ()...)

	cmd.Stdout = stdout
	cmd.Stderr = new(bytes.Buffer)
	if err := cmd.Run(); err != nil {
		return "", err
	}

	re := regexp.MustCompile(`inet[^\d]+([\d\.]+)\s`)
	matches := re.FindStringSubmatch(stdout.String())
	if matches == nil {
		return "", errors.New("IP not found in ifconfig output...")
	}

	return matches[1], nil
}
<|endoftext|>


<commit_before>package mbtest

import (
	"bytes"
	"io/ioutil"
	"path/filepath"
	"testing"
)

const testdataDir = "testdata"

// Testdata returns a file's bytes based on the path relative to the testdata
// directory. It fails the test if the testdata file can not be read.
func Testdata(t *testing.T, relativePath string) []byte {
	path := filepath.Join(testdataDir, relativePath)

	b, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatalf("%s", err)
	}

	return b
}

// AssertTestdata gets testdata and asserts it equals actual.
func AssertTestdata(t *testing.T, relativePath string, actual []byte) {
	expected := Testdata(t, relativePath)

	if !bytes.Equal(expected, actual) {
		t.Fatalf("expected %s, got %s", expected, actual)
	}
}

// AssertEndpointCalled fails the test if the last request was not made to the
// provided endpoint (e.g. combination of HTTP method and path).
func AssertEndpointCalled(t *testing.T, method, path string) {
	if Request.Method != method {
		t.Fatalf("expected %s, got %s", method, Request.Method)
	}

	if escapedPath := Request.URL.EscapedPath(); escapedPath != path {
		t.Fatalf("expected %s, got %s", path, escapedPath)
	}
}
<commit_msg>Fix tests using testdata with trailing newlines by slicing off whitespace<commit_after>package mbtest

import (
	"bytes"
	"io/ioutil"
	"path/filepath"
	"testing"
)

const testdataDir = "testdata"

// Testdata returns a file's bytes based on the path relative to the testdata
// directory. It fails the test if the testdata file can not be read.
func Testdata(t *testing.T, relativePath string) []byte {
	path := filepath.Join(testdataDir, relativePath)

	b, err := ioutil.ReadFile(path)
	if err != nil {
		t.Fatalf("%s", err)
	}

	return b
}

// AssertTestdata gets testdata and asserts it equals actual. We start by
// slicing off all leading and trailing white space, as defined by Unicode.
func AssertTestdata(t *testing.T, relativePath string, actual []byte) {
	expected := bytes.TrimSpace(Testdata(t, relativePath))
	actual = bytes.TrimSpace(actual)

	if !bytes.Equal(expected, actual) {
		t.Fatalf("expected %s, got %s", expected, actual)
	}
}

// AssertEndpointCalled fails the test if the last request was not made to the
// provided endpoint (e.g. combination of HTTP method and path).
func AssertEndpointCalled(t *testing.T, method, path string) {
	if Request.Method != method {
		t.Fatalf("expected %s, got %s", method, Request.Method)
	}

	if escapedPath := Request.URL.EscapedPath(); escapedPath != path {
		t.Fatalf("expected %s, got %s", path, escapedPath)
	}
}
<|endoftext|>


<commit_before>package models

import "strings"

type Expression struct {
	Value      string
	IsStar     bool
	IsVariadic bool
	IsWriter   bool
	Underlying string
}

func (e *Expression) String() string {
	value := e.Value
	if e.IsStar {
		value = "*" + value
	}
	if e.IsVariadic {
		return "[]" + value
	}
	return value
}

type Field struct {
	Name  string
	Type  *Expression
	Index int
}

func (f *Field) IsWriter() bool {
	return f.Type.IsWriter
}

func (f *Field) IsStruct() bool {
	return strings.HasPrefix(f.Type.Underlying, "struct")
}

func (f *Field) IsBasicType() bool {
	return isBasicType(f.Type.String()) || isBasicType(f.Type.Underlying)
}

func isBasicType(t string) bool {
	switch t {
	case "bool", "string", "int", "int8", "int16", "int32", "int64", "uint",
		"uint8", "uint16", "uint32", "uint64", "uintptr", "byte", "rune",
		"float32", "float64", "complex64", "complex128":
		return true
	default:
		return false
	}
}

func (f *Field) IsNamed() bool {
	return f.Name != "" && f.Name != "_"
}

func (f *Field) ShortName() string {
	return strings.ToLower(string([]rune(f.Type.Value)[0]))
}

type Receiver struct {
	*Field
	Fields []*Field
}

type Function struct {
	Name         string
	IsExported   bool
	Receiver     *Receiver
	Parameters   []*Field
	Results      []*Field
	ReturnsError bool
}

func (f *Function) TestParameters() []*Field {
	var ps []*Field
	for _, p := range f.Parameters {
		if p.IsWriter() {
			continue
		}
		ps = append(ps, p)
	}
	return ps
}

func (f *Function) TestResults() []*Field {
	var ps []*Field
	ps = append(ps, f.Results...)
	for _, p := range f.Parameters {
		if !p.IsWriter() {
			continue
		}
		ps = append(ps, &Field{
			Name: p.Name,
			Type: &Expression{
				Value:      "string",
				IsWriter:   true,
				Underlying: "string",
			},
			Index: len(ps),
		})
	}
	return ps
}

func (f *Function) ReturnsMultiple() bool {
	return len(f.Results) > 1
}

func (f *Function) OnlyReturnsOneValue() bool {
	return len(f.Results) == 1 && !f.ReturnsError
}

func (f *Function) OnlyReturnsError() bool {
	return len(f.Results) == 0 && f.ReturnsError
}

func (f *Function) FullName() string {
	var r string
	if f.Receiver != nil {
		r = f.Receiver.Type.Value
	}
	return strings.Title(r) + strings.Title(f.Name)
}

func (f *Function) TestName() string {
	var r string
	if f.Receiver != nil {
		r = f.Receiver.Type.Value
	}
	return "Test" + strings.Title(r) + strings.Title(f.Name)
}

type Import struct {
	Name, Path string
}

type Header struct {
	Package string
	Imports []*Import
	Code    []byte
}

type Path string

func (p Path) TestPath() string {
	if p.IsTestPath() {
		return string(p)
	}
	return strings.TrimSuffix(string(p), ".go") + "_test.go"
}

func (p Path) IsTestPath() bool {
	return strings.HasSuffix(string(p), "_test.go")
}
<commit_msg>Simplify Path.TestPath.<commit_after>package models

import "strings"

type Expression struct {
	Value      string
	IsStar     bool
	IsVariadic bool
	IsWriter   bool
	Underlying string
}

func (e *Expression) String() string {
	value := e.Value
	if e.IsStar {
		value = "*" + value
	}
	if e.IsVariadic {
		return "[]" + value
	}
	return value
}

type Field struct {
	Name  string
	Type  *Expression
	Index int
}

func (f *Field) IsWriter() bool {
	return f.Type.IsWriter
}

func (f *Field) IsStruct() bool {
	return strings.HasPrefix(f.Type.Underlying, "struct")
}

func (f *Field) IsBasicType() bool {
	return isBasicType(f.Type.String()) || isBasicType(f.Type.Underlying)
}

func isBasicType(t string) bool {
	switch t {
	case "bool", "string", "int", "int8", "int16", "int32", "int64", "uint",
		"uint8", "uint16", "uint32", "uint64", "uintptr", "byte", "rune",
		"float32", "float64", "complex64", "complex128":
		return true
	default:
		return false
	}
}

func (f *Field) IsNamed() bool {
	return f.Name != "" && f.Name != "_"
}

func (f *Field) ShortName() string {
	return strings.ToLower(string([]rune(f.Type.Value)[0]))
}

type Receiver struct {
	*Field
	Fields []*Field
}

type Function struct {
	Name         string
	IsExported   bool
	Receiver     *Receiver
	Parameters   []*Field
	Results      []*Field
	ReturnsError bool
}

func (f *Function) TestParameters() []*Field {
	var ps []*Field
	for _, p := range f.Parameters {
		if p.IsWriter() {
			continue
		}
		ps = append(ps, p)
	}
	return ps
}

func (f *Function) TestResults() []*Field {
	var ps []*Field
	ps = append(ps, f.Results...)
	for _, p := range f.Parameters {
		if !p.IsWriter() {
			continue
		}
		ps = append(ps, &Field{
			Name: p.Name,
			Type: &Expression{
				Value:      "string",
				IsWriter:   true,
				Underlying: "string",
			},
			Index: len(ps),
		})
	}
	return ps
}

func (f *Function) ReturnsMultiple() bool {
	return len(f.Results) > 1
}

func (f *Function) OnlyReturnsOneValue() bool {
	return len(f.Results) == 1 && !f.ReturnsError
}

func (f *Function) OnlyReturnsError() bool {
	return len(f.Results) == 0 && f.ReturnsError
}

func (f *Function) FullName() string {
	var r string
	if f.Receiver != nil {
		r = f.Receiver.Type.Value
	}
	return strings.Title(r) + strings.Title(f.Name)
}

func (f *Function) TestName() string {
	var r string
	if f.Receiver != nil {
		r = f.Receiver.Type.Value
	}
	return "Test" + strings.Title(r) + strings.Title(f.Name)
}

type Import struct {
	Name, Path string
}

type Header struct {
	Package string
	Imports []*Import
	Code    []byte
}

type Path string

func (p Path) TestPath() string {
	return strings.TrimSuffix(string(p), ".go") + "_test.go"
}

func (p Path) IsTestPath() bool {
	return strings.HasSuffix(string(p), "_test.go")
}
<|endoftext|>