<commit_before>package java

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/ezbuy/tgen/global"
	"github.com/ezbuy/tgen/langs"
	"github.com/ezbuy/tgen/tmpl"
	"github.com/samuel/go-thrift/parser"
)

const (
	javaLang = "java"
	javaExt  = ".java"
)

const (
	JavaTypeshort  = "short"
	JavaTypeint    = "int"
	JavaTypelong   = "long"
	JavaTypebool   = "boolean"
	JavaTypebyte   = "byte"
	JavaTypedouble = "double"

	JavaTypeString = "String"

	JavaTypeShort  = "Short"
	JavaTypeInt    = "Integer"
	JavaTypeLong   = "Long"
	JavaTypeBool   = "Boolean"
	JavaTypeByte   = "Byte"
	JavaTypeDouble = "Double"

	// other types (such as array, map, etc.) are implemented in the method 'Typecast'
)

const (
	TPL_ENUM    = "tgen/java/enum"
	TPL_STRUCT  = "tgen/java/struct"
	TPL_SERVICE = "tgen/java/service"
)

var plaintypemapping = map[string]string{
	langs.ThriftTypeI16:    JavaTypeshort,
	langs.ThriftTypeI32:    JavaTypeint,
	langs.ThriftTypeI64:    JavaTypelong,
	langs.ThriftTypeString: JavaTypeString,
	langs.ThriftTypeByte:   JavaTypebyte,
	langs.ThriftTypeBool:   JavaTypebool,
	langs.ThriftTypeDouble: JavaTypedouble,
}

var objecttypemapping = map[string]string{
	langs.ThriftTypeI16:    JavaTypeShort,
	langs.ThriftTypeI32:    JavaTypeInt,
	langs.ThriftTypeI64:    JavaTypeLong,
	langs.ThriftTypeString: JavaTypeString,
	langs.ThriftTypeByte:   JavaTypeByte,
	langs.ThriftTypeBool:   JavaTypeBool,
	langs.ThriftTypeDouble: JavaTypeDouble,
}

type JavaGen struct {
	langs.BaseGen
}

type BaseJava struct {
	Namespace string
	t         *parser.Thrift
	ts        map[string]*parser.Thrift
}

func (b *BaseJava) FilterVariableName(n string) string {
	if b.IsKeyword(n) {
		return fmt.Sprintf("t%s%s", strings.ToUpper(n[:1]), n[1:])
	}
	return n
}

func (b *BaseJava) IsKeyword(n string) bool {
	switch n {
	case "package", "int", "short", "long", "byte", "boolean", "case", "switch", "if ", "for", "else",
		"goto", "Integer", "Short", "Long", "Byte", "Boolean", "class", "break", "try", "catch",
		"double", "Double", "do", "while", "final", "finally", "continue", "interface", "private",
		"public", "protected", "return", "this", "throw", "static", "super", "throws",
		"true", "false", "float", "volatile", "synchronized", "abstract", "default", "extends",
		"native", "new":
		return true
	}
	return false
}

func (b *BaseJava) PlainTypecast(t *parser.Type) string {
	return b.typecast(t, true)
}

func (b *BaseJava) ObjectTypecast(t *parser.Type) string {
	return b.typecast(t, false)
}

func (b *BaseJava) typecast(t *parser.Type, isplain bool) string {
	if t == nil {
		if isplain {
			return "void"
		} else {
			return "Void"
		}
	}

	var typemapping map[string]string

	if isplain {
		typemapping = plaintypemapping
	} else {
		typemapping = objecttypemapping
	}

	if t, ok := typemapping[t.Name]; ok {
		return t
	}

	switch t.Name {
	case langs.ThriftTypeList, langs.ThriftTypeSet:
		return fmt.Sprintf("java.util.ArrayList<%s>", b.ObjectTypecast(t.ValueType))
	case langs.ThriftTypeMap:
		return fmt.Sprintf("java.util.Map<%s, %s>", b.ObjectTypecast(t.KeyType), b.ObjectTypecast(t.ValueType))
	default:
		s := strings.Split(t.Name, ".")
		if len(s) == 1 {
			return s[0]
		} else if len(s) == 2 {
			pkg := ""
			for k, v := range b.t.Includes {
				if k == s[0] {
					for p, t := range b.ts {
						if v == p {
							pkg = t.Namespaces[javaLang]
							break
						}
					}

					break
				}
			}

			if pkg == "" {
				return s[1]
			}
			return fmt.Sprintf("%s.%s", pkg, s[1])
		} else {
			return t.Name
		}
	}
}

func (b *BaseJava) AssembleParams(method *parser.Method) string {
	var buf bytes.Buffer

	for i, arg := range method.Arguments {
		if i != 0 {
			buf.WriteString(", ")
		}

		buf.WriteString(fmt.Sprintf("final %s %s", b.PlainTypecast(arg.Type), b.FilterVariableName(arg.Name)))
	}

	if len(method.Arguments) == 0 {
		buf.WriteString("")
	} else {
		buf.WriteString(", ")
	}

	buf.WriteString(fmt.Sprintf("final Listener<%s> listener", b.ObjectTypecast(method.ReturnType)))

	return buf.String()
}

func (b *BaseJava) GetInnerType(t *parser.Type) string {
	if t == nil {
		return "Void"
	}

	// map is ignored
	if t.Name == langs.ThriftTypeList || t.Name == langs.ThriftTypeSet {
		return b.GetInnerType(t.ValueType)
	}

	return b.ObjectTypecast(t)
}

// IsEnum checks whether a type is enum.
// it first checks in its own definition, than check from included files
func (b *BaseJava) IsEnum(t *parser.Type) bool {
	if t == nil {
		return false
	}

	names := strings.Split(t.Name, ".")

	if len(names) == 1 {
		for n := range b.t.Enums {
			if n == t.Name {
				return true
			}
		}

		return false
	}

	for path, thrift := range b.ts {
		if thrift == b.t {
			continue
		}

		filename := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
		if filename != names[0] {
			continue
		}

		for n := range thrift.Enums {
			if n == names[1] {
				return true
			}
		}
	}

	return false
}

type javaEnum struct {
	*BaseJava
	*parser.Enum
}

func (e *javaEnum) GenerateProperties() string {
	size := len(e.Enum.Values)
	i := 0

	var buf bytes.Buffer
	for _, v := range e.Enum.Values {
		buf.WriteString(fmt.Sprintf("\t@SerializedName(\"%d\")\n", v.Value))
		buf.WriteString(fmt.Sprintf("\t%s(%d)", strings.ToUpper(v.Name), v.Value))
		if i == size-1 {
			buf.WriteString(";\n")
		} else {
			buf.WriteString(",\n")
		}
		i++
	}
	return buf.String()
}

type javaStruct struct {
	*BaseJava
	*parser.Struct
}

func (this *javaStruct) HasKeyword() bool {
	for _, f := range this.Struct.Fields {
		if this.BaseJava.IsKeyword(f.Name) {
			return true
		}
	}
	return false
}

type javaService struct {
	*BaseJava
	*parser.Service
}

func generateAll(gen *JavaGen, output string, parsedThrift map[string]*parser.Thrift) {
	generateWithModel(gen, global.MODE_REST, filepath.Join(output, global.MODE_REST), parsedThrift)
	generateWithModel(gen, global.MODE_JSONRPC, filepath.Join(output, global.MODE_JSONRPC), parsedThrift)
}

func (g *JavaGen) Generate(output string, parsedThrift map[string]*parser.Thrift) {
	if global.Mode != "" {
		generateWithModel(g, global.Mode, output, parsedThrift)
	} else {
		generateAll(g, output, parsedThrift)
	}
}

func generateWithModel(gen *JavaGen, m string, output string, parsedThrift map[string]*parser.Thrift) {
	if m != global.MODE_REST && m != global.MODE_JSONRPC {
		log.Fatalf("mode '%s' is invalid", m)
	}

	gen.BaseGen.Init(javaLang, parsedThrift)

	if err := os.MkdirAll(output, 0755); err != nil {
		panic(fmt.Errorf("failed to create output directory %s", output))
	}

	// init templates
	enumTpl := initemplate(TPL_ENUM, "tmpl/java/enum.gojava")

	var structTpl *template.Template
	var serviceTpl *template.Template
	if m == global.MODE_REST {
		structTpl = initemplate(TPL_STRUCT, "tmpl/java/rest_struct.gojava")
		serviceTpl = initemplate(TPL_SERVICE, "tmpl/java/rest_service.gojava")
	} else if m == global.MODE_JSONRPC {
		structTpl = initemplate(TPL_STRUCT, "tmpl/java/jsonrpc_struct.gojava")
		serviceTpl = initemplate(TPL_SERVICE, "tmpl/java/jsonrpc_service.gojava")
	}

	// key is the absoule path of thrift file
	for f, t := range parsedThrift {
		if f != global.InputFile {
			continue // ignore
		}

		ns := t.Namespaces["java"]

		if len(t.Enums) > 0 {
			log.Printf("## enums")

			for _, e := range t.Enums {
				name := e.Name + ".java"

				// fix java file path
				p := filepath.Join(output, strings.Replace(ns, ".", "/", -1))
				if err := os.MkdirAll(p, 0755); err != nil {
					panic(fmt.Errorf("failed to create output directory %s", p))
				}

				path := filepath.Join(p, name)

				base := BaseJava{Namespace: ns, t: t, ts: parsedThrift}
				data := &javaEnum{BaseJava: &base, Enum: e}

				if err := outputfile(path, enumTpl, TPL_ENUM, data); err != nil {
					panic(fmt.Errorf("failed to write file %s. error: %v\n", path, err))
				}

				log.Printf("%s", path)
			}
		}

		log.Printf("## structs")

		for _, s := range t.Structs {
			// filename is the struct name
			name := s.Name + javaExt

			// fix java file path
			p := filepath.Join(output, strings.Replace(ns, ".", "/", -1))
			if err := os.MkdirAll(p, 0755); err != nil {
				panic(fmt.Errorf("failed to create output directory %s", p))
			}

			path := filepath.Join(p, name)

			base := BaseJava{Namespace: ns, t: t, ts: parsedThrift}
			data := &javaStruct{BaseJava: &base, Struct: s}

			if err := outputfile(path, structTpl, TPL_STRUCT, data); err != nil {
				panic(fmt.Errorf("failed to write file %s. error: %v\n", path, err))
			}

			log.Printf("%s", path)
		}

		log.Printf("## services")

		for _, s := range t.Services {
			// filename is the service name plus 'Service'
			name := s.Name + "Service" + javaExt

			// fix java file path
			p := filepath.Join(output, strings.Replace(ns, ".", "/", -1))
			if err := os.MkdirAll(p, 0755); err != nil {
				panic(fmt.Errorf("failed to create output directory %s", p))
			}

			path := filepath.Join(p, name)

			base := BaseJava{Namespace: ns, t: t, ts: parsedThrift}
			data := &javaService{BaseJava: &base, Service: s}

			if err := outputfile(path, serviceTpl, TPL_SERVICE, data); err != nil {
				panic(fmt.Errorf("failed to write file %s. error: %v\n", path, err))
			}

			log.Printf("%s", path)
		}
	}
}

