<commit_before>package echo

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/webx-top/webx/lib/tagfast"
)

var DefaultHtmlFilter = func(v string) (r string) {
	return v
}

type (
	// Binder is the interface that wraps the Bind method.
	Binder interface {
		Bind(interface{}, Context) error
	}
	binder struct {
		*Echo
	}
)

func (b *binder) Bind(i interface{}, c Context) (err error) {
	r := c.Request()
	body := r.Body()
	if body == nil {
		err = NewHTTPError(http.StatusBadRequest, "Request body can't be nil")
		return
	}
	defer body.Close()
	ct := r.Header().Get(HeaderContentType)
	err = ErrUnsupportedMediaType
	if strings.HasPrefix(ct, MIMEApplicationJSON) {
		err = json.NewDecoder(body).Decode(i)
	} else if strings.HasPrefix(ct, MIMEApplicationXML) {
		err = xml.NewDecoder(body).Decode(i)
	} else if strings.HasPrefix(ct, MIMEApplicationForm) {
		err = b.structMap(i, r.PostForm().All())
	} else if strings.Contains(ct, MIMEMultipartForm) {
		err = b.structMap(i, r.Form().All())
	}
	return
}

// StructMap function mapping params to controller's properties
func (b *binder) structMap(m interface{}, data map[string][]string) error {
	return NamedStructMap(b.Echo, m, data, ``)
}

// SplitJSON user[name][test]
func SplitJSON(s string) ([]string, error) {
	res := make([]string, 0)
	var begin, end int
	var isleft bool
	for i, r := range s {
		switch r {
		case '[':
			isleft = true
			if i > 0 && s[i-1] != ']' {
				if begin == end {
					return nil, errors.New(`unknow character`)
				}
				res = append(res, s[begin:end+1])
			}
			begin = i + 1
			end = begin
		case ']':
			if !isleft {
				return nil, errors.New(`unknow character`)
			}
			isleft = false
			if begin != end {
				res = append(res, s[begin:end+1])
				begin = i + 1
				end = begin
			}
		default:
			end = i
		}
		if i == len(s)-1 && begin != end {
			res = append(res, s[begin:end+1])
		}
	}
	return res, nil
}

func NamedStructMap(e *Echo, m interface{}, data map[string][]string, topName string) error {
	vc := reflect.ValueOf(m)
	tc := reflect.TypeOf(m)

	switch tc.Kind() {
	case reflect.Struct:
	case reflect.Ptr:
		vc = vc.Elem()
		tc = tc.Elem()
	}

	for k, t := range data {

		if k == `` || k[0] == '_' {
			continue
		}

		if topName != `` {
			if !strings.HasPrefix(k, topName) {
				continue
			}
			k = k[len(topName)+1:]
		}

		v := t[0]
		names := strings.Split(k, `.`)
		var err error
		length := len(names)
		if length == 1 && strings.HasSuffix(k, `]`) {
			names, err = SplitJSON(k)
			if err != nil {
				e.Logger().Warnf(`Unrecognize form key %v %v`, k, err)
				continue
			}
			length = len(names)
		}
		value := vc
		typev := tc
		for i, name := range names {
			name = strings.Title(name)

			//不是最后一个元素
			if i != length-1 {
				if value.Kind() != reflect.Struct {
					e.Logger().Warnf(`arg error, value kind is %v`, value.Kind())
					break
				}
				value = value.FieldByName(name)
				if !value.IsValid() {
					e.Logger().Warnf(`(%v value is not valid %v)`, name, value)
					break
				}
				if !value.CanSet() {
					e.Logger().Warnf(`can not set %v -> %v`, name, value.Interface())
					break
				}
				if value.Kind() == reflect.Ptr {
					if value.IsNil() {
						value.Set(reflect.New(value.Type().Elem()))
					}
					value = value.Elem()
				}
				typev = value.Type()
				f, _ := typev.FieldByName(name)
				if tagfast.Value(tc, f, `form_options`) == `-` {
					break
				}
			} else {
				if value.Kind() != reflect.Struct {
					e.Logger().Warnf(`arg error, value %v kind is %v`, name, value.Kind())
					break
				}
				tv := value.FieldByName(name)
				if !tv.IsValid() {
					break
				}
				if !tv.CanSet() {
					e.Logger().Warnf(`can not set %v to %v`, k, tv)
					break
				}
				f, _ := typev.FieldByName(name)
				if tagfast.Value(tc, f, `form_options`) == `-` {
					break
				}
				if tv.Kind() == reflect.Ptr {
					tv.Set(reflect.New(tv.Type().Elem()))
					tv = tv.Elem()
				}

				var l interface{}
				switch k := tv.Kind(); k {
				case reflect.String:
					switch tagfast.Value(tc, f, `form_filter`) {
					case `html`:
						v = DefaultHtmlFilter(v)
					}
					l = v
					tv.Set(reflect.ValueOf(l))
				case reflect.Bool:
					l = (v != `false` && v != `0` && v != ``)
					tv.Set(reflect.ValueOf(l))
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
					x, err := strconv.Atoi(v)
					if err != nil {
						e.Logger().Warnf(`arg %v as int: %v`, v, err)
						break
					}
					l = x
					tv.Set(reflect.ValueOf(l))
				case reflect.Int64:
					x, err := strconv.ParseInt(v, 10, 64)
					if err != nil {
						e.Logger().Warnf(`arg %v as int64: %v`, v, err)
						break
					}
					l = x
					tv.Set(reflect.ValueOf(l))
				case reflect.Float32, reflect.Float64:
					x, err := strconv.ParseFloat(v, 64)
					if err != nil {
						e.Logger().Warnf(`arg %v as float64: %v`, v, err)
						break
					}
					l = x
					tv.Set(reflect.ValueOf(l))
				case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
					x, err := strconv.ParseUint(v, 10, 64)
					if err != nil {
						e.Logger().Warnf(`arg %v as uint: %v`, v, err)
						break
					}
					l = x
					tv.Set(reflect.ValueOf(l))
				case reflect.Struct:
					if tvf, ok := tv.Interface().(FromConversion); ok {
						err := tvf.FromString(v)
						if err != nil {
							e.Logger().Warnf(`struct %v invoke FromString faild`, tvf)
						}
					} else if tv.Type().String() == `time.Time` {
						x, err := time.Parse(`2006-01-02 15:04:05.000 -0700`, v)
						if err != nil {
							x, err = time.Parse(`2006-01-02 15:04:05`, v)
							if err != nil {
								x, err = time.Parse(`2006-01-02`, v)
								if err != nil {
									e.Logger().Warnf(`unsupported time format %v, %v`, v, err)
									break
								}
							}
						}
						l = x
						tv.Set(reflect.ValueOf(l))
					} else {
						e.Logger().Warn(`can not set an struct which is not implement Fromconversion interface`)
					}
				case reflect.Ptr:
					e.Logger().Warn(`can not set an ptr of ptr`)
				case reflect.Slice, reflect.Array:
					tt := tv.Type().Elem()
					tk := tt.Kind()

					if tv.IsNil() {
						tv.Set(reflect.MakeSlice(tv.Type(), len(t), len(t)))
					}

					for i, s := range t {
						var err error
						switch tk {
						case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64:
							var v int64
							v, err = strconv.ParseInt(s, 10, tt.Bits())
							if err == nil {
								tv.Index(i).SetInt(v)
							}
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
							var v uint64
							v, err = strconv.ParseUint(s, 10, tt.Bits())
							if err == nil {
								tv.Index(i).SetUint(v)
							}
						case reflect.Float32, reflect.Float64:
							var v float64
							v, err = strconv.ParseFloat(s, tt.Bits())
							if err == nil {
								tv.Index(i).SetFloat(v)
							}
						case reflect.Bool:
							var v bool
							v, err = strconv.ParseBool(s)
							if err == nil {
								tv.Index(i).SetBool(v)
							}
						case reflect.String:
							tv.Index(i).SetString(s)
						case reflect.Complex64, reflect.Complex128:
							// TODO:
							err = fmt.Errorf(`unsupported slice element type %v`, tk.String())
						default:
							err = fmt.Errorf(`unsupported slice element type %v`, tk.String())
						}
						if err != nil {
							e.Logger().Warnf(`slice error: %v, %v`, name, err)
							break
						}
					}
				default:
					break
				}
			}
		}
	}
	return nil
}

// FromConversion a struct implements this interface can be convert from request param to a struct
type FromConversion interface {
	FromString(content string) error
}

// ToConversion a struct implements this interface can be convert from struct to template variable
// Not Implemented
type ToConversion interface {
	ToString() string
}
<commit_msg>update<commit_after>package echo

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/webx-top/webx/lib/tagfast"
)

var DefaultHtmlFilter = func(v string) (r string) {
	return v
}

type (
	// Binder is the interface that wraps the Bind method.
	Binder interface {
		Bind(interface{}, Context) error
	}
	binder struct {
		*Echo
	}
)

func (b *binder) Bind(i interface{}, c Context) (err error) {
	r := c.Request()
	body := r.Body()
	if body == nil {
		err = NewHTTPError(http.StatusBadRequest, "Request body can't be nil")
		return
	}
	defer body.Close()
	ct := r.Header().Get(HeaderContentType)
	err = ErrUnsupportedMediaType
	if strings.HasPrefix(ct, MIMEApplicationJSON) {
		err = json.NewDecoder(body).Decode(i)
	} else if strings.HasPrefix(ct, MIMEApplicationXML) {
		err = xml.NewDecoder(body).Decode(i)
	} else if strings.HasPrefix(ct, MIMEApplicationForm) {
		err = b.structMap(i, r.PostForm().All())
	} else if strings.Contains(ct, MIMEMultipartForm) {
		err = b.structMap(i, r.Form().All())
	}
	return
}

// StructMap function mapping params to controller's properties
func (b *binder) structMap(m interface{}, data map[string][]string) error {
	return NamedStructMap(b.Echo, m, data, ``)
}

// SplitJSON user[name][test]
func SplitJSON(s string) ([]string, error) {
	res := make([]string, 0)
	var begin, end int
	var isleft bool
	for i, r := range s {
		switch r {
		case '[':
			isleft = true
			if i > 0 && s[i-1] != ']' {
				if begin == end {
					return nil, errors.New(`unknow character`)
				}
				res = append(res, s[begin:end+1])
			}
			begin = i + 1
			end = begin
		case ']':
			if !isleft {
				return nil, errors.New(`unknow character`)
			}
			isleft = false
			if begin != end {
				res = append(res, s[begin:end+1])
				begin = i + 1
				end = begin
			}
		default:
			end = i
		}
		if i == len(s)-1 && begin != end {
			res = append(res, s[begin:end+1])
		}
	}
	return res, nil
}

