<commit_before>package rss

import (
	"strings"
	"time"
)

// TimeLayouts is contains a list of time.Parse() layouts that are used in
// attempts to convert item.Date and item.PubDate string to time.Time values.
// The layouts are attempted in ascending order until either time.Parse()
// does not return an error or all layouts are attempted.
var TimeLayouts = []string{
	"Mon, _2 Jan 2006 15:04:05 MST",
	"Mon, _2 Jan 2006 15:04:05 -0700",
	time.ANSIC,
	time.UnixDate,
	time.RubyDate,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
}

func parseTime(s string) (time.Time, error) {
	s = strings.TrimSpace(s)

	var e error
	var t time.Time

	for _, layout := range TimeLayouts {
		t, e = time.Parse(layout, s)
		if e == nil {
			return t, e
		}
	}

	return time.Time{}, e
}
<commit_msg>Added more time layouts to time.go to parse more pubDate variations<commit_after>package rss

import (
	"strings"
	"time"
)

// TimeLayouts is contains a list of time.Parse() layouts that are used in
// attempts to convert item.Date and item.PubDate string to time.Time values.
// The layouts are attempted in ascending order until either time.Parse()
// does not return an error or all layouts are attempted.
var TimeLayouts = []string{
	"Mon, _2 Jan 2006 15:04:05 MST",
	"Mon, _2 Jan 2006 15:04:05 -0700",
	"_2 Jan 2006 15:04:05 MST",
	"_2 Jan 2006 15:04:05 -0700",
	"2006-01-02 15:04:05",
	"Jan _2, 2006 15:04 PM MST",
	time.ANSIC,
	time.UnixDate,
	time.RubyDate,
	time.RFC822,
	time.RFC822Z,
	time.RFC850,
	time.RFC1123,
	time.RFC1123Z,
	time.RFC3339,
	time.RFC3339Nano,
}

func parseTime(s string) (time.Time, error) {
	s = strings.TrimSpace(s)

	var e error
	var t time.Time

	for _, layout := range TimeLayouts {
		t, e = time.Parse(layout, s)
		if e == nil {
			return t, e
		}
	}

	return time.Time{}, e
}
<|endoftext|>


<commit_before>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// Package recovery 提供了处理 panic 操作的中间件。
package recovery

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

// RecoverFunc 错误处理函数。Recovery 需要此函数作为出错时的处理。
//
// msg 为输出的错误信息，可能是任意类型的数据，一般为从 recover() 返回的数据。
type RecoverFunc func(w http.ResponseWriter, msg interface{})

// RecoverFunc 的默认实现。
//
// 为一个简单的 500 错误信息。不会输出 msg 参数的内容。
func defaultRecoverFunc(w http.ResponseWriter, msg interface{}) {
	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}

// PrintDebug 是 RecoverFunc 类型的实现。方便 NewRecovery 在调试期间将函数的调用信息输出到 w。
func PrintDebug(w http.ResponseWriter, msg interface{}) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintln(w, msg)
	for i := 1; true; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			return
		}

		fmt.Fprintf(w, "@ %v:%v\n", file, line)
	}
}

// New 声明一个处理 panic 操作的中间件。
// next 参数中发生的 panic 将被截获并处理，不会再向上级反映。
//
// 当 next 参数为空时，将直接 panic。
// rf 参数用于指定处理 panic 信息的函数，其原型为 RecoverFunc，
// 当将 rf 指定为 nil 时，将使用默认的处理函数，仅仅向客户端输出 500 的错误信息，没有具体内容。
func New(next http.Handler, rf RecoverFunc) http.Handler {
	if next == nil {
		panic("参数 h 不能为空")
	}

	if rf == nil {
		rf = defaultRecoverFunc
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				rf(w, err)
			}
		}()

		next.ServeHTTP(w, r)
	})
}
<commit_msg>PrintDebug 内部改成调用 utils.TraceStack<commit_after>// Copyright 2015 by caixw, All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.

// Package recovery 提供了处理 panic 操作的中间件。
package recovery

import (
	"fmt"
	"net/http"

	"github.com/issue9/utils"
)

// RecoverFunc 错误处理函数。Recovery 需要此函数作为出错时的处理。
//
// msg 为输出的错误信息，可能是任意类型的数据，一般为从 recover() 返回的数据。
type RecoverFunc func(w http.ResponseWriter, msg interface{})

// RecoverFunc 的默认实现。
//
// 为一个简单的 500 错误信息。不会输出 msg 参数的内容。
func defaultRecoverFunc(w http.ResponseWriter, msg interface{}) {
	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}

// PrintDebug 是 RecoverFunc 类型的实现。方便 NewRecovery 在调试期间将函数的调用信息输出到 w。
func PrintDebug(w http.ResponseWriter, msg interface{}) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintln(w, msg)
	utils.TraceStack(w, 2)
}

// New 声明一个处理 panic 操作的中间件。
// next 参数中发生的 panic 将被截获并处理，不会再向上级反映。
//
// 当 next 参数为空时，将直接 panic。
// rf 参数用于指定处理 panic 信息的函数，其原型为 RecoverFunc，
// 当将 rf 指定为 nil 时，将使用默认的处理函数，仅仅向客户端输出 500 的错误信息，没有具体内容。
func New(next http.Handler, rf RecoverFunc) http.Handler {
	if next == nil {
		panic("参数 h 不能为空")
	}

	if rf == nil {
		rf = defaultRecoverFunc
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				rf(w, err)
			}
		}()

		next.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>// Package reflectx implements extensions to the standard reflect lib suitable
// for implementing marshaling and unmarshaling packages.  The main Mapper type
// allows for Go-compatible named atribute access, including accessing embedded
// struct attributes and the ability to use  functions and struct tags to
// customize field names.
//
package reflectx

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"sync"
)

// A FieldInfo is a collection of metadata about a struct field.
type FieldInfo struct {
	Index    []int
	Path     string
	Field    reflect.StructField
	Zero     reflect.Value
	Name     string
	Options  map[string]string
	Embedded bool
	Children []*FieldInfo
	Parent   *FieldInfo
}

// A StructMap is an index of field metadata for a struct.
type StructMap struct {
	Tree  *FieldInfo
	Index []*FieldInfo
	Paths map[string]*FieldInfo
	Names map[string]*FieldInfo
}

// GetByPath returns a *FieldInfo for a given string path.
func (f StructMap) GetByPath(path string) *FieldInfo {
	return f.Paths[path]
}

// GetByTraversal returns a *FieldInfo for a given integer path.  It is
// analagous to reflect.FieldByIndex.
func (f StructMap) GetByTraversal(index []int) *FieldInfo {
	if len(index) == 0 {
		return nil
	}

	tree := f.Tree
	for _, i := range index {
		if i >= len(tree.Children) || tree.Children[i] == nil {
			return nil
		}
		tree = tree.Children[i]
	}
	return tree
}

// Mapper is a general purpose mapper of names to struct fields.  A Mapper
// behaves like most marshallers, optionally obeying a field tag for name
// mapping and a function to provide a basic mapping of fields to names.
type Mapper struct {
	cache      map[reflect.Type]*StructMap
	tagName    string
	tagMapFunc func(string) string
	mapFunc    func(string) string
	mutex      sync.Mutex
}

// NewMapper returns a new mapper which optionally obeys the field tag given
// by tagName.  If tagName is the empty string, it is ignored.
func NewMapper(tagName string) *Mapper {
	return &Mapper{
		cache:   make(map[reflect.Type]*StructMap),
		tagName: tagName,
	}
}

// NewMapperTagFunc returns a new mapper which contains a mapper for field names
// AND a mapper for tag values.  This is useful for tags like json which can
// have values like "name,omitempty".
func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
	return &Mapper{
		cache:      make(map[reflect.Type]*StructMap),
		tagName:    tagName,
		mapFunc:    mapFunc,
		tagMapFunc: tagMapFunc,
	}
}

// NewMapperFunc returns a new mapper which optionally obeys a field tag and
// a struct field name mapper func given by f.  Tags will take precedence, but
// for any other field, the mapped name will be f(field.Name)
func NewMapperFunc(tagName string, f func(string) string) *Mapper {
	return &Mapper{
		cache:   make(map[reflect.Type]*StructMap),
		tagName: tagName,
		mapFunc: f,
	}
}

// TypeMap returns a mapping of field strings to int slices representing
// the traversal down the struct to reach the field.
func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
	m.mutex.Lock()
	mapping, ok := m.cache[t]
	if !ok {
		mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
		m.cache[t] = mapping
	}
	m.mutex.Unlock()
	return mapping
}

// FieldMap returns the mapper's mapping of field names to reflect values.  Panics
// if v's Kind is not Struct, or v is not Indirectable to a struct kind.
func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	r := map[string]reflect.Value{}
	tm := m.TypeMap(v.Type())
	for tagName, fi := range tm.Names {
		r[tagName] = FieldByIndexes(v, fi.Index)
	}
	return r
}

// FieldByName returns a field by the its mapped name as a reflect.Value.
// Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
// Returns zero Value if the name is not found.
func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	tm := m.TypeMap(v.Type())
	fi, ok := tm.Names[name]
	if !ok {
		return v
	}
	return FieldByIndexes(v, fi.Index)
}

// FieldsByName returns a slice of values corresponding to the slice of names
// for the value.  Panics if v's Kind is not Struct or v is not Indirectable
// to a struct Kind.  Returns zero Value for each name not found.
func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	tm := m.TypeMap(v.Type())
	vals := make([]reflect.Value, 0, len(names))
	for _, name := range names {
		fi, ok := tm.Names[name]
		if !ok {
			vals = append(vals, *new(reflect.Value))
		} else {
			vals = append(vals, FieldByIndexes(v, fi.Index))
		}
	}
	return vals
}