func initemplate(n string, path string) *template.Template {
	data, err := tmpl.Asset(path)
	if err != nil {
		panic(err)
	}

	tpl := template.New(n)

	// register functions
	funcMap := template.FuncMap{
		"ToUpper": strings.ToUpper,
	}
	tpl.Funcs(funcMap)

	_, err = tpl.Parse(string(data))
	if err != nil {
		panic(err)
	}

	return tpl
}

func outputfile(fp string, t *template.Template, tplname string, data interface{}) error {
	file, err := os.OpenFile(fp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}

	defer file.Close()

	return t.ExecuteTemplate(file, tplname, data)
}

func init() {
	langs.Langs[javaLang] = &JavaGen{}
}
<commit_msg>remove unnecessary check<commit_after>package java

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"github.com/ezbuy/tgen/global"
	"github.com/ezbuy/tgen/langs"
	"github.com/ezbuy/tgen/tmpl"
	"github.com/samuel/go-thrift/parser"
)

const (
	javaLang = "java"
	javaExt  = ".java"
)

const (
	JavaTypeshort  = "short"
	JavaTypeint    = "int"
	JavaTypelong   = "long"
	JavaTypebool   = "boolean"
	JavaTypebyte   = "byte"
	JavaTypedouble = "double"

	JavaTypeString = "String"

	JavaTypeShort  = "Short"
	JavaTypeInt    = "Integer"
	JavaTypeLong   = "Long"
	JavaTypeBool   = "Boolean"
	JavaTypeByte   = "Byte"
	JavaTypeDouble = "Double"

	// other types (such as array, map, etc.) are implemented in the method 'Typecast'
)

const (
	TPL_ENUM    = "tgen/java/enum"
	TPL_STRUCT  = "tgen/java/struct"
	TPL_SERVICE = "tgen/java/service"
)

var plaintypemapping = map[string]string{
	langs.ThriftTypeI16:    JavaTypeshort,
	langs.ThriftTypeI32:    JavaTypeint,
	langs.ThriftTypeI64:    JavaTypelong,
	langs.ThriftTypeString: JavaTypeString,
	langs.ThriftTypeByte:   JavaTypebyte,
	langs.ThriftTypeBool:   JavaTypebool,
	langs.ThriftTypeDouble: JavaTypedouble,
}

var objecttypemapping = map[string]string{
	langs.ThriftTypeI16:    JavaTypeShort,
	langs.ThriftTypeI32:    JavaTypeInt,
	langs.ThriftTypeI64:    JavaTypeLong,
	langs.ThriftTypeString: JavaTypeString,
	langs.ThriftTypeByte:   JavaTypeByte,
	langs.ThriftTypeBool:   JavaTypeBool,
	langs.ThriftTypeDouble: JavaTypeDouble,
}

type JavaGen struct {
	langs.BaseGen
}

type BaseJava struct {
	Namespace string
	t         *parser.Thrift
	ts        map[string]*parser.Thrift
}

func (b *BaseJava) FilterVariableName(n string) string {
	if b.IsKeyword(n) {
		return fmt.Sprintf("t%s%s", strings.ToUpper(n[:1]), n[1:])
	}
	return n
}

func (b *BaseJava) IsKeyword(n string) bool {
	switch n {
	case "package", "int", "short", "long", "byte", "boolean", "case", "switch", "if ", "for", "else",
		"goto", "Integer", "Short", "Long", "Byte", "Boolean", "class", "break", "try", "catch",
		"double", "Double", "do", "while", "final", "finally", "continue", "interface", "private",
		"public", "protected", "return", "this", "throw", "static", "super", "throws",
		"true", "false", "float", "volatile", "synchronized", "abstract", "default", "extends",
		"native", "new":
		return true
	}
	return false
}

func (b *BaseJava) PlainTypecast(t *parser.Type) string {
	return b.typecast(t, true)
}

func (b *BaseJava) ObjectTypecast(t *parser.Type) string {
	return b.typecast(t, false)
}

func (b *BaseJava) typecast(t *parser.Type, isplain bool) string {
	if t == nil {
		if isplain {
			return "void"
		} else {
			return "Void"
		}
	}

	var typemapping map[string]string

	if isplain {
		typemapping = plaintypemapping
	} else {
		typemapping = objecttypemapping
	}

	if t, ok := typemapping[t.Name]; ok {
		return t
	}

	switch t.Name {
	case langs.ThriftTypeList, langs.ThriftTypeSet:
		return fmt.Sprintf("java.util.ArrayList<%s>", b.ObjectTypecast(t.ValueType))
	case langs.ThriftTypeMap:
		return fmt.Sprintf("java.util.Map<%s, %s>", b.ObjectTypecast(t.KeyType), b.ObjectTypecast(t.ValueType))
	default:
		s := strings.Split(t.Name, ".")
		if len(s) == 1 {
			return s[0]
		} else if len(s) == 2 {
			pkg := ""
			for k, v := range b.t.Includes {
				if k == s[0] {
					for p, t := range b.ts {
						if v == p {
							pkg = t.Namespaces[javaLang]
							break
						}
					}

					break
				}
			}

			if pkg == "" {
				return s[1]
			}
			return fmt.Sprintf("%s.%s", pkg, s[1])
		} else {
			return t.Name
		}
	}
}

func (b *BaseJava) AssembleParams(method *parser.Method) string {
	var buf bytes.Buffer

	for i, arg := range method.Arguments {
		if i != 0 {
			buf.WriteString(", ")
		}

		buf.WriteString(fmt.Sprintf("final %s %s", b.PlainTypecast(arg.Type), b.FilterVariableName(arg.Name)))
	}

	if len(method.Arguments) == 0 {
		buf.WriteString("")
	} else {
		buf.WriteString(", ")
	}

	buf.WriteString(fmt.Sprintf("final Listener<%s> listener", b.ObjectTypecast(method.ReturnType)))

	return buf.String()
}

func (b *BaseJava) GetInnerType(t *parser.Type) string {
	if t == nil {
		return "Void"
	}

	// map is ignored
	if t.Name == langs.ThriftTypeList || t.Name == langs.ThriftTypeSet {
		return b.GetInnerType(t.ValueType)
	}

	return b.ObjectTypecast(t)
}

// IsEnum checks whether a type is enum.
// it first checks in its own definition, than check from included files
func (b *BaseJava) IsEnum(t *parser.Type) bool {
	if t == nil {
		return false
	}

	names := strings.Split(t.Name, ".")

	if len(names) == 1 {
		for n := range b.t.Enums {
			if n == t.Name {
				return true
			}
		}

		return false
	}

	for path, thrift := range b.ts {
		if thrift == b.t {
			continue
		}

		filename := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
		if filename != names[0] {
			continue
		}

		for n := range thrift.Enums {
			if n == names[1] {
				return true
			}
		}
	}

	return false
}

type javaEnum struct {
	*BaseJava
	*parser.Enum
}

func (e *javaEnum) GenerateProperties() string {
	size := len(e.Enum.Values)
	i := 0

	var buf bytes.Buffer
	for _, v := range e.Enum.Values {
		buf.WriteString(fmt.Sprintf("\t@SerializedName(\"%d\")\n", v.Value))
		buf.WriteString(fmt.Sprintf("\t%s(%d)", strings.ToUpper(v.Name), v.Value))
		if i == size-1 {
			buf.WriteString(";\n")
		} else {
			buf.WriteString(",\n")
		}
		i++
	}
	return buf.String()
}

type javaStruct struct {
	*BaseJava
	*parser.Struct
}

func (this *javaStruct) HasKeyword() bool {
	for _, f := range this.Struct.Fields {
		if this.BaseJava.IsKeyword(f.Name) {
			return true
		}
	}
	return false
}

type javaService struct {
	*BaseJava
	*parser.Service
}

func generateAll(gen *JavaGen, output string, parsedThrift map[string]*parser.Thrift) {
	generateWithModel(gen, global.MODE_REST, filepath.Join(output, global.MODE_REST), parsedThrift)
	generateWithModel(gen, global.MODE_JSONRPC, filepath.Join(output, global.MODE_JSONRPC), parsedThrift)
}

func (g *JavaGen) Generate(output string, parsedThrift map[string]*parser.Thrift) {
	if global.Mode != "" {
		generateWithModel(g, global.Mode, output, parsedThrift)
	} else {
		generateAll(g, output, parsedThrift)
	}
}