func NamedStructMap(e *Echo, m interface{}, data map[string][]string, topName string) error {
	vc := reflect.ValueOf(m)
	tc := reflect.TypeOf(m)

	switch tc.Kind() {
	case reflect.Struct:
	case reflect.Ptr:
		vc = vc.Elem()
		tc = tc.Elem()
	}

	for k, t := range data {

		if k == `` || k[0] == '_' {
			continue
		}

		if topName != `` {
			if !strings.HasPrefix(k, topName) {
				continue
			}
			k = k[len(topName)+1:]
		}

		v := t[0]
		names := strings.Split(k, `.`)
		var err error
		length := len(names)
		if length == 1 && strings.HasSuffix(k, `]`) {
			names, err = SplitJSON(k)
			if err != nil {
				e.Logger().Warnf(`Unrecognize form key %v %v`, k, err)
				continue
			}
			length = len(names)
		}
		value := vc
		typev := tc
		for i, name := range names {
			name = strings.Title(name)

			//不是最后一个元素
			if i != length-1 {
				if value.Kind() != reflect.Struct {
					e.Logger().Warnf(`arg error, value kind is %v`, value.Kind())
					break
				}
				value = value.FieldByName(name)
				if !value.IsValid() {
					e.Logger().Warnf(`(%v value is not valid %v)`, name, value)
					break
				}
				if !value.CanSet() {
					e.Logger().Warnf(`can not set %v -> %v`, name, value.Interface())
					break
				}
				if value.Kind() == reflect.Ptr {
					if value.IsNil() {
						value.Set(reflect.New(value.Type().Elem()))
					}
					value = value.Elem()
				}
				typev = value.Type()
				f, _ := typev.FieldByName(name)
				if tagfast.Value(tc, f, `form_options`) == `-` {
					break
				}
			} else {
				if value.Kind() != reflect.Struct {
					e.Logger().Warnf(`arg error, value %v kind is %v`, name, value.Kind())
					break
				}
				tv := value.FieldByName(name)
				if !tv.IsValid() {
					break
				}
				if !tv.CanSet() {
					e.Logger().Warnf(`can not set %v to %v`, k, tv)
					break
				}
				f, _ := typev.FieldByName(name)
				if tagfast.Value(tc, f, `form_options`) == `-` {
					break
				}
				if tv.Kind() == reflect.Ptr {
					tv.Set(reflect.New(tv.Type().Elem()))
					tv = tv.Elem()
				}

				var l interface{}
				switch k := tv.Kind(); k {
				case reflect.String:
					switch tagfast.Value(tc, f, `form_filter`) {
					case `html`:
						v = DefaultHtmlFilter(v)
					}
					l = v
					tv.Set(reflect.ValueOf(l))
				case reflect.Bool:
					l = (v != `false` && v != `0` && v != ``)
					tv.Set(reflect.ValueOf(l))
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
					dateformat := tagfast.Value(tc, f, `form_format`)
					if dateformat != `` {
						t, err := time.Parse(dateformat, v)
						if err != nil {
							e.Logger().Warnf(`arg %v as int: %v`, v, err)
							break
						}
						l = int(t.Unix())
					} else {
						x, err := strconv.Atoi(v)
						if err != nil {
							e.Logger().Warnf(`arg %v as int: %v`, v, err)
							break
						}
						l = x
					}
					tv.Set(reflect.ValueOf(l))
				case reflect.Int64:
					dateformat := tagfast.Value(tc, f, `form_format`)
					if dateformat != `` {
						t, err := time.Parse(dateformat, v)
						if err != nil {
							e.Logger().Warnf(`arg %v as int64: %v`, v, err)
							break
						}
						l = t.Unix()
					} else {
						x, err := strconv.ParseInt(v, 10, 64)
						if err != nil {
							e.Logger().Warnf(`arg %v as int64: %v`, v, err)
							break
						}
						l = x
					}
					tv.Set(reflect.ValueOf(l))
				case reflect.Float32, reflect.Float64:
					x, err := strconv.ParseFloat(v, 64)
					if err != nil {
						e.Logger().Warnf(`arg %v as float64: %v`, v, err)
						break
					}
					l = x
					tv.Set(reflect.ValueOf(l))
				case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
					dateformat := tagfast.Value(tc, f, `form_format`)
					if dateformat != `` {
						t, err := time.Parse(dateformat, v)
						if err != nil {
							e.Logger().Warnf(`arg %v as uint: %v`, v, err)
							break
						}
						l = uint64(t.Unix())
					} else {
						x, err := strconv.ParseUint(v, 10, 64)
						if err != nil {
							e.Logger().Warnf(`arg %v as uint: %v`, v, err)
							break
						}
						l = x
					}
					tv.Set(reflect.ValueOf(l))
				case reflect.Struct:
					if tvf, ok := tv.Interface().(FromConversion); ok {
						err := tvf.FromString(v)
						if err != nil {
							e.Logger().Warnf(`struct %v invoke FromString faild`, tvf)
						}
					} else if tv.Type().String() == `time.Time` {
						x, err := time.Parse(`2006-01-02 15:04:05.000 -0700`, v)
						if err != nil {
							x, err = time.Parse(`2006-01-02 15:04:05`, v)
							if err != nil {
								x, err = time.Parse(`2006-01-02`, v)
								if err != nil {
									e.Logger().Warnf(`unsupported time format %v, %v`, v, err)
									break
								}
							}
						}
						l = x
						tv.Set(reflect.ValueOf(l))
					} else {
						e.Logger().Warn(`can not set an struct which is not implement Fromconversion interface`)
					}
				case reflect.Ptr:
					e.Logger().Warn(`can not set an ptr of ptr`)
				case reflect.Slice, reflect.Array:
					tt := tv.Type().Elem()
					tk := tt.Kind()

					if tv.IsNil() {
						tv.Set(reflect.MakeSlice(tv.Type(), len(t), len(t)))
					}

					for i, s := range t {
						var err error
						switch tk {
						case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int8, reflect.Int64:
							var v int64
							v, err = strconv.ParseInt(s, 10, tt.Bits())
							if err == nil {
								tv.Index(i).SetInt(v)
							}
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
							var v uint64
							v, err = strconv.ParseUint(s, 10, tt.Bits())
							if err == nil {
								tv.Index(i).SetUint(v)
							}
						case reflect.Float32, reflect.Float64:
							var v float64
							v, err = strconv.ParseFloat(s, tt.Bits())
							if err == nil {
								tv.Index(i).SetFloat(v)
							}
						case reflect.Bool:
							var v bool
							v, err = strconv.ParseBool(s)
							if err == nil {
								tv.Index(i).SetBool(v)
							}
						case reflect.String:
							tv.Index(i).SetString(s)
						case reflect.Complex64, reflect.Complex128:
							// TODO:
							err = fmt.Errorf(`unsupported slice element type %v`, tk.String())
						default:
							err = fmt.Errorf(`unsupported slice element type %v`, tk.String())
						}
						if err != nil {
							e.Logger().Warnf(`slice error: %v, %v`, name, err)
							break
						}
					}
				default:
					break
				}
			}
		}
	}
	return nil
}

// FromConversion a struct implements this interface can be convert from request param to a struct
type FromConversion interface {
	FromString(content string) error
}

// ToConversion a struct implements this interface can be convert from struct to template variable
// Not Implemented
type ToConversion interface {
	ToString() string
}
<|endoftext|>


<commit_before>// UNREVIEWED
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types2_test

import (
	"internal/testenv"
	"testing"

	"cmd/compile/internal/syntax"
	. "cmd/compile/internal/types2"
)

const filename = "<src>"

func makePkg(src string) (*Package, error) {
	file, err := parseSrc(filename, src)
	if err != nil {
		return nil, err
	}
	// use the package name as package path
	conf := Config{Importer: defaultImporter()}
	return conf.Check(file.PkgName.Value, []*syntax.File{file}, nil)
}

type testEntry struct {
	src, str string
}

// dup returns a testEntry where both src and str are the same.
func dup(s string) testEntry {
	return testEntry{s, s}
}

// types that don't depend on any other type declarations
var independentTestTypes = []testEntry{
	// basic types
	dup("int"),
	dup("float32"),
	dup("string"),

	// arrays
	dup("[10]int"),

	// slices
	dup("[]int"),
	dup("[][]int"),

	// structs
	dup("struct{}"),
	dup("struct{x int}"),
	{`struct {
		x, y int
		z float32 "foo"
	}`, `struct{x int; y int; z float32 "foo"}`},
	{`struct {
		string
		elems []complex128
	}`, `struct{string; elems []complex128}`},

	// pointers
	dup("*int"),
	dup("***struct{}"),
	dup("*struct{a int; b float32}"),

	// functions
	dup("func()"),
	dup("func(x int)"),
	{"func(x, y int)", "func(x int, y int)"},
	{"func(x, y int, z string)", "func(x int, y int, z string)"},
	dup("func(int)"),
	{"func(int, string, byte)", "func(int, string, byte)"},

	dup("func() int"),
	{"func() (string)", "func() string"},
	dup("func() (u int)"),
	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},

	dup("func(int) string"),
	dup("func(x int) string"),
	dup("func(x int) (u string)"),
	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},

	dup("func(...int) string"),
	dup("func(x ...int) string"),
	dup("func(x ...int) (u string)"),
	{"func(x int, y ...int) (u string)", "func(x int, y ...int) (u string)"},

	// interfaces
	dup("interface{}"),
	dup("interface{m()}"),
	dup(`interface{String() string; m(int) float32}`),
	dup(`interface{type int, float32, complex128}`),

	// maps
	dup("map[string]int"),
	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},

	// channels
	dup("chan<- chan int"),
	dup("chan<- <-chan int"),
	dup("<-chan <-chan int"),
	dup("chan (<-chan int)"),
	dup("chan<- func()"),
	dup("<-chan []func() int"),
}