// TraversalsByName returns a slice of int slices which represent the struct
// traversals for each mapped name.  Panics if t is not a struct or Indirectable
// to a struct.  Returns empty int slice for each name not found.
func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
	t = Deref(t)
	mustBe(t, reflect.Struct)
	tm := m.TypeMap(t)

	r := make([][]int, 0, len(names))
	for _, name := range names {
		fi, ok := tm.Names[name]
		if !ok {
			r = append(r, []int{})
		} else {
			r = append(r, fi.Index)
		}
	}
	return r
}

// FieldByIndexes returns a value for a particular struct traversal.
func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
	for _, i := range indexes {
		v = reflect.Indirect(v).Field(i)
		// if this is a pointer, it's possible it is nil
		if v.Kind() == reflect.Ptr && v.IsNil() {
			alloc := reflect.New(Deref(v.Type()))
			v.Set(alloc)
		}
		if v.Kind() == reflect.Map && v.IsNil() {
			v.Set(reflect.MakeMap(v.Type()))
		}
	}
	return v
}

// FieldByIndexesReadOnly returns a value for a particular struct traversal,
// but is not concerned with allocating nil pointers because the value is
// going to be used for reading and not setting.
func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
	for _, i := range indexes {
		v = reflect.Indirect(v).Field(i)
	}
	return v
}

// Deref is Indirect for reflect.Types
func Deref(t reflect.Type) reflect.Type {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

// -- helpers & utilities --

type kinder interface {
	Kind() reflect.Kind
}

// mustBe checks a value against a kind, panicing with a reflect.ValueError
// if the kind isn't that which is required.
func mustBe(v kinder, expected reflect.Kind) {
	k := v.Kind()
	if k != expected {
		panic(&reflect.ValueError{Method: methodName(), Kind: k})
	}
}

// methodName is returns the caller of the function calling methodName
func methodName() string {
	pc, _, _, _ := runtime.Caller(2)
	f := runtime.FuncForPC(pc)
	if f == nil {
		return "unknown method"
	}
	return f.Name()
}

type typeQueue struct {
	t  reflect.Type
	fi *FieldInfo
	pp string // Parent path
}

// A copying append that creates a new slice each time.
func apnd(is []int, i int) []int {
	x := make([]int, len(is)+1)
	for p, n := range is {
		x[p] = n
	}
	x[len(x)-1] = i
	return x
}

// getMapping returns a mapping for the t type, using the tagName, mapFunc and
// tagMapFunc to determine the canonical names of fields.
func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc func(string) string) *StructMap {
	m := []*FieldInfo{}

	root := &FieldInfo{}
	queue := []typeQueue{}
	queue = append(queue, typeQueue{Deref(t), root, ""})

	for len(queue) != 0 {
		// pop the first item off of the queue
		tq := queue[0]
		queue = queue[1:]
		nChildren := 0
		if tq.t.Kind() == reflect.Struct {
			nChildren = tq.t.NumField()
		}
		tq.fi.Children = make([]*FieldInfo, nChildren)

		// iterate through all of its fields
		for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
			f := tq.t.Field(fieldPos)

			fi := FieldInfo{}
			fi.Field = f
			fi.Zero = reflect.New(f.Type).Elem()
			fi.Options = map[string]string{}

			var tag, name string
			if tagName != "" && strings.Contains(string(f.Tag), tagName+":") {
				tag = f.Tag.Get(tagName)
				name = tag
			} else {
				if mapFunc != nil {
					name = mapFunc(f.Name)
				}
			}

			parts := strings.Split(name, ",")
			if len(parts) > 1 {
				name = parts[0]
				for _, opt := range parts[1:] {
					kv := strings.Split(opt, "=")
					if len(kv) > 1 {
						fi.Options[kv[0]] = kv[1]
					} else {
						fi.Options[kv[0]] = ""
					}
				}
			}

			if tagMapFunc != nil {
				tag = tagMapFunc(tag)
			}

			fi.Name = name

			if tq.pp == "" || (tq.pp == "" && tag == "") {
				fi.Path = fi.Name
			} else {
				fi.Path = fmt.Sprintf("%s.%s", tq.pp, fi.Name)
			}

			// if the name is "-", disabled via a tag, skip it
			if name == "-" {
				continue
			}

			// skip unexported fields
			if len(f.PkgPath) != 0 {
				continue
			}

			// bfs search of anonymous embedded structs
			if f.Anonymous {
				pp := tq.pp
				if tag != "" {
					pp = fi.Path
				}

				fi.Embedded = true
				fi.Index = apnd(tq.fi.Index, fieldPos)
				nChildren := 0
				ft := Deref(f.Type)
				if ft.Kind() == reflect.Struct {
					nChildren = ft.NumField()
				}
				fi.Children = make([]*FieldInfo, nChildren)
				queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
			} else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
				fi.Index = apnd(tq.fi.Index, fieldPos)
				fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
				queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
			}

			fi.Index = apnd(tq.fi.Index, fieldPos)
			fi.Parent = tq.fi
			tq.fi.Children[fieldPos] = &fi
			m = append(m, &fi)
		}
	}

	flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
	for _, fi := range flds.Index {
		flds.Paths[fi.Path] = fi
		if fi.Name != "" && !fi.Embedded {
			flds.Names[fi.Path] = fi
		}
	}

	return flds
}
<commit_msg>map first found unique column when reflecting embedded structs<commit_after>// Package reflectx implements extensions to the standard reflect lib suitable
// for implementing marshaling and unmarshaling packages.  The main Mapper type
// allows for Go-compatible named atribute access, including accessing embedded
// struct attributes and the ability to use  functions and struct tags to
// customize field names.
//
package reflectx

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"sync"
)

// A FieldInfo is a collection of metadata about a struct field.
type FieldInfo struct {
	Index    []int
	Path     string
	Field    reflect.StructField
	Zero     reflect.Value
	Name     string
	Options  map[string]string
	Embedded bool
	Children []*FieldInfo
	Parent   *FieldInfo
}

// A StructMap is an index of field metadata for a struct.
type StructMap struct {
	Tree  *FieldInfo
	Index []*FieldInfo
	Paths map[string]*FieldInfo
	Names map[string]*FieldInfo
}

// GetByPath returns a *FieldInfo for a given string path.
func (f StructMap) GetByPath(path string) *FieldInfo {
	return f.Paths[path]
}

// GetByTraversal returns a *FieldInfo for a given integer path.  It is
// analagous to reflect.FieldByIndex.
func (f StructMap) GetByTraversal(index []int) *FieldInfo {
	if len(index) == 0 {
		return nil
	}

	tree := f.Tree
	for _, i := range index {
		if i >= len(tree.Children) || tree.Children[i] == nil {
			return nil
		}
		tree = tree.Children[i]
	}
	return tree
}

// Mapper is a general purpose mapper of names to struct fields.  A Mapper
// behaves like most marshallers, optionally obeying a field tag for name
// mapping and a function to provide a basic mapping of fields to names.
type Mapper struct {
	cache      map[reflect.Type]*StructMap
	tagName    string
	tagMapFunc func(string) string
	mapFunc    func(string) string
	mutex      sync.Mutex
}

// NewMapper returns a new mapper which optionally obeys the field tag given
// by tagName.  If tagName is the empty string, it is ignored.
func NewMapper(tagName string) *Mapper {
	return &Mapper{
		cache:   make(map[reflect.Type]*StructMap),
		tagName: tagName,
	}
}

// NewMapperTagFunc returns a new mapper which contains a mapper for field names
// AND a mapper for tag values.  This is useful for tags like json which can
// have values like "name,omitempty".
func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
	return &Mapper{
		cache:      make(map[reflect.Type]*StructMap),
		tagName:    tagName,
		mapFunc:    mapFunc,
		tagMapFunc: tagMapFunc,
	}
}

// NewMapperFunc returns a new mapper which optionally obeys a field tag and
// a struct field name mapper func given by f.  Tags will take precedence, but
// for any other field, the mapped name will be f(field.Name)
func NewMapperFunc(tagName string, f func(string) string) *Mapper {
	return &Mapper{
		cache:   make(map[reflect.Type]*StructMap),
		tagName: tagName,
		mapFunc: f,
	}
}

// TypeMap returns a mapping of field strings to int slices representing
// the traversal down the struct to reach the field.
func (m *Mapper) TypeMap(t reflect.Type) *StructMap {
	m.mutex.Lock()
	mapping, ok := m.cache[t]
	if !ok {
		mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
		m.cache[t] = mapping
	}
	m.mutex.Unlock()
	return mapping
}

// FieldMap returns the mapper's mapping of field names to reflect values.  Panics
// if v's Kind is not Struct, or v is not Indirectable to a struct kind.
func (m *Mapper) FieldMap(v reflect.Value) map[string]reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	r := map[string]reflect.Value{}
	tm := m.TypeMap(v.Type())
	for tagName, fi := range tm.Names {
		r[tagName] = FieldByIndexes(v, fi.Index)
	}
	return r
}

// FieldByName returns a field by the its mapped name as a reflect.Value.
// Panics if v's Kind is not Struct or v is not Indirectable to a struct Kind.
// Returns zero Value if the name is not found.
func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	tm := m.TypeMap(v.Type())
	fi, ok := tm.Names[name]
	if !ok {
		return v
	}
	return FieldByIndexes(v, fi.Index)
}

// FieldsByName returns a slice of values corresponding to the slice of names
// for the value.  Panics if v's Kind is not Struct or v is not Indirectable
// to a struct Kind.  Returns zero Value for each name not found.
func (m *Mapper) FieldsByName(v reflect.Value, names []string) []reflect.Value {
	v = reflect.Indirect(v)
	mustBe(v, reflect.Struct)

	tm := m.TypeMap(v.Type())
	vals := make([]reflect.Value, 0, len(names))
	for _, name := range names {
		fi, ok := tm.Names[name]
		if !ok {
			vals = append(vals, *new(reflect.Value))
		} else {
			vals = append(vals, FieldByIndexes(v, fi.Index))
		}
	}
	return vals
}