func generateWithModel(gen *JavaGen, m string, output string, parsedThrift map[string]*parser.Thrift) {
	if m != global.MODE_REST && m != global.MODE_JSONRPC {
		log.Fatalf("mode '%s' is invalid", m)
	}

	gen.BaseGen.Init(javaLang, parsedThrift)

	if err := os.MkdirAll(output, 0755); err != nil {
		panic(fmt.Errorf("failed to create output directory %s", output))
	}

	// init templates
	enumTpl := initemplate(TPL_ENUM, "tmpl/java/enum.gojava")

	var structTpl *template.Template
	var serviceTpl *template.Template
	if m == global.MODE_REST {
		structTpl = initemplate(TPL_STRUCT, "tmpl/java/rest_struct.gojava")
		serviceTpl = initemplate(TPL_SERVICE, "tmpl/java/rest_service.gojava")
	} else if m == global.MODE_JSONRPC {
		structTpl = initemplate(TPL_STRUCT, "tmpl/java/jsonrpc_struct.gojava")
		serviceTpl = initemplate(TPL_SERVICE, "tmpl/java/jsonrpc_service.gojava")
	}

	// key is the absoule path of thrift file
	for _, t := range parsedThrift {
		// due to java's features,
		// we generate the struct and service in seperate template file

		ns := t.Namespaces["java"]

		log.Printf("## structs")

		for _, s := range t.Structs {
			// filename is the struct name
			name := s.Name + javaExt

			// fix java file path
			p := filepath.Join(output, strings.Replace(ns, ".", "/", -1))
			if err := os.MkdirAll(p, 0755); err != nil {
				panic(fmt.Errorf("failed to create output directory %s", p))
			}

			path := filepath.Join(p, name)

			base := BaseJava{Namespace: ns, t: t, ts: parsedThrift}
			data := &javaStruct{BaseJava: &base, Struct: s}

			if err := outputfile(path, structTpl, TPL_STRUCT, data); err != nil {
				panic(fmt.Errorf("failed to write file %s. error: %v\n", path, err))
			}

			log.Printf("%s", path)
		}

		log.Printf("## services")

		for _, s := range t.Services {
			// filename is the service name plus 'Service'
			name := s.Name + "Service" + javaExt

			// fix java file path
			p := filepath.Join(output, strings.Replace(ns, ".", "/", -1))
			if err := os.MkdirAll(p, 0755); err != nil {
				panic(fmt.Errorf("failed to create output directory %s", p))
			}

			path := filepath.Join(p, name)

			base := BaseJava{Namespace: ns, t: t, ts: parsedThrift}
			data := &javaService{BaseJava: &base, Service: s}

			if err := outputfile(path, serviceTpl, TPL_SERVICE, data); err != nil {
				panic(fmt.Errorf("failed to write file %s. error: %v\n", path, err))
			}

			log.Printf("%s", path)
		}
	}
}

func initemplate(n string, path string) *template.Template {
	data, err := tmpl.Asset(path)
	if err != nil {
		panic(err)
	}

	tpl := template.New(n)

	// register functions
	funcMap := template.FuncMap{
		"ToUpper": strings.ToUpper,
	}
	tpl.Funcs(funcMap)

	_, err = tpl.Parse(string(data))
	if err != nil {
		panic(err)
	}

	return tpl
}

func outputfile(fp string, t *template.Template, tplname string, data interface{}) error {
	file, err := os.OpenFile(fp, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}

	defer file.Close()

	return t.ExecuteTemplate(file, tplname, data)
}

func init() {
	langs.Langs[javaLang] = &JavaGen{}
}
<|endoftext|>


<commit_before>package dog_pool

import "fmt"
import "strings"
import "github.com/fzzy/radix/redis"

const BITOP = "BITOP"
const BIT_AND = "AND"
const BIT_OR = "OR"
const BIT_NOT = "NOT"

const BITCOUNT = "BITCOUNT"

type RedisBatchCommand struct {
	Cmd   string
	Args  []string
	Reply *redis.Reply
}

func (p *RedisBatchCommand) String() string {
	return fmt.Sprintf("%s %s --> %#v", p.Cmd, strings.Join(p.Args, " "), p.Reply)
}

func MakeBitopAnd(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_AND, dest, sources)
}

func MakeBitopOr(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_OR, dest, sources)
}

func MakeBitopNot(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_NOT, dest, sources)
}

func MakeBitCount(key string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = BITCOUNT
	output.Args = []string{key}
	return output
}

func MakeGet(key string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = "GET"
	output.Args = []string{key}
	return output
}

func MakeDelete(keys []string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = "DEL"
	output.Args = keys
	return output
}

func SelectBitopDestKeys(commands []*RedisBatchCommand) []string {
	output := []string{}
	for _, command := range commands {
		if command.Cmd == BITOP {
			output = append(output, command.Args[1])
		}
	}
	return output
}

func makeBitopCommand(operation, dest string, sources []string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = BITOP
	output.Args = make([]string, 2+len(sources))
	output.Args[0] = operation
	output.Args[1] = dest
	copy(output.Args[2:], sources)
	return output
}
<commit_msg>Added Bit Set/Get commands<commit_after>package dog_pool

import "fmt"
import "strings"
import "github.com/fzzy/radix/redis"

const BITOP = "BITOP"
const BIT_AND = "AND"
const BIT_OR = "OR"
const BIT_NOT = "NOT"

const BITCOUNT = "BITCOUNT"

type RedisBatchCommand struct {
	Cmd   string
	Args  []string
	Reply *redis.Reply
}

func (p *RedisBatchCommand) String() string {
	return fmt.Sprintf("%s %s --> %#v", p.Cmd, strings.Join(p.Args, " "), p.Reply)
}

func MakeBitopAnd(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_AND, dest, sources)
}

func MakeBitopOr(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_OR, dest, sources)
}

func MakeBitopNot(dest string, sources []string) *RedisBatchCommand {
	return makeBitopCommand(BIT_NOT, dest, sources)
}

func MakeGetBit(key string, index int64) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = "GETBIT"
	output.Args = []string{key, fmt.Sprintf("%d", index)}
	return output
}

func MakeSetBit(key string, index int64, state bool) *RedisBatchCommand {
	state_str = "1"
	if (!state) {
		state_str ="0"
	}

	output := &RedisBatchCommand{}
	output.Cmd = "SETBIT"
	output.Args = []string{key, fmt.Sprintf("%d", index), state_str}
	return output
}

func MakeBitCount(key string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = BITCOUNT
	output.Args = []string{key}
	return output
}

func MakeGet(key string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = "GET"
	output.Args = []string{key}
	return output
}

func MakeDelete(keys []string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = "DEL"
	output.Args = keys
	return output
}

func SelectBitopDestKeys(commands []*RedisBatchCommand) []string {
	output := []string{}
	for _, command := range commands {
		if command.Cmd == BITOP {
			output = append(output, command.Args[1])
		}
	}
	return output
}

func makeBitopCommand(operation, dest string, sources []string) *RedisBatchCommand {
	output := &RedisBatchCommand{}
	output.Cmd = BITOP
	output.Args = make([]string, 2+len(sources))
	output.Args[0] = operation
	output.Args[1] = dest
	copy(output.Args[2:], sources)
	return output
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"github.com/applariat/go-apl/pkg/apl"
	"github.com/spf13/cobra"
)

// NewDeploymentsOverridesCommand
func NewDeploymentsOverridesCommand() *cobra.Command {

	var (
		componentsMap ComponentStringMap
	)

	cmd := &cobra.Command{
		Use:   "override [ID]",
		Short: fmt.Sprintf("Override a component artifact"),
		Long:  "",

		PreRunE: func(cmd *cobra.Command, args []string) error {
			err := checkCommandHasIDInArgs(args, "credential")
			if err != nil {
				return err
			}
			// If there is a file, no other checking is needed
			if isInputFileDefined() {
				return nil
			}

			var missingFlags []string

			if len(componentsMap.Values) <= 0 {
				missingFlags = append(missingFlags, "--component")
			}

			if len(missingFlags) > 0 {
				return fmt.Errorf("Missing required flags: %s", missingFlags)
			}

			return nil
		},

		Run: func(ccmd *cobra.Command, args []string) {
			aplSvc := apl.NewClient()

			in := &apl.DeploymentUpdateInput{}

			if !isInputFileDefined() {

				// Create the []apl.Components
				c := []apl.DeploymentComponent{}
				for _, cmp := range componentsMap.Values {

					artifact := deploymentArtifactFactory(aplSvc, cmp.StackArtifactIDs)

					dc := apl.DeploymentComponent{
						StackComponentID: cmp.StackComponentID,
						Services: []apl.Service{
							{
								Name: cmp.ServiceName,
								Build: apl.Build{
									Artifact: artifact,
								},
								Run: apl.Run{
									Instances: cmp.Instances,
								},
							},
						},
					}

					c = append(c, dc)

				}

				in = &apl.DeploymentUpdateInput{
					Command:    "override",
					Components: c,
				}

			}

			runUpdateCommand(args, in, aplSvc.Deployments.Update)
		},
	}

	cmd.Flags().Var(&componentsMap, "component", componentsMap.Usage())
	return cmd
}
<commit_msg>Fix message shown when ID is missing for Deployment Override<commit_after>package app

import (
	"fmt"
	"github.com/applariat/go-apl/pkg/apl"
	"github.com/spf13/cobra"
)

// NewDeploymentsOverridesCommand
func NewDeploymentsOverridesCommand() *cobra.Command {

	var (
		componentsMap ComponentStringMap
	)

	cmd := &cobra.Command{
		Use:   "override [ID]",
		Short: fmt.Sprintf("Override a component artifact"),
		Long:  "",

		PreRunE: func(cmd *cobra.Command, args []string) error {
			err := checkCommandHasIDInArgs(args, "deployment")
			if err != nil {
				return err
			}
			// If there is a file, no other checking is needed
			if isInputFileDefined() {
				return nil
			}

			var missingFlags []string

			if len(componentsMap.Values) <= 0 {
				missingFlags = append(missingFlags, "--component")
			}

			if len(missingFlags) > 0 {
				return fmt.Errorf("Missing required flags: %s", missingFlags)
			}

			return nil
		},

		Run: func(ccmd *cobra.Command, args []string) {
			aplSvc := apl.NewClient()

			in := &apl.DeploymentUpdateInput{}

			if !isInputFileDefined() {

				// Create the []apl.Components
				c := []apl.DeploymentComponent{}
				for _, cmp := range componentsMap.Values {

					artifact := deploymentArtifactFactory(aplSvc, cmp.StackArtifactIDs)

					dc := apl.DeploymentComponent{
						StackComponentID: cmp.StackComponentID,
						Services: []apl.Service{
							{
								Name: cmp.ServiceName,
								Build: apl.Build{
									Artifact: artifact,
								},
								Run: apl.Run{
									Instances: cmp.Instances,
								},
							},
						},
					}

					c = append(c, dc)

				}

				in = &apl.DeploymentUpdateInput{
					Command:    "override",
					Components: c,
				}

			}

			runUpdateCommand(args, in, aplSvc.Deployments.Update)
		},
	}

	cmd.Flags().Var(&componentsMap, "component", componentsMap.Usage())
	return cmd
}
<|endoftext|>


<commit_before>// Command deploy-from-docker creates/updates single configuration from the
// docker image save output read as stdin.
//
// Usage example:
//
// 	docker save alpine:latest | deploy-from-docker
//
// This would create/update configuration named alpine.latest
package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/knownhosts"

	"github.com/artyom/autoflags"
	"github.com/pkg/errors"
	"github.com/pkg/sftp"
)

// defaults can be pre-defined on build time using -ldflags="-X=..."
var defaultAddress, defaultFingerprint string