// types that depend on other type declarations (src in TestTypes)
var dependentTestTypes = []testEntry{
	// interfaces
	dup(`interface{io.Reader; io.Writer}`),
	dup(`interface{m() int; io.Writer}`),
	{`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
}

func TestTypeString(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	var tests []testEntry
	tests = append(tests, independentTestTypes...)
	tests = append(tests, dependentTestTypes...)

	for _, test := range tests {
		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
		pkg, err := makePkg(src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		typ := pkg.Scope().Lookup("T").Type().Underlying()
		if got := typ.String(); got != test.str {
			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
		}
	}
}

var nopos syntax.Pos

func TestIncompleteInterfaces(t *testing.T) {
	sig := NewSignature(nil, nil, nil, false)
	m := NewFunc(nopos, nil, "m", sig)
	for _, test := range []struct {
		typ  *Interface
		want string
	}{
		{new(Interface), "interface{/* incomplete */}"},
		{new(Interface).Complete(), "interface{}"},

		{NewInterface(nil, nil), "interface{}"},
		{NewInterface(nil, nil).Complete(), "interface{}"},
		{NewInterface([]*Func{}, nil), "interface{}"},
		{NewInterface([]*Func{}, nil).Complete(), "interface{}"},
		{NewInterface(nil, []*Named{}), "interface{}"},
		{NewInterface(nil, []*Named{}).Complete(), "interface{}"},
		{NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"},
		{NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"},
		{NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"},

		{NewInterfaceType(nil, nil), "interface{}"},
		{NewInterfaceType(nil, nil).Complete(), "interface{}"},
		{NewInterfaceType([]*Func{}, nil), "interface{}"},
		{NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"},
		{NewInterfaceType(nil, []Type{}), "interface{}"},
		{NewInterfaceType(nil, []Type{}).Complete(), "interface{}"},
		{NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"},
		{NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"},
		{NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
	} {
		got := test.typ.String()
		if got != test.want {
			t.Errorf("got: %s, want: %s", got, test.want)
		}
	}
}

// newDefined creates a new defined type named T with the given underlying type.
// Helper function for use with TestIncompleteInterfaces only.
func newDefined(underlying Type) *Named {
	tname := NewTypeName(nopos, nil, "T", nil)
	return NewNamed(tname, underlying, nil)
}

func TestQualifiedTypeString(t *testing.T) {
	p, _ := pkgFor("p.go", "package p; type T int", nil)
	q, _ := pkgFor("q.go", "package q", nil)

	pT := p.Scope().Lookup("T").Type()
	for _, test := range []struct {
		typ  Type
		this *Package
		want string
	}{
		{nil, nil, "<nil>"},
		{pT, nil, "p.T"},
		{pT, p, "T"},
		{pT, q, "p.T"},
		{NewPointer(pT), p, "*T"},
		{NewPointer(pT), q, "*p.T"},
	} {
		qualifier := func(pkg *Package) string {
			if pkg != test.this {
				return pkg.Name()
			}
			return ""
		}
		if got := TypeString(test.typ, qualifier); got != test.want {
			t.Errorf("TypeString(%s, %s) = %s, want %s",
				test.this, test.typ, got, test.want)
		}
	}
}
<commit_msg>[dev.typeparams] cmd/compile/internal/types: review of typestring_test.go<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types2_test

import (
	"internal/testenv"
	"testing"

	"cmd/compile/internal/syntax"
	. "cmd/compile/internal/types2"
)

const filename = "<src>"

func makePkg(src string) (*Package, error) {
	file, err := parseSrc(filename, src)
	if err != nil {
		return nil, err
	}
	// use the package name as package path
	conf := Config{Importer: defaultImporter()}
	return conf.Check(file.PkgName.Value, []*syntax.File{file}, nil)
}

type testEntry struct {
	src, str string
}

// dup returns a testEntry where both src and str are the same.
func dup(s string) testEntry {
	return testEntry{s, s}
}

// types that don't depend on any other type declarations
var independentTestTypes = []testEntry{
	// basic types
	dup("int"),
	dup("float32"),
	dup("string"),

	// arrays
	dup("[10]int"),

	// slices
	dup("[]int"),
	dup("[][]int"),

	// structs
	dup("struct{}"),
	dup("struct{x int}"),
	{`struct {
		x, y int
		z float32 "foo"
	}`, `struct{x int; y int; z float32 "foo"}`},
	{`struct {
		string
		elems []complex128
	}`, `struct{string; elems []complex128}`},

	// pointers
	dup("*int"),
	dup("***struct{}"),
	dup("*struct{a int; b float32}"),

	// functions
	dup("func()"),
	dup("func(x int)"),
	{"func(x, y int)", "func(x int, y int)"},
	{"func(x, y int, z string)", "func(x int, y int, z string)"},
	dup("func(int)"),
	{"func(int, string, byte)", "func(int, string, byte)"},

	dup("func() int"),
	{"func() (string)", "func() string"},
	dup("func() (u int)"),
	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},

	dup("func(int) string"),
	dup("func(x int) string"),
	dup("func(x int) (u string)"),
	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},

	dup("func(...int) string"),
	dup("func(x ...int) string"),
	dup("func(x ...int) (u string)"),
	{"func(x int, y ...int) (u string)", "func(x int, y ...int) (u string)"},

	// interfaces
	dup("interface{}"),
	dup("interface{m()}"),
	dup(`interface{String() string; m(int) float32}`),
	dup(`interface{type int, float32, complex128}`),

	// maps
	dup("map[string]int"),
	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},

	// channels
	dup("chan<- chan int"),
	dup("chan<- <-chan int"),
	dup("<-chan <-chan int"),
	dup("chan (<-chan int)"),
	dup("chan<- func()"),
	dup("<-chan []func() int"),
}

// types that depend on other type declarations (src in TestTypes)
var dependentTestTypes = []testEntry{
	// interfaces
	dup(`interface{io.Reader; io.Writer}`),
	dup(`interface{m() int; io.Writer}`),
	{`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
}

func TestTypeString(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	var tests []testEntry
	tests = append(tests, independentTestTypes...)
	tests = append(tests, dependentTestTypes...)

	for _, test := range tests {
		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
		pkg, err := makePkg(src)
		if err != nil {
			t.Errorf("%s: %s", src, err)
			continue
		}
		typ := pkg.Scope().Lookup("T").Type().Underlying()
		if got := typ.String(); got != test.str {
			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
		}
	}
}

var nopos syntax.Pos

func TestIncompleteInterfaces(t *testing.T) {
	sig := NewSignature(nil, nil, nil, false)
	m := NewFunc(nopos, nil, "m", sig)
	for _, test := range []struct {
		typ  *Interface
		want string
	}{
		{new(Interface), "interface{/* incomplete */}"},
		{new(Interface).Complete(), "interface{}"},

		{NewInterface(nil, nil), "interface{}"},
		{NewInterface(nil, nil).Complete(), "interface{}"},
		{NewInterface([]*Func{}, nil), "interface{}"},
		{NewInterface([]*Func{}, nil).Complete(), "interface{}"},
		{NewInterface(nil, []*Named{}), "interface{}"},
		{NewInterface(nil, []*Named{}).Complete(), "interface{}"},
		{NewInterface([]*Func{m}, nil), "interface{m() /* incomplete */}"},
		{NewInterface([]*Func{m}, nil).Complete(), "interface{m()}"},
		{NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(new(Interface).Complete())}).Complete(), "interface{T}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil))}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"},
		{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"},

		{NewInterfaceType(nil, nil), "interface{}"},
		{NewInterfaceType(nil, nil).Complete(), "interface{}"},
		{NewInterfaceType([]*Func{}, nil), "interface{}"},
		{NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"},
		{NewInterfaceType(nil, []Type{}), "interface{}"},
		{NewInterfaceType(nil, []Type{}).Complete(), "interface{}"},
		{NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"},
		{NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"},
		{NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
		{NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
	} {
		got := test.typ.String()
		if got != test.want {
			t.Errorf("got: %s, want: %s", got, test.want)
		}
	}
}

// newDefined creates a new defined type named T with the given underlying type.
// Helper function for use with TestIncompleteInterfaces only.
func newDefined(underlying Type) *Named {
	tname := NewTypeName(nopos, nil, "T", nil)
	return NewNamed(tname, underlying, nil)
}

func TestQualifiedTypeString(t *testing.T) {
	p, _ := pkgFor("p.go", "package p; type T int", nil)
	q, _ := pkgFor("q.go", "package q", nil)

	pT := p.Scope().Lookup("T").Type()
	for _, test := range []struct {
		typ  Type
		this *Package
		want string
	}{
		{nil, nil, "<nil>"},
		{pT, nil, "p.T"},
		{pT, p, "T"},
		{pT, q, "p.T"},
		{NewPointer(pT), p, "*T"},
		{NewPointer(pT), q, "*p.T"},
	} {
		qualifier := func(pkg *Package) string {
			if pkg != test.this {
				return pkg.Name()
			}
			return ""
		}
		if got := TypeString(test.typ, qualifier); got != test.want {
			t.Errorf("TypeString(%s, %s) = %s, want %s",
				test.this, test.typ, got, test.want)
		}
	}
}
<|endoftext|>


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

package orchestrator

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/model"
	converter "github.com/andreaskoch/allmark2/services/converter/markdowntohtml"
	"github.com/andreaskoch/allmark2/web/view/viewmodel"
)

type ViewModelOrchestrator struct {
	*Orchestrator

	navigationOrchestrator *NavigationOrchestrator
	tagOrchestrator        *TagsOrchestrator
	fileOrchestrator       *FileOrchestrator
	locationOrchestrator   *LocationOrchestrator

	latestByRoute     map[string][]*viewmodel.Model
	viewmodelsByRoute map[string]*viewmodel.Model
}

func (orchestrator *ViewModelOrchestrator) blockingCacheWarmup() {
	orchestrator.getViewModel(orchestrator.rootItem())
	orchestrator.GetLatest(route.New(), 5, 1)
}

func (orchestrator *ViewModelOrchestrator) GetFullViewModel(itemRoute route.Route) (viewModel viewmodel.Model, found bool) {

	// get the requested item
	item := orchestrator.getItem(itemRoute)
	if item == nil {
		return viewModel, false
	}

	// get the base view model
	viewModel = *orchestrator.getViewModel(item)

	// navigation
	viewModel.ToplevelNavigation = orchestrator.navigationOrchestrator.GetToplevelNavigation()
	viewModel.BreadcrumbNavigation = orchestrator.navigationOrchestrator.GetBreadcrumbNavigation(itemRoute)
	viewModel.ItemNavigation = orchestrator.navigationOrchestrator.GetItemNavigation(itemRoute)

	// childs
	viewModel.Childs = orchestrator.getChildModels(itemRoute)

	// tags
	viewModel.Tags = orchestrator.tagOrchestrator.getItemTags(itemRoute)

	// Locations
	viewModel.Locations = orchestrator.locationOrchestrator.GetLocations(item.MetaData.Locations, func(i *model.Item) viewmodel.Model {
		return *orchestrator.getViewModel(i)
	})

	// Geo Coordinates
	viewModel.GeoLocation = getGeoLocation(item)

	// Analytics Settings
	viewModel.Analytics = orchestrator.getAnalyticsSettings()

	// Hash / ETag
	viewModel.Hash = item.Hash

	// special viewmodel attributes
	isRepositoryItem := item.Type == model.TypeRepository
	if isRepositoryItem {

		// tag cloud
		repositoryIsNotEmpty := orchestrator.index().Size() >= 5 // don't bother to create a tag cloud if there aren't enough documents
		if repositoryIsNotEmpty {

			tagCloud := orchestrator.tagOrchestrator.GetTagCloud()
			viewModel.TagCloud = tagCloud

		}

	}

	return viewModel, true
}

func (orchestrator *ViewModelOrchestrator) GetViewModel(itemRoute route.Route) (viewModel viewmodel.Model, found bool) {

	// get the requested item
	item := orchestrator.getItem(itemRoute)
	if item == nil {
		return viewModel, false
	}

	return *orchestrator.getViewModel(item), true
}

func (orchestrator *ViewModelOrchestrator) GetLatest(itemRoute route.Route, pageSize, page int) (latest []*viewmodel.Model, found bool) {

	cacheType := "latest"

	// load from cache
	if orchestrator.latestByRoute != nil {

		// re-prime the cache if it is stale
		if orchestrator.isCacheStale(cacheType) {
			go orchestrator.primeCache(cacheType)
		}

		// return the result
		if models, exists := orchestrator.latestByRoute[itemRoute.Value()]; exists {
			return pagedViewmodels(models, pageSize, page)
		}

		return []*viewmodel.Model{}, false

	}

	orchestrator.setCache(cacheType, func() {

		latestModelsByRoute := make(map[string][]*viewmodel.Model)

		for _, childRoute := range orchestrator.repository.Routes() {

			// get the latest items
			latestItems := orchestrator.getLatestItems(childRoute)

			// store the results
			latestModelsByRoute[childRoute.Value()] = orchestrator.getLastesViewModelsFromItemList(latestItems)

		}

		// save the result
		orchestrator.latestByRoute = latestModelsByRoute

	})

	// return a result
	if models, exists := orchestrator.latestByRoute[itemRoute.Value()]; exists {
		return pagedViewmodels(models, pageSize, page)
	}

	return []*viewmodel.Model{}, false
}

// Converts a list of model.Item elements into a view models for the latest-items controller
func (orchestrator *ViewModelOrchestrator) getLastesViewModelsFromItemList(items []*model.Item) []*viewmodel.Model {

	// create viewmodels
	models := make([]*viewmodel.Model, 0, len(items))
	for _, item := range items {

		viewModel := orchestrator.getViewModel(item)

		// prepare lazy loading
		viewModel.Content = converter.LazyLoad(viewModel.Content)

		models = append(models, viewModel)
	}

	return models
}

func (orchestrator *ViewModelOrchestrator) getViewModel(item *model.Item) *viewmodel.Model {

	// get the root item
	root := orchestrator.rootItem()
	if root == nil {
		panic(fmt.Sprintf("Cannot get viewmodel for route %q because no root item was found.", item))
	}

	itemRoute := item.Route()
	cacheType := "viewmodels"

	// load from cache
	if orchestrator.viewmodelsByRoute != nil {

		// re-prime the cache if it is stale
		if orchestrator.isCacheStale(cacheType) {
			go orchestrator.primeCache(cacheType)
		}

		// return the result
		return orchestrator.viewmodelsByRoute[itemRoute.Value()]
	}

	orchestrator.setCache(cacheType, func() {

		viewmodelsByRoute := make(map[string]*viewmodel.Model)

		for _, child := range orchestrator.index().GetAllItems() {

			childRoute := child.Route()

			// convert content
			convertedContent, err := orchestrator.converter.Convert(orchestrator.getItemByAlias, orchestrator.relativePather(childRoute), child)
			if err != nil {
				orchestrator.logger.Warn("Cannot convert content for item %q. Error: %s.", child.String(), err.Error())
				convertedContent = "<!-- Conversion Error -->"
			}

			// create a view model
			viewModel := &viewmodel.Model{
				Base:    getBaseModel(root, child, orchestrator.itemPather()),
				Content: convertedContent,

				// files
				Files: orchestrator.fileOrchestrator.GetFiles(childRoute),

				IsRepositoryItem: true,
			}

			// store the view model
			viewmodelsByRoute[childRoute.Value()] = viewModel

		}

		orchestrator.viewmodelsByRoute = viewmodelsByRoute

	})

	return orchestrator.viewmodelsByRoute[itemRoute.Value()]
}

func (orchestrator *ViewModelOrchestrator) getChildModels(itemRoute route.Route) []*viewmodel.Base {

	rootItem := orchestrator.rootItem()
	if rootItem == nil {
		orchestrator.logger.Fatal("No root item found")
	}

	pathProvider := orchestrator.relativePather(itemRoute)

	childModels := make([]*viewmodel.Base, 0)

	childItems := orchestrator.getChilds(itemRoute)
	for _, childItem := range childItems {
		baseModel := getBaseModel(rootItem, childItem, pathProvider)
		childModels = append(childModels, &baseModel)
	}

	// sort the models
	viewmodel.SortBaseModelBy(sortBaseModelsByDate).Sort(childModels)

	return childModels
}
<commit_msg>Fixed a null pointer exception<commit_after>// Copyright 2014 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package orchestrator

import (
	"fmt"
	"github.com/andreaskoch/allmark2/common/route"
	"github.com/andreaskoch/allmark2/model"
	converter "github.com/andreaskoch/allmark2/services/converter/markdowntohtml"
	"github.com/andreaskoch/allmark2/web/view/viewmodel"
)

type ViewModelOrchestrator struct {
	*Orchestrator

	navigationOrchestrator *NavigationOrchestrator
	tagOrchestrator        *TagsOrchestrator
	fileOrchestrator       *FileOrchestrator
	locationOrchestrator   *LocationOrchestrator

	latestByRoute     map[string][]*viewmodel.Model
	viewmodelsByRoute map[string]*viewmodel.Model
}

func (orchestrator *ViewModelOrchestrator) blockingCacheWarmup() {
	orchestrator.getViewModel(orchestrator.rootItem())
	orchestrator.GetLatest(route.New(), 5, 1)
}

func (orchestrator *ViewModelOrchestrator) GetFullViewModel(itemRoute route.Route) (viewModel viewmodel.Model, found bool) {

	// get the requested item
	item := orchestrator.getItem(itemRoute)
	if item == nil {
		return viewModel, false
	}

	// get the base view model
	viewModel = *orchestrator.getViewModel(item)

	// navigation
	viewModel.ToplevelNavigation = orchestrator.navigationOrchestrator.GetToplevelNavigation()
	viewModel.BreadcrumbNavigation = orchestrator.navigationOrchestrator.GetBreadcrumbNavigation(itemRoute)
	viewModel.ItemNavigation = orchestrator.navigationOrchestrator.GetItemNavigation(itemRoute)

	// childs
	viewModel.Childs = orchestrator.getChildModels(itemRoute)

	// tags
	viewModel.Tags = orchestrator.tagOrchestrator.getItemTags(itemRoute)

	// Locations
	viewModel.Locations = orchestrator.locationOrchestrator.GetLocations(item.MetaData.Locations, func(i *model.Item) viewmodel.Model {
		return *orchestrator.getViewModel(i)
	})

	// Geo Coordinates
	viewModel.GeoLocation = getGeoLocation(item)

	// Analytics Settings
	viewModel.Analytics = orchestrator.getAnalyticsSettings()

	// Hash / ETag
	viewModel.Hash = item.Hash

	// special viewmodel attributes
	isRepositoryItem := item.Type == model.TypeRepository
	if isRepositoryItem {

		// tag cloud
		repositoryIsNotEmpty := orchestrator.index().Size() >= 5 // don't bother to create a tag cloud if there aren't enough documents
		if repositoryIsNotEmpty {

			tagCloud := orchestrator.tagOrchestrator.GetTagCloud()
			viewModel.TagCloud = tagCloud

		}

	}

	return viewModel, true
}

func (orchestrator *ViewModelOrchestrator) GetViewModel(itemRoute route.Route) (viewModel viewmodel.Model, found bool) {

	// get the requested item
	item := orchestrator.getItem(itemRoute)
	if item == nil {
		return viewModel, false
	}

	return *orchestrator.getViewModel(item), true
}

func (orchestrator *ViewModelOrchestrator) GetLatest(itemRoute route.Route, pageSize, page int) (latest []*viewmodel.Model, found bool) {

	cacheType := "latest"

	// load from cache
	if orchestrator.latestByRoute != nil {

		// re-prime the cache if it is stale
		if orchestrator.isCacheStale(cacheType) {
			go orchestrator.primeCache(cacheType)
		}

		// return the result
		if models, exists := orchestrator.latestByRoute[itemRoute.Value()]; exists {
			return pagedViewmodels(models, pageSize, page)
		}

		return []*viewmodel.Model{}, false

	}

	orchestrator.setCache(cacheType, func() {

		latestModelsByRoute := make(map[string][]*viewmodel.Model)

		for _, childRoute := range orchestrator.repository.Routes() {

			// get the latest items
			latestItems := orchestrator.getLatestItems(childRoute)

			// store the results
			latestModelsByRoute[childRoute.Value()] = orchestrator.getLastesViewModelsFromItemList(latestItems)

		}

		// save the result
		orchestrator.latestByRoute = latestModelsByRoute

	})

	// return a result
	if models, exists := orchestrator.latestByRoute[itemRoute.Value()]; exists {
		return pagedViewmodels(models, pageSize, page)
	}

	return []*viewmodel.Model{}, false
}

// Converts a list of model.Item elements into a view models for the latest-items controller
func (orchestrator *ViewModelOrchestrator) getLastesViewModelsFromItemList(items []*model.Item) []*viewmodel.Model {

	// create viewmodels
	models := make([]*viewmodel.Model, 0, len(items))
	for _, item := range items {

		viewModel := orchestrator.getViewModel(item)
		if viewModel == nil {
			// todo: log warning
			continue
		}

		// prepare lazy loading
		viewModel.Content = converter.LazyLoad(viewModel.Content)

		models = append(models, viewModel)
	}

	return models
}

func (orchestrator *ViewModelOrchestrator) getViewModel(item *model.Item) *viewmodel.Model {

	// get the root item
	root := orchestrator.rootItem()
	if root == nil {
		panic(fmt.Sprintf("Cannot get viewmodel for route %q because no root item was found.", item))
	}

	itemRoute := item.Route()
	cacheType := "viewmodels"

	// load from cache
	if orchestrator.viewmodelsByRoute != nil {

		// re-prime the cache if it is stale
		if orchestrator.isCacheStale(cacheType) {
			go orchestrator.primeCache(cacheType)
		}

		// return the result
		return orchestrator.viewmodelsByRoute[itemRoute.Value()]
	}

	orchestrator.setCache(cacheType, func() {

		viewmodelsByRoute := make(map[string]*viewmodel.Model)

		for _, child := range orchestrator.index().GetAllItems() {

			childRoute := child.Route()

			// convert content
			convertedContent, err := orchestrator.converter.Convert(orchestrator.getItemByAlias, orchestrator.relativePather(childRoute), child)
			if err != nil {
				orchestrator.logger.Warn("Cannot convert content for item %q. Error: %s.", child.String(), err.Error())
				convertedContent = "<!-- Conversion Error -->"
			}

			// create a view model
			viewModel := &viewmodel.Model{
				Base:    getBaseModel(root, child, orchestrator.itemPather()),
				Content: convertedContent,

				// files
				Files: orchestrator.fileOrchestrator.GetFiles(childRoute),

				IsRepositoryItem: true,
			}

			// store the view model
			viewmodelsByRoute[childRoute.Value()] = viewModel

		}

		orchestrator.viewmodelsByRoute = viewmodelsByRoute

	})

	return orchestrator.viewmodelsByRoute[itemRoute.Value()]
}

func (orchestrator *ViewModelOrchestrator) getChildModels(itemRoute route.Route) []*viewmodel.Base {

	rootItem := orchestrator.rootItem()
	if rootItem == nil {
		orchestrator.logger.Fatal("No root item found")
	}

	pathProvider := orchestrator.relativePather(itemRoute)

	childModels := make([]*viewmodel.Base, 0)

	childItems := orchestrator.getChilds(itemRoute)
	for _, childItem := range childItems {
		baseModel := getBaseModel(rootItem, childItem, pathProvider)
		childModels = append(childModels, &baseModel)
	}

	// sort the models
	viewmodel.SortBaseModelBy(sortBaseModelsByDate).Sort(childModels)

	return childModels
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/dronemill/harmony-client-go"
	"github.com/fsouza/go-dockerclient"
)

// Batond is the main app contianer
type Batond struct {
	// hamrony client
	Harmony *harmonyclient.Client
}

// maestroConnect will get a connected maestro client
func (b *Batond) harmonyConnect() error {
	hconf := harmonyclient.Config{
		APIHost:      config.Harmony.API,
		APIVersion:   "v1",
		APIVerifySSL: config.Harmony.VerifySSL,
	}

	log.WithField("harmonyAPI", config.Harmony.API).Info("Attempting connection to HarmonyAPI")

	var err error
	b.Harmony, err = harmonyclient.NewHarmonyClient(hconf)

	if err != nil {
		// TODO: maybe like dont bomb out here.. @pmccarren
		log.Fatalf("Failed connecting to the HarmonyAPI: %s", err.Error())
	}

	return nil
}

// getMachine will get the Harmony Machine
func (b *Batond) getMachine() *harmonyclient.Machine {
	// check if we already have a MachineID
	machine := b.getMachineByName()
	if machine != nil {
		return machine
	}

	return b.createMachine()
}

// getMachineByName will get a Harmony Machine resource by name
func (b *Batond) getMachineByName() *harmonyclient.Machine {
	machine, err := b.Harmony.MachineByName(config.Machine.Name)
	if err != nil {
		// TODO: need to get some better error handling in here.. @pmccarren
		log.WithField("name", config.Machine.Name).WithField("error", err.Error()).Fatal("Failed fetching machine by name")
	}

	return machine
}

// createMachine will create a Harmony Machine resource
func (b *Batond) createMachine() *harmonyclient.Machine {

	machine := &harmonyclient.Machine{
		Name:     config.Machine.Name,
		Hostname: config.Machine.Hostname,
	}

	machineResource, err := b.Harmony.MachinesAdd(machine)

	if err != nil {
		log.WithField("error", err.Error()).Fatal("Failed creating machine")
	}

	return machineResource
}

/**
 * Fetch container from Harmony
 *
 * Check if the container is already created
 * 		IF IS NOT; check if image is pulled
 * 			IF NO:: pull
 * 		create it and store the cID w/ Harmony
 *
 * Check if container is enabled
 * 		IF IS: ensure started
 * 		IF IS: NOT ensure stopped
 */
// checkContainerState will ensure a container is in the propper state
func (b *Batond) checkContainerState(cID string) {
	// first we need to get the container resource
	container, err := b.Harmony.Container(cID)
	if err != nil {
		// TODO: need to get some better error handling in here.. @pmccarren
		log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed fetching container")
	}
	log.WithField("containerID", container.ID).Info("Successfuly retreived Harmony container resource")

	// check if the container is already created
	exists, err := b.containerExists(container)
	if err != nil {
		log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed checking if container exists")
	}

	// FIXME: need to handle the case wheere the container.CID is set, but the container does not actually exist

	if !exists {
		log.WithField("containerID", container.ID).Info("Container does not exist. Creating.")

		// ensure image exists
		if err := b.ensureImageExists(container.Image); err != nil {
			log.WithField("containerID", cID).WithField("image", container.Image).WithField("error", err.Error()).Fatal("Failed ensuring image exists")
		}

		dkrContainer, err := b.createContainer(container)
		if err != nil {
			log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed creating container")
		}

		log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).Info("Created container")

		if err := b.Harmony.ContainersCIDUpdate(cID, dkrContainer.ID); err != nil {
			log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).WithField("error", err.Error()).Fatal("Failed updating container")
		}

		// manually set it here, so we dont have to refetch the container resource
		container.CID = dkrContainer.ID

		log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).Info("Updated container cID")
	} else {
		log.WithField("containerID", container.ID).WithField("cID", container.CID).Debug("Container already exists")
	}

	// get the running state of the container
	running, err := b.containerRunning(container)
	if err != nil {
		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed checking if container is running")
	}

	log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", running).Debug("Checked container running state")

	// if container is stopped, and should be running, start it
	if !running && container.Enabled {
		if err := b.startContainer(container); err != nil {
			log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed starting container")
		}

		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", true).Info("Started container")
	}

	// if container is running, and should be stopped, stop it
	if running && !container.Enabled {
		if err := b.stopContainer(container); err != nil {
			log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed stopping container")
		}

		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", false).Info("Stopped container")
	}
}

// ensureImageExists will make sure that we have an image pulled
func (b *Batond) ensureImageExists(name string) error {
	// get the image id
	imageID, err := b.dkrImageNameToId(name)

	if err != nil {
		log.WithField("image", name).WithField("error", err.Error()).Error("Failed checking if image is already pulled")
		return err
	}

	// FIXME this is not working
	if imageID != "" {
		log.WithField("image", name).
			Debug("Image is already pulled")
		return nil
	}

	log.WithField("image", name).Info("Pulling image")

	var registry, image, tag string

	// We need to split up the image name
	parts := strings.Split(name, ":")
	image = parts[0]

	// if we have a tag, then set it
	if len(parts) > 1 {
		tag = parts[1]
	}

	// check and see if we have two slashes, because if we do,
	// then preceeding the first one is the registry
	if count := strings.Count(image, "/"); count == 2 {
		imageParts := strings.Split(image, "/")
		registry = imageParts[0]
	}

	opts := docker.PullImageOptions{
		Registry:   registry,
		Repository: image,
		Tag:        tag,
	}

	// FIXME
	// auth := docker.AuthConfiguration{
	// 	Username:      conf.DockerRegistry.Username,
	// 	Password:      conf.DockerRegistry.Password,
	// 	Email:         conf.DockerRegistry.Email,
	// 	ServerAddress: conf.DockerRegistry.Url,
	// }
	auth := docker.AuthConfiguration{}

	// Pull the image
	err = dkr.PullImage(opts, auth)

	if err != nil {
		log.WithField("image", name).WithField("error", err.Error()).Error("Failed pulling image")
		return err
	}

	log.WithField("image", name).
		Debug("Pulled image")

	return nil
}

// dkrImageNameToID will convery an image name to the docker imageID
func (b *Batond) dkrImageNameToId(name string) (string, error) {
	images, err := dkr.ListImages(docker.ListImagesOptions{})

	if err != nil {
		log.Error(err.Error())
		return "", err
	}

	for _, i := range images {
		for _, tag := range i.RepoTags {
			if tag == name {
				return i.ID, nil
			}
		}
	}

	return "", nil
}

// containerExists will check if the container is already created
func (b *Batond) containerExists(container *harmonyclient.Container) (bool, error) {
	if container.CID == "" {
		return false, nil
	}

	// see if the container is already created
	dkrContainer, err := dkr.InspectContainer(container.CID)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Fatal("Failed inspecting container")
		return false, err
	}

	// if we received a container, then return so!
	if dkrContainer != nil {
		return true, nil
	}

	return false, nil
}