// TraversalsByName returns a slice of int slices which represent the struct
// traversals for each mapped name.  Panics if t is not a struct or Indirectable
// to a struct.  Returns empty int slice for each name not found.
func (m *Mapper) TraversalsByName(t reflect.Type, names []string) [][]int {
	t = Deref(t)
	mustBe(t, reflect.Struct)
	tm := m.TypeMap(t)

	r := make([][]int, 0, len(names))
	for _, name := range names {
		fi, ok := tm.Names[name]
		if !ok {
			r = append(r, []int{})
		} else {
			r = append(r, fi.Index)
		}
	}
	return r
}

// FieldByIndexes returns a value for a particular struct traversal.
func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value {
	for _, i := range indexes {
		v = reflect.Indirect(v).Field(i)
		// if this is a pointer, it's possible it is nil
		if v.Kind() == reflect.Ptr && v.IsNil() {
			alloc := reflect.New(Deref(v.Type()))
			v.Set(alloc)
		}
		if v.Kind() == reflect.Map && v.IsNil() {
			v.Set(reflect.MakeMap(v.Type()))
		}
	}
	return v
}

// FieldByIndexesReadOnly returns a value for a particular struct traversal,
// but is not concerned with allocating nil pointers because the value is
// going to be used for reading and not setting.
func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value {
	for _, i := range indexes {
		v = reflect.Indirect(v).Field(i)
	}
	return v
}

// Deref is Indirect for reflect.Types
func Deref(t reflect.Type) reflect.Type {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	return t
}

// -- helpers & utilities --

type kinder interface {
	Kind() reflect.Kind
}

// mustBe checks a value against a kind, panicing with a reflect.ValueError
// if the kind isn't that which is required.
func mustBe(v kinder, expected reflect.Kind) {
	k := v.Kind()
	if k != expected {
		panic(&reflect.ValueError{Method: methodName(), Kind: k})
	}
}

// methodName is returns the caller of the function calling methodName
func methodName() string {
	pc, _, _, _ := runtime.Caller(2)
	f := runtime.FuncForPC(pc)
	if f == nil {
		return "unknown method"
	}
	return f.Name()
}

type typeQueue struct {
	t  reflect.Type
	fi *FieldInfo
	pp string // Parent path
}

// A copying append that creates a new slice each time.
func apnd(is []int, i int) []int {
	x := make([]int, len(is)+1)
	for p, n := range is {
		x[p] = n
	}
	x[len(x)-1] = i
	return x
}

// getMapping returns a mapping for the t type, using the tagName, mapFunc and
// tagMapFunc to determine the canonical names of fields.
func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc func(string) string) *StructMap {
	m := []*FieldInfo{}

	root := &FieldInfo{}
	queue := []typeQueue{}
	queue = append(queue, typeQueue{Deref(t), root, ""})

	for len(queue) != 0 {
		// pop the first item off of the queue
		tq := queue[0]
		queue = queue[1:]
		nChildren := 0
		if tq.t.Kind() == reflect.Struct {
			nChildren = tq.t.NumField()
		}
		tq.fi.Children = make([]*FieldInfo, nChildren)

		// iterate through all of its fields
		for fieldPos := 0; fieldPos < nChildren; fieldPos++ {
			f := tq.t.Field(fieldPos)

			fi := FieldInfo{}
			fi.Field = f
			fi.Zero = reflect.New(f.Type).Elem()
			fi.Options = map[string]string{}

			var tag, name string
			if tagName != "" && strings.Contains(string(f.Tag), tagName+":") {
				tag = f.Tag.Get(tagName)
				name = tag
			} else {
				if mapFunc != nil {
					name = mapFunc(f.Name)
				}
			}

			parts := strings.Split(name, ",")
			if len(parts) > 1 {
				name = parts[0]
				for _, opt := range parts[1:] {
					kv := strings.Split(opt, "=")
					if len(kv) > 1 {
						fi.Options[kv[0]] = kv[1]
					} else {
						fi.Options[kv[0]] = ""
					}
				}
			}

			if tagMapFunc != nil {
				tag = tagMapFunc(tag)
			}

			fi.Name = name

			if tq.pp == "" || (tq.pp == "" && tag == "") {
				fi.Path = fi.Name
			} else {
				fi.Path = fmt.Sprintf("%s.%s", tq.pp, fi.Name)
			}

			// if the name is "-", disabled via a tag, skip it
			if name == "-" {
				continue
			}

			// skip unexported fields
			if len(f.PkgPath) != 0 {
				continue
			}

			// bfs search of anonymous embedded structs
			if f.Anonymous {
				pp := tq.pp
				if tag != "" {
					pp = fi.Path
				}

				fi.Embedded = true
				fi.Index = apnd(tq.fi.Index, fieldPos)
				nChildren := 0
				ft := Deref(f.Type)
				if ft.Kind() == reflect.Struct {
					nChildren = ft.NumField()
				}
				fi.Children = make([]*FieldInfo, nChildren)
				queue = append(queue, typeQueue{Deref(f.Type), &fi, pp})
			} else if fi.Zero.Kind() == reflect.Struct || (fi.Zero.Kind() == reflect.Ptr && fi.Zero.Type().Elem().Kind() == reflect.Struct) {
				fi.Index = apnd(tq.fi.Index, fieldPos)
				fi.Children = make([]*FieldInfo, Deref(f.Type).NumField())
				queue = append(queue, typeQueue{Deref(f.Type), &fi, fi.Path})
			}

			fi.Index = apnd(tq.fi.Index, fieldPos)
			fi.Parent = tq.fi
			tq.fi.Children[fieldPos] = &fi
			m = append(m, &fi)
		}
	}

	flds := &StructMap{Index: m, Tree: root, Paths: map[string]*FieldInfo{}, Names: map[string]*FieldInfo{}}
	for _, fi := range flds.Index {
		// use only the first found tag column in BFS
		if flds.Paths[fi.Path] != nil {
			continue
		}
		flds.Paths[fi.Path] = fi
		if fi.Name != "" && !fi.Embedded {
			flds.Names[fi.Path] = fi
		}
	}

	return flds
}
<|endoftext|>


<commit_before>package irc

import (
	"fmt"
	"hash/fnv"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

const (
	timestampFormat = "15:04:05"
	alertSender     = "~!~"
	resetColors     = "\x1B[0m"
)

var nickColors = []string{
	"\x1B[30;1m",
	"\x1B[31;1m",
	"\x1B[32;1m",
	"\x1B[33;1m",
	"\x1B[34;1m",
	"\x1B[35;1m",
	"\x1B[36;1m",
	"\x1B[30m",
	"\x1B[31m",
	"\x1B[32m",
	"\x1B[33m",
	"\x1B[34m",
	"\x1B[35m",
	"\x1B[36m",
}

func colorizeNick(nick string) string {
	h := fnv.New32a()
	h.Write([]byte(nick))

	i := int(h.Sum32()) % len(nickColors)
	col := nickColors[i]

	return fmt.Sprintf("%s%15s%s", col, nick, resetColors)
}

func formatMessage(m *irc.Message) string {
	ts := time.Now().Format(timestampFormat)
	sender := alertSender
	line := fmt.Sprintf("%s %s", m.Command, m.Trailing())

	switch m.Command {
	case irc.PRIVMSG, irc.NOTICE:
		sender = colorizeNick(m.Prefix.User)
		line = m.Trailing()

	case irc.RPL_TOPIC:
		sender = m.Prefix.User
		line = fmt.Sprintf("%s: topic is \"%s\"", m.Params[1], m.Trailing())

	case irc.PING, irc.RPL_TOPICWHOTIME,
		irc.RPL_NAMREPLY, irc.RPL_ENDOFNAMES:
		// These are the skippable ones.
		return ""
	}

	return fmt.Sprintf("%s %s %s", ts, sender, line)

}
<commit_msg>Print nicks, not user names<commit_after>package irc

import (
	"fmt"
	"hash/fnv"
	"time"

	"gopkg.in/sorcix/irc.v2"
)

const (
	timestampFormat = "15:04:05"
	alertSender     = "~!~"
	resetColors     = "\x1B[0m"
)

var nickColors = []string{
	"\x1B[30;1m",
	"\x1B[31;1m",
	"\x1B[32;1m",
	"\x1B[33;1m",
	"\x1B[34;1m",
	"\x1B[35;1m",
	"\x1B[36;1m",
	"\x1B[30m",
	"\x1B[31m",
	"\x1B[32m",
	"\x1B[33m",
	"\x1B[34m",
	"\x1B[35m",
	"\x1B[36m",
}

func colorizeNick(nick string) string {
	h := fnv.New32a()
	h.Write([]byte(nick))

	i := int(h.Sum32()) % len(nickColors)
	col := nickColors[i]

	return fmt.Sprintf("%s%15s%s", col, nick, resetColors)
}

func formatMessage(m *irc.Message) string {
	ts := time.Now().Format(timestampFormat)
	sender := alertSender
	line := fmt.Sprintf("%s %s", m.Command, m.Trailing())

	switch m.Command {
	case irc.PRIVMSG, irc.NOTICE:
		sender = colorizeNick(m.Prefix.Name)
		line = m.Trailing()

	case irc.RPL_TOPIC:
		sender = m.Prefix.Name
		line = fmt.Sprintf("%s: topic is \"%s\"", m.Params[1], m.Trailing())

	case irc.PING, irc.RPL_TOPICWHOTIME,
		irc.RPL_NAMREPLY, irc.RPL_ENDOFNAMES:
		// These are the skippable ones.
		return ""
	}

	return fmt.Sprintf("%s %s %s", ts, sender, line)

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gsora/sysinfobot/support"
	"log"
	"net/http"
	"net/url"
)

func main() {
	conf, err := support.CheckConfigFile()
	if err != nil {
		log.Fatal(err)
	}

	baseURL := "https://api.telegram.org/bot" + conf.BotToken + "/"

	//declare eventHook for method messageUpdate
	fmt.Println(conf.URL + ":" + conf.Port + "/" + conf.Endpoint)
	_, err = http.PostForm(baseURL+"setWebhook", url.Values{"url": {conf.URL + ":" + conf.Port + "/" + conf.Endpoint}})
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/"+conf.Endpoint, endpointHandler)
	log.Fatal(http.ListenAndServeTLS(":"+conf.Port, conf.CertPath, conf.KeyPath, nil))
}

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	data := support.LoadJSONToTelegramObject(r.Body)
	fmt.Println(data)
}
<commit_msg>pretty-print some bot information when starting up<commit_after>package main