func main() {
	args := &runArgs{
		Addr: defaultAddress,
		Fp:   defaultFingerprint,
	}
	if val, ok := os.LookupEnv("DEPLOYCTL_ADDR"); ok {
		args.Addr = val
	}
	if val, ok := os.LookupEnv("DEPLOYCTL_FINGERPRINT"); ok {
		args.Fp = val
	}
	autoflags.Parse(args)
	if err := args.Validate(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
		flag.Usage()
		os.Exit(2)
	}
	if err := run(args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(args *runArgs) error {
	if err := args.Validate(); err != nil {
		return err
	}
	var hostKeyCallback ssh.HostKeyCallback
	var err error
	switch args.Fp {
	case "":
		hostKeyCallback, err = knownhosts.New(os.ExpandEnv("${HOME}/.ssh/known_hosts"))
		if err != nil {
			return err
		}
	default:
		hostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			if hostFp := ssh.FingerprintSHA256(key); hostFp != args.Fp {
				return errors.Errorf("host key fingerprint mismatch: %v", hostFp)
			}
			return nil
		}
	}
	name, layers, err := repack(os.Stdin)
	if err != nil {
		return err
	}
	if args.Name != "" {
		name = args.Name
	}
	client, cclose, err := dialSSH(args.Addr, args.Key, hostKeyCallback)
	if err != nil {
		return err
	}
	defer cclose()
	return uploadAndSwitch(client, name, layers)
}

func uploadAndSwitch(client *ssh.Client, name string, layers []io.Reader) error {
	if name == "" {
		return errors.New("empty name")
	}
	if len(layers) == 0 {
		return errors.New("no layers found")
	}
	name = strings.Map(func(r rune) rune {
		switch r {
		case ':', '/':
			return '.'
		}
		return r
	}, name)
	components := make([]string, 0, len(layers))
	for i, rd := range layers {
		lname := fmt.Sprintf("%s.l%d", name, i+1)
		fmt.Fprintf(os.Stderr, "uploading %d/%d: %q\n", i+1, len(layers), lname)
		h, err := upload(client, rd)
		if err != nil {
			return errors.WithMessage(err, "upload failed")
		}
		hash := fmt.Sprintf("%x", h)
		if err := addVersion(client, lname, hash); err != nil {
			return errors.WithMessage(err, "failed to add version")
		}
		components = append(components, lname+":"+hash)
	}
	cmdArgs := make([]string, 0, 2+len(components))
	cmdArgs = append(cmdArgs, "addconf", fmt.Sprintf("-name=%q", name))
	for _, s := range components {
		cmdArgs = append(cmdArgs, fmt.Sprintf("-layer=%q", s))
	}
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	fmt.Fprintf(os.Stderr, "updating configuration %q\n", name)
	return session.Run(strings.Join(cmdArgs, " "))
}

func addVersion(client *ssh.Client, name, hash string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	buf, err := session.CombinedOutput(
		fmt.Sprintf("addver -name=%q -version=%s -hash=%[2]s", name, hash))
	if err != nil && bytes.Contains(buf, []byte("already exists")) {
		return nil
	}
	if err != nil {
		os.Stderr.Write(buf)
		return err
	}
	return nil
}

func upload(client *ssh.Client, src io.Reader) ([]byte, error) {
	sftpconn, err := sftp.NewClient(client)
	if err != nil {
		return nil, err
	}
	defer sftpconn.Close()
	dst, err := sftpconn.Create("upload")
	if err != nil {
		return nil, err
	}
	defer dst.Close()
	h := sha256.New()
	gw := gzip.NewWriter(io.MultiWriter(dst, h))
	if _, err := io.Copy(gw, src); err != nil {
		return nil, errors.WithMessage(err, "upload failure")
	}
	if err := gw.Close(); err != nil {
		return nil, errors.WithMessage(err, "upload failure")
	}
	return h.Sum(nil), dst.Close()
}

func dialSSH(addr, keyFile string, hostKeyCallback ssh.HostKeyCallback) (client *ssh.Client, closeFunc func(), err error) {
	var signers []ssh.Signer
	switch {
	case keyFile != "":
		s, err := readKey(keyFile)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "failed to read/parse key file %q", keyFile)
		}
		signers = append(signers, s)
	default:
		agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
		if err != nil {
			return nil, nil, errors.WithMessage(err, "cannot connect to ssh-agent, check if SSH_AUTH_SOCK is set")
		}
		defer agentConn.Close()
		sshAgent := agent.NewClient(agentConn)
		signers, err = sshAgent.Signers()
		if err != nil {
			return nil, nil, err
		}
	}
	config := &ssh.ClientConfig{
		User:            os.Getenv("USER"),
		Auth:            []ssh.AuthMethod{ssh.PublicKeys(signers...)},
		Timeout:         30 * time.Second,
		HostKeyCallback: hostKeyCallback,
	}
	client, err = ssh.Dial("tcp", addr, config)
	if err != nil {
		return nil, nil, err
	}
	closeFunc = func() { client.Close() }
	return client, closeFunc, nil
}

type runArgs struct {
	Addr string `flag:"addr,$DEPLOYCTL_ADDR, registry host address (host:port)"`
	Fp   string `flag:"fp,$DEPLOYCTL_FINGERPRINT, sha256 host key fingerprint (sha256:...)"`
	Key  string `flag:"key,ssh private key to use; if not set, ssh-agent is used"`
	Name string `flag:"name,configuration name; derived from docker image tag if not set"`
}

func (a *runArgs) Validate() error {
	if a.Addr == "" {
		return errors.New("addr should be set")
	}
	return nil
}

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "docker save myimage:tag | deploy-from-docker [flags]")
		flag.PrintDefaults()
	}
}

func readKey(name string) (ssh.Signer, error) {
	privateBytes, err := ioutil.ReadFile(name)
	if err != nil {
		return nil, err
	}
	return ssh.ParsePrivateKey(privateBytes)
}

func repack(input io.Reader) (string, []io.Reader, error) {
	tr := tar.NewReader(input)
	layers := make(map[string]*os.File)
	var name string
	var mlayers []*layerMeta
	var happyPath bool
	defer func() {
		if !happyPath {
			for _, f := range layers {
				f.Close()
			}
		}
	}()
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			if err := fillSkips(layers, mlayers); err != nil {
				return "", nil, err
			}
			ret := make([]io.Reader, 0, len(mlayers))
			defer func() { // make sure to unblock io.PipeWriters
				if !happyPath {
					for _, c := range ret {
						c.(io.Closer).Close()
					}
				}
			}()
			for _, meta := range mlayers {
				f, ok := layers[meta.name]
				if !ok {
					return "", nil, fmt.Errorf("manifest references unknown layer %q", meta.name)
				}
				if _, err := f.Seek(0, io.SeekStart); err != nil {
					return "", nil, err
				}
				ret = append(ret, restream(f, meta.skip))
			}
			happyPath = true
			return name, ret, nil
		}
		if err != nil {
			return "", nil, err
		}
		if strings.HasSuffix(hdr.Name, "/layer.tar") {
			f, err := dumpStream(tr)
			if err != nil {
				return "", nil, err
			}
			layers[hdr.Name] = f
			continue
		}
		if hdr.Name == "manifest.json" {
			if name, mlayers, err = decodeManifest(tr); err != nil {
				return "", nil, err
			}
		}
	}
}

func restream(input io.Reader, skip map[string]struct{}) io.Reader {
	pr, pw := io.Pipe()
	go func() { pw.CloseWithError(copyStream(pw, input, skip)) }()
	return pr
}

func copyStream(output io.Writer, input io.Reader, skip map[string]struct{}) error {
	tr := tar.NewReader(input)
	tw := tar.NewWriter(output)
	defer tw.Close()
tarLoop:
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			return tw.Close()
		}
		if err != nil {
			return err
		}
		if _, ok := skip[hdr.Name]; ok {
			continue
		}
		if hdr.Mode == 0 && strings.HasPrefix(path.Base(hdr.Name), tombstone) {
			continue
		}
		for prefix := range skip {
			if strings.HasPrefix(hdr.Name, prefix+"/") {
				continue tarLoop
			}
		}
		if err := tw.WriteHeader(hdr); err != nil {
			return err
		}
		if _, err := io.Copy(tw, tr); err != nil {
			return err
		}
	}
}

func decodeManifest(r io.Reader) (string, []*layerMeta, error) {
	data := []struct {
		RepoTags []string
		Layers   []string
	}{}
	if err := json.NewDecoder(r).Decode(&data); err != nil {
		return "", nil, err
	}
	if l := len(data); l != 1 {
		return "", nil, fmt.Errorf("manifest.json describes %d objects, call docker save for a single image", l)
	}
	out := make([]*layerMeta, len(data[0].Layers))
	for i, name := range data[0].Layers {
		out[i] = &layerMeta{name: name}
	}
	var name string
	if len(data[0].RepoTags) > 0 {
		name = data[0].RepoTags[0]
	}
	return name, out, nil
}

func dumpStream(r io.Reader) (*os.File, error) {
	f, err := ioutil.TempFile("", "merge-docker-save-")
	if err != nil {
		return nil, err
	}
	os.Remove(f.Name())
	if _, err := io.Copy(f, r); err != nil {
		f.Close()
		return nil, err
	}
	return f, nil
}

type layerMeta struct {
	name string
	skip map[string]struct{}
}

// fillSkips fills skip fields of mlayers elements from the tombstone items
// discovered in files referenced in layers map. skip fields filled in such
// a way that for each layer it holds a set of names that should be skipped when
// repacking tar stream since these items would be removed by the following
// layers.
func fillSkips(layers map[string]*os.File, mlayers []*layerMeta) error {
	for i := len(mlayers) - 1; i > 0; i-- {
		meta := mlayers[i]
		f, ok := layers[meta.name]
		if !ok {
			return fmt.Errorf("manifest references unknown layer %q", meta.name)
		}
		skips, err := findSkips(f)
		if err != nil {
			return err
		}
		if skips == nil {
			continue
		}
		for _, meta := range mlayers[:i] {
			if meta.skip == nil {
				meta.skip = make(map[string]struct{})
			}
			for _, s := range skips {
				meta.skip[s] = struct{}{}
			}
		}
	}
	return nil
}