// containerRunning will check if the container is running
func (b *Batond) containerRunning(container *harmonyclient.Container) (bool, error) {
	// see if the container is already created
	dkrContainer, err := dkr.InspectContainer(container.CID)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Fatal("Failed inspecting container")
		return false, err
	}

	return dkrContainer.State.Running, nil
}

// createContainer will create a new docker container
func (b *Batond) createContainer(container *harmonyclient.Container) (*docker.Container, error) {
	log.WithField("containerID", container.ID).Info("Creating container")

	// setup some vars
	var entryPoint, cmd, env []string

	// set EntryPoint if exists
	if container.EntryPoint != "" {
		entryPoint = make([]string, 1)
		entryPoint[0] = container.EntryPoint
	}

	// set Cmd if exists
	if container.Cmd != "" {
		cmd = strings.Split(container.Cmd, " ")
	}

	// compile the env
	env = make([]string, len(container.ContainerEnvsIDs))
	for i, eID := range container.ContainerEnvsIDs {
		e, err := b.Harmony.ContainerEnv(eID)
		if err != nil {
			log.WithField("ContainerEnvID", eID).WithField("error", err.Error()).Fatalf("Failed retreiving env")
		}

		// TODO excape this better
		env[i] = fmt.Sprintf("%s=\"%s\"", e.Name, e.Value)
	}

	hostConfig, err := b.containerHostConfig(container)

	if err != nil {
		log.WithField("ContainerID", container.ID).WithField("error", err.Error()).Fatalf("Failed building hostConfig")
	}

	dkrConfig := docker.Config{
		Hostname:   container.Hostname,
		Env:        env,
		Entrypoint: entryPoint,
		Cmd:        cmd,
		DNS:        hostConfig.DNS,
		Image:      container.Image,
		Tty:        container.Tty,
		OpenStdin:  container.Interactive,
		StdinOnce:  container.Interactive,
	}

	opts := docker.CreateContainerOptions{
		Name:       container.Name,
		Config:     &dkrConfig,
		HostConfig: &hostConfig,
	}

	c, err := dkr.CreateContainer(opts)

	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed creating docker container")

		return nil, err
	}

	log.WithField("containerID", container.ID).WithField("cID", c.ID).Info("Created docker container")

	return c, nil
}