import (
	"fmt"
	"github.com/gsora/sysinfobot/support"
	"log"
	"net/http"
	"net/url"
)

func main() {
	conf, err := support.CheckConfigFile()
	if err != nil {
		log.Fatal(err)
	}

	baseURL := "https://api.telegram.org/bot" + conf.BotToken + "/"

	//declare eventHook for method messageUpdate
	_, err = http.PostForm(baseURL+"setWebhook", url.Values{"url": {conf.URL + ":" + conf.Port + "/" + conf.Endpoint}})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("--> Starting sysinfobot")
	err = support.PrintBotInformations(conf.BotToken)
	if err != nil {
		log.Fatal(err)
	}

	http.HandleFunc("/"+conf.Endpoint, endpointHandler)
	log.Fatal(http.ListenAndServeTLS(":"+conf.Port, conf.CertPath, conf.KeyPath, nil))
}

func endpointHandler(w http.ResponseWriter, r *http.Request) {
	data := support.LoadJSONToTelegramObject(r.Body)
	fmt.Println(data)
}
<|endoftext|>


<commit_before>package gofakeit

import rand "math/rand"

// Verb will generate a random verb
func Verb() string { return verb(globalFaker.Rand) }

// Verb will generate a random verb
func (f *Faker) Verb() string { return verb(f.Rand) }

func verb(r *rand.Rand) string {
	var nounType = map[int]string{
		0: "verb_action",
		1: "verb_linking",
		2: "verb_helping",
	}
	return getRandValue(r, []string{"word", nounType[number(r, 0, 2)]})
}

// VerbAction will generate a random action verb
func VerbAction() string { return verbAction(globalFaker.Rand) }

// VerbAction will generate a random action verb
func (f *Faker) VerbAction() string { return verbAction(f.Rand) }

func verbAction(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_action"}) }

// VerbLinking will generate a random linking verb
func VerbLinking() string { return verbLinking(globalFaker.Rand) }

// VerbLinking will generate a random linking verb
func (f *Faker) VerbLinking() string { return verbLinking(f.Rand) }

func verbLinking(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_linking"}) }

// VerbHelping will generate a random helping verb
func VerbHelping() string { return verbHelping(globalFaker.Rand) }

// VerbHelping will generate a random helping verb
func (f *Faker) VerbHelping() string { return verbHelping(f.Rand) }

func verbHelping(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_helping"}) }

func addWordVerbLookup() {
	AddFuncLookup("verb", Info{
		Display:     "Verb",
		Category:    "word",
		Description: "Random verb",
		Example:     "release",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verb(r), nil
		},
	})

	AddFuncLookup("verbaction", Info{
		Display:     "Action Verb",
		Category:    "word",
		Description: "Random action verb",
		Example:     "close",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbAction(r), nil
		},
	})

	AddFuncLookup("verblinking", Info{
		Display:     "Linking Verb",
		Category:    "word",
		Description: "Random linking verb",
		Example:     "was",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbLinking(r), nil
		},
	})

	AddFuncLookup("verbhelping", Info{
		Display:     "Helping Verb",
		Category:    "word",
		Description: "Random helping verb",
		Example:     "be",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbHelping(r), nil
		},
	})
}
<commit_msg>word - verb variable update<commit_after>package gofakeit

import rand "math/rand"

// Verb will generate a random verb
func Verb() string { return verb(globalFaker.Rand) }

// Verb will generate a random verb
func (f *Faker) Verb() string { return verb(f.Rand) }

func verb(r *rand.Rand) string {
	var verbType = map[int]string{
		0: "verb_action",
		1: "verb_linking",
		2: "verb_helping",
	}
	return getRandValue(r, []string{"word", verbType[number(r, 0, 2)]})
}

// VerbAction will generate a random action verb
func VerbAction() string { return verbAction(globalFaker.Rand) }

// VerbAction will generate a random action verb
func (f *Faker) VerbAction() string { return verbAction(f.Rand) }

func verbAction(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_action"}) }

// VerbLinking will generate a random linking verb
func VerbLinking() string { return verbLinking(globalFaker.Rand) }

// VerbLinking will generate a random linking verb
func (f *Faker) VerbLinking() string { return verbLinking(f.Rand) }

func verbLinking(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_linking"}) }

// VerbHelping will generate a random helping verb
func VerbHelping() string { return verbHelping(globalFaker.Rand) }

// VerbHelping will generate a random helping verb
func (f *Faker) VerbHelping() string { return verbHelping(f.Rand) }

func verbHelping(r *rand.Rand) string { return getRandValue(r, []string{"word", "verb_helping"}) }

func addWordVerbLookup() {
	AddFuncLookup("verb", Info{
		Display:     "Verb",
		Category:    "word",
		Description: "Random verb",
		Example:     "release",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verb(r), nil
		},
	})

	AddFuncLookup("verbaction", Info{
		Display:     "Action Verb",
		Category:    "word",
		Description: "Random action verb",
		Example:     "close",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbAction(r), nil
		},
	})

	AddFuncLookup("verblinking", Info{
		Display:     "Linking Verb",
		Category:    "word",
		Description: "Random linking verb",
		Example:     "was",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbLinking(r), nil
		},
	})

	AddFuncLookup("verbhelping", Info{
		Display:     "Helping Verb",
		Category:    "word",
		Description: "Random helping verb",
		Example:     "be",
		Output:      "string",
		Generate: func(r *rand.Rand, m *MapParams, info *Info) (interface{}, error) {
			return verbHelping(r), nil
		},
	})
}
<|endoftext|>


<commit_before>package langd

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"sync"

	"github.com/object88/langd/log"
	"github.com/object88/rope"
)

// Workspace is a mass of code
type Workspace struct {
	rwm sync.RWMutex

	Loader *Loader

	log *log.Log
}

// CreateWorkspace returns a new instance of the Workspace struct
func CreateWorkspace(loader *Loader, log *log.Log) *Workspace {
	return &Workspace{
		Loader: loader,
		log:    log,
	}
}

// ChangeFile applies changes to an opened file
func (w *Workspace) ChangeFile(absFilepath string, startLine, startCharacter, endLine, endCharacter int, text string) error {
	buf, ok := w.Loader.openedFiles[absFilepath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absFilepath)
	}

	// Have position (line, character), need to transform into offset into file
	// Then replace starting from there.
	r1 := buf.NewReader()
	startOffset, err := CalculateOffsetForPosition(r1, startLine, startCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from start: %s", err.Error())
	}

	r2 := buf.NewReader()
	endOffset, err := CalculateOffsetForPosition(r2, endLine, endCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from end: %s", err.Error())
	}

	fmt.Printf("offsets: [%d:%d]\n", startOffset, endOffset)

	if err = buf.Alter(startOffset, endOffset, text); err != nil {
		return err
	}

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	m := p.checker.Uses

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	i := 0
	fmt.Printf("Uses:\n")
	for k, v := range m {
		fmt.Printf("%003d: %#v -> %#v\n", i, k, v)
		fmt.Printf("\tIdent: %#v\n", k)
		fmt.Printf("\tTypeName: %#v\n", v.(*types.TypeName))

		if k.Obj != nil {
			fmt.Printf("\tk.Obj: %#v\n", k.Obj)
		}
	}
	fmt.Printf("\n")

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// CloseFile will take a file out of the OpenedFiles struct and reparse
func (w *Workspace) CloseFile(absPath string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		w.log.Warnf("File %s is not opened\n", absPath)
		return nil
	}

	delete(w.Loader.openedFiles, absPath)

	w.log.Debugf("File %s is closed\n", absPath)

	return nil
}

// LocateIdent scans the loaded fset for the identifier at the requested
// position
func (w *Workspace) LocateIdent(p *token.Position) (*ast.Ident, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x *ast.Ident

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}
		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if WithinPosition(p, &pStart, &pEnd) {
			switch v := n.(type) {
			case *ast.Ident:
				offset := int(v.NamePos) - int(f.Pos())
				fmt.Printf("Found;     (offset %d) %#v\n", offset, n)
				x = v
				return false
			default:
				fmt.Printf("Narrowing; %#v\n", n)
			}
			return true
		}
		return false
	})

	return x, nil
}

// LocateDeclaration returns the position where the provided identifier is
// declared & defined
func (w *Workspace) LocateDeclaration(p *token.Position) (*token.Position, error) {
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		return nil, err
	}

	declPos := pkg.Fset.Position(obj.Pos())

	return &declPos, nil
}

// LocateReferences returns the array of positions where the given identifier
// is referenced or used
func (w *Workspace) LocateReferences(p *token.Position) []token.Position {
	// Get declaration position, ident, and package
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		// Crappy crap.
		return nil
	}

	// TODO: If declaration should be included in results set, add to `ps`

	refs := w.locateReferences(obj, pkg)

	ps := make([]token.Position, len(refs)+1)
	ps[0] = pkg.Fset.Position(obj.Pos())
	i := 1
	for _, v := range refs {
		ps[i] = v.pkg.Fset.Position(v.pos)
		i++
	}

	return ps
}