// findSkips scans tar archive for tombstone items and returns list of
// corresponding file names.
func findSkips(f io.ReadSeeker) ([]string, error) {
	if _, err := f.Seek(0, io.SeekStart); err != nil {
		return nil, err
	}
	var skips []string
	tr := tar.NewReader(f)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			return skips, nil
		}
		if err != nil {
			return nil, err
		}
		if hdr.Mode != 0 {
			continue
		}
		if base := path.Base(hdr.Name); strings.HasPrefix(base, tombstone) && base != tombstone {
			skips = append(skips, path.Join(path.Dir(hdr.Name), strings.TrimPrefix(base, tombstone)))
		}
	}
}

const tombstone = ".wh." // prefix docker uses to mark deleted files
<commit_msg>deploy-from-docker: always close files explicitly<commit_after>// Command deploy-from-docker creates/updates single configuration from the
// docker image save output read as stdin.
//
// Usage example:
//
// 	docker save alpine:latest | deploy-from-docker
//
// This would create/update configuration named alpine.latest
package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"path"
	"strings"
	"time"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
	"golang.org/x/crypto/ssh/knownhosts"

	"github.com/artyom/autoflags"
	"github.com/pkg/errors"
	"github.com/pkg/sftp"
)

// defaults can be pre-defined on build time using -ldflags="-X=..."
var defaultAddress, defaultFingerprint string

func main() {
	args := &runArgs{
		Addr: defaultAddress,
		Fp:   defaultFingerprint,
	}
	if val, ok := os.LookupEnv("DEPLOYCTL_ADDR"); ok {
		args.Addr = val
	}
	if val, ok := os.LookupEnv("DEPLOYCTL_FINGERPRINT"); ok {
		args.Fp = val
	}
	autoflags.Parse(args)
	if err := args.Validate(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n\n", err)
		flag.Usage()
		os.Exit(2)
	}
	if err := run(args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func run(args *runArgs) error {
	if err := args.Validate(); err != nil {
		return err
	}
	var hostKeyCallback ssh.HostKeyCallback
	var err error
	switch args.Fp {
	case "":
		hostKeyCallback, err = knownhosts.New(os.ExpandEnv("${HOME}/.ssh/known_hosts"))
		if err != nil {
			return err
		}
	default:
		hostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			if hostFp := ssh.FingerprintSHA256(key); hostFp != args.Fp {
				return errors.Errorf("host key fingerprint mismatch: %v", hostFp)
			}
			return nil
		}
	}
	name, layers, err := repack(os.Stdin)
	if err != nil {
		return err
	}
	defer func() {
		for _, c := range layers {
			c.Close()
		}
	}()
	if args.Name != "" {
		name = args.Name
	}
	client, cclose, err := dialSSH(args.Addr, args.Key, hostKeyCallback)
	if err != nil {
		return err
	}
	defer cclose()
	return uploadAndSwitch(client, name, layers)
}

func uploadAndSwitch(client *ssh.Client, name string, layers []io.ReadCloser) error {
	if name == "" {
		return errors.New("empty name")
	}
	if len(layers) == 0 {
		return errors.New("no layers found")
	}
	name = strings.Map(func(r rune) rune {
		switch r {
		case ':', '/':
			return '.'
		}
		return r
	}, name)
	components := make([]string, 0, len(layers))
	for i, rd := range layers {
		lname := fmt.Sprintf("%s.l%d", name, i+1)
		fmt.Fprintf(os.Stderr, "uploading %d/%d: %q\n", i+1, len(layers), lname)
		h, err := upload(client, rd)
		if err != nil {
			return errors.WithMessage(err, "upload failed")
		}
		hash := fmt.Sprintf("%x", h)
		if err := addVersion(client, lname, hash); err != nil {
			return errors.WithMessage(err, "failed to add version")
		}
		components = append(components, lname+":"+hash)
	}
	cmdArgs := make([]string, 0, 2+len(components))
	cmdArgs = append(cmdArgs, "addconf", fmt.Sprintf("-name=%q", name))
	for _, s := range components {
		cmdArgs = append(cmdArgs, fmt.Sprintf("-layer=%q", s))
	}
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	session.Stdout = os.Stdout
	session.Stderr = os.Stderr
	fmt.Fprintf(os.Stderr, "updating configuration %q\n", name)
	return session.Run(strings.Join(cmdArgs, " "))
}

func addVersion(client *ssh.Client, name, hash string) error {
	session, err := client.NewSession()
	if err != nil {
		return err
	}
	defer session.Close()
	buf, err := session.CombinedOutput(
		fmt.Sprintf("addver -name=%q -version=%s -hash=%[2]s", name, hash))
	if err != nil && bytes.Contains(buf, []byte("already exists")) {
		return nil
	}
	if err != nil {
		os.Stderr.Write(buf)
		return err
	}
	return nil
}

func upload(client *ssh.Client, src io.Reader) ([]byte, error) {
	sftpconn, err := sftp.NewClient(client)
	if err != nil {
		return nil, err
	}
	defer sftpconn.Close()
	dst, err := sftpconn.Create("upload")
	if err != nil {
		return nil, err
	}
	defer dst.Close()
	h := sha256.New()
	gw := gzip.NewWriter(io.MultiWriter(dst, h))
	if _, err := io.Copy(gw, src); err != nil {
		return nil, errors.WithMessage(err, "upload failure")
	}
	if err := gw.Close(); err != nil {
		return nil, errors.WithMessage(err, "upload failure")
	}
	return h.Sum(nil), dst.Close()
}

func dialSSH(addr, keyFile string, hostKeyCallback ssh.HostKeyCallback) (client *ssh.Client, closeFunc func(), err error) {
	var signers []ssh.Signer
	switch {
	case keyFile != "":
		s, err := readKey(keyFile)
		if err != nil {
			return nil, nil, errors.Wrapf(err, "failed to read/parse key file %q", keyFile)
		}
		signers = append(signers, s)
	default:
		agentConn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
		if err != nil {
			return nil, nil, errors.WithMessage(err, "cannot connect to ssh-agent, check if SSH_AUTH_SOCK is set")
		}
		defer agentConn.Close()
		sshAgent := agent.NewClient(agentConn)
		signers, err = sshAgent.Signers()
		if err != nil {
			return nil, nil, err
		}
	}
	config := &ssh.ClientConfig{
		User:            os.Getenv("USER"),
		Auth:            []ssh.AuthMethod{ssh.PublicKeys(signers...)},
		Timeout:         30 * time.Second,
		HostKeyCallback: hostKeyCallback,
	}
	client, err = ssh.Dial("tcp", addr, config)
	if err != nil {
		return nil, nil, err
	}
	closeFunc = func() { client.Close() }
	return client, closeFunc, nil
}

type runArgs struct {
	Addr string `flag:"addr,$DEPLOYCTL_ADDR, registry host address (host:port)"`
	Fp   string `flag:"fp,$DEPLOYCTL_FINGERPRINT, sha256 host key fingerprint (sha256:...)"`
	Key  string `flag:"key,ssh private key to use; if not set, ssh-agent is used"`
	Name string `flag:"name,configuration name; derived from docker image tag if not set"`
}

func (a *runArgs) Validate() error {
	if a.Addr == "" {
		return errors.New("addr should be set")
	}
	return nil
}

func init() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "docker save myimage:tag | deploy-from-docker [flags]")
		flag.PrintDefaults()
	}
}

func readKey(name string) (ssh.Signer, error) {
	privateBytes, err := ioutil.ReadFile(name)
	if err != nil {
		return nil, err
	}
	return ssh.ParsePrivateKey(privateBytes)
}

func repack(input io.Reader) (string, []io.ReadCloser, error) {
	tr := tar.NewReader(input)
	layers := make(map[string]*os.File)
	var name string
	var mlayers []*layerMeta
	var happyPath bool
	defer func() {
		if !happyPath {
			for _, f := range layers {
				f.Close()
			}
		}
	}()
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			if err := fillSkips(layers, mlayers); err != nil {
				return "", nil, err
			}
			ret := make([]io.ReadCloser, 0, len(mlayers))
			defer func() { // make sure to unblock io.PipeWriters
				if !happyPath {
					for _, c := range ret {
						c.Close()
					}
				}
			}()
			for _, meta := range mlayers {
				f, ok := layers[meta.name]
				if !ok {
					return "", nil, fmt.Errorf("manifest references unknown layer %q", meta.name)
				}
				if _, err := f.Seek(0, io.SeekStart); err != nil {
					return "", nil, err
				}
				ret = append(ret, restream(f, meta.skip))
			}
			happyPath = true
			return name, ret, nil
		}
		if err != nil {
			return "", nil, err
		}
		if strings.HasSuffix(hdr.Name, "/layer.tar") {
			f, err := dumpStream(tr)
			if err != nil {
				return "", nil, err
			}
			layers[hdr.Name] = f
			continue
		}
		if hdr.Name == "manifest.json" {
			if name, mlayers, err = decodeManifest(tr); err != nil {
				return "", nil, err
			}
		}
	}
}

func restream(input io.ReadCloser, skip map[string]struct{}) io.ReadCloser {
	pr, pw := io.Pipe()
	go func() { pw.CloseWithError(copyStream(pw, input, skip)) }()
	return pr
}

func copyStream(output io.Writer, input io.ReadCloser, skip map[string]struct{}) error {
	defer input.Close()
	tr := tar.NewReader(input)
	tw := tar.NewWriter(output)
	defer tw.Close()
tarLoop:
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			return tw.Close()
		}
		if err != nil {
			return err
		}
		if _, ok := skip[hdr.Name]; ok {
			continue
		}
		if hdr.Mode == 0 && strings.HasPrefix(path.Base(hdr.Name), tombstone) {
			continue
		}
		for prefix := range skip {
			if strings.HasPrefix(hdr.Name, prefix+"/") {
				continue tarLoop
			}
		}
		if err := tw.WriteHeader(hdr); err != nil {
			return err
		}
		if _, err := io.Copy(tw, tr); err != nil {
			return err
		}
	}
}

func decodeManifest(r io.Reader) (string, []*layerMeta, error) {
	data := []struct {
		RepoTags []string
		Layers   []string
	}{}
	if err := json.NewDecoder(r).Decode(&data); err != nil {
		return "", nil, err
	}
	if l := len(data); l != 1 {
		return "", nil, fmt.Errorf("manifest.json describes %d objects, call docker save for a single image", l)
	}
	out := make([]*layerMeta, len(data[0].Layers))
	for i, name := range data[0].Layers {
		out[i] = &layerMeta{name: name}
	}
	var name string
	if len(data[0].RepoTags) > 0 {
		name = data[0].RepoTags[0]
	}
	return name, out, nil
}