// containerHostConfig will generate a container's config by fetching the relevant
// resources from Harmony, and composing the env and dns slices
func (b *Batond) containerHostConfig(container *harmonyclient.Container) (docker.HostConfig, error) {
	// compile the dns
	dns := make([]string, len(container.ContainerDnsIDs))
	for i, dID := range container.ContainerDnsIDs {
		d, err := b.Harmony.ContainerDns(dID)
		if err != nil {
			log.WithField("ContainerDnsID", dID).WithField("error", err.Error()).Fatal("Failed retreiving container dns")
		}

		dns[i] = d.Nameserver
	}

	// compile the binds
	binds := make([]string, len(container.ContainerVolumesIDs))
	for i, vID := range container.ContainerVolumesIDs {
		v, err := b.Harmony.ContainerVolume(vID)
		if err != nil {
			log.WithField("ContainerVolumeID", vID).WithField("error", err.Error()).Fatal("Failed retreiving container volume")
		}

		binds[i] = fmt.Sprintf("%s:%s", v.PathHost, v.PathContainer)
	}

	log.WithField("containerID", container.ID).Debug("Successfully built containerHostConfig")

	return docker.HostConfig{
		Binds: binds,
		DNS:   dns,
	}, nil
}

// startContainer will start a docker container
func (b *Batond) startContainer(container *harmonyclient.Container) error {
	hostConfig, err := b.containerHostConfig(container)
	if err != nil {
		log.WithField("ContainerID", container.ID).WithField("error", err.Error()).Fatalf("Failed building hostConfig")
	}

	err = dkr.StartContainer(container.CID, &hostConfig)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed starting container")
	}

	return err
}

// stopContainer will start a docker container
func (b *Batond) stopContainer(container *harmonyclient.Container) error {
	// FIXME
	var timeout uint
	timeout = 5

	err := dkr.StopContainer(container.CID, timeout)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed stopping container")
	}

	return err
}
<commit_msg>Dont fatal out if container doesnt exist<commit_after>package main

import (
	"fmt"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/dronemill/harmony-client-go"
	"github.com/fsouza/go-dockerclient"
)

// Batond is the main app contianer
type Batond struct {
	// hamrony client
	Harmony *harmonyclient.Client
}

// maestroConnect will get a connected maestro client
func (b *Batond) harmonyConnect() error {
	hconf := harmonyclient.Config{
		APIHost:      config.Harmony.API,
		APIVersion:   "v1",
		APIVerifySSL: config.Harmony.VerifySSL,
	}

	log.WithField("harmonyAPI", config.Harmony.API).Info("Attempting connection to HarmonyAPI")

	var err error
	b.Harmony, err = harmonyclient.NewHarmonyClient(hconf)

	if err != nil {
		// TODO: maybe like dont bomb out here.. @pmccarren
		log.Fatalf("Failed connecting to the HarmonyAPI: %s", err.Error())
	}

	return nil
}

// getMachine will get the Harmony Machine
func (b *Batond) getMachine() *harmonyclient.Machine {
	// check if we already have a MachineID
	machine := b.getMachineByName()
	if machine != nil {
		return machine
	}

	return b.createMachine()
}

// getMachineByName will get a Harmony Machine resource by name
func (b *Batond) getMachineByName() *harmonyclient.Machine {
	machine, err := b.Harmony.MachineByName(config.Machine.Name)
	if err != nil {
		// TODO: need to get some better error handling in here.. @pmccarren
		log.WithField("name", config.Machine.Name).WithField("error", err.Error()).Fatal("Failed fetching machine by name")
	}

	return machine
}

// createMachine will create a Harmony Machine resource
func (b *Batond) createMachine() *harmonyclient.Machine {

	machine := &harmonyclient.Machine{
		Name:     config.Machine.Name,
		Hostname: config.Machine.Hostname,
	}

	machineResource, err := b.Harmony.MachinesAdd(machine)

	if err != nil {
		log.WithField("error", err.Error()).Fatal("Failed creating machine")
	}

	return machineResource
}