// OpenFile shadows the file read from the disk with an in-memory version,
// which the workspace can accept edits to.
func (w *Workspace) OpenFile(absFilepath, text string) error {
	if _, ok := w.Loader.openedFiles[absFilepath]; ok {
		return fmt.Errorf("File %s is already opened", absFilepath)
	}
	w.Loader.openedFiles[absFilepath] = rope.CreateRope(text)

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	w.log.Debugf("Shadowed file '%s'\n", absFilepath)

	return nil
}

// ReplaceFile replaces the entire contents of an opened file
func (w *Workspace) ReplaceFile(absPath, text string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absPath)
	}

	// Replace the entire document
	buf := rope.CreateRope(text)
	w.Loader.openedFiles[absPath] = buf

	return nil
}

// Lock will synchronize access to the workspace for read or write access
func (w *Workspace) Lock(write bool) {
	if write {
		w.rwm.Lock()
	} else {
		w.rwm.RLock()
	}
}

// Unlock will synchronize access to the workspace for read or write access
func (w *Workspace) Unlock(write bool) {
	if write {
		w.rwm.Unlock()
	} else {
		w.rwm.RUnlock()
	}
}

func (w *Workspace) locateDeclaration(p *token.Position) (types.Object, *Package, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x ast.Node

	fmt.Printf("LocateDeclaration: %s\n", p.String())

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}

		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if !WithinPosition(p, &pStart, &pEnd) {
			return false
		}

		switch v := n.(type) {
		case *ast.Ident:
			fmt.Printf("... found ident; %#v\n", v)
			x = v
			return false
		case *ast.SelectorExpr:
			fmt.Printf("... found selector; %#v\n", v)
			selPos := v.Sel
			pSelStart := pkg.Fset.Position(selPos.Pos())
			pSelEnd := pkg.Fset.Position(selPos.End())
			if WithinPosition(p, &pSelStart, &pSelEnd) {
				s := pkg.checker.Selections[v]
				fmt.Printf("Selector: %#v\n", s)
				x = v
				return false
			}
		}

		return true
	})

	if x == nil {
		fmt.Printf("No x found\n")
		return nil, nil, nil
	}

	return w.xyz(x, pkg)
}

func (w *Workspace) xyz(x ast.Node, pkg *Package) (types.Object, *Package, error) {
	switch v := x.(type) {
	case *ast.Ident:
		fmt.Printf("Have ident %#v\n", v)
		if v.Obj != nil {
			fmt.Printf("Ident has obj %#v (%d)\n", v.Obj, v.Pos())
			vObj := pkg.checker.ObjectOf(v)
			return vObj, pkg, nil
		}
		if vDef, ok := pkg.checker.Defs[v]; ok {
			fmt.Printf("Have vDef from Defs: %#v\n", vDef)
			return vDef, pkg, nil
		}
		if vUse, ok := pkg.checker.Uses[v]; ok {
			// Used when var is defined in a package, in another file
			fmt.Printf("Have vUse from Uses: %#v\n", vUse)
			return vUse, pkg, nil
		}

	case *ast.SelectorExpr:
		return w.processSelectorExpr(v, pkg)

	default:
		fmt.Printf("Is %#v\n", x)
	}

	return nil, nil, nil
}

func (w *Workspace) processSelectorExpr(v *ast.SelectorExpr, pkg *Package) (types.Object, *Package, error) {
	fmt.Printf("Have SelectorExpr\n")
	switch vX := v.X.(type) {
	case *ast.Ident:
		vXObj := pkg.checker.ObjectOf(vX)
		if vXObj == nil {
			return nil, nil, fmt.Errorf("v.X (%s) not in ObjectOf", vX.Name)
		}
		fmt.Printf("checker.ObjectOf(v.X): %#v\n", vXObj)
		switch v1 := vXObj.(type) {
		case *types.PkgName:
			fmt.Printf("Have PkgName %s, type %s\n", v1.Name(), v1.Type())
			absPath := v1.Imported().Path()
			n, _ := w.Loader.caravan.Find(absPath)
			pkg1 := n.Element.(*Package)
			fmt.Printf("From pkg %#v\n", pkg1)

			oooo := pkg1.typesPkg.Scope().Lookup(v.Sel.Name)
			if oooo != nil {
				return oooo, pkg1, nil
			}

		case *types.Var:
			fmt.Printf("Have Var %s, type %s\n\tv1: %#v\n\tv1.Sel: %#v\n", v1.Name(), v1.Type(), v1, v.Sel)
			vSelObj := pkg.checker.ObjectOf(v.Sel)
			path := vSelObj.Pkg().Path()
			n, _ := w.Loader.caravan.Find(path)
			pkg1 := n.Element.(*Package)
			return vSelObj, pkg1, nil
		}
	case *ast.SelectorExpr:
		vSelObj := pkg.checker.ObjectOf(v.Sel)
		path := vSelObj.Pkg().Path()
		n, _ := w.Loader.caravan.Find(path)
		pkg1 := n.Element.(*Package)
		return vSelObj, pkg1, nil
	}

	return nil, nil, nil
}
<commit_msg>Fix error with logging<commit_after>package langd

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"path/filepath"
	"sync"

	"github.com/object88/langd/log"
	"github.com/object88/rope"
)

// Workspace is a mass of code
type Workspace struct {
	rwm sync.RWMutex

	Loader *Loader

	log *log.Log
}

// CreateWorkspace returns a new instance of the Workspace struct
func CreateWorkspace(loader *Loader, log *log.Log) *Workspace {
	return &Workspace{
		Loader: loader,
		log:    log,
	}
}

// ChangeFile applies changes to an opened file
func (w *Workspace) ChangeFile(absFilepath string, startLine, startCharacter, endLine, endCharacter int, text string) error {
	buf, ok := w.Loader.openedFiles[absFilepath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absFilepath)
	}

	// Have position (line, character), need to transform into offset into file
	// Then replace starting from there.
	r1 := buf.NewReader()
	startOffset, err := CalculateOffsetForPosition(r1, startLine, startCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from start: %s", err.Error())
	}

	r2 := buf.NewReader()
	endOffset, err := CalculateOffsetForPosition(r2, endLine, endCharacter)
	if err != nil {
		// Crap crap crap crap.
		fmt.Printf("Error from end: %s", err.Error())
	}

	fmt.Printf("offsets: [%d:%d]\n", startOffset, endOffset)

	if err = buf.Alter(startOffset, endOffset, text); err != nil {
		return err
	}

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	asc := flattenAscendants(n)

	for _, p1 := range asc {
		p1.loadState = unloaded
		p1.ResetChecker()
		w.Loader.stateChange <- p1.absPath
	}

	return nil
}

// CloseFile will take a file out of the OpenedFiles struct and reparse
func (w *Workspace) CloseFile(absPath string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		w.log.Warnf("File %s is not opened\n", absPath)
		return nil
	}

	delete(w.Loader.openedFiles, absPath)

	w.log.Debugf("File %s is closed\n", absPath)

	return nil
}

// LocateIdent scans the loaded fset for the identifier at the requested
// position
func (w *Workspace) LocateIdent(p *token.Position) (*ast.Ident, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x *ast.Ident

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}
		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if WithinPosition(p, &pStart, &pEnd) {
			switch v := n.(type) {
			case *ast.Ident:
				offset := int(v.NamePos) - int(f.Pos())
				fmt.Printf("Found;     (offset %d) %#v\n", offset, n)
				x = v
				return false
			default:
				fmt.Printf("Narrowing; %#v\n", n)
			}
			return true
		}
		return false
	})

	return x, nil
}

// LocateDeclaration returns the position where the provided identifier is
// declared & defined
func (w *Workspace) LocateDeclaration(p *token.Position) (*token.Position, error) {
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		return nil, err
	}

	declPos := pkg.Fset.Position(obj.Pos())

	return &declPos, nil
}

// LocateReferences returns the array of positions where the given identifier
// is referenced or used
func (w *Workspace) LocateReferences(p *token.Position) []token.Position {
	// Get declaration position, ident, and package
	obj, pkg, err := w.locateDeclaration(p)
	if err != nil {
		// Crappy crap.
		return nil
	}

	// TODO: If declaration should be included in results set, add to `ps`

	refs := w.locateReferences(obj, pkg)

	ps := make([]token.Position, len(refs)+1)
	ps[0] = pkg.Fset.Position(obj.Pos())
	i := 1
	for _, v := range refs {
		ps[i] = v.pkg.Fset.Position(v.pos)
		i++
	}

	return ps
}

// OpenFile shadows the file read from the disk with an in-memory version,
// which the workspace can accept edits to.
func (w *Workspace) OpenFile(absFilepath, text string) error {
	if _, ok := w.Loader.openedFiles[absFilepath]; ok {
		return fmt.Errorf("File %s is already opened", absFilepath)
	}
	w.Loader.openedFiles[absFilepath] = rope.CreateRope(text)

	absPath := filepath.Dir(absFilepath)
	n, ok := w.Loader.caravan.Find(absPath)

	if !ok {
		// Crapola.
		return fmt.Errorf("Failed to find package for file %s", absFilepath)
	}
	p := n.Element.(*Package)

	p.loadState = unloaded
	p.ResetChecker()
	w.Loader.done = false
	w.Loader.stateChange <- absPath

	w.log.Debugf("Shadowed file '%s'\n", absFilepath)

	return nil
}

// ReplaceFile replaces the entire contents of an opened file
func (w *Workspace) ReplaceFile(absPath, text string) error {
	_, ok := w.Loader.openedFiles[absPath]
	if !ok {
		return fmt.Errorf("File %s is not opened", absPath)
	}

	// Replace the entire document
	buf := rope.CreateRope(text)
	w.Loader.openedFiles[absPath] = buf

	return nil
}

// Lock will synchronize access to the workspace for read or write access
func (w *Workspace) Lock(write bool) {
	if write {
		w.rwm.Lock()
	} else {
		w.rwm.RLock()
	}
}