func dumpStream(r io.Reader) (*os.File, error) {
	f, err := ioutil.TempFile("", "merge-docker-save-")
	if err != nil {
		return nil, err
	}
	os.Remove(f.Name())
	if _, err := io.Copy(f, r); err != nil {
		f.Close()
		return nil, err
	}
	return f, nil
}

type layerMeta struct {
	name string
	skip map[string]struct{}
}

// fillSkips fills skip fields of mlayers elements from the tombstone items
// discovered in files referenced in layers map. skip fields filled in such
// a way that for each layer it holds a set of names that should be skipped when
// repacking tar stream since these items would be removed by the following
// layers.
func fillSkips(layers map[string]*os.File, mlayers []*layerMeta) error {
	for i := len(mlayers) - 1; i > 0; i-- {
		meta := mlayers[i]
		f, ok := layers[meta.name]
		if !ok {
			return fmt.Errorf("manifest references unknown layer %q", meta.name)
		}
		skips, err := findSkips(f)
		if err != nil {
			return err
		}
		if skips == nil {
			continue
		}
		for _, meta := range mlayers[:i] {
			if meta.skip == nil {
				meta.skip = make(map[string]struct{})
			}
			for _, s := range skips {
				meta.skip[s] = struct{}{}
			}
		}
	}
	return nil
}

// findSkips scans tar archive for tombstone items and returns list of
// corresponding file names.
func findSkips(f io.ReadSeeker) ([]string, error) {
	if _, err := f.Seek(0, io.SeekStart); err != nil {
		return nil, err
	}
	var skips []string
	tr := tar.NewReader(f)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			return skips, nil
		}
		if err != nil {
			return nil, err
		}
		if hdr.Mode != 0 {
			continue
		}
		if base := path.Base(hdr.Name); strings.HasPrefix(base, tombstone) && base != tombstone {
			skips = append(skips, path.Join(path.Dir(hdr.Name), strings.TrimPrefix(base, tombstone)))
		}
	}
}

const tombstone = ".wh." // prefix docker uses to mark deleted files
<|endoftext|>


<commit_before>package exporter

/*
  to run the tests with redis running on anything but localhost:6379 use
  $ go test   --redis.addr=<host>:<port>

  for html coverage report run
  $ go test -coverprofile=coverage.out  && go tool cover -html=coverage.out
*/

import (
	"flag"
	"fmt"
	"log"
	"strings"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

var (
	keys         = []string{}
	keysExpiring = []string{}
	ts           = int32(time.Now().Unix())
	r            = RedisHost{}

	dbNumStr     = "11"
	dbNumStrFull = fmt.Sprintf("db%s", dbNumStr)
)

func setupDBKeys(t *testing.T) error {

	c, err := redis.Dial("tcp", r.Addrs[0])
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}
	defer c.Close()

	_, err = c.Do("SELECT", dbNumStr)
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}

	for _, key := range keys {
		_, err = c.Do("SET", key, "value")
		if err != nil {
			t.Errorf("couldn't setup redis, err: %s ", err)
			return err
		}
	}

	// setting to expire in 300 seconds, should be plenty for a test run
	for _, key := range keysExpiring {
		_, err = c.Do("SETEX", key, "300", "value")
		if err != nil {
			t.Errorf("couldn't setup redis, err: %s ", err)
			return err
		}
	}

	time.Sleep(time.Millisecond * 150)

	return nil
}

func deleteKeysFromDB(t *testing.T) error {

	c, err := redis.Dial("tcp", r.Addrs[0])
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}
	defer c.Close()

	_, err = c.Do("SELECT", dbNumStr)
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}

	for _, key := range keys {
		c.Do("DEL", key)
	}

	for _, key := range keysExpiring {
		c.Do("DEL", key)
	}

	return nil
}

func TestCountingKeys(t *testing.T) {

	e := NewRedisExporter(r, "test")

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	var keysTestDB float64 = 0
	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			keysTestDB = s.Value
			break
		}
	}

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes = make(chan scrapeResult)
	go e.scrape(scrapes)

	want := keysTestDB + float64(len(keys)) + float64(len(keysExpiring))

	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			if want != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
	}

	deleteKeysFromDB(t)
	scrapes = make(chan scrapeResult)
	go e.scrape(scrapes)

	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			if keysTestDB != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
		if s.Name == "db_avg_ttl_seconds" && s.DB == dbNumStrFull {
			if keysTestDB != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
	}
}

func TestExporterMetrics(t *testing.T) {

	e := NewRedisExporter(r, "test")

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	e.setMetrics(scrapes)

	want := 25
	if len(e.metrics) < want {
		t.Errorf("need moar metrics, found %d, want > %d", len(e.metrics), want)
	}

	wantKeys := []string{
		"db_keys_total",
		"db_avg_ttl_seconds",
		"instantaneous_ops_per_sec",
		"used_cpu_sys",
		"repl_loading", // testing renameMap
	}

	for _, k := range wantKeys {
		if _, ok := e.metrics[k]; !ok {
			t.Errorf("missing metrics key: %s", k)
		}
	}
}

func TestExporterValues(t *testing.T) {

	e := NewRedisExporter(r, "test")

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	wantValues := map[string]float64{
		"db_keys_total":          float64(len(keys) + len(keysExpiring)),
		"db_expiring_keys_total": float64(len(keysExpiring)),
	}

	for s := range scrapes {
		if wantVal, ok := wantValues[s.Name]; ok {
			if dbNumStrFull == s.DB && wantVal != s.Value {
				t.Errorf("values not matching, %f != %f", wantVal, s.Value)
			}
		}
	}
}

type tstData struct {
	db                        string
	stats                     string
	keysTotal, keysEx, avgTTL float64
	ok                        bool
}

func TestKeyspaceStringParser(t *testing.T) {
	tsts := []tstData{
		tstData{db: "xxx", stats: "", ok: false},
		tstData{db: "xxx", stats: "keys=1,expires=0,avg_ttl=0", ok: false},
		tstData{db: "db0", stats: "xxx", ok: false},
		tstData{db: "db1", stats: "keys=abcd,expires=0,avg_ttl=0", ok: false},
		tstData{db: "db2", stats: "keys=1234=1234,expires=0,avg_ttl=0", ok: false},

		tstData{db: "db3", stats: "keys=abcde,expires=0", ok: false},
		tstData{db: "db3", stats: "keys=213,expires=xxx", ok: false},
		tstData{db: "db3", stats: "keys=123,expires=0,avg_ttl=zzz", ok: false},

		tstData{db: "db0", stats: "keys=1,expires=0,avg_ttl=0", keysTotal: 1, keysEx: 0, avgTTL: 0, ok: true},
	}

	for _, tst := range tsts {
		if kt, kx, ttl, ok := parseDBKeyspaceString(tst.db, tst.stats); true {

			if ok != tst.ok {
				t.Errorf("failed for: db:%s stats:%s", tst.db, tst.stats)
				continue
			}

			if ok && (kt != tst.keysTotal || kx != tst.keysEx || ttl != tst.avgTTL) {
				t.Errorf("values not matching, db:%s stats:%s   %f %f %f", tst.db, tst.stats, kt, kx, ttl)
			}
		}
	}
}

func init() {
	for _, n := range []string{"john", "paul", "ringo", "george"} {
		key := fmt.Sprintf("key-%s-%d", n, ts)
		keys = append(keys, key)
	}

	for _, n := range []string{"A.J.", "Howie", "Nick", "Kevin", "Brian"} {
		key := fmt.Sprintf("key-exp-%s-%d", n, ts)
		keysExpiring = append(keysExpiring, key)
	}

	redisAddr := flag.String("redis.addr", "localhost:6379", "Address of one or more redis nodes, separated by separator")

	flag.Parse()
	addrs := strings.Split(*redisAddr, ",")
	if len(addrs) == 0 || len(addrs[0]) == 0 {
		log.Fatal("Invalid parameter --redis.addr")
	}
	log.Printf("Using redis addrs: %#v", addrs)
	r = RedisHost{Addrs: addrs}
}
<commit_msg>heed golint<commit_after>package exporter

/*
  to run the tests with redis running on anything but localhost:6379 use
  $ go test   --redis.addr=<host>:<port>

  for html coverage report run
  $ go test -coverprofile=coverage.out  && go tool cover -html=coverage.out
*/

import (
	"flag"
	"fmt"
	"log"
	"strings"
	"testing"
	"time"

	"github.com/garyburd/redigo/redis"
)

var (
	keys         = []string{}
	keysExpiring = []string{}
	ts           = int32(time.Now().Unix())
	r            = RedisHost{}

	dbNumStr     = "11"
	dbNumStrFull = fmt.Sprintf("db%s", dbNumStr)
)

func setupDBKeys(t *testing.T) error {

	c, err := redis.Dial("tcp", r.Addrs[0])
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}
	defer c.Close()

	_, err = c.Do("SELECT", dbNumStr)
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}

	for _, key := range keys {
		_, err = c.Do("SET", key, "value")
		if err != nil {
			t.Errorf("couldn't setup redis, err: %s ", err)
			return err
		}
	}

	// setting to expire in 300 seconds, should be plenty for a test run
	for _, key := range keysExpiring {
		_, err = c.Do("SETEX", key, "300", "value")
		if err != nil {
			t.Errorf("couldn't setup redis, err: %s ", err)
			return err
		}
	}

	time.Sleep(time.Millisecond * 150)

	return nil
}

func deleteKeysFromDB(t *testing.T) error {

	c, err := redis.Dial("tcp", r.Addrs[0])
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}
	defer c.Close()

	_, err = c.Do("SELECT", dbNumStr)
	if err != nil {
		t.Errorf("couldn't setup redis, err: %s ", err)
		return err
	}

	for _, key := range keys {
		c.Do("DEL", key)
	}

	for _, key := range keysExpiring {
		c.Do("DEL", key)
	}

	return nil
}

func TestCountingKeys(t *testing.T) {

	e := NewRedisExporter(r, "test")

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	var keysTestDB float64
	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			keysTestDB = s.Value
			break
		}
	}

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes = make(chan scrapeResult)
	go e.scrape(scrapes)

	want := keysTestDB + float64(len(keys)) + float64(len(keysExpiring))

	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			if want != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
	}

	deleteKeysFromDB(t)
	scrapes = make(chan scrapeResult)
	go e.scrape(scrapes)

	for s := range scrapes {
		if s.Name == "db_keys_total" && s.DB == dbNumStrFull {
			if keysTestDB != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
		if s.Name == "db_avg_ttl_seconds" && s.DB == dbNumStrFull {
			if keysTestDB != s.Value {
				t.Errorf("values not matching, %f != %f", keysTestDB, s.Value)
			}
			break
		}
	}
}