/**
 * Fetch container from Harmony
 *
 * Check if the container is already created
 * 		IF IS NOT; check if image is pulled
 * 			IF NO:: pull
 * 		create it and store the cID w/ Harmony
 *
 * Check if container is enabled
 * 		IF IS: ensure started
 * 		IF IS: NOT ensure stopped
 */
// checkContainerState will ensure a container is in the propper state
func (b *Batond) checkContainerState(cID string) {
	// first we need to get the container resource
	container, err := b.Harmony.Container(cID)
	if err != nil {
		// TODO: need to get some better error handling in here.. @pmccarren
		log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed fetching container")
	}
	log.WithField("containerID", container.ID).Info("Successfuly retreived Harmony container resource")

	// check if the container is already created
	exists, err := b.containerExists(container)
	if err != nil {
		log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed checking if container exists")
	}

	// FIXME: need to handle the case wheere the container.CID is set, but the container does not actually exist

	if !exists {
		log.WithField("containerID", container.ID).Info("Container does not exist. Creating.")

		// ensure image exists
		if err := b.ensureImageExists(container.Image); err != nil {
			log.WithField("containerID", cID).WithField("image", container.Image).WithField("error", err.Error()).Fatal("Failed ensuring image exists")
		}

		dkrContainer, err := b.createContainer(container)
		if err != nil {
			log.WithField("containerID", cID).WithField("error", err.Error()).Fatal("Failed creating container")
		}

		log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).Info("Created container")

		if err := b.Harmony.ContainersCIDUpdate(cID, dkrContainer.ID); err != nil {
			log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).WithField("error", err.Error()).Fatal("Failed updating container")
		}

		// manually set it here, so we dont have to refetch the container resource
		container.CID = dkrContainer.ID

		log.WithField("containerID", cID).WithField("cID", dkrContainer.ID).Info("Updated container cID")
	} else {
		log.WithField("containerID", container.ID).WithField("cID", container.CID).Debug("Container already exists")
	}

	// get the running state of the container
	running, err := b.containerRunning(container)
	if err != nil {
		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed checking if container is running")
	}

	log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", running).Debug("Checked container running state")

	// if container is stopped, and should be running, start it
	if !running && container.Enabled {
		if err := b.startContainer(container); err != nil {
			log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed starting container")
		}

		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", true).Info("Started container")
	}

	// if container is running, and should be stopped, stop it
	if running && !container.Enabled {
		if err := b.stopContainer(container); err != nil {
			log.WithField("containerID", cID).WithField("cID", container.CID).WithField("error", err.Error()).Fatal("Failed stopping container")
		}

		log.WithField("containerID", cID).WithField("cID", container.CID).WithField("running", false).Info("Stopped container")
	}
}

// ensureImageExists will make sure that we have an image pulled
func (b *Batond) ensureImageExists(name string) error {
	// get the image id
	imageID, err := b.dkrImageNameToId(name)

	if err != nil {
		log.WithField("image", name).WithField("error", err.Error()).Error("Failed checking if image is already pulled")
		return err
	}

	// FIXME this is not working
	if imageID != "" {
		log.WithField("image", name).
			Debug("Image is already pulled")
		return nil
	}

	log.WithField("image", name).Info("Pulling image")

	var registry, image, tag string

	// We need to split up the image name
	parts := strings.Split(name, ":")
	image = parts[0]

	// if we have a tag, then set it
	if len(parts) > 1 {
		tag = parts[1]
	}

	// check and see if we have two slashes, because if we do,
	// then preceeding the first one is the registry
	if count := strings.Count(image, "/"); count == 2 {
		imageParts := strings.Split(image, "/")
		registry = imageParts[0]
	}

	opts := docker.PullImageOptions{
		Registry:   registry,
		Repository: image,
		Tag:        tag,
	}

	// FIXME
	// auth := docker.AuthConfiguration{
	// 	Username:      conf.DockerRegistry.Username,
	// 	Password:      conf.DockerRegistry.Password,
	// 	Email:         conf.DockerRegistry.Email,
	// 	ServerAddress: conf.DockerRegistry.Url,
	// }
	auth := docker.AuthConfiguration{}

	// Pull the image
	err = dkr.PullImage(opts, auth)

	if err != nil {
		log.WithField("image", name).WithField("error", err.Error()).Error("Failed pulling image")
		return err
	}

	log.WithField("image", name).
		Debug("Pulled image")

	return nil
}

// dkrImageNameToID will convery an image name to the docker imageID
func (b *Batond) dkrImageNameToId(name string) (string, error) {
	images, err := dkr.ListImages(docker.ListImagesOptions{})

	if err != nil {
		log.Error(err.Error())
		return "", err
	}

	for _, i := range images {
		for _, tag := range i.RepoTags {
			if tag == name {
				return i.ID, nil
			}
		}
	}

	return "", nil
}

// containerExists will check if the container is already created
func (b *Batond) containerExists(container *harmonyclient.Container) (bool, error) {
	if container.CID == "" {
		return false, nil
	}

	// see if the container is already created
	dkrContainer, err := dkr.InspectContainer(container.CID)
	if err != nil {
		if _, ok := err.(*docker.NoSuchContainer); ok {
			return false, nil
		}

		log.WithField("containerID", container.ID).WithField("error", err.Error()).Fatal("Failed inspecting container")
		return false, err
	}

	// if we received a container, then return so!
	if dkrContainer != nil {
		return true, nil
	}

	return false, nil
}

// containerRunning will check if the container is running
func (b *Batond) containerRunning(container *harmonyclient.Container) (bool, error) {
	// see if the container is already created
	dkrContainer, err := dkr.InspectContainer(container.CID)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Fatal("Failed inspecting container")
		return false, err
	}

	return dkrContainer.State.Running, nil
}

// createContainer will create a new docker container
func (b *Batond) createContainer(container *harmonyclient.Container) (*docker.Container, error) {
	log.WithField("containerID", container.ID).Info("Creating container")

	// setup some vars
	var entryPoint, cmd, env []string

	// set EntryPoint if exists
	if container.EntryPoint != "" {
		entryPoint = make([]string, 1)
		entryPoint[0] = container.EntryPoint
	}

	// set Cmd if exists
	if container.Cmd != "" {
		cmd = strings.Split(container.Cmd, " ")
	}

	// compile the env
	env = make([]string, len(container.ContainerEnvsIDs))
	for i, eID := range container.ContainerEnvsIDs {
		e, err := b.Harmony.ContainerEnv(eID)
		if err != nil {
			log.WithField("ContainerEnvID", eID).WithField("error", err.Error()).Fatalf("Failed retreiving env")
		}

		// TODO excape this better
		env[i] = fmt.Sprintf("%s=\"%s\"", e.Name, e.Value)
	}

	hostConfig, err := b.containerHostConfig(container)

	if err != nil {
		log.WithField("ContainerID", container.ID).WithField("error", err.Error()).Fatalf("Failed building hostConfig")
	}

	dkrConfig := docker.Config{
		Hostname:   container.Hostname,
		Env:        env,
		Entrypoint: entryPoint,
		Cmd:        cmd,
		DNS:        hostConfig.DNS,
		Image:      container.Image,
		Tty:        container.Tty,
		OpenStdin:  container.Interactive,
		StdinOnce:  container.Interactive,
	}

	opts := docker.CreateContainerOptions{
		Name:       container.Name,
		Config:     &dkrConfig,
		HostConfig: &hostConfig,
	}

	c, err := dkr.CreateContainer(opts)

	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed creating docker container")

		return nil, err
	}

	log.WithField("containerID", container.ID).WithField("cID", c.ID).Info("Created docker container")

	return c, nil
}

// containerHostConfig will generate a container's config by fetching the relevant
// resources from Harmony, and composing the env and dns slices
func (b *Batond) containerHostConfig(container *harmonyclient.Container) (docker.HostConfig, error) {
	// compile the dns
	dns := make([]string, len(container.ContainerDnsIDs))
	for i, dID := range container.ContainerDnsIDs {
		d, err := b.Harmony.ContainerDns(dID)
		if err != nil {
			log.WithField("ContainerDnsID", dID).WithField("error", err.Error()).Fatal("Failed retreiving container dns")
		}

		dns[i] = d.Nameserver
	}

	// compile the binds
	binds := make([]string, len(container.ContainerVolumesIDs))
	for i, vID := range container.ContainerVolumesIDs {
		v, err := b.Harmony.ContainerVolume(vID)
		if err != nil {
			log.WithField("ContainerVolumeID", vID).WithField("error", err.Error()).Fatal("Failed retreiving container volume")
		}

		binds[i] = fmt.Sprintf("%s:%s", v.PathHost, v.PathContainer)
	}

	log.WithField("containerID", container.ID).Debug("Successfully built containerHostConfig")

	return docker.HostConfig{
		Binds: binds,
		DNS:   dns,
	}, nil
}

// startContainer will start a docker container
func (b *Batond) startContainer(container *harmonyclient.Container) error {
	hostConfig, err := b.containerHostConfig(container)
	if err != nil {
		log.WithField("ContainerID", container.ID).WithField("error", err.Error()).Fatalf("Failed building hostConfig")
	}

	err = dkr.StartContainer(container.CID, &hostConfig)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed starting container")
	}

	return err
}

// stopContainer will start a docker container
func (b *Batond) stopContainer(container *harmonyclient.Container) error {
	// FIXME
	var timeout uint
	timeout = 5

	err := dkr.StopContainer(container.CID, timeout)
	if err != nil {
		log.WithField("containerID", container.ID).WithField("error", err.Error()).Error("Failed stopping container")
	}

	return err
}
<|endoftext|>


<commit_before>package client

import (
	"net/http"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"

	"github.com/frodenas/bosh-google-cpi/google/config"

	"golang.org/x/oauth2"
	oauthgoogle "golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v1"
	"google.golang.org/api/storage/v1"
)

const computeScope = compute.ComputeScope
const storageScope = storage.DevstorageFullControlScope

type GoogleClient struct {
	config         config.Config
	computeService *compute.Service
	storageService *storage.Service
	logger         boshlog.Logger
}

func NewGoogleClient(
	config config.Config,
	logger boshlog.Logger,
) (GoogleClient, error) {
	var err error
	var computeClient, storageClient *http.Client
	userAgent := "bosh-google-cpi/0.0.1"

	if config.JSONKey != "" {
		computeJwtConf, err := oauthgoogle.JWTConfigFromJSON([]byte(config.JSONKey), computeScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Reading Google JSON Key")
		}
		computeClient = computeJwtConf.Client(oauth2.NoContext)

		storageJwtConf, err := oauthgoogle.JWTConfigFromJSON([]byte(config.JSONKey), storageScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Reading Google JSON Key")
		}
		storageClient = storageJwtConf.Client(oauth2.NoContext)
	} else {
		computeClient, err = oauthgoogle.DefaultClient(oauth2.NoContext, computeScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Creating a Google default client")
		}

		storageClient, err = oauthgoogle.DefaultClient(oauth2.NoContext, storageScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Creating a Google default client")
		}
	}

	computeService, err := compute.New(computeClient)
	if err != nil {
		return GoogleClient{}, bosherr.WrapError(err, "Creating a Google Compute Service client")
	}
	computeService.UserAgent = userAgent

	storageService, err := storage.New(storageClient)
	if err != nil {
		return GoogleClient{}, bosherr.WrapError(err, "Creating a Google Storage Service client")
	}
	storageService.UserAgent = userAgent

	return GoogleClient{
		config:         config,
		computeService: computeService,
		storageService: storageService,
		logger:         logger,
	}, nil
}