// Unlock will synchronize access to the workspace for read or write access
func (w *Workspace) Unlock(write bool) {
	if write {
		w.rwm.Unlock()
	} else {
		w.rwm.RUnlock()
	}
}

func (w *Workspace) locateDeclaration(p *token.Position) (types.Object, *Package, error) {
	absPath := filepath.Dir(p.Filename)

	n, ok := w.Loader.caravan.Find(absPath)
	if !ok {
		return nil, nil, fmt.Errorf("No package loaded for '%s'", p.Filename)
	}
	pkg := n.Element.(*Package)
	fi := pkg.files[filepath.Base(p.Filename)]
	f := fi.file

	if f == nil {
		// Failure response is failure.
		return nil, nil, fmt.Errorf("File %s isn't in our workspace", p.Filename)
	}

	var x ast.Node

	fmt.Printf("LocateDeclaration: %s\n", p.String())

	ast.Inspect(f, func(n ast.Node) bool {
		if n == nil {
			return false
		}

		pStart := pkg.Fset.Position(n.Pos())
		pEnd := pkg.Fset.Position(n.End())

		if !WithinPosition(p, &pStart, &pEnd) {
			return false
		}

		switch v := n.(type) {
		case *ast.Ident:
			fmt.Printf("... found ident; %#v\n", v)
			x = v
			return false
		case *ast.SelectorExpr:
			fmt.Printf("... found selector; %#v\n", v)
			selPos := v.Sel
			pSelStart := pkg.Fset.Position(selPos.Pos())
			pSelEnd := pkg.Fset.Position(selPos.End())
			if WithinPosition(p, &pSelStart, &pSelEnd) {
				s := pkg.checker.Selections[v]
				fmt.Printf("Selector: %#v\n", s)
				x = v
				return false
			}
		}

		return true
	})

	if x == nil {
		fmt.Printf("No x found\n")
		return nil, nil, nil
	}

	return w.xyz(x, pkg)
}

func (w *Workspace) xyz(x ast.Node, pkg *Package) (types.Object, *Package, error) {
	switch v := x.(type) {
	case *ast.Ident:
		fmt.Printf("Have ident %#v\n", v)
		if v.Obj != nil {
			fmt.Printf("Ident has obj %#v (%d)\n", v.Obj, v.Pos())
			vObj := pkg.checker.ObjectOf(v)
			return vObj, pkg, nil
		}
		if vDef, ok := pkg.checker.Defs[v]; ok {
			fmt.Printf("Have vDef from Defs: %#v\n", vDef)
			return vDef, pkg, nil
		}
		if vUse, ok := pkg.checker.Uses[v]; ok {
			// Used when var is defined in a package, in another file
			fmt.Printf("Have vUse from Uses: %#v\n", vUse)
			return vUse, pkg, nil
		}

	case *ast.SelectorExpr:
		return w.processSelectorExpr(v, pkg)

	default:
		fmt.Printf("Is %#v\n", x)
	}

	return nil, nil, nil
}

func (w *Workspace) processSelectorExpr(v *ast.SelectorExpr, pkg *Package) (types.Object, *Package, error) {
	fmt.Printf("Have SelectorExpr\n")
	switch vX := v.X.(type) {
	case *ast.Ident:
		vXObj := pkg.checker.ObjectOf(vX)
		if vXObj == nil {
			return nil, nil, fmt.Errorf("v.X (%s) not in ObjectOf", vX.Name)
		}
		fmt.Printf("checker.ObjectOf(v.X): %#v\n", vXObj)
		switch v1 := vXObj.(type) {
		case *types.PkgName:
			fmt.Printf("Have PkgName %s, type %s\n", v1.Name(), v1.Type())
			absPath := v1.Imported().Path()
			n, _ := w.Loader.caravan.Find(absPath)
			pkg1 := n.Element.(*Package)
			fmt.Printf("From pkg %#v\n", pkg1)

			oooo := pkg1.typesPkg.Scope().Lookup(v.Sel.Name)
			if oooo != nil {
				return oooo, pkg1, nil
			}

		case *types.Var:
			fmt.Printf("Have Var %s, type %s\n\tv1: %#v\n\tv1.Sel: %#v\n", v1.Name(), v1.Type(), v1, v.Sel)
			vSelObj := pkg.checker.ObjectOf(v.Sel)
			path := vSelObj.Pkg().Path()
			n, _ := w.Loader.caravan.Find(path)
			pkg1 := n.Element.(*Package)
			return vSelObj, pkg1, nil
		}
	case *ast.SelectorExpr:
		vSelObj := pkg.checker.ObjectOf(v.Sel)
		path := vSelObj.Pkg().Path()
		n, _ := w.Loader.caravan.Find(path)
		pkg1 := n.Element.(*Package)
		return vSelObj, pkg1, nil
	}

	return nil, nil, nil
}
<|endoftext|>


<commit_before>package google

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/StackExchange/dnscontrol/models"
	"github.com/StackExchange/dnscontrol/providers"

	"github.com/StackExchange/dnscontrol/providers/diff"
	"golang.org/x/oauth2"
	gauth "golang.org/x/oauth2/google"
	"google.golang.org/api/dns/v1"
	"strings"
)

func init() {
	providers.RegisterDomainServiceProviderType("GCLOUD", New)
}

type gcloud struct {
	client  *dns.Service
	project string
	zones   map[string]*dns.ManagedZone
}

func New(cfg map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) {
	for _, key := range []string{"clientId", "clientSecret", "refreshToken", "project"} {
		if cfg[key] == "" {
			return nil, fmt.Errorf("%s required for google cloud provider", key)
		}
	}
	ocfg := &oauth2.Config{
		Endpoint:     gauth.Endpoint,
		ClientID:     cfg["clientId"],
		ClientSecret: cfg["clientSecret"],
	}
	tok := &oauth2.Token{
		RefreshToken: cfg["refreshToken"],
	}
	client := ocfg.Client(context.Background(), tok)
	dcli, err := dns.New(client)
	if err != nil {
		return nil, err
	}
	return &gcloud{
		client:  dcli,
		project: cfg["project"],
	}, nil
}

func (g *gcloud) getZone(domain string) (*dns.ManagedZone, error) {
	if g.zones == nil {
		g.zones = map[string]*dns.ManagedZone{}
		pageToken := ""
		for {
			resp, err := g.client.ManagedZones.List(g.project).PageToken(pageToken).Do()
			if err != nil {
				return nil, err
			}
			for _, z := range resp.ManagedZones {
				g.zones[z.DnsName] = z
			}
			if pageToken = resp.NextPageToken; pageToken == "" {
				break
			}
		}
	}
	if g.zones[domain+"."] == nil {
		return nil, fmt.Errorf("Domain %s not found in gcloud account", domain)
	}
	return g.zones[domain+"."], nil
}

func (g *gcloud) GetNameservers(domain string) ([]*models.Nameserver, error) {
	zone, err := g.getZone(domain)
	if err != nil {
		return nil, err
	}
	return models.StringsToNameservers(zone.NameServers), nil
}

type key struct {
	Type string
	Name string
}

func keyFor(r *dns.ResourceRecordSet) key {
	return key{Type: r.Type, Name: r.Name}
}
func keyForRec(r *models.RecordConfig) key {
	return key{Type: r.Type, Name: r.NameFQDN + "."}
}

func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	rrs, zoneName, err := g.getRecords(dc.Name)
	if err != nil {
		return nil, err
	}
	//convert to dnscontrol RecordConfig format
	existingRecords := []diff.Record{}
	oldRRs := map[key]*dns.ResourceRecordSet{}
	for _, set := range rrs {
		nameWithoutDot := set.Name
		if strings.HasSuffix(nameWithoutDot, ".") {
			nameWithoutDot = nameWithoutDot[:len(nameWithoutDot)-1]
		}
		oldRRs[keyFor(set)] = set
		for _, rec := range set.Rrdatas {
			r := &models.RecordConfig{
				NameFQDN: nameWithoutDot,
				Type:     set.Type,
				Target:   rec,
				TTL:      uint32(set.Ttl),
			}
			existingRecords = append(existingRecords, r)
		}
	}

	w := []diff.Record{}
	for _, want := range dc.Records {
		if want.TTL == 0 {
			want.TTL = 300
		}
		if want.Type == "MX" {
			want.Target = fmt.Sprintf("%d %s", want.Priority, want.Target)
			want.Priority = 0
		} else if want.Type == "TXT" {
			//add quotes to txts
			want.Target = fmt.Sprintf(`"%s"`, want.Target)
		}
		w = append(w, want)
	}

	// first collect keys that have changed
	_, create, delete, modify := diff.IncrementalDiff(existingRecords, w)
	changedKeys := map[key]bool{}
	desc := ""
	for _, c := range create {
		desc += fmt.Sprintln(c)
		changedKeys[keyForRec(c.Desired.(*models.RecordConfig))] = true
	}
	for _, d := range delete {
		desc += fmt.Sprintln(d)
		changedKeys[keyForRec(d.Existing.(*models.RecordConfig))] = true
	}
	for _, m := range modify {
		desc += fmt.Sprintln(m)
		changedKeys[keyForRec(m.Existing.(*models.RecordConfig))] = true
	}
	if len(changedKeys) == 0 {
		return nil, nil
	}
	chg := &dns.Change{Kind: "dns#change"}
	for ck := range changedKeys {
		// remove old version (if present)
		if old, ok := oldRRs[ck]; ok {
			chg.Deletions = append(chg.Deletions, old)
		}
		//collect records to replace with
		newRRs := &dns.ResourceRecordSet{
			Name: ck.Name,
			Type: ck.Type,
			Kind: "dns#resourceRecordSet",
		}
		for _, r := range dc.Records {
			if keyForRec(r) == ck {
				newRRs.Rrdatas = append(newRRs.Rrdatas, r.Target)
				newRRs.Ttl = int64(r.TTL)
			}
		}
		if len(newRRs.Rrdatas) > 0 {
			chg.Additions = append(chg.Additions, newRRs)
		}
	}

	runChange := func() error {
		_, err := g.client.Changes.Create(g.project, zoneName, chg).Do()
		return err
	}
	return []*models.Correction{
		{
			Msg: desc,
			F:   runChange,
		},
	}, nil
}