func TestExporterMetrics(t *testing.T) {

	e := NewRedisExporter(r, "test")

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	e.setMetrics(scrapes)

	want := 25
	if len(e.metrics) < want {
		t.Errorf("need moar metrics, found %d, want > %d", len(e.metrics), want)
	}

	wantKeys := []string{
		"db_keys_total",
		"db_avg_ttl_seconds",
		"instantaneous_ops_per_sec",
		"used_cpu_sys",
		"repl_loading", // testing renameMap
	}

	for _, k := range wantKeys {
		if _, ok := e.metrics[k]; !ok {
			t.Errorf("missing metrics key: %s", k)
		}
	}
}

func TestExporterValues(t *testing.T) {

	e := NewRedisExporter(r, "test")

	setupDBKeys(t)
	defer deleteKeysFromDB(t)

	scrapes := make(chan scrapeResult)
	go e.scrape(scrapes)

	wantValues := map[string]float64{
		"db_keys_total":          float64(len(keys) + len(keysExpiring)),
		"db_expiring_keys_total": float64(len(keysExpiring)),
	}

	for s := range scrapes {
		if wantVal, ok := wantValues[s.Name]; ok {
			if dbNumStrFull == s.DB && wantVal != s.Value {
				t.Errorf("values not matching, %f != %f", wantVal, s.Value)
			}
		}
	}
}

type tstData struct {
	db                        string
	stats                     string
	keysTotal, keysEx, avgTTL float64
	ok                        bool
}

func TestKeyspaceStringParser(t *testing.T) {
	tsts := []tstData{
		tstData{db: "xxx", stats: "", ok: false},
		tstData{db: "xxx", stats: "keys=1,expires=0,avg_ttl=0", ok: false},
		tstData{db: "db0", stats: "xxx", ok: false},
		tstData{db: "db1", stats: "keys=abcd,expires=0,avg_ttl=0", ok: false},
		tstData{db: "db2", stats: "keys=1234=1234,expires=0,avg_ttl=0", ok: false},

		tstData{db: "db3", stats: "keys=abcde,expires=0", ok: false},
		tstData{db: "db3", stats: "keys=213,expires=xxx", ok: false},
		tstData{db: "db3", stats: "keys=123,expires=0,avg_ttl=zzz", ok: false},

		tstData{db: "db0", stats: "keys=1,expires=0,avg_ttl=0", keysTotal: 1, keysEx: 0, avgTTL: 0, ok: true},
	}

	for _, tst := range tsts {
		if kt, kx, ttl, ok := parseDBKeyspaceString(tst.db, tst.stats); true {

			if ok != tst.ok {
				t.Errorf("failed for: db:%s stats:%s", tst.db, tst.stats)
				continue
			}

			if ok && (kt != tst.keysTotal || kx != tst.keysEx || ttl != tst.avgTTL) {
				t.Errorf("values not matching, db:%s stats:%s   %f %f %f", tst.db, tst.stats, kt, kx, ttl)
			}
		}
	}
}

func init() {
	for _, n := range []string{"john", "paul", "ringo", "george"} {
		key := fmt.Sprintf("key-%s-%d", n, ts)
		keys = append(keys, key)
	}

	for _, n := range []string{"A.J.", "Howie", "Nick", "Kevin", "Brian"} {
		key := fmt.Sprintf("key-exp-%s-%d", n, ts)
		keysExpiring = append(keysExpiring, key)
	}

	redisAddr := flag.String("redis.addr", "localhost:6379", "Address of one or more redis nodes, separated by separator")

	flag.Parse()
	addrs := strings.Split(*redisAddr, ",")
	if len(addrs) == 0 || len(addrs[0]) == 0 {
		log.Fatal("Invalid parameter --redis.addr")
	}
	log.Printf("Using redis addrs: %#v", addrs)
	r = RedisHost{Addrs: addrs}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
)

const AppVersion = "0.0.6"

var APIKey = ""

func init() {
	if os.Getenv("DIGITAL_OCEAN_API_KEY") != "" {
		APIKey = os.Getenv("DIGITAL_OCEAN_API_KEY")
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "doctl"
	app.Version = AppVersion
	app.Usage = "Digital Ocean Control TooL."
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "api-key,k", Value: "", Usage: "API Key for DO APIv2."},
	}
	app.Before = func(ctx *cli.Context) error {
		if ctx.String("api-key") != "" {
			APIKey = ctx.String("api-key")
		}

		if APIKey == "" {
			fmt.Println("Must provide API Key via DIGITAL_OCEAN_API_KEY environment variable or via CLI argument.")
			os.Exit(1)
		}
		return nil
	}
	app.Commands = []cli.Command{
		DropletCommand,
		SSHCommand,
		RegionCommand,
		SizeCommand,
	}

	app.Run(os.Args)
}
<commit_msg>update version<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/codegangsta/cli"
)

const AppVersion = "0.0.7"

var APIKey = ""

func init() {
	if os.Getenv("DIGITAL_OCEAN_API_KEY") != "" {
		APIKey = os.Getenv("DIGITAL_OCEAN_API_KEY")
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "doctl"
	app.Version = AppVersion
	app.Usage = "Digital Ocean Control TooL."
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "api-key,k", Value: "", Usage: "API Key for DO APIv2."},
	}
	app.Before = func(ctx *cli.Context) error {
		if ctx.String("api-key") != "" {
			APIKey = ctx.String("api-key")
		}

		if APIKey == "" {
			fmt.Println("Must provide API Key via DIGITAL_OCEAN_API_KEY environment variable or via CLI argument.")
			os.Exit(1)
		}
		return nil
	}
	app.Commands = []cli.Command{
		DropletCommand,
		SSHCommand,
		RegionCommand,
		SizeCommand,
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"os"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSVPCPeeringConnection_basic(t *testing.T) {
	var connection ec2.VpcPeeringConnection

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			if os.Getenv("AWS_ACCOUNT_ID") == "" {
				t.Fatal("AWS_ACCOUNT_ID must be set")
			}
		},
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSVpcPeeringConnectionDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccVpcPeeringConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSVpcPeeringConnectionExists("aws_vpc_peering_connection.foo", &connection),
				),
			},
		},
	})
}

func TestAccAWSVPCPeeringConnection_tags(t *testing.T) {
	var connection ec2.VpcPeeringConnection
	peerId := os.Getenv("TF_PEER_ID")
	if peerId == "" {
		t.Skip("Error: TestAccAWSVPCPeeringConnection_tags requires a peer id to be set")
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckVpcDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: fmt.Sprintf(testAccVpcPeeringConfigTags, peerId),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSVpcPeeringConnectionExists("aws_vpc_peering_connection.foo", &connection),
					testAccCheckTags(&connection.Tags, "foo", "bar"),
				),
			},
		},
	})
}

func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_vpc_peering_connection" {
			continue
		}

		describe, err := conn.DescribeVpcPeeringConnections(
			&ec2.DescribeVpcPeeringConnectionsInput{
				VpcPeeringConnectionIds: []*string{aws.String(rs.Primary.ID)},
			})

		if err == nil {
			if len(describe.VpcPeeringConnections) != 0 {
				return fmt.Errorf("vpc peering connection still exists")
			}
		}
	}

	return nil
}

func testAccCheckAWSVpcPeeringConnectionExists(n string, connection *ec2.VpcPeeringConnection) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No vpc peering connection id is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).ec2conn
		resp, err := conn.DescribeVpcPeeringConnections(
			&ec2.DescribeVpcPeeringConnectionsInput{
				VpcPeeringConnectionIds: []*string{aws.String(rs.Primary.ID)},
			})
		if err != nil {
			return err
		}
		if len(resp.VpcPeeringConnections) == 0 {
			return fmt.Errorf("VPC peering connection not found")
		}

		*connection = *resp.VpcPeeringConnections[0]

		return nil
	}
}

const testAccVpcPeeringConfig = `
resource "aws_vpc" "foo" {
		cidr_block = "10.0.0.0/16"
}

resource "aws_vpc" "bar" {
		cidr_block = "10.1.0.0/16"
}

resource "aws_vpc_peering_connection" "foo" {
		vpc_id = "${aws_vpc.foo.id}"
		peer_vpc_id = "${aws_vpc.bar.id}"
		auto_accept = true
}
`

const testAccVpcPeeringConfigTags = `
resource "aws_vpc" "foo" {
		cidr_block = "10.0.0.0/16"
}

resource "aws_vpc" "bar" {
		cidr_block = "10.1.0.0/16"
}

resource "aws_vpc_peering_connection" "foo" {
		vpc_id = "${aws_vpc.foo.id}"
		peer_vpc_id = "${aws_vpc.bar.id}"
		peer_owner_id = "%s"
		tags {
			foo = "bar"
		}
}
`
<commit_msg>provider/aws: Update testAccCheckAWSVpcPeeringConnectionDestroy to correctly check the destroyed state<commit_after>package aws

import (
	"fmt"
	"os"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSVPCPeeringConnection_basic(t *testing.T) {
	var connection ec2.VpcPeeringConnection

	resource.Test(t, resource.TestCase{
		PreCheck: func() {
			testAccPreCheck(t)
			if os.Getenv("AWS_ACCOUNT_ID") == "" {
				t.Fatal("AWS_ACCOUNT_ID must be set")
			}
		},
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckAWSVpcPeeringConnectionDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccVpcPeeringConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSVpcPeeringConnectionExists("aws_vpc_peering_connection.foo", &connection),
				),
			},
		},
	})
}

func TestAccAWSVPCPeeringConnection_tags(t *testing.T) {
	var connection ec2.VpcPeeringConnection
	peerId := os.Getenv("TF_PEER_ID")
	if peerId == "" {
		t.Skip("Error: TestAccAWSVPCPeeringConnection_tags requires a peer id to be set")
	}

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckVpcDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: fmt.Sprintf(testAccVpcPeeringConfigTags, peerId),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckAWSVpcPeeringConnectionExists("aws_vpc_peering_connection.foo", &connection),
					testAccCheckTags(&connection.Tags, "foo", "bar"),
				),
			},
		},
	})
}