func (c GoogleClient) Project() string {
	return c.config.Project
}

func (c GoogleClient) DefaultRootDiskSizeGb() int {
	return c.config.DefaultRootDiskSizeGb
}

func (c GoogleClient) DefaultRootDiskType() string {
	return c.config.DefaultRootDiskType
}

func (c GoogleClient) DefaultZone() string {
	return c.config.DefaultZone
}

func (c GoogleClient) ComputeService() *compute.Service {
	return c.computeService
}

func (c GoogleClient) StorageService() *storage.Service {
	return c.storageService
}
<commit_msg>Specify the GCE metadata hostname.<commit_after>package client

import (
	"net/http"
	"os"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"
	boshlog "github.com/cloudfoundry/bosh-utils/logger"

	"github.com/frodenas/bosh-google-cpi/google/config"

	"golang.org/x/oauth2"
	oauthgoogle "golang.org/x/oauth2/google"
	"google.golang.org/api/compute/v1"
	"google.golang.org/api/storage/v1"
)

const (
	computeScope = compute.ComputeScope
	storageScope = storage.DevstorageFullControlScope
	metadataHost = "metadata"
)

type GoogleClient struct {
	config         config.Config
	computeService *compute.Service
	storageService *storage.Service
	logger         boshlog.Logger
}

func NewGoogleClient(
	config config.Config,
	logger boshlog.Logger,
) (GoogleClient, error) {
	var err error
	var computeClient, storageClient *http.Client
	userAgent := "bosh-google-cpi/0.0.1"

	if config.JSONKey != "" {
		computeJwtConf, err := oauthgoogle.JWTConfigFromJSON([]byte(config.JSONKey), computeScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Reading Google JSON Key")
		}
		computeClient = computeJwtConf.Client(oauth2.NoContext)

		storageJwtConf, err := oauthgoogle.JWTConfigFromJSON([]byte(config.JSONKey), storageScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Reading Google JSON Key")
		}
		storageClient = storageJwtConf.Client(oauth2.NoContext)
	} else {
		if v := os.Getenv("GCE_METADATA_HOST"); v == "" {
			os.Setenv("GCE_METADATA_HOST", metadataHost)
		}
		computeClient, err = oauthgoogle.DefaultClient(oauth2.NoContext, computeScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Creating a Google default client")
		}

		storageClient, err = oauthgoogle.DefaultClient(oauth2.NoContext, storageScope)
		if err != nil {
			return GoogleClient{}, bosherr.WrapError(err, "Creating a Google default client")
		}
	}

	computeService, err := compute.New(computeClient)
	if err != nil {
		return GoogleClient{}, bosherr.WrapError(err, "Creating a Google Compute Service client")
	}
	computeService.UserAgent = userAgent

	storageService, err := storage.New(storageClient)
	if err != nil {
		return GoogleClient{}, bosherr.WrapError(err, "Creating a Google Storage Service client")
	}
	storageService.UserAgent = userAgent

	return GoogleClient{
		config:         config,
		computeService: computeService,
		storageService: storageService,
		logger:         logger,
	}, nil
}

func (c GoogleClient) Project() string {
	return c.config.Project
}

func (c GoogleClient) DefaultRootDiskSizeGb() int {
	return c.config.DefaultRootDiskSizeGb
}

func (c GoogleClient) DefaultRootDiskType() string {
	return c.config.DefaultRootDiskType
}

func (c GoogleClient) DefaultZone() string {
	return c.config.DefaultZone
}

func (c GoogleClient) ComputeService() *compute.Service {
	return c.computeService
}

func (c GoogleClient) StorageService() *storage.Service {
	return c.storageService
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package discover

import (
	"bytes"
	"encoding/hex"
	"errors"
	"io"
	"net"
	"net/url"
	"strconv"
	"time"

	"github.com/syncthing/syncthing/lib/beacon"
	"github.com/syncthing/syncthing/lib/events"
	"github.com/syncthing/syncthing/lib/protocol"
	"github.com/thejerf/suture"
)

type localClient struct {
	*suture.Supervisor
	myID      protocol.DeviceID
	addrList  AddressLister
	relayStat RelayStatusProvider
	name      string

	beacon          beacon.Interface
	localBcastStart time.Time
	localBcastTick  <-chan time.Time
	forcedBcastTick chan time.Time

	*cache
}

const (
	BroadcastInterval = 30 * time.Second
	CacheLifeTime     = 3 * BroadcastInterval
)

var (
	ErrIncorrectMagic = errors.New("incorrect magic number")
)

func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister, relayStat RelayStatusProvider) (FinderService, error) {
	c := &localClient{
		Supervisor:      suture.NewSimple("local"),
		myID:            id,
		addrList:        addrList,
		relayStat:       relayStat,
		localBcastTick:  time.Tick(BroadcastInterval),
		forcedBcastTick: make(chan time.Time),
		localBcastStart: time.Now(),
		cache:           newCache(),
	}

	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}

	if len(host) == 0 {
		// A broadcast client
		c.name = "IPv4 local"
		bcPort, err := strconv.Atoi(port)
		if err != nil {
			return nil, err
		}
		c.startLocalIPv4Broadcasts(bcPort)
	} else {
		// A multicast client
		c.name = "IPv6 local"
		c.startLocalIPv6Multicasts(addr)
	}

	go c.sendLocalAnnouncements()

	return c, nil
}

func (c *localClient) startLocalIPv4Broadcasts(localPort int) {
	c.beacon = beacon.NewBroadcast(localPort)
	c.Add(c.beacon)
	go c.recvAnnouncements(c.beacon)
}

func (c *localClient) startLocalIPv6Multicasts(localMCAddr string) {
	c.beacon = beacon.NewMulticast(localMCAddr)
	c.Add(c.beacon)
	go c.recvAnnouncements(c.beacon)
}

// Lookup returns a list of addresses the device is available at. Local
// discovery never returns relays.
func (c *localClient) Lookup(device protocol.DeviceID) (direct []string, relays []Relay, err error) {
	if cache, ok := c.Get(device); ok {
		if time.Since(cache.when) < CacheLifeTime {
			direct = cache.Direct
			relays = cache.Relays
		}
	}

	return
}

func (c *localClient) String() string {
	return c.name
}

func (c *localClient) Error() error {
	return c.beacon.Error()
}

func (c *localClient) announcementPkt() Announce {
	var addrs []Address
	for _, addr := range c.addrList.AllAddresses() {
		addrs = append(addrs, Address{
			URL: addr,
		})
	}

	var relays []Relay
	for _, relay := range c.relayStat.Relays() {
		latency, ok := c.relayStat.RelayStatus(relay)
		if ok {
			relays = append(relays, Relay{
				URL:     relay,
				Latency: int32(latency / time.Millisecond),
			})
		}
	}

	return Announce{
		Magic: AnnouncementMagic,
		This: Device{
			ID:        c.myID[:],
			Addresses: addrs,
			Relays:    relays,
		},
	}
}

func (c *localClient) sendLocalAnnouncements() {
	var pkt = c.announcementPkt()
	msg := pkt.MustMarshalXDR()

	for {
		c.beacon.Send(msg)

		select {
		case <-c.localBcastTick:
		case <-c.forcedBcastTick:
		}
	}
}

func (c *localClient) recvAnnouncements(b beacon.Interface) {
	for {
		buf, addr := b.Recv()

		var pkt Announce
		err := pkt.UnmarshalXDR(buf)
		if err != nil && err != io.EOF {
			l.Debugf("discover: Failed to unmarshal local announcement from %s:\n%s", addr, hex.Dump(buf))
			continue
		}

		l.Debugf("discover: Received local announcement from %s for %s", addr, protocol.DeviceIDFromBytes(pkt.This.ID))

		var newDevice bool
		if bytes.Compare(pkt.This.ID, c.myID[:]) != 0 {
			newDevice = c.registerDevice(addr, pkt.This)
		}

		if newDevice {
			select {
			case c.forcedBcastTick <- time.Now():
			}
		}
	}
}