func (g *gcloud) getRecords(domain string) ([]*dns.ResourceRecordSet, string, error) {
	zone, err := g.getZone(domain)
	if err != nil {
		return nil, "", err
	}
	pageToken := ""
	sets := []*dns.ResourceRecordSet{}
	for {
		call := g.client.ResourceRecordSets.List(g.project, zone.Name)
		if pageToken != "" {
			call = call.PageToken(pageToken)
		}
		resp, err := call.Do()
		if err != nil {
			return nil, "", err
		}
		for _, rrs := range resp.Rrsets {
			if rrs.Type == "SOA" {
				continue
			}
			sets = append(sets, rrs)
		}
		if pageToken = resp.NextPageToken; pageToken == "" {
			break
		}
	}
	return sets, zone.Name, nil
}
<commit_msg>google creates zones as needed<commit_after>package google

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"strings"

	"golang.org/x/oauth2"
	gauth "golang.org/x/oauth2/google"
	"google.golang.org/api/dns/v1"

	"github.com/StackExchange/dnscontrol/models"
	"github.com/StackExchange/dnscontrol/providers"
	"github.com/StackExchange/dnscontrol/providers/diff"
)

func init() {
	providers.RegisterDomainServiceProviderType("GCLOUD", New)
}

type gcloud struct {
	client  *dns.Service
	project string
	zones   map[string]*dns.ManagedZone
}

// New creates a new gcloud provider
func New(cfg map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) {
	for _, key := range []string{"clientId", "clientSecret", "refreshToken", "project"} {
		if cfg[key] == "" {
			return nil, fmt.Errorf("%s required for google cloud provider", key)
		}
	}
	ocfg := &oauth2.Config{
		Endpoint:     gauth.Endpoint,
		ClientID:     cfg["clientId"],
		ClientSecret: cfg["clientSecret"],
	}
	tok := &oauth2.Token{
		RefreshToken: cfg["refreshToken"],
	}
	client := ocfg.Client(context.Background(), tok)
	dcli, err := dns.New(client)
	if err != nil {
		return nil, err
	}
	return &gcloud{
		client:  dcli,
		project: cfg["project"],
	}, nil
}

type errNoExist struct {
	domain string
}

func (e errNoExist) Error() string {
	return fmt.Sprintf("Domain %s not found in gcloud account", e.domain)
}

func (g *gcloud) getZone(domain string) (*dns.ManagedZone, error) {
	if g.zones == nil {
		g.zones = map[string]*dns.ManagedZone{}
		pageToken := ""
		for {
			resp, err := g.client.ManagedZones.List(g.project).PageToken(pageToken).Do()
			if err != nil {
				return nil, err
			}
			for _, z := range resp.ManagedZones {
				g.zones[z.DnsName] = z
			}
			if pageToken = resp.NextPageToken; pageToken == "" {
				break
			}
		}
	}
	if g.zones[domain+"."] == nil {
		return nil, errNoExist{domain}
	}
	return g.zones[domain+"."], nil
}

func (g *gcloud) GetNameservers(domain string) ([]*models.Nameserver, error) {
	zone, err := g.getZone(domain)
	if err != nil {
		if _, ok := err.(errNoExist); ok {
			log.Printf("WARNING: Domain %s is not on your google cloud account. Dnscontrol will add it, but you will need to run a second time to configure nameservers properly.", domain)
			return nil, nil
		}
		return nil, err
	}
	return models.StringsToNameservers(zone.NameServers), nil
}

type key struct {
	Type string
	Name string
}

func keyFor(r *dns.ResourceRecordSet) key {
	return key{Type: r.Type, Name: r.Name}
}
func keyForRec(r *models.RecordConfig) key {
	return key{Type: r.Type, Name: r.NameFQDN + "."}
}

func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
	corrections := []*models.Correction{}
	rrs, zoneName, err := g.getRecords(dc.Name)
	if err != nil {
		if _, ok := err.(errNoExist); ok {
			c, zn := g.addZone(dc.Name)
			corrections = append(corrections, c)
			zoneName = zn
		} else {
			return nil, err
		}
	}
	//convert to dnscontrol RecordConfig format
	existingRecords := []diff.Record{}
	oldRRs := map[key]*dns.ResourceRecordSet{}
	for _, set := range rrs {
		nameWithoutDot := set.Name
		if strings.HasSuffix(nameWithoutDot, ".") {
			nameWithoutDot = nameWithoutDot[:len(nameWithoutDot)-1]
		}
		oldRRs[keyFor(set)] = set
		for _, rec := range set.Rrdatas {
			r := &models.RecordConfig{
				NameFQDN: nameWithoutDot,
				Type:     set.Type,
				Target:   rec,
				TTL:      uint32(set.Ttl),
			}
			existingRecords = append(existingRecords, r)
		}
	}

	w := []diff.Record{}
	for _, want := range dc.Records {
		if want.TTL == 0 {
			want.TTL = 300
		}
		if want.Type == "MX" {
			want.Target = fmt.Sprintf("%d %s", want.Priority, want.Target)
			want.Priority = 0
		} else if want.Type == "TXT" {
			//add quotes to txts
			want.Target = fmt.Sprintf(`"%s"`, want.Target)
		}
		w = append(w, want)
	}

	// first collect keys that have changed
	_, create, delete, modify := diff.IncrementalDiff(existingRecords, w)
	changedKeys := map[key]bool{}
	desc := ""
	for _, c := range create {
		desc += fmt.Sprintln(c)
		changedKeys[keyForRec(c.Desired.(*models.RecordConfig))] = true
	}
	for _, d := range delete {
		desc += fmt.Sprintln(d)
		changedKeys[keyForRec(d.Existing.(*models.RecordConfig))] = true
	}
	for _, m := range modify {
		desc += fmt.Sprintln(m)
		changedKeys[keyForRec(m.Existing.(*models.RecordConfig))] = true
	}
	if len(changedKeys) == 0 {
		return nil, nil
	}
	chg := &dns.Change{Kind: "dns#change"}
	for ck := range changedKeys {
		// remove old version (if present)
		if old, ok := oldRRs[ck]; ok {
			chg.Deletions = append(chg.Deletions, old)
		}
		//collect records to replace with
		newRRs := &dns.ResourceRecordSet{
			Name: ck.Name,
			Type: ck.Type,
			Kind: "dns#resourceRecordSet",
		}
		for _, r := range dc.Records {
			if keyForRec(r) == ck {
				newRRs.Rrdatas = append(newRRs.Rrdatas, r.Target)
				newRRs.Ttl = int64(r.TTL)
			}
		}
		if len(newRRs.Rrdatas) > 0 {
			chg.Additions = append(chg.Additions, newRRs)
		}
	}

	runChange := func() error {
		_, err := g.client.Changes.Create(g.project, zoneName, chg).Do()
		return err
	}
	corrections = append(corrections, &models.Correction{
		Msg: desc,
		F:   runChange,
	})
	return corrections, nil
}

func (g *gcloud) getRecords(domain string) ([]*dns.ResourceRecordSet, string, error) {
	zone, err := g.getZone(domain)
	if err != nil {
		return nil, "", err
	}
	pageToken := ""
	sets := []*dns.ResourceRecordSet{}
	for {
		call := g.client.ResourceRecordSets.List(g.project, zone.Name)
		if pageToken != "" {
			call = call.PageToken(pageToken)
		}
		resp, err := call.Do()
		if err != nil {
			return nil, "", err
		}
		for _, rrs := range resp.Rrsets {
			if rrs.Type == "SOA" {
				continue
			}
			sets = append(sets, rrs)
		}
		if pageToken = resp.NextPageToken; pageToken == "" {
			break
		}
	}
	return sets, zone.Name, nil
}

func (g *gcloud) addZone(name string) (*models.Correction, string) {
	mz := &dns.ManagedZone{}
	mz.DnsName = name + "."
	mz.Name = strings.Replace(name, ".", "-", -1)
	mz.Description = "zone added by dnscontrol"
	return &models.Correction{
		Msg: fmt.Sprintf("Add zone for %s", name),
		F: func() error {
			_, err := g.client.ManagedZones.Create(g.project, mz).Do()
			if err != nil {
				return err
			}
			return nil
		},
	}, mz.Name
}
<|endoftext|>


<commit_before>// Copyright 2013 tsuru 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath,
	}, nil
}

func runContainerCmd(app provision.App) ([]string, string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, "", err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, "", err
	}
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		return nil, "", err
	}
	appRepo := repository.GetReadOnlyUrl(app.GetName())
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		return nil, "", err
	}
	runArgs, err := config.GetString("docker:run-cmd:args")
	if err != nil {
		return nil, "", err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, "", err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, "", err
	}
	commands = append(commands, fmt.Sprintf("%s %s", deployCmd, appRepo), fmt.Sprintf("%s %s", runBin, runArgs))
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, port, nil
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		return err
	}
	cmd, port, err := runContainerCmd(app)
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.Replace(id, "\n", "", -1)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	hostPort, err := c.hostPort()
	if err != nil {
		hostPort = c.Port
	}
	return r.AddRoute(app.GetName(), fmt.Sprintf("http://%s:%s", hostAddr, hostPort))
}

// start starts a docker container.
func (c *container) start() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Stating container %s", c.Id)
	out, err := runCmd(docker, "start", c.Id)
	log.Printf("docker start output: %s", out)
	return err
}