func testAccCheckAWSVpcPeeringConnectionDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_vpc_peering_connection" {
			continue
		}

		describe, err := conn.DescribeVpcPeeringConnections(
			&ec2.DescribeVpcPeeringConnectionsInput{
				VpcPeeringConnectionIds: []*string{aws.String(rs.Primary.ID)},
			})

		if err != nil {
			return err
		}

		var pc *ec2.VpcPeeringConnection
		for _, c := range describe.VpcPeeringConnections {
			if rs.Primary.ID == *c.VpcPeeringConnectionId {
				pc = c
			}
		}

		if pc == nil {
			// not found
			return nil
		}

		if pc.Status != nil {
			if *pc.Status.Code == "deleted" {
				return nil
			}
			return fmt.Errorf("Found vpc peering connection in unexpected state: %s", pc)
		}

	}

	return fmt.Errorf("Fall through error for testAccCheckAWSVpcPeeringConnectionDestroy")
}

func testAccCheckAWSVpcPeeringConnectionExists(n string, connection *ec2.VpcPeeringConnection) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[n]
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No vpc peering connection id is set")
		}

		conn := testAccProvider.Meta().(*AWSClient).ec2conn
		resp, err := conn.DescribeVpcPeeringConnections(
			&ec2.DescribeVpcPeeringConnectionsInput{
				VpcPeeringConnectionIds: []*string{aws.String(rs.Primary.ID)},
			})
		if err != nil {
			return err
		}
		if len(resp.VpcPeeringConnections) == 0 {
			return fmt.Errorf("VPC peering connection not found")
		}

		*connection = *resp.VpcPeeringConnections[0]

		return nil
	}
}

const testAccVpcPeeringConfig = `
resource "aws_vpc" "foo" {
		cidr_block = "10.0.0.0/16"
}

resource "aws_vpc" "bar" {
		cidr_block = "10.1.0.0/16"
}

resource "aws_vpc_peering_connection" "foo" {
		vpc_id = "${aws_vpc.foo.id}"
		peer_vpc_id = "${aws_vpc.bar.id}"
		auto_accept = true
}
`

const testAccVpcPeeringConfigTags = `
resource "aws_vpc" "foo" {
		cidr_block = "10.0.0.0/16"
}

resource "aws_vpc" "bar" {
		cidr_block = "10.1.0.0/16"
}

resource "aws_vpc_peering_connection" "foo" {
		vpc_id = "${aws_vpc.foo.id}"
		peer_vpc_id = "${aws_vpc.bar.id}"
		peer_owner_id = "%s"
		tags {
			foo = "bar"
		}
}
`
<|endoftext|>


<commit_before>package version

const (
	Version = "0.1.4+git"
)
<commit_msg>version: bump to v0.1.5<commit_after>package version

const (
	Version = "0.1.5"
)
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{0, 8, 3}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<commit_msg>Bumping version to 0.8.4<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{0, 8, 4}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<|endoftext|>


<commit_before>package version

const Version = "0.1.2"
<commit_msg>Revert "Revert "chore(release): bump version to 0.1.2+git""<commit_after>package version

const Version = "0.1.2+git"
<|endoftext|>


<commit_before>package version

const Version = "0.1.4+git"
<commit_msg>chore(release): Bump version to v0.2.0+git<commit_after>package version

const Version = "0.2.0+git"
<|endoftext|>


<commit_before>package version

const Version = "1.0.0"
<commit_msg>chore(version): 2.1.0<commit_after>package version

const Version = "2.1.0"
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{0, 3, 3}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<commit_msg>bumping version to 0.4.0<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either Version 3 of the License, or
// (at your option) any later Version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package version

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

// CurrentGaugeVersion represents the current version of Gauge
var CurrentGaugeVersion = &Version{0, 4, 0}

// BuildMetadata represents build information of current release (e.g, nightly build information)
var BuildMetadata = ""

type Version struct {
	Major int
	Minor int
	Patch int
}

type VersionSupport struct {
	Minimum string
	Maximum string
}

func ParseVersion(versionText string) (*Version, error) {
	splits := strings.Split(versionText, ".")
	if len(splits) != 3 {
		return nil, fmt.Errorf("Incorrect Version format. Version should be in the form 1.5.7")
	}
	Major, err := strconv.Atoi(splits[0])
	if err != nil {
		return nil, VersionError("major", splits[0], err)
	}
	Minor, err := strconv.Atoi(splits[1])
	if err != nil {
		return nil, VersionError("minor", splits[1], err)
	}
	Patch, err := strconv.Atoi(splits[2])
	if err != nil {
		return nil, VersionError("patch", splits[2], err)
	}

	return &Version{Major, Minor, Patch}, nil
}

func VersionError(level, text string, err error) error {
	return fmt.Errorf("Error parsing %s Version %s to integer. %s", level, text, err.Error())
}

func (Version *Version) IsBetween(lower *Version, greater *Version) bool {
	return Version.IsGreaterThanEqualTo(lower) && Version.IsLesserThanEqualTo(greater)
}

func (Version *Version) IsLesserThan(version1 *Version) bool {
	return CompareVersions(Version, version1, LesserThanFunc)
}

func (Version *Version) IsGreaterThan(version1 *Version) bool {
	return CompareVersions(Version, version1, GreaterThanFunc)
}

func (Version *Version) IsLesserThanEqualTo(version1 *Version) bool {
	return Version.IsLesserThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsGreaterThanEqualTo(version1 *Version) bool {
	return Version.IsGreaterThan(version1) || Version.IsEqualTo(version1)
}

func (Version *Version) IsEqualTo(version1 *Version) bool {
	return IsEqual(Version.Major, version1.Major) && IsEqual(Version.Minor, version1.Minor) && IsEqual(Version.Patch, version1.Patch)
}

func CompareVersions(first *Version, second *Version, compareFunc func(int, int) bool) bool {
	if compareFunc(first.Major, second.Major) {
		return true
	} else if IsEqual(first.Major, second.Major) {
		if compareFunc(first.Minor, second.Minor) {
			return true
		} else if IsEqual(first.Minor, second.Minor) {
			if compareFunc(first.Patch, second.Patch) {
				return true
			}
			return false
		}
	}
	return false
}

func LesserThanFunc(first, second int) bool {
	return first < second
}

func GreaterThanFunc(first, second int) bool {
	return first > second
}

func IsEqual(first, second int) bool {
	return first == second
}

func (Version *Version) String() string {
	return fmt.Sprintf("%d.%d.%d", Version.Major, Version.Minor, Version.Patch)
}

// FullVersion returns the CurrentGaugeVersion including build metadata.
func FullVersion() string {
	var metadata string
	if BuildMetadata != "" {
		metadata = fmt.Sprintf(".%s", BuildMetadata)
	}
	return fmt.Sprintf("%s%s", CurrentGaugeVersion.String(), metadata)
}

type byDecreasingVersion []*Version

func (a byDecreasingVersion) Len() int      { return len(a) }
func (a byDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byDecreasingVersion) Less(i, j int) bool {
	return a[i].IsGreaterThan(a[j])
}

func GetLatestVersion(versions []*Version) *Version {
	sort.Sort(byDecreasingVersion(versions))
	return versions[0]
}

func CheckCompatibility(currentVersion *Version, versionSupport *VersionSupport) error {
	minSupportVersion, err := ParseVersion(versionSupport.Minimum)
	if err != nil {
		return fmt.Errorf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err.Error())
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := ParseVersion(versionSupport.Maximum)
		if err != nil {
			return fmt.Errorf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err.Error())
		}
		if currentVersion.IsBetween(minSupportVersion, maxSupportVersion) {
			return nil
		}
		return fmt.Errorf("Version %s is not between %s and %s", currentVersion, minSupportVersion, maxSupportVersion)
	}

	if minSupportVersion.IsLesserThanEqualTo(currentVersion) {
		return nil
	}
	return fmt.Errorf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, currentVersion)
}
<|endoftext|>


<commit_before>package version

var (
	Version   = "3.0.0"
	GitCommit = "HEAD"
)
<commit_msg>bump 3.0.1<commit_after>package version

var (
	Version   = "3.0.1"
	GitCommit = "HEAD"
)
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version app version
	Version = "0.0.1-alpha"
	// Revision git commit short commithash
	Revision = "xxxxxx" // set on build
)

// FullVersion return sackerel full version text
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, Revision)
}
<commit_msg>Bump to v0.0.2-alpha<commit_after>package version

import "fmt"

var (
	// Version app version
	Version = "0.0.2-alpha"
	// Revision git commit short commithash
	Revision = "xxxxxx" // set on build
)

// FullVersion return sackerel full version text
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, Revision)
}
<|endoftext|>


<commit_before>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 2
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 1

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = ""
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<commit_msg>bump to v5.2.2-dev<commit_after>package version

import "fmt"

const (
	// VersionMajor is for an API incompatible changes
	VersionMajor = 5
	// VersionMinor is for functionality in a backwards-compatible manner
	VersionMinor = 2
	// VersionPatch is for backwards-compatible bug fixes
	VersionPatch = 2

	// VersionDev indicates development branch. Releases will be empty string.
	VersionDev = "-dev"
)

// Version is the specification version that the package types support.
var Version = fmt.Sprintf("%d.%d.%d%s", VersionMajor, VersionMinor, VersionPatch, VersionDev)
<|endoftext|>


<commit_before>package version

var (
	// VERSION should be updated by hand at each release
	VERSION = "0.0.0-dev"

	// GITCOMMIT will be overwritten automatically by the build system
	GITCOMMIT = "HEAD"
)
<commit_msg>Bump version 0.1.0<commit_after>package version

var (
	// VERSION should be updated by hand at each release
	VERSION = "0.1.0"

	// GITCOMMIT will be overwritten automatically by the build system
	GITCOMMIT = "HEAD"
)
<|endoftext|>


<commit_before>package version

import (
	"github.com/coreos/go-semver/semver"
)

const Version = "0.2.1+git"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<commit_msg>version: bump to v0.2.2+git<commit_after>package version

import (
	"github.com/coreos/go-semver/semver"
)

const Version = "0.2.2+git"

var SemVersion semver.Version

func init() {
	sv, err := semver.NewVersion(Version)
	if err != nil {
		panic("bad version string!")
	}
	SemVersion = *sv
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 version

const (
	// Version is the version of locksmithctl that this is
	Version = "0.6.0"
)
<commit_msg>locksmith: bump to v0.6.0+git<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 version

const (
	// Version is the version of locksmithctl that this is
	Version = "0.6.0+git"
)
<|endoftext|>