func (c *localClient) registerDevice(src net.Addr, device Device) bool {
	var id protocol.DeviceID
	copy(id[:], device.ID)

	// Remember whether we already had a valid cache entry for this device.

	ce, existsAlready := c.Get(id)
	isNewDevice := !existsAlready || time.Since(ce.when) > CacheLifeTime

	// Any empty or unspecified addresses should be set to the source address
	// of the announcement. We also skip any addresses we can't parse.

	l.Debugln("discover: Registering addresses for", id)
	var validAddresses []string
	for _, addr := range device.Addresses {
		u, err := url.Parse(addr.URL)
		if err != nil {
			continue
		}

		tcpAddr, err := net.ResolveTCPAddr("tcp", u.Host)
		if err != nil {
			continue
		}

		if len(tcpAddr.IP) == 0 || tcpAddr.IP.IsUnspecified() {
			host, _, err := net.SplitHostPort(src.String())
			if err != nil {
				continue
			}
			u.Host = net.JoinHostPort(host, strconv.Itoa(tcpAddr.Port))
			validAddresses = append(validAddresses, u.String())
			l.Debugf("discover: Replaced address %v in %s to get %s", tcpAddr.IP, addr.URL, u.String())
		} else {
			validAddresses = append(validAddresses, addr.URL)
			l.Debugf("discover: Accepted address %s verbatim", addr.URL)
		}
	}

	c.Set(id, CacheEntry{
		Direct: validAddresses,
		Relays: device.Relays,
		when:   time.Now(),
		found:  true,
	})

	if isNewDevice {
		events.Default.Log(events.DeviceDiscovered, map[string]interface{}{
			"device": id.String(),
			"addrs":  validAddresses,
			"relays": device.Relays,
		})
	}

	return isNewDevice
}
<commit_msg>More local discovery URL debugging (ref #2444)<commit_after>// Copyright (C) 2014 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package discover

import (
	"bytes"
	"encoding/hex"
	"errors"
	"io"
	"net"
	"net/url"
	"strconv"
	"time"

	"github.com/syncthing/syncthing/lib/beacon"
	"github.com/syncthing/syncthing/lib/events"
	"github.com/syncthing/syncthing/lib/protocol"
	"github.com/thejerf/suture"
)

type localClient struct {
	*suture.Supervisor
	myID      protocol.DeviceID
	addrList  AddressLister
	relayStat RelayStatusProvider
	name      string

	beacon          beacon.Interface
	localBcastStart time.Time
	localBcastTick  <-chan time.Time
	forcedBcastTick chan time.Time

	*cache
}

const (
	BroadcastInterval = 30 * time.Second
	CacheLifeTime     = 3 * BroadcastInterval
)

var (
	ErrIncorrectMagic = errors.New("incorrect magic number")
)

func NewLocal(id protocol.DeviceID, addr string, addrList AddressLister, relayStat RelayStatusProvider) (FinderService, error) {
	c := &localClient{
		Supervisor:      suture.NewSimple("local"),
		myID:            id,
		addrList:        addrList,
		relayStat:       relayStat,
		localBcastTick:  time.Tick(BroadcastInterval),
		forcedBcastTick: make(chan time.Time),
		localBcastStart: time.Now(),
		cache:           newCache(),
	}

	host, port, err := net.SplitHostPort(addr)
	if err != nil {
		return nil, err
	}

	if len(host) == 0 {
		// A broadcast client
		c.name = "IPv4 local"
		bcPort, err := strconv.Atoi(port)
		if err != nil {
			return nil, err
		}
		c.startLocalIPv4Broadcasts(bcPort)
	} else {
		// A multicast client
		c.name = "IPv6 local"
		c.startLocalIPv6Multicasts(addr)
	}

	go c.sendLocalAnnouncements()

	return c, nil
}

func (c *localClient) startLocalIPv4Broadcasts(localPort int) {
	c.beacon = beacon.NewBroadcast(localPort)
	c.Add(c.beacon)
	go c.recvAnnouncements(c.beacon)
}

func (c *localClient) startLocalIPv6Multicasts(localMCAddr string) {
	c.beacon = beacon.NewMulticast(localMCAddr)
	c.Add(c.beacon)
	go c.recvAnnouncements(c.beacon)
}

// Lookup returns a list of addresses the device is available at. Local
// discovery never returns relays.
func (c *localClient) Lookup(device protocol.DeviceID) (direct []string, relays []Relay, err error) {
	if cache, ok := c.Get(device); ok {
		if time.Since(cache.when) < CacheLifeTime {
			direct = cache.Direct
			relays = cache.Relays
		}
	}

	return
}

func (c *localClient) String() string {
	return c.name
}

func (c *localClient) Error() error {
	return c.beacon.Error()
}

func (c *localClient) announcementPkt() Announce {
	var addrs []Address
	for _, addr := range c.addrList.AllAddresses() {
		addrs = append(addrs, Address{
			URL: addr,
		})
	}

	var relays []Relay
	for _, relay := range c.relayStat.Relays() {
		latency, ok := c.relayStat.RelayStatus(relay)
		if ok {
			relays = append(relays, Relay{
				URL:     relay,
				Latency: int32(latency / time.Millisecond),
			})
		}
	}

	return Announce{
		Magic: AnnouncementMagic,
		This: Device{
			ID:        c.myID[:],
			Addresses: addrs,
			Relays:    relays,
		},
	}
}

func (c *localClient) sendLocalAnnouncements() {
	var pkt = c.announcementPkt()
	msg := pkt.MustMarshalXDR()

	for {
		c.beacon.Send(msg)

		select {
		case <-c.localBcastTick:
		case <-c.forcedBcastTick:
		}
	}
}

func (c *localClient) recvAnnouncements(b beacon.Interface) {
	for {
		buf, addr := b.Recv()

		var pkt Announce
		err := pkt.UnmarshalXDR(buf)
		if err != nil && err != io.EOF {
			l.Debugf("discover: Failed to unmarshal local announcement from %s:\n%s", addr, hex.Dump(buf))
			continue
		}

		l.Debugf("discover: Received local announcement from %s for %s", addr, protocol.DeviceIDFromBytes(pkt.This.ID))

		var newDevice bool
		if bytes.Compare(pkt.This.ID, c.myID[:]) != 0 {
			newDevice = c.registerDevice(addr, pkt.This)
		}

		if newDevice {
			select {
			case c.forcedBcastTick <- time.Now():
			}
		}
	}
}

func (c *localClient) registerDevice(src net.Addr, device Device) bool {
	var id protocol.DeviceID
	copy(id[:], device.ID)

	// Remember whether we already had a valid cache entry for this device.

	ce, existsAlready := c.Get(id)
	isNewDevice := !existsAlready || time.Since(ce.when) > CacheLifeTime

	// Any empty or unspecified addresses should be set to the source address
	// of the announcement. We also skip any addresses we can't parse.

	l.Debugln("discover: Registering addresses for", id)
	var validAddresses []string
	for _, addr := range device.Addresses {
		u, err := url.Parse(addr.URL)
		if err != nil {
			continue
		}

		tcpAddr, err := net.ResolveTCPAddr("tcp", u.Host)
		if err != nil {
			continue
		}

		if len(tcpAddr.IP) == 0 || tcpAddr.IP.IsUnspecified() {
			host, _, err := net.SplitHostPort(src.String())
			if err != nil {
				continue
			}
			u.Host = net.JoinHostPort(host, strconv.Itoa(tcpAddr.Port))
			l.Debugf("discover: Reconstructed URL is %#v", u)
			validAddresses = append(validAddresses, u.String())
			l.Debugf("discover: Replaced address %v in %s to get %s", tcpAddr.IP, addr.URL, u.String())
		} else {
			validAddresses = append(validAddresses, addr.URL)
			l.Debugf("discover: Accepted address %s verbatim", addr.URL)
		}
	}

	c.Set(id, CacheEntry{
		Direct: validAddresses,
		Relays: device.Relays,
		when:   time.Now(),
		found:  true,
	})

	if isNewDevice {
		events.Default.Log(events.DeviceDiscovered, map[string]interface{}{
			"device": id.String(),
			"addrs":  validAddresses,
			"relays": device.Relays,
		})
	}

	return isNewDevice
}
<|endoftext|>


<commit_before>package gorm4

import (
	"time"

	"github.com/jinzhu/gorm"
)

func getGormDB() *gorm.DB {
	db, _ := gorm.Open("mysql",
		"user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
	return db
}

//go:generate go run ../../../cmd/goqueryset/goqueryset.go -in gorm4.go

// User struct represents user model.
// gen:qs
type User struct {
	gorm.Model
	Rating      int
	RatingMarks int
}

func getTodayBegin() time.Time {
	year, month, day := time.Now().Date()
	return time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location())
}

// WithMaxRating is our defined on UserQuerySet method, that selects
// users with max rating.
// UserQuerySet is an autogenerated struct with a lot of typesafe methods.
// We can define any methods on it because it's in the same package
func (qs UserQuerySet) WithMaxRating(minMarks int) UserQuerySet {
	return qs.RatingMarksGte(minMarks).OrderAscByRating()
}

// RegisteredToday returns only users registered today
func (qs UserQuerySet) RegisteredToday() UserQuerySet {
	// autogenerated typesafe method CreatedAtGte(time.Time)
	return qs.CreatedAtGte(getTodayBegin())
}

// now we can parametrize it
const minRatingMarks = 10

// GetUsersWithMaxRating returns limit users with max rating
func GetUsersWithMaxRating(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		WithMaxRating(minRatingMarks). // reuse our method
		Limit(limit).                  // autogenerated typesafe method Limit(int)
		All(&users)                    // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}

// GetUsersRegisteredToday returns limit users registered today
func GetUsersRegisteredToday(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		RegisteredToday(). // reuse our method
		Limit(limit).      // autogenerated typesafe method Limit(int)
		All(&users)        // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}

// GetUsersRegisteredTodayWithMaxRating returns limit users
// registered today and with max rating
func GetUsersRegisteredTodayWithMaxRating(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		RegisteredToday().             // reuse our method
		WithMaxRating(minRatingMarks). // reuse our method
		Limit(limit).
		All(&users) // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}
<commit_msg>use installed binary goqueryset in example<commit_after>package gorm4

import (
	"time"

	"github.com/jinzhu/gorm"
)

func getGormDB() *gorm.DB {
	db, _ := gorm.Open("mysql",
		"user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
	return db
}

//go:generate goqueryset -in gorm4.go

// User struct represents user model.
// gen:qs
type User struct {
	gorm.Model
	Rating      int
	RatingMarks int
}

func getTodayBegin() time.Time {
	year, month, day := time.Now().Date()
	return time.Date(year, month, day, 0, 0, 0, 0, time.Now().Location())
}

// WithMaxRating is our defined on UserQuerySet method, that selects
// users with max rating.
// UserQuerySet is an autogenerated struct with a lot of typesafe methods.
// We can define any methods on it because it's in the same package
func (qs UserQuerySet) WithMaxRating(minMarks int) UserQuerySet {
	return qs.RatingMarksGte(minMarks).OrderAscByRating()
}

// RegisteredToday returns only users registered today
func (qs UserQuerySet) RegisteredToday() UserQuerySet {
	// autogenerated typesafe method CreatedAtGte(time.Time)
	return qs.CreatedAtGte(getTodayBegin())
}

// now we can parametrize it
const minRatingMarks = 10

// GetUsersWithMaxRating returns limit users with max rating
func GetUsersWithMaxRating(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		WithMaxRating(minRatingMarks). // reuse our method
		Limit(limit).                  // autogenerated typesafe method Limit(int)
		All(&users)                    // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}

// GetUsersRegisteredToday returns limit users registered today
func GetUsersRegisteredToday(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		RegisteredToday(). // reuse our method
		Limit(limit).      // autogenerated typesafe method Limit(int)
		All(&users)        // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}

// GetUsersRegisteredTodayWithMaxRating returns limit users
// registered today and with max rating
func GetUsersRegisteredTodayWithMaxRating(limit int) ([]User, error) {
	var users []User
	err := NewUserQuerySet(getGormDB()).
		RegisteredToday().             // reuse our method
		WithMaxRating(minRatingMarks). // reuse our method
		Limit(limit).
		All(&users) // autogenerated typesafe method All(*[]User)
	if err != nil {
		return nil, err
	}
	return users, nil
}
<|endoftext|>


<commit_before>package internal

type FuncMeasurement string

const (
	Lines                FuncMeasurement = "lines"
	TotalLines                           = "total_lines"
	Len                                  = "len"
	TotalLen                             = "total_len"
	CommentLines                         = "comment_lines"
	Comments                             = "comments"
	Complexity                           = "complexity"
	MaxNesting                           = "max_nesting"
	TotalNesting                         = "total_nesting"
	InputParams                          = "in_params"
	OutputParams                         = "out_params"
	Variables                            = "variables"
	Assignments                          = "assignments"
	Control                              = "control"
	Todos                                = "todos"
	TodosCaseinsensitive                 = "todos-case-insensitive"
)

var AllTypes = []FuncMeasurement{
	Lines,
	TotalLines,
	Len,
	TotalLen,
	CommentLines,
	Comments,
	Complexity,
	MaxNesting,
	TotalNesting,
	InputParams,
	OutputParams,
	Variables,
	Assignments,
	Control,
	Todos,
	TodosCaseinsensitive,
}

func isValidBasicType(ty FuncMeasurement) bool {
	for _, t := range AllTypes {
		if t == ty {
			return true
		}
	}
	return false
}
<commit_msg>Typoo<commit_after>package internal

type FuncMeasurement string

const (
	Lines                FuncMeasurement = "lines"
	TotalLines                           = "total_lines"
	Len                                  = "len"
	TotalLen                             = "total_len"
	CommentLines                         = "comment_lines"
	Comments                             = "comments"
	Complexity                           = "complexity"
	MaxNesting                           = "max_nesting"
	TotalNesting                         = "total_nesting"
	InputParams                          = "in_params"
	OutputParams                         = "out_params"
	Variables                            = "variables"
	Assignments                          = "assignments"
	Control                              = "control"
	Todos                                = "todos"
	TodosCaseinsensitive                 = "todos_case_insensitive"
)

var AllTypes = []FuncMeasurement{
	Lines,
	TotalLines,
	Len,
	TotalLen,
	CommentLines,
	Comments,
	Complexity,
	MaxNesting,
	TotalNesting,
	InputParams,
	OutputParams,
	Variables,
	Assignments,
	Control,
	Todos,
	TodosCaseinsensitive,
}

func isValidBasicType(ty FuncMeasurement) bool {
	for _, t := range AllTypes {
		if t == ty {
			return true
		}
	}
	return false
}
<|endoftext|>