// stop stops a docker container.
func (c *container) stop() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	//TODO: better error handling
	log.Printf("Stopping container %s", c.Id)
	output, err := runCmd(docker, "stop", c.Id)
	log.Printf("docker stop output: %s", output)
	return err
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Removing container %s from docker", c.Id)
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func getContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<commit_msg>provision/docker: nitpick<commit_after>// Copyright 2013 tsuru 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath,
	}, nil
}

func runContainerCmd(app provision.App) ([]string, string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, "", err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, "", err
	}
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		return nil, "", err
	}
	appRepo := repository.GetReadOnlyUrl(app.GetName())
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		return nil, "", err
	}
	runArgs, err := config.GetString("docker:run-cmd:args")
	if err != nil {
		return nil, "", err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, "", err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, "", err
	}
	commands = append(commands, fmt.Sprintf("%s %s", deployCmd, appRepo), fmt.Sprintf("%s %s", runBin, runArgs))
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, port, nil
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		return err
	}
	cmd, port, err := runContainerCmd(app)
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.TrimSpace(id)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	hostPort, err := c.hostPort()
	if err != nil {
		hostPort = c.Port
	}
	return r.AddRoute(app.GetName(), fmt.Sprintf("http://%s:%s", hostAddr, hostPort))
}

// start starts a docker container.
func (c *container) start() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Stating container %s", c.Id)
	out, err := runCmd(docker, "start", c.Id)
	log.Printf("docker start output: %s", out)
	return err
}

// stop stops a docker container.
func (c *container) stop() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	//TODO: better error handling
	log.Printf("Stopping container %s", c.Id)
	output, err := runCmd(docker, "stop", c.Id)
	log.Printf("docker stop output: %s", output)
	return err
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Removing container %s from docker", c.Id)
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func getContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<|endoftext|>


<commit_before>package tarfs

import (
	"archive/tar"
	"bytes"
	"io/ioutil"
	"log"
	"testing"
)

func TestOpen(t *testing.T) {

	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new tar archive.
	tw := tar.NewWriter(buf)

	// Add some files to the archive.
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling licence."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	// Make sure to check the error on Close.
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}

	// Open the tar archive for reading.
	fs, err := New(bytes.NewReader(buf.Bytes()))
	if err != nil {
		t.Fatal(err)
	}

	for _, file := range files {
		f, err := fs.Open(file.Name)
		if err != nil {
			t.Fatal(err)
		}
		content, _ := ioutil.ReadAll(f)
		if string(content) != file.Body {
			t.Fatalf("For '%s'\nExpected:\n%s\nGot:\n%s\n", file.Name, file.Body, content)
		}
	}
}
<commit_msg>Better test.<commit_after>package tarfs

import (
	"archive/tar"
	"bytes"
	"io/ioutil"
	"log"
	"testing"
)

func TestOpen(t *testing.T) {

	// Create a buffer to write our archive to.
	buf := new(bytes.Buffer)

	// Create a new tar archive.
	tw := tar.NewWriter(buf)

	// Add some files to the archive.
	var files = []struct {
		Name, Body string
	}{
		{"readme.txt", "This archive contains some text files."},
		{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
		{"todo.txt", "Get animal handling licence."},
	}
	for _, file := range files {
		hdr := &tar.Header{
			Name: file.Name,
			Size: int64(len(file.Body)),
		}
		if err := tw.WriteHeader(hdr); err != nil {
			log.Fatalln(err)
		}
		if _, err := tw.Write([]byte(file.Body)); err != nil {
			log.Fatalln(err)
		}
	}
	// Make sure to check the error on Close.
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}

	// Open the tar archive for reading.
	fs, err := New(bytes.NewReader(buf.Bytes()))
	if err != nil {
		t.Fatal(err)
	}

	for _, file := range files {
		f, err := fs.Open(file.Name)
		if err != nil {
			t.Fatal(err)
		}
		content, _ := ioutil.ReadAll(f)
		if string(content) != file.Body {
			t.Fatalf("For '%s'\nExpected:\n%s\nGot:\n%s\n", file.Name, file.Body, content)
		}

		var (
			s, _ = f.Stat()
			size = int64(len(file.Body))
			got  = s.Size()
		)

		if size != got {
			t.Fatalf("For '%s'\nExpected Size:\n%v\nGot:\n%v\n", file.Name, size, got)
		}
	}
}
<|endoftext|>


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

package oglematchers_test

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type IdenticalToTest struct {
}

func init() { RegisterTestSuite(&IdenticalToTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *IdenticalToTest) TypesNotIdentical() {
	var m Matcher
	var err error

	type intAlias int

	// Type alias expected value
	m = IdenticalTo(intAlias(17))
	err = m.Matches(int(17))
	ExpectThat(err, Error(Equals("which is of type int")))

	// Type alias candidate
	m = IdenticalTo(int(17))
	err = m.Matches(intAlias(17))
	ExpectThat(err, Error(Equals("which is of type intAlias")))

	// int and uint
	m = IdenticalTo(int(17))
	err = m.Matches(uint(17))
	ExpectThat(err, Error(Equals("which is of type uint")))
}

func (t *IdenticalToTest) NilExpectedValue() {
}

func (t *IdenticalToTest) NilCandidate() {
}

func (t *IdenticalToTest) Slices() {
}

func (t *IdenticalToTest) Maps() {
}

func (t *IdenticalToTest) Functions() {
}

func (t *IdenticalToTest) Channels() {
}

func (t *IdenticalToTest) Bools() {
}

func (t *IdenticalToTest) Ints() {
}

func (t *IdenticalToTest) Int8s() {
}

func (t *IdenticalToTest) Int16s() {
}

func (t *IdenticalToTest) Int32s() {
}

func (t *IdenticalToTest) Int64s() {
}

func (t *IdenticalToTest) Uints() {
}

func (t *IdenticalToTest) Uint8s() {
}

func (t *IdenticalToTest) Uint16s() {
}

func (t *IdenticalToTest) Uint32s() {
}

func (t *IdenticalToTest) Uint64s() {
}

func (t *IdenticalToTest) Float32s() {
}

func (t *IdenticalToTest) Float64s() {
}

func (t *IdenticalToTest) Complex64s() {
}

func (t *IdenticalToTest) Complex128s() {
}

func (t *IdenticalToTest) ComparableArrays() {
}

func (t *IdenticalToTest) NonComparableArrays() {
}

func (t *IdenticalToTest) ComparableInterfaces() {
}

func (t *IdenticalToTest) NonComparableInterfaces() {
}

func (t *IdenticalToTest) Pointers() {
}

func (t *IdenticalToTest) Strings() {
}

func (t *IdenticalToTest) ComparableStructs() {
}

func (t *IdenticalToTest) NonComparableStructs() {
}

func (t *IdenticalToTest) UnsafePointers() {
}

func (t *IdenticalToTest) IntAlias() {
}
<commit_msg>IdenticalToTest.NilExpectedValue<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oglematchers_test

import (
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////

type IdenticalToTest struct {
}

func init() { RegisterTestSuite(&IdenticalToTest{}) }

////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////

func (t *IdenticalToTest) TypesNotIdentical() {
	var m Matcher
	var err error

	type intAlias int

	// Type alias expected value
	m = IdenticalTo(intAlias(17))
	err = m.Matches(int(17))
	ExpectThat(err, Error(Equals("which is of type int")))

	// Type alias candidate
	m = IdenticalTo(int(17))
	err = m.Matches(intAlias(17))
	ExpectThat(err, Error(Equals("which is of type intAlias")))

	// int and uint
	m = IdenticalTo(int(17))
	err = m.Matches(uint(17))
	ExpectThat(err, Error(Equals("which is of type uint")))
}

func (t *IdenticalToTest) NilExpectedValue() {
	m := IdenticalTo(nil)
	var err error

	// Nil candidate
	err = m.Matches(nil)
	ExpectEq(nil, err)

	// Casted nil chan candidate
	err = m.Matches((chan int)(nil))
	ExpectEq(nil, err)

	// Non-nil chan candidate
	err = m.Matches(make(chan int))
	ExpectThat(err, Error(Equals("which is of type chan int")))

	// Integer candidate
	err = m.Matches(17)
	ExpectThat(err, Error(Equals("which is of type int")))
}

func (t *IdenticalToTest) CastedNilExpectedValue() {
}

func (t *IdenticalToTest) NilCandidate() {
}

func (t *IdenticalToTest) Slices() {
}

func (t *IdenticalToTest) Maps() {
}

func (t *IdenticalToTest) Functions() {
}

func (t *IdenticalToTest) Channels() {
}

func (t *IdenticalToTest) Bools() {
}

func (t *IdenticalToTest) Ints() {
}

func (t *IdenticalToTest) Int8s() {
}

func (t *IdenticalToTest) Int16s() {
}

func (t *IdenticalToTest) Int32s() {
}

func (t *IdenticalToTest) Int64s() {
}

func (t *IdenticalToTest) Uints() {
}

func (t *IdenticalToTest) Uint8s() {
}

func (t *IdenticalToTest) Uint16s() {
}

func (t *IdenticalToTest) Uint32s() {
}

func (t *IdenticalToTest) Uint64s() {
}

func (t *IdenticalToTest) Float32s() {
}

func (t *IdenticalToTest) Float64s() {
}

func (t *IdenticalToTest) Complex64s() {
}

func (t *IdenticalToTest) Complex128s() {
}

func (t *IdenticalToTest) ComparableArrays() {
}

func (t *IdenticalToTest) NonComparableArrays() {
}

func (t *IdenticalToTest) ComparableInterfaces() {
}

func (t *IdenticalToTest) NonComparableInterfaces() {
}

func (t *IdenticalToTest) Pointers() {
}

func (t *IdenticalToTest) Strings() {
}

func (t *IdenticalToTest) ComparableStructs() {
}

func (t *IdenticalToTest) NonComparableStructs() {
}

func (t *IdenticalToTest) UnsafePointers() {
}

func (t *IdenticalToTest) IntAlias() {
}
<|endoftext|>