<commit_before>package interp

import (
	"bufio"
	"fmt"
	"go/scanner"
	"os"
	"reflect"
)

// Node structure for AST and CFG
type Node struct {
	child    []*Node          // child subtrees (AST)
	anc      *Node            // ancestor (AST)
	start    *Node            // entry point in subtree (CFG)
	tnext    *Node            // true branch successor (CFG)
	fnext    *Node            // false branch successor (CFG)
	interp   *Interpreter     // interpreter context
	frame    *Frame           // frame pointer used for closures only (TODO: suppress this)
	index    int              // node index (dot display)
	findex   int              // index of value in frame or frame size (func def, type def)
	fsize    int              // number of entries in frame (call expressions)
	flen     int              // frame length (function definition)
	level    int              // number of frame indirections to access value
	kind     Kind             // kind of node
	sym      *Symbol          // associated symbol
	typ      *Type            // type of value in frame, or nil
	recv     *Receiver        // method receiver node for call, or nil
	types    []reflect.Type   // frame types, used by function litterals only
	framepos []int            // frame positions of function parameters
	action   Action           // action
	exec     Builtin          // generated function to execute
	gen      BuiltinGenerator // generator function to produce above bltn
	val      interface{}      // static generic value (CFG execution)
	rval     reflect.Value    // reflection value to let runtime access interpreter (CFG)
	ident    string           // set if node is a var or func
}

// Receiver stores method receiver object access path
type Receiver struct {
	node  *Node
	index []int
}

// Frame contains values for the current execution level
type Frame struct {
	anc  *Frame          // ancestor frame (global space)
	data []reflect.Value // values
}

// LibValueMap stores the map of extern values per package
type LibValueMap map[string]map[string]reflect.Value

// LibTypeMap stores the map of extern types per package
type LibTypeMap map[string]map[string]reflect.Type

// Opt stores interpreter options
type Opt struct {
	AstDot bool   // display AST graph (debug)
	CfgDot bool   // display CFG graph (debug)
	NoRun  bool   // compile, but do not run
	Entry  string // interpreter entry point
}

// Interpreter contains global resources and state
type Interpreter struct {
	Opt
	Name     string            // program name
	Frame    *Frame            // programe data storage during execution
	fsize    int               // global interpreter frame size
	nindex   int               // next node index
	universe *Scope            // interpreter global level scope
	scope    map[string]*Scope // package level scopes, indexed by package name
	binValue LibValueMap       // runtime binary values used in interpreter
	binType  LibTypeMap        // runtime binary types used in interpreter
}

// ExportValue exposes interpreter values
var ExportValue = LibValueMap{}

// ExportType exposes interpreter types
var ExportType = LibTypeMap{}

func init() {
	me := "github.com/containous/dyngo/interp"
	ExportValue[me] = map[string]reflect.Value{
		"New": reflect.ValueOf(New),
	}
	ExportType[me] = map[string]reflect.Type{
		"Interpreter": reflect.TypeOf((*Interpreter)(nil)).Elem(),
		"Opt":         reflect.TypeOf((*Opt)(nil)).Elem(),
	}
	ExportValue[me]["ExportType"] = reflect.ValueOf(ExportType)
	ExportValue[me]["ExportValue"] = reflect.ValueOf(ExportValue)
}

// Walk traverses AST n in depth first order, call cbin function
// at node entry and cbout function at node exit.
func (n *Node) Walk(in func(n *Node) bool, out func(n *Node)) {
	if in != nil && !in(n) {
		return
	}
	for _, child := range n.child {
		child.Walk(in, out)
	}
	if out != nil {
		out(n)
	}
}

// New creates and returns a new interpreter object
func New(opt Opt) *Interpreter {
	return &Interpreter{
		Opt:      opt,
		universe: initUniverse(),
		scope:    map[string]*Scope{},
		binValue: LibValueMap{},
		binType:  LibTypeMap{},
		Frame:    &Frame{data: []reflect.Value{}},
	}
}

func initUniverse() *Scope {
	scope := &Scope{global: true, sym: SymMap{
		// predefined Go types
		"bool":       &Symbol{kind: Typ, typ: &Type{cat: BoolT}},
		"byte":       &Symbol{kind: Typ, typ: &Type{cat: ByteT}},
		"complex64":  &Symbol{kind: Typ, typ: &Type{cat: Complex64T}},
		"complex128": &Symbol{kind: Typ, typ: &Type{cat: Complex128T}},
		"error":      &Symbol{kind: Typ, typ: &Type{cat: ErrorT}},
		"float32":    &Symbol{kind: Typ, typ: &Type{cat: Float32T}},
		"float64":    &Symbol{kind: Typ, typ: &Type{cat: Float64T}},
		"int":        &Symbol{kind: Typ, typ: &Type{cat: IntT}},
		"int8":       &Symbol{kind: Typ, typ: &Type{cat: Int8T}},
		"int16":      &Symbol{kind: Typ, typ: &Type{cat: Int16T}},
		"int32":      &Symbol{kind: Typ, typ: &Type{cat: Int32T}},
		"int64":      &Symbol{kind: Typ, typ: &Type{cat: Int64T}},
		"rune":       &Symbol{kind: Typ, typ: &Type{cat: RuneT}},
		"string":     &Symbol{kind: Typ, typ: &Type{cat: StringT}},
		"uint":       &Symbol{kind: Typ, typ: &Type{cat: UintT}},
		"uint8":      &Symbol{kind: Typ, typ: &Type{cat: Uint8T}},
		"uint16":     &Symbol{kind: Typ, typ: &Type{cat: Uint16T}},
		"uint32":     &Symbol{kind: Typ, typ: &Type{cat: Uint32T}},
		"uint64":     &Symbol{kind: Typ, typ: &Type{cat: Uint64T}},
		"uintptr":    &Symbol{kind: Typ, typ: &Type{cat: UintptrT}},

		// predefined Go constants
		"false": &Symbol{kind: Const, typ: &Type{cat: BoolT}, val: false},
		"true":  &Symbol{kind: Const, typ: &Type{cat: BoolT}, val: true},
		"iota":  &Symbol{kind: Const, typ: &Type{cat: IntT}},

		// predefined Go zero value
		"nil": &Symbol{typ: &Type{cat: UnsetT}},

		// predefined Go builtins
		"append":  &Symbol{kind: Bltn, builtin: _append},
		"cap":     &Symbol{kind: Bltn, builtin: _cap},
		"len":     &Symbol{kind: Bltn, builtin: _len},
		"make":    &Symbol{kind: Bltn, builtin: _make},
		"panic":   &Symbol{kind: Bltn, builtin: _panic},
		"println": &Symbol{kind: Bltn, builtin: _println},
		// TODO: close, complex, copy, delete, imag, new, print, real, recover
	}}
	return scope
}

// resizeFrame resizes the global frame of interpeter
func (i *Interpreter) resizeFrame() {
	f := &Frame{data: make([]reflect.Value, i.fsize)}
	copy(f.data, i.Frame.data)
	i.Frame = f
}

// Eval evaluates Go code represented as a string. It returns a map on
// current interpreted package exported symbols
func (i *Interpreter) Eval(src string) (reflect.Value, error) {
	var res reflect.Value

	// Parse source to AST
	pkgName, root, err := i.ast(src, i.Name)
	if err != nil {
		return res, err
	}

	if i.AstDot {
		root.AstDot(DotX(), i.Name)
	}

	// Global type analysis
	i.Gta(root)

	// Annotate AST with CFG infos
	initNodes := i.Cfg(root)
	if pkgName != "_" {
		if sym := i.scope[pkgName].sym[i.Entry]; sym != nil {
			initNodes = append(initNodes, sym.node)
		}
	} else {
		root.types = frameTypes(root, i.fsize+1)
		setExec(root.start)
	}

	if i.CfgDot {
		root.CfgDot(DotX())
	}

	// Execute CFG
	if !i.NoRun {
		genRun(root)
		i.fsize++
		i.resizeFrame()
		i.run(root, nil)

		for _, n := range initNodes {
			i.run(n, i.Frame)
		}
		v := genValue(root)
		res = v(i.Frame)
	}

	// If result is an interpreter node, wrap it in a runtime callable function
	if res.IsValid() {
		if n, ok := res.Interface().(*Node); ok {
			res = genNodeWrapper(n)(i.Frame)
		}
	}
	return res, err
}

// Use loads binary runtime symbols in the interpreter context so
// they can be used in interpreted code
func (i *Interpreter) Use(values LibValueMap, types LibTypeMap) {
	for k, v := range values {
		i.binValue[k] = v
	}
	for k, v := range types {
		i.binType[k] = v
	}
}

// Repl performs a Read-Eval-Print-Loop on input file descriptor.
// Results are printed on output.
func (i *Interpreter) Repl(in, out *os.File) {
	s := bufio.NewScanner(in)
	prompt := getPrompt(in)
	prompt()
	src := ""
	for s.Scan() {
		src += s.Text() + "\n"
		if v, err := i.Eval(src); err != nil {
			switch err.(type) {
			case scanner.ErrorList:
				// Early failure in the scanner: the source is incomplete
				// and no AST could be produced, neither compiled / run.
				// Get one more line, and retry
				continue
			}
			fmt.Fprintln(out, err)
		} else if v.IsValid() {
			fmt.Fprintln(out, v)
		}
		src = ""
		prompt()
	}
}

// getPrompt returns a function which prints a prompt only if stdin is a terminal
func getPrompt(f *os.File) func() {
	if stat, err := f.Stat(); err == nil && stat.Mode()&os.ModeCharDevice != 0 {
		return func() { fmt.Print("> ") }
	}
	return func() {}
}
<commit_msg>REPL: fix prompt if output is not stdout<commit_after>package interp

import (
	"bufio"
	"fmt"
	"go/scanner"
	"os"
	"reflect"
)

// Node structure for AST and CFG
type Node struct {
	child    []*Node          // child subtrees (AST)
	anc      *Node            // ancestor (AST)
	start    *Node            // entry point in subtree (CFG)
	tnext    *Node            // true branch successor (CFG)
	fnext    *Node            // false branch successor (CFG)
	interp   *Interpreter     // interpreter context
	frame    *Frame           // frame pointer used for closures only (TODO: suppress this)
	index    int              // node index (dot display)
	findex   int              // index of value in frame or frame size (func def, type def)
	fsize    int              // number of entries in frame (call expressions)
	flen     int              // frame length (function definition)
	level    int              // number of frame indirections to access value
	kind     Kind             // kind of node
	sym      *Symbol          // associated symbol
	typ      *Type            // type of value in frame, or nil
	recv     *Receiver        // method receiver node for call, or nil
	types    []reflect.Type   // frame types, used by function litterals only
	framepos []int            // frame positions of function parameters
	action   Action           // action
	exec     Builtin          // generated function to execute
	gen      BuiltinGenerator // generator function to produce above bltn
	val      interface{}      // static generic value (CFG execution)
	rval     reflect.Value    // reflection value to let runtime access interpreter (CFG)
	ident    string           // set if node is a var or func
}

// Receiver stores method receiver object access path
type Receiver struct {
	node  *Node
	index []int
}

// Frame contains values for the current execution level
type Frame struct {
	anc  *Frame          // ancestor frame (global space)
	data []reflect.Value // values
}

// LibValueMap stores the map of extern values per package
type LibValueMap map[string]map[string]reflect.Value

// LibTypeMap stores the map of extern types per package
type LibTypeMap map[string]map[string]reflect.Type

// Opt stores interpreter options
type Opt struct {
	AstDot bool   // display AST graph (debug)
	CfgDot bool   // display CFG graph (debug)
	NoRun  bool   // compile, but do not run
	Entry  string // interpreter entry point
}

// Interpreter contains global resources and state
type Interpreter struct {
	Opt
	Name     string            // program name
	Frame    *Frame            // programe data storage during execution
	fsize    int               // global interpreter frame size
	nindex   int               // next node index
	universe *Scope            // interpreter global level scope
	scope    map[string]*Scope // package level scopes, indexed by package name
	binValue LibValueMap       // runtime binary values used in interpreter
	binType  LibTypeMap        // runtime binary types used in interpreter
}

// ExportValue exposes interpreter values
var ExportValue = LibValueMap{}

// ExportType exposes interpreter types
var ExportType = LibTypeMap{}

func init() {
	me := "github.com/containous/dyngo/interp"
	ExportValue[me] = map[string]reflect.Value{
		"New": reflect.ValueOf(New),
	}
	ExportType[me] = map[string]reflect.Type{
		"Interpreter": reflect.TypeOf((*Interpreter)(nil)).Elem(),
		"Opt":         reflect.TypeOf((*Opt)(nil)).Elem(),
	}
	ExportValue[me]["ExportType"] = reflect.ValueOf(ExportType)
	ExportValue[me]["ExportValue"] = reflect.ValueOf(ExportValue)
}

// Walk traverses AST n in depth first order, call cbin function
// at node entry and cbout function at node exit.
func (n *Node) Walk(in func(n *Node) bool, out func(n *Node)) {
	if in != nil && !in(n) {
		return
	}
	for _, child := range n.child {
		child.Walk(in, out)
	}
	if out != nil {
		out(n)
	}
}

// New creates and returns a new interpreter object
func New(opt Opt) *Interpreter {
	return &Interpreter{
		Opt:      opt,
		universe: initUniverse(),
		scope:    map[string]*Scope{},
		binValue: LibValueMap{},
		binType:  LibTypeMap{},
		Frame:    &Frame{data: []reflect.Value{}},
	}
}

func initUniverse() *Scope {
	scope := &Scope{global: true, sym: SymMap{
		// predefined Go types
		"bool":       &Symbol{kind: Typ, typ: &Type{cat: BoolT}},
		"byte":       &Symbol{kind: Typ, typ: &Type{cat: ByteT}},
		"complex64":  &Symbol{kind: Typ, typ: &Type{cat: Complex64T}},
		"complex128": &Symbol{kind: Typ, typ: &Type{cat: Complex128T}},
		"error":      &Symbol{kind: Typ, typ: &Type{cat: ErrorT}},
		"float32":    &Symbol{kind: Typ, typ: &Type{cat: Float32T}},
		"float64":    &Symbol{kind: Typ, typ: &Type{cat: Float64T}},
		"int":        &Symbol{kind: Typ, typ: &Type{cat: IntT}},
		"int8":       &Symbol{kind: Typ, typ: &Type{cat: Int8T}},
		"int16":      &Symbol{kind: Typ, typ: &Type{cat: Int16T}},
		"int32":      &Symbol{kind: Typ, typ: &Type{cat: Int32T}},
		"int64":      &Symbol{kind: Typ, typ: &Type{cat: Int64T}},
		"rune":       &Symbol{kind: Typ, typ: &Type{cat: RuneT}},
		"string":     &Symbol{kind: Typ, typ: &Type{cat: StringT}},
		"uint":       &Symbol{kind: Typ, typ: &Type{cat: UintT}},
		"uint8":      &Symbol{kind: Typ, typ: &Type{cat: Uint8T}},
		"uint16":     &Symbol{kind: Typ, typ: &Type{cat: Uint16T}},
		"uint32":     &Symbol{kind: Typ, typ: &Type{cat: Uint32T}},
		"uint64":     &Symbol{kind: Typ, typ: &Type{cat: Uint64T}},
		"uintptr":    &Symbol{kind: Typ, typ: &Type{cat: UintptrT}},

		// predefined Go constants
		"false": &Symbol{kind: Const, typ: &Type{cat: BoolT}, val: false},
		"true":  &Symbol{kind: Const, typ: &Type{cat: BoolT}, val: true},
		"iota":  &Symbol{kind: Const, typ: &Type{cat: IntT}},

		// predefined Go zero value
		"nil": &Symbol{typ: &Type{cat: UnsetT}},

		// predefined Go builtins
		"append":  &Symbol{kind: Bltn, builtin: _append},
		"cap":     &Symbol{kind: Bltn, builtin: _cap},
		"len":     &Symbol{kind: Bltn, builtin: _len},
		"make":    &Symbol{kind: Bltn, builtin: _make},
		"panic":   &Symbol{kind: Bltn, builtin: _panic},
		"println": &Symbol{kind: Bltn, builtin: _println},
		// TODO: close, complex, copy, delete, imag, new, print, real, recover
	}}
	return scope
}

// resizeFrame resizes the global frame of interpeter
func (i *Interpreter) resizeFrame() {
	f := &Frame{data: make([]reflect.Value, i.fsize)}
	copy(f.data, i.Frame.data)
	i.Frame = f
}

// Eval evaluates Go code represented as a string. It returns a map on
// current interpreted package exported symbols
func (i *Interpreter) Eval(src string) (reflect.Value, error) {
	var res reflect.Value

	// Parse source to AST
	pkgName, root, err := i.ast(src, i.Name)
	if err != nil {
		return res, err
	}

	if i.AstDot {
		root.AstDot(DotX(), i.Name)
	}

	// Global type analysis
	i.Gta(root)

	// Annotate AST with CFG infos
	initNodes := i.Cfg(root)
	if pkgName != "_" {
		if sym := i.scope[pkgName].sym[i.Entry]; sym != nil {
			initNodes = append(initNodes, sym.node)
		}
	} else {
		root.types = frameTypes(root, i.fsize+1)
		setExec(root.start)
	}

	if i.CfgDot {
		root.CfgDot(DotX())
	}

	// Execute CFG
	if !i.NoRun {
		genRun(root)
		i.fsize++
		i.resizeFrame()
		i.run(root, nil)

		for _, n := range initNodes {
			i.run(n, i.Frame)
		}
		v := genValue(root)
		res = v(i.Frame)
	}

	// If result is an interpreter node, wrap it in a runtime callable function
	if res.IsValid() {
		if n, ok := res.Interface().(*Node); ok {
			res = genNodeWrapper(n)(i.Frame)
		}
	}
	return res, err
}

// Use loads binary runtime symbols in the interpreter context so
// they can be used in interpreted code
func (i *Interpreter) Use(values LibValueMap, types LibTypeMap) {
	for k, v := range values {
		i.binValue[k] = v
	}
	for k, v := range types {
		i.binType[k] = v
	}
}

// Repl performs a Read-Eval-Print-Loop on input file descriptor.
// Results are printed on output.
func (i *Interpreter) Repl(in, out *os.File) {
	s := bufio.NewScanner(in)
	prompt := getPrompt(in, out)
	prompt()
	src := ""
	for s.Scan() {
		src += s.Text() + "\n"
		if v, err := i.Eval(src); err != nil {
			switch err.(type) {
			case scanner.ErrorList:
				// Early failure in the scanner: the source is incomplete
				// and no AST could be produced, neither compiled / run.
				// Get one more line, and retry
				continue
			}
			fmt.Fprintln(out, err)
		} else if v.IsValid() {
			fmt.Fprintln(out, v)
		}
		src = ""
		prompt()
	}
}

// getPrompt returns a function which prints a prompt only if input is a terminal
func getPrompt(in, out *os.File) func() {
	if stat, err := in.Stat(); err == nil && stat.Mode()&os.ModeCharDevice != 0 {
		return func() { fmt.Fprint(out, "> ") }
	}
	return func() {}
}
<|endoftext|>


<commit_before>/*
Copyright 2013 Volker Poplawski
Modified 2015 Ben Echols -- changed from float64 to int32 space
*/

// Package quadtree is a simple 2D implementation of the Quad-Tree data structure.
package quadtree

// MaxEntriesPerTile is the number of entries until a quad is split
const MaxEntriesPerTile = 16

// MaxLevels is the maximum depth of quad-tree (not counting the root node)
const MaxLevels = 10

// some constants for tile-indeces, for clarity
const (
	topRightTile    = 0
	topLeftTile     = 1
	bottomLeftTile  = 2
	bottomRightTile = 3
)

// BoundingBoxer interface allows arbitrary objects to be inserted into the quadtree since it only requires a bounding box.
type BoundingBoxer interface {
	Bounds() BoundingBox
	BoxID() uint32
	Clone() BoundingBoxer
}

// QuadTree is the core tree structure.
type QuadTree struct {
	root qtile
}

// NewQuadTree constructs an empty quad-tree
// bbox specifies the extends of the coordinate system.
func NewQuadTree(bbox BoundingBox) QuadTree {
	qt := QuadTree{qtile{BoundingBox: bbox}}

	return qt
}

// quad-tile / node of the quad-tree
type qtile struct {
	BoundingBox
	level    int             // level this tile is at. root is level 0
	contents []BoundingBoxer // values stored in this tile
	childs   [4]*qtile       // sub-tiles. none or four.
}

// Add a value to the quad-tree by trickle down from the root node.
func (qb *QuadTree) Add(v BoundingBoxer) {
	qb.root.add(v)
}

// Remove a value from the quad-tree by trickle down from the root node.
func (qb *QuadTree) Remove(v BoundingBoxer) bool {
	return qb.root.remove(v.Bounds(), v.BoxID())
}

// Move a box to new box
func (qb *QuadTree) Move(v BoundingBoxer, oldloc BoundingBox) int {
	return qb.root.move(v.BoxID(), v, oldloc, v.Bounds())
}

// Clone will create a full copy of this quadtree.
func (qb *QuadTree) Clone() *QuadTree {
	return &QuadTree{
		root: qb.root.clone(),
	}
}

// Query will return all objects which intersect the query box
func (qb *QuadTree) Query(bbox BoundingBox) []BoundingBoxer {
	return qb.root.query(bbox)
}

func (tile qtile) clone() qtile {
	ntile := qtile{
		BoundingBox: tile.BoundingBox,
		level:       tile.level,
		contents:    make([]BoundingBoxer, len(tile.contents)),
		childs:      [4]*qtile{},
	}
	for idx, bb := range tile.contents {
		ntile.contents[idx] = bb.Clone()
	}
	for idx, c := range tile.childs {
		if c != nil {
			cClone := c.clone()
			ntile.childs[idx] = &cClone
		}
	}
	return ntile
}

func (tile *qtile) add(v BoundingBoxer) {
	// look for sub-tile directly below this tile to accomodate value.
	if i := tile.findChildIndex(v.Bounds()); i < 0 {
		// no suitable sub-tile for value found.
		// either this tile has no childs or
		// value does not fit in any subtile.
		// store value at this level.
		tile.contents = append(tile.contents, v)

		// tile is split if exceeds it max number of entries and
		// has not childs already and max tree depth for this sub-tree not reached.
		if len(tile.contents) > MaxEntriesPerTile && tile.childs[topRightTile] == nil && tile.level < MaxLevels {
			tile.split()
		}
	} else {
		// suitable sub-tile for value found at index i.
		// recursivly add value.
		tile.childs[i].add(v)
	}
}

// return child index for BoundingBox
// returns -1 if quad has no children or BoundingBox does not fit into any child
func (tile *qtile) findChildIndex(bbox BoundingBox) int {
	if tile.childs[topRightTile] == nil {
		return -1
	}

	for i, child := range tile.childs {
		if child.Contains(bbox) {
			return i
		}
	}

	return -1
}

// create four child quads.
// distribute contents of this tiles on newly created childs.
func (tile *qtile) split() {
	mx := tile.MaxX/2.0 + tile.MinX/2.0
	my := tile.MaxY/2.0 + tile.MinY/2.0

	tile.childs[topRightTile] = &qtile{BoundingBox: NewBoundingBox(mx, tile.MaxX, my, tile.MaxY), level: tile.level + 1}
	tile.childs[topLeftTile] = &qtile{BoundingBox: NewBoundingBox(tile.MinX, mx, my, tile.MaxY), level: tile.level + 1}
	tile.childs[bottomLeftTile] = &qtile{BoundingBox: NewBoundingBox(tile.MinX, mx, tile.MinY, my), level: tile.level + 1}
	tile.childs[bottomRightTile] = &qtile{BoundingBox: NewBoundingBox(mx, tile.MaxX, tile.MinY, my), level: tile.level + 1}

	tempList := tile.contents

	// clear values on this tile
	tile.contents = []BoundingBoxer{}

	// reinsert from parent slice
	for _, v := range tempList {
		tile.add(v)
	}

}

// 0 == not found, 1 == found, needs home, 2 == completed
func (tile *qtile) move(id uint32, bb BoundingBoxer, old, newb BoundingBox) int {
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(old) {
		return 0
	}

	for vidx, v := range tile.contents {
		if id == v.BoxID() {
			if tile.Intersects(newb) {
				return 2
			}
			// REMOVE IT
			tile.contents = append(tile.contents[:vidx], tile.contents[vidx+1:]...)
			return 1
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			cr := child.move(id, bb, old, newb)
			// Not found, continue searching
			if cr == 0 {
				continue
			}
			// Found&Handled, return now!
			if cr == 2 {
				return 2
			}
			// Found but not inserted
			if !tile.Intersects(newb) {
				// New loc doesn't fit in here, pass it up!
				return 1
			}
			// Add new loc here!
			tile.add(bb)
			return 2
		}
	}

	return 0
}

func (tile *qtile) remove(qbox BoundingBox, id uint32) bool {
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(qbox) {
		return false
	}

	// return candidates at this tile
	for vidx, v := range tile.contents {
		if id == v.BoxID() {
			// REMOVE IT
			tile.contents = append(tile.contents[:vidx], tile.contents[vidx+1:]...)
			return true
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			if child.remove(qbox, id) {
				return true
			}
		}
	}

	return false
}

func (tile *qtile) query(qbox BoundingBox) []BoundingBoxer {
	ret := []BoundingBoxer{}
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(qbox) {
		return ret
	}

	// return candidates at this tile
	for _, v := range tile.contents {
		if qbox.Intersects(v.Bounds()) {
			ret = append(ret, v)
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			ret = append(ret, child.query(qbox)...)
		}
	}

	return ret
}
<commit_msg>made clone also return all copied children<commit_after>/*
Copyright 2013 Volker Poplawski
Modified 2015 Ben Echols -- changed from float64 to int32 space
*/

// Package quadtree is a simple 2D implementation of the Quad-Tree data structure.
package quadtree

// MaxEntriesPerTile is the number of entries until a quad is split
const MaxEntriesPerTile = 16

// MaxLevels is the maximum depth of quad-tree (not counting the root node)
const MaxLevels = 10

// some constants for tile-indeces, for clarity
const (
	topRightTile    = 0
	topLeftTile     = 1
	bottomLeftTile  = 2
	bottomRightTile = 3
)

// BoundingBoxer interface allows arbitrary objects to be inserted into the quadtree since it only requires a bounding box.
type BoundingBoxer interface {
	Bounds() BoundingBox
	BoxID() uint32
	Clone() BoundingBoxer
}

// QuadTree is the core tree structure.
type QuadTree struct {
	root qtile
}

// NewQuadTree constructs an empty quad-tree
// bbox specifies the extends of the coordinate system.
func NewQuadTree(bbox BoundingBox) QuadTree {
	qt := QuadTree{qtile{BoundingBox: bbox}}

	return qt
}

// quad-tile / node of the quad-tree
type qtile struct {
	BoundingBox
	level    int             // level this tile is at. root is level 0
	contents []BoundingBoxer // values stored in this tile
	childs   [4]*qtile       // sub-tiles. none or four.
}

// Add a value to the quad-tree by trickle down from the root node.
func (qb *QuadTree) Add(v BoundingBoxer) {
	qb.root.add(v)
}

// Remove a value from the quad-tree by trickle down from the root node.
func (qb *QuadTree) Remove(v BoundingBoxer) bool {
	return qb.root.remove(v.Bounds(), v.BoxID())
}

// Move a box to new box
func (qb *QuadTree) Move(v BoundingBoxer, oldloc BoundingBox) int {
	return qb.root.move(v.BoxID(), v, oldloc, v.Bounds())
}

// Clone will create a full copy of this quadtree.
func (qb *QuadTree) Clone() (*QuadTree, []BoundingBoxer) {
	root, children := qb.root.clone()
	return &QuadTree{root: root}, children
}

// Query will return all objects which intersect the query box
func (qb *QuadTree) Query(bbox BoundingBox) []BoundingBoxer {
	return qb.root.query(bbox)
}

func (tile qtile) clone() (qtile, []BoundingBoxer) {
	ntile := qtile{
		BoundingBox: tile.BoundingBox,
		level:       tile.level,
		contents:    make([]BoundingBoxer, len(tile.contents)),
		childs:      [4]*qtile{},
	}
	for idx, bb := range tile.contents {
		ntile.contents[idx] = bb.Clone()
	}
	contents := ntile.contents
	for idx, c := range tile.childs {
		if c != nil {
			cClone, ccont := c.clone()
			ntile.childs[idx] = &cClone
			contents = append(contents, ccont...)
		}
	}
	return ntile, contents
}

func (tile *qtile) add(v BoundingBoxer) {
	// look for sub-tile directly below this tile to accomodate value.
	if i := tile.findChildIndex(v.Bounds()); i < 0 {
		// no suitable sub-tile for value found.
		// either this tile has no childs or
		// value does not fit in any subtile.
		// store value at this level.
		tile.contents = append(tile.contents, v)

		// tile is split if exceeds it max number of entries and
		// has not childs already and max tree depth for this sub-tree not reached.
		if len(tile.contents) > MaxEntriesPerTile && tile.childs[topRightTile] == nil && tile.level < MaxLevels {
			tile.split()
		}
	} else {
		// suitable sub-tile for value found at index i.
		// recursivly add value.
		tile.childs[i].add(v)
	}
}

// return child index for BoundingBox
// returns -1 if quad has no children or BoundingBox does not fit into any child
func (tile *qtile) findChildIndex(bbox BoundingBox) int {
	if tile.childs[topRightTile] == nil {
		return -1
	}

	for i, child := range tile.childs {
		if child.Contains(bbox) {
			return i
		}
	}

	return -1
}

// create four child quads.
// distribute contents of this tiles on newly created childs.
func (tile *qtile) split() {
	mx := tile.MaxX/2.0 + tile.MinX/2.0
	my := tile.MaxY/2.0 + tile.MinY/2.0

	tile.childs[topRightTile] = &qtile{BoundingBox: NewBoundingBox(mx, tile.MaxX, my, tile.MaxY), level: tile.level + 1}
	tile.childs[topLeftTile] = &qtile{BoundingBox: NewBoundingBox(tile.MinX, mx, my, tile.MaxY), level: tile.level + 1}
	tile.childs[bottomLeftTile] = &qtile{BoundingBox: NewBoundingBox(tile.MinX, mx, tile.MinY, my), level: tile.level + 1}
	tile.childs[bottomRightTile] = &qtile{BoundingBox: NewBoundingBox(mx, tile.MaxX, tile.MinY, my), level: tile.level + 1}

	tempList := tile.contents

	// clear values on this tile
	tile.contents = []BoundingBoxer{}

	// reinsert from parent slice
	for _, v := range tempList {
		tile.add(v)
	}

}

// 0 == not found, 1 == found, needs home, 2 == completed
func (tile *qtile) move(id uint32, bb BoundingBoxer, old, newb BoundingBox) int {
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(old) {
		return 0
	}

	for vidx, v := range tile.contents {
		if id == v.BoxID() {
			if tile.Intersects(newb) {
				return 2
			}
			// REMOVE IT
			tile.contents = append(tile.contents[:vidx], tile.contents[vidx+1:]...)
			return 1
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			cr := child.move(id, bb, old, newb)
			// Not found, continue searching
			if cr == 0 {
				continue
			}
			// Found&Handled, return now!
			if cr == 2 {
				return 2
			}
			// Found but not inserted
			if !tile.Intersects(newb) {
				// New loc doesn't fit in here, pass it up!
				return 1
			}
			// Add new loc here!
			tile.add(bb)
			return 2
		}
	}

	return 0
}

func (tile *qtile) remove(qbox BoundingBox, id uint32) bool {
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(qbox) {
		return false
	}

	// return candidates at this tile
	for vidx, v := range tile.contents {
		if id == v.BoxID() {
			// REMOVE IT
			tile.contents = append(tile.contents[:vidx], tile.contents[vidx+1:]...)
			return true
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			if child.remove(qbox, id) {
				return true
			}
		}
	}

	return false
}

func (tile *qtile) query(qbox BoundingBox) []BoundingBoxer {
	ret := []BoundingBoxer{}
	// end recursion if this tile does not intersect the query range
	if !tile.Intersects(qbox) {
		return ret
	}

	// return candidates at this tile
	for _, v := range tile.contents {
		if qbox.Intersects(v.Bounds()) {
			ret = append(ret, v)
		}
	}

	// recurse into childs (if any)
	if tile.childs[topRightTile] != nil {
		for _, child := range tile.childs {
			ret = append(ret, child.query(qbox)...)
		}
	}

	return ret
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"syscall"
	"time"
)

type LocalizedEP struct {
	EP      *EndPointInfo
	LocalFD *os.File
}

type LocalInfo struct {
	A, B LocalizedEP
}

type EndPoint struct {
	PID int
	FD  int
}

type NetAddr struct {
	IP   string
	Port int
}

type EndPointInfo struct {
	EP         EndPoint
	Info       *LocalInfo
	KludgePair *EndPointInfo
	S_CRC      int
	R_CRC      int
	Src        NetAddr
	Dst        NetAddr
	IsAccept   bool
	Start      time.Time
	End        time.Time
	RefCount   int
	ID         int
}

type IPCContext struct {
	EPMap  map[int]*EndPointInfo
	Lock   sync.Mutex
	FreeID int
	// Used for Endpoint sync kludge
	WaitingEPI  *EndPointInfo
	WaitingTime time.Time
}

func InvalidAddr() NetAddr {
	return NetAddr{"", -1}
}

func (N *NetAddr) isValid() bool {
	return N.Port != -1
}

func (E *EndPointInfo) matchesWithoutCRC(R *EndPointInfo) bool {
	// Not enough information to say.
	if !E.Src.isValid() || !R.Src.isValid() {
		return false
	}
	// If already has a pair, also nothing to be done here
	if E.KludgePair != nil || R.KludgePair != nil {
		return false
	}

	if E.IsAccept == R.IsAccept {
		return false
	}
	if E.Src != R.Dst || E.Dst != R.Src {
		return false
	}

	// Use "IsAccept" to designate client/server
	Client, Server := E, R
	if !E.IsAccept {
		Client, Server = R, E
	}

	// Hmm, might not actually matter which is which
	// looking at the code below.  Oh well O:)

	if Client.Start.After(Server.End) {
		// Accept returned before connect() started, definitely not valid
		return false
	}
	if Server.Start.After(Client.End) {
		// connect() finished before accept was called, also not valid.
		// XXX: Nope, this definitely can happen.  This might happen generally,
		//      but can easily happen with non-blocking accept().
		// return false
	}

	// TODO: Check time delta? Or is this enough?

	return true
}
func (E *EndPointInfo) matches(R *EndPointInfo) bool {
	return E.matchesWithoutCRC(R) &&
		E.S_CRC == R.R_CRC && E.R_CRC == R.S_CRC
}

func NewContext() *IPCContext {
	C := &IPCContext{}
	C.EPMap = make(map[int]*EndPointInfo)
	return C
}

func (C *IPCContext) register(PID, FD int) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	ID := C.FreeID

	EPI := EndPointInfo{EndPoint{PID, FD}, nil,
		nil,           /* kludge pair */
		0,             /* S_CRC */
		0,             /* R_CRC */
		InvalidAddr(), /* Src */
		InvalidAddr(), /* Dst*/
		false,         /* IsAccept */
		time.Time{},   /* Start */
		time.Time{},   /* End */
		1,             /* refcnt */
		ID}

	C.EPMap[ID] = &EPI

	// Find next free ID
	used := true
	for used {
		C.FreeID++
		_, used = C.EPMap[C.FreeID]
	}

	return ID, nil
}

func (C *IPCContext) localize(LID, RID int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	LEP, exist := C.EPMap[LID]
	if !exist {
		return errors.New("Invalid Local ID")
	}
	REP, exist := C.EPMap[RID]
	if !exist {
		return errors.New("Invalid Remote ID")
	}

	if LEP.Info != REP.Info {
		return errors.New("Attempt to localize already localized FD?")
	}
	if LEP.Info != nil {
		// These have already been localized, with same endpoints.  All is well.
		return nil
	}

	// Okay, spawn connected pair of sockets for these
	LFD, RFD, err := Socketpair(syscall.SOCK_STREAM)
	if err != nil {
		return err
	}

	LEP_A, LEP_B := LocalizedEP{LEP, LFD}, LocalizedEP{REP, RFD}
	if RID < LID {
		LEP_B, LEP_A = LEP_A, LEP_B
	}

	LI := &LocalInfo{LEP_A, LEP_B}
	LEP.Info = LI
	REP.Info = LI

	return nil
}

func (C *IPCContext) getLocalFD(ID int) (*os.File, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EP, exist := C.EPMap[ID]
	if !exist {
		return nil, errors.New("Invalid ID")
	}

	if EP.Info == nil {
		return nil, errors.New("Requested local FD for non-localized Endpoint")
	}

	if EP.Info.A.EP == EP {
		return EP.Info.A.LocalFD, nil
	}
	if EP.Info.B.EP == EP {
		return EP.Info.B.LocalFD, nil
	}

	return nil, errors.New("LocalInfo mismatch: Endpoint not found??")
}

func (C *IPCContext) unregister(ID int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	EPI.RefCount--
	if EPI.RefCount > 0 {
		// More references, leave it registered
		return nil
	}

	// Remove enties from map
	delete(C.EPMap, ID)

	if ID < C.FreeID {
		C.FreeID = ID
	}

	// TODO: "Un-localize" endpoint?
	if EPI.Info != nil {
		// TODO: Close as part of handing to endpoints?
		EPI.Info.A.LocalFD.Close()
		EPI.Info.B.LocalFD.Close()
	}

	if C.WaitingEPI == EPI {
		C.WaitingEPI = nil
	}

	return nil
}

func (C *IPCContext) removeall(PID int) int {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	count := 0

	RemoveIDs := []int{}
	RemoveEPIs := []*EndPointInfo{}

	// TODO: reregistration means an endpoint could
	// have multiple owning processes, handle this!
	// This all really needs a do-over! O:)
	for k, v := range C.EPMap {
		if v.EP.PID == PID {
			RemoveIDs = append(RemoveIDs, k)
			RemoveEPIs = append(RemoveEPIs, v)
			count++
		}
	}

	for _, ID := range RemoveIDs {
		delete(C.EPMap, ID)
	}
	for _, EPI := range RemoveEPIs {
		if EPI.Info != nil {
			// TODO: Close as part of handing to endpoints?
			EPI.Info.A.LocalFD.Close()
			EPI.Info.B.LocalFD.Close()
		}

		if C.WaitingEPI == EPI {
			C.WaitingEPI = nil
		}
	}

	return count
}

func (C *IPCContext) pairkludge(ID int) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// Otherwise, is there a pair candidate waiting?
	Waiting := C.WaitingEPI

	if Waiting != nil {
		if time.Since(C.WaitingTime) >= 100*time.Millisecond {
			C.WaitingEPI = nil
			Waiting = nil
		}
	}

	if Waiting != nil && Waiting != EPI {
		EPI.KludgePair = Waiting
		Waiting.KludgePair = EPI
		C.WaitingEPI = nil
		return Waiting.ID, nil
	}

	// Nope, well track this in case someone
	// comes looking for this unpaired endpoint:

	C.WaitingEPI = EPI
	C.WaitingTime = time.Now()

	return ID, nil
}

func (C *IPCContext) reregister(ID, PID, FD int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	EPI.RefCount++

	return nil
}

func (C *IPCContext) crc_match(ID, S_CRC, R_CRC int, LastTry bool) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// TODO: Zero is a valid CRC value!
	if EPI.S_CRC != 0 || EPI.R_CRC != 0 {
		if EPI.S_CRC != S_CRC && EPI.R_CRC != R_CRC {
			return ID, errors.New("CRC match attempted with changed values")
		}
	}

	EPI.S_CRC = S_CRC
	EPI.R_CRC = R_CRC

	MatchID := -1
	for k, v := range C.EPMap {
		if k == ID {
			continue
		}
		if v.KludgePair != nil {
			continue
		}
		if v.S_CRC == R_CRC && v.R_CRC == S_CRC {
			MatchID = k
			break
		}
	}
	// NOPAIR
	if MatchID == -1 {
		// If this is the last time the program
		// will attempt to find its communication pair,
		// remove the CRC information to prevent pairing.
		if LastTry {
			EPI.S_CRC = 0
			EPI.R_CRC = 0
		}
		return ID, nil
	}

	Match := C.EPMap[MatchID]
	EPI.KludgePair = Match
	Match.KludgePair = EPI

	return MatchID, nil
}

func (C *IPCContext) endpoint_info(ID int, Src, Dst NetAddr, Start, End time.Time, IsAccept bool) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	// TODO: Access same clock ourselves to verify updates?

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	if EPI.KludgePair != nil {
		return errors.New("Cannot update info for paired endpoint")
	}

	if EPI.Src.isValid() || EPI.Dst.isValid() {
		if EPI.Src != Src || EPI.Dst != Dst {
			return errors.New("cannot change address")
		}
		if EPI.IsAccept != IsAccept {
			return errors.New("cannot change is_accept")
		}
		if EPI.Start != Start || EPI.End != EPI.End {
			return errors.New("cannot change timings")
		}
	}

	EPI.Src = Src
	EPI.Dst = Dst
	EPI.Start = Start
	EPI.End = End
	EPI.IsAccept = IsAccept

	return nil
}

func (C *IPCContext) find_pair(ID, S_CRC, R_CRC int, LastTry bool) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// XXX: Zero is a valid CRC value!!
	// If we already received CRC information, ensure it's the same
	if EPI.S_CRC != 0 || EPI.R_CRC != 0 {
		if EPI.S_CRC != S_CRC && EPI.R_CRC != R_CRC {
			return ID, errors.New("pairing attempted with changed CRC values")
		}
	}

	if !EPI.Src.isValid() || !EPI.Dst.isValid() {
		return ID, errors.New("pairing without endpoint information")
	}

	EPI.S_CRC = S_CRC
	EPI.R_CRC = R_CRC

	// Find matches ignoring timing information and crc
	Matches := []int{}

	for k, v := range C.EPMap {
		if k == ID {
			continue
		}
		if EPI.matchesWithoutCRC(v) {
			Matches = append(Matches, k)
		}
	}

	if len(Matches) > 1 {
		return ID, errors.New("too many potential matches")
	}
	if len(Matches) > 0 {
		MatchID := Matches[0]
		Match := C.EPMap[MatchID]
		// Try to find endpoints that could
		// be matched with our potential match.
		Dups := []int{}
		for k, v := range C.EPMap {
			if k == ID {
				continue
			}
			if Match.matchesWithoutCRC(v) {
				Dups = append(Dups, k)
			}
		}

		if len(Dups) > 0 {
			return ID, errors.New("potential dup detected")
		}

		// No dups! Let's check CRC:
		if EPI.matches(Match) {
			EPI.KludgePair = Match
			Match.KludgePair = EPI
			return MatchID, nil
		}
	}
	// NOPAIR
	// If this is the last time the program
	// will attempt to find its communication pair,
	// remove the CRC information to prevent pairing.
	if LastTry {
		EPI.S_CRC = 0
		EPI.R_CRC = 0
	}
	return ID, nil
}
<commit_msg>ipcd: Fix server/client naming mixup, didn't matter previously.<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"sync"
	"syscall"
	"time"
)

type LocalizedEP struct {
	EP      *EndPointInfo
	LocalFD *os.File
}

type LocalInfo struct {
	A, B LocalizedEP
}

type EndPoint struct {
	PID int
	FD  int
}

type NetAddr struct {
	IP   string
	Port int
}

type EndPointInfo struct {
	EP         EndPoint
	Info       *LocalInfo
	KludgePair *EndPointInfo
	S_CRC      int
	R_CRC      int
	Src        NetAddr
	Dst        NetAddr
	IsAccept   bool
	Start      time.Time
	End        time.Time
	RefCount   int
	ID         int
}

type IPCContext struct {
	EPMap  map[int]*EndPointInfo
	Lock   sync.Mutex
	FreeID int
	// Used for Endpoint sync kludge
	WaitingEPI  *EndPointInfo
	WaitingTime time.Time
}

func InvalidAddr() NetAddr {
	return NetAddr{"", -1}
}

func (N *NetAddr) isValid() bool {
	return N.Port != -1
}

func (E *EndPointInfo) matchesWithoutCRC(R *EndPointInfo) bool {
	// Not enough information to say.
	if !E.Src.isValid() || !R.Src.isValid() {
		return false
	}
	// If already has a pair, also nothing to be done here
	if E.KludgePair != nil || R.KludgePair != nil {
		return false
	}

	if E.IsAccept == R.IsAccept {
		return false
	}
	if E.Src != R.Dst || E.Dst != R.Src {
		return false
	}

	// Use "IsAccept" to designate client/server
	Client, Server := E, R
	if E.IsAccept {
		Client, Server = R, E
	}

	// Hmm, might not actually matter which is which
	// looking at the code below.  Oh well O:)

	if Client.Start.After(Server.End) {
		// Accept returned before connect() started, definitely not valid
		return false
	}
	if Server.Start.After(Client.End) {
		// connect() finished before accept was called, also not valid.
		// XXX: Nope, this definitely can happen.  This might happen generally,
		//      but can easily happen with non-blocking accept().
		// return false
	}

	// TODO: Check time delta? Or is this enough?

	return true
}
func (E *EndPointInfo) matches(R *EndPointInfo) bool {
	return E.matchesWithoutCRC(R) &&
		E.S_CRC == R.R_CRC && E.R_CRC == R.S_CRC
}

func NewContext() *IPCContext {
	C := &IPCContext{}
	C.EPMap = make(map[int]*EndPointInfo)
	return C
}

func (C *IPCContext) register(PID, FD int) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	ID := C.FreeID

	EPI := EndPointInfo{EndPoint{PID, FD}, nil,
		nil,           /* kludge pair */
		0,             /* S_CRC */
		0,             /* R_CRC */
		InvalidAddr(), /* Src */
		InvalidAddr(), /* Dst*/
		false,         /* IsAccept */
		time.Time{},   /* Start */
		time.Time{},   /* End */
		1,             /* refcnt */
		ID}

	C.EPMap[ID] = &EPI

	// Find next free ID
	used := true
	for used {
		C.FreeID++
		_, used = C.EPMap[C.FreeID]
	}

	return ID, nil
}

func (C *IPCContext) localize(LID, RID int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	LEP, exist := C.EPMap[LID]
	if !exist {
		return errors.New("Invalid Local ID")
	}
	REP, exist := C.EPMap[RID]
	if !exist {
		return errors.New("Invalid Remote ID")
	}

	if LEP.Info != REP.Info {
		return errors.New("Attempt to localize already localized FD?")
	}
	if LEP.Info != nil {
		// These have already been localized, with same endpoints.  All is well.
		return nil
	}

	// Okay, spawn connected pair of sockets for these
	LFD, RFD, err := Socketpair(syscall.SOCK_STREAM)
	if err != nil {
		return err
	}

	LEP_A, LEP_B := LocalizedEP{LEP, LFD}, LocalizedEP{REP, RFD}
	if RID < LID {
		LEP_B, LEP_A = LEP_A, LEP_B
	}

	LI := &LocalInfo{LEP_A, LEP_B}
	LEP.Info = LI
	REP.Info = LI

	return nil
}

func (C *IPCContext) getLocalFD(ID int) (*os.File, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EP, exist := C.EPMap[ID]
	if !exist {
		return nil, errors.New("Invalid ID")
	}

	if EP.Info == nil {
		return nil, errors.New("Requested local FD for non-localized Endpoint")
	}

	if EP.Info.A.EP == EP {
		return EP.Info.A.LocalFD, nil
	}
	if EP.Info.B.EP == EP {
		return EP.Info.B.LocalFD, nil
	}

	return nil, errors.New("LocalInfo mismatch: Endpoint not found??")
}

func (C *IPCContext) unregister(ID int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	EPI.RefCount--
	if EPI.RefCount > 0 {
		// More references, leave it registered
		return nil
	}

	// Remove enties from map
	delete(C.EPMap, ID)

	if ID < C.FreeID {
		C.FreeID = ID
	}

	// TODO: "Un-localize" endpoint?
	if EPI.Info != nil {
		// TODO: Close as part of handing to endpoints?
		EPI.Info.A.LocalFD.Close()
		EPI.Info.B.LocalFD.Close()
	}

	if C.WaitingEPI == EPI {
		C.WaitingEPI = nil
	}

	return nil
}

func (C *IPCContext) removeall(PID int) int {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	count := 0

	RemoveIDs := []int{}
	RemoveEPIs := []*EndPointInfo{}

	// TODO: reregistration means an endpoint could
	// have multiple owning processes, handle this!
	// This all really needs a do-over! O:)
	for k, v := range C.EPMap {
		if v.EP.PID == PID {
			RemoveIDs = append(RemoveIDs, k)
			RemoveEPIs = append(RemoveEPIs, v)
			count++
		}
	}

	for _, ID := range RemoveIDs {
		delete(C.EPMap, ID)
	}
	for _, EPI := range RemoveEPIs {
		if EPI.Info != nil {
			// TODO: Close as part of handing to endpoints?
			EPI.Info.A.LocalFD.Close()
			EPI.Info.B.LocalFD.Close()
		}

		if C.WaitingEPI == EPI {
			C.WaitingEPI = nil
		}
	}

	return count
}

func (C *IPCContext) pairkludge(ID int) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// Otherwise, is there a pair candidate waiting?
	Waiting := C.WaitingEPI

	if Waiting != nil {
		if time.Since(C.WaitingTime) >= 100*time.Millisecond {
			C.WaitingEPI = nil
			Waiting = nil
		}
	}

	if Waiting != nil && Waiting != EPI {
		EPI.KludgePair = Waiting
		Waiting.KludgePair = EPI
		C.WaitingEPI = nil
		return Waiting.ID, nil
	}

	// Nope, well track this in case someone
	// comes looking for this unpaired endpoint:

	C.WaitingEPI = EPI
	C.WaitingTime = time.Now()

	return ID, nil
}

func (C *IPCContext) reregister(ID, PID, FD int) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	EPI.RefCount++

	return nil
}

func (C *IPCContext) crc_match(ID, S_CRC, R_CRC int, LastTry bool) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// TODO: Zero is a valid CRC value!
	if EPI.S_CRC != 0 || EPI.R_CRC != 0 {
		if EPI.S_CRC != S_CRC && EPI.R_CRC != R_CRC {
			return ID, errors.New("CRC match attempted with changed values")
		}
	}

	EPI.S_CRC = S_CRC
	EPI.R_CRC = R_CRC

	MatchID := -1
	for k, v := range C.EPMap {
		if k == ID {
			continue
		}
		if v.KludgePair != nil {
			continue
		}
		if v.S_CRC == R_CRC && v.R_CRC == S_CRC {
			MatchID = k
			break
		}
	}
	// NOPAIR
	if MatchID == -1 {
		// If this is the last time the program
		// will attempt to find its communication pair,
		// remove the CRC information to prevent pairing.
		if LastTry {
			EPI.S_CRC = 0
			EPI.R_CRC = 0
		}
		return ID, nil
	}

	Match := C.EPMap[MatchID]
	EPI.KludgePair = Match
	Match.KludgePair = EPI

	return MatchID, nil
}

func (C *IPCContext) endpoint_info(ID int, Src, Dst NetAddr, Start, End time.Time, IsAccept bool) error {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	// TODO: Access same clock ourselves to verify updates?

	EPI, exist := C.EPMap[ID]
	if !exist {
		return errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	if EPI.KludgePair != nil {
		return errors.New("Cannot update info for paired endpoint")
	}

	if EPI.Src.isValid() || EPI.Dst.isValid() {
		if EPI.Src != Src || EPI.Dst != Dst {
			return errors.New("cannot change address")
		}
		if EPI.IsAccept != IsAccept {
			return errors.New("cannot change is_accept")
		}
		if EPI.Start != Start || EPI.End != EPI.End {
			return errors.New("cannot change timings")
		}
	}

	EPI.Src = Src
	EPI.Dst = Dst
	EPI.Start = Start
	EPI.End = End
	EPI.IsAccept = IsAccept

	return nil
}

func (C *IPCContext) find_pair(ID, S_CRC, R_CRC int, LastTry bool) (int, error) {
	C.Lock.Lock()
	defer C.Lock.Unlock()

	EPI, exist := C.EPMap[ID]
	if !exist {
		return ID, errors.New(fmt.Sprintf("Invalid Endpoint ID '%d'", ID))
	}

	// If already kludge-paired this, return its kludge-pal
	if EPI.KludgePair != nil {
		return EPI.KludgePair.ID, nil
	}

	// XXX: Zero is a valid CRC value!!
	// If we already received CRC information, ensure it's the same
	if EPI.S_CRC != 0 || EPI.R_CRC != 0 {
		if EPI.S_CRC != S_CRC && EPI.R_CRC != R_CRC {
			return ID, errors.New("pairing attempted with changed CRC values")
		}
	}

	if !EPI.Src.isValid() || !EPI.Dst.isValid() {
		return ID, errors.New("pairing without endpoint information")
	}

	EPI.S_CRC = S_CRC
	EPI.R_CRC = R_CRC

	// Find matches ignoring timing information and crc
	Matches := []int{}

	for k, v := range C.EPMap {
		if k == ID {
			continue
		}
		if EPI.matchesWithoutCRC(v) {
			Matches = append(Matches, k)
		}
	}

	if len(Matches) > 1 {
		return ID, errors.New("too many potential matches")
	}
	if len(Matches) > 0 {
		MatchID := Matches[0]
		Match := C.EPMap[MatchID]
		// Try to find endpoints that could
		// be matched with our potential match.
		Dups := []int{}
		for k, v := range C.EPMap {
			if k == ID {
				continue
			}
			if Match.matchesWithoutCRC(v) {
				Dups = append(Dups, k)
			}
		}

		if len(Dups) > 0 {
			return ID, errors.New("potential dup detected")
		}

		// No dups! Let's check CRC:
		if EPI.matches(Match) {
			EPI.KludgePair = Match
			Match.KludgePair = EPI
			return MatchID, nil
		}
	}
	// NOPAIR
	// If this is the last time the program
	// will attempt to find its communication pair,
	// remove the CRC information to prevent pairing.
	if LastTry {
		EPI.S_CRC = 0
		EPI.R_CRC = 0
	}
	return ID, nil
}
<|endoftext|>


<commit_before>package build

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestDescription(t *testing.T) {
	assert.NotEmpty(t, Pipe{}.Description())
}
<commit_msg>more tests<commit_after>package build

import (
	"runtime"
	"testing"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/stretchr/testify/assert"
)

func TestDescription(t *testing.T) {
	assert.NotEmpty(t, Pipe{}.Description())
}

func TestRun(t *testing.T) {
	assert.NoError(t, run(runtime.GOOS, runtime.GOARCH, []string{"go", "list", "./..."}))
}

func TestRunInvalidCommand(t *testing.T) {
	assert.Error(t, run(runtime.GOOS, runtime.GOARCH, []string{"gggggo", "nope"}))
}

func TestBuild(t *testing.T) {
	assert := assert.New(t)
	var config = config.Project{
		Build: config.Build{
			Binary: "testing",
			Flags:  "-n",
		},
	}
	var ctx = &context.Context{
		Config: config,
	}
	assert.NoError(build("build_test", runtime.GOOS, runtime.GOARCH, ctx))
}
<|endoftext|>


<commit_before>package main

import "github.com/dmulholland/clio/go/clio"

import (
    "fmt"
    "os"
    "path/filepath"
)

import (
    "github.com/dmulholland/ironclad/ironconfig"
)

// Application version number.
const version = "0.14.0.dev"

// Application help text.
var helptext = fmt.Sprintf(`
Usage: %s [FLAGS] [COMMAND]

  A utility for creating and managing encrypted password databases.

Flags:
  --help            Print the application's help text and exit.
  --version         Print the application's version number and exit.

Commands:
  add               Add a new entry to a database.
  config            Set or print a configuration option.
  decrypt           Decrypt a file.
  delete            Delete entries from a database.
  dump              Dump a database's internal JSON data store.
  edit              Edit an existing database entry.
  encrypt           Encrypt a file.
  export            Export entries from a database.
  gen               Generate a new random password.
  import            Import entries into a database.
  list              List database entries.
  new               Create a new database.
  pass              Copy a password to the clipboard.
  purge             Purge deleted entries from a database.
  tags              List database tags.
  user              Copy a username to the clipboard.

Command Help:
  help <command>    Print the specified command's help text and exit.
`, filepath.Base(os.Args[0]))

// Path to the application's configuration directory.
var configdir = filepath.Join(os.Getenv("HOME"), ".config", "ironclad")

// Path to the application's configuration file.
var configfile = filepath.Join(configdir, "goconfig.toml")

// Default port for the cached-password server.
const defaultport = "54313"

// Application entry point.
func main() {

    // Set the location of the application's configuration file.
    ironconfig.ConfigFile = configfile

    // Instantiate an argument parser.
    parser := clio.NewParser(helptext, version)

    // Register the 'add' command.
    addParser := parser.AddCmd("add", addHelp, addCallback)
    addParser.AddStr("file f", "")
    addParser.AddStr("masterpass", "")

    // Register the 'cache' command.
    parser.AddCmd("cache", cacheHelp, cacheCallback)

    // Register the 'config' command.
    parser.AddCmd("config", configHelp, configCallback)

    // Register the 'decrypt' command.
    decryptParser := parser.AddCmd("decrypt", decryptHelp, decryptCallback)
    decryptParser.AddStr("out o", "")

    // Register the 'delete' command.
    deleteParser := parser.AddCmd("delete", deleteHelp, deleteCallback)
    deleteParser.AddStr("file f", "")
    deleteParser.AddStr("masterpass", "")

    // Register the 'dump' command.
    dumpParser := parser.AddCmd("dump", dumpHelp, dumpCallback)
    dumpParser.AddStr("file f", "")
    dumpParser.AddStr("masterpass", "")

    // Register the 'edit' command.
    editParser := parser.AddCmd("edit", editHelp, editCallback)
    editParser.AddStr("file f", "")
    editParser.AddStr("masterpass", "")
    editParser.AddFlag("title t")
    editParser.AddFlag("url l")
    editParser.AddFlag("username u")
    editParser.AddFlag("password p")
    editParser.AddFlag("notes n")
    editParser.AddFlag("tags s")
    editParser.AddFlag("email e")

    // Register the 'encrypt' command.
    encryptParser := parser.AddCmd("encrypt", encryptHelp, encryptCallback)
    encryptParser.AddStr("out o", "")

    // Register the 'export' command.
    exportParser := parser.AddCmd("export", exportHelp, exportCallback)
    exportParser.AddStr("file f", "")
    exportParser.AddStr("masterpass", "")
    exportParser.AddStr("tag t", "")

    // Register the 'gen' command.
    genParser := parser.AddCmd("gen", genHelp, genCallback)
    genParser.AddStr("file f", "")
    genParser.AddStr("masterpass", "")
    genParser.AddFlag("digits d")
    genParser.AddFlag("exclude-similar x")
    genParser.AddFlag("lowercase l")
    genParser.AddFlag("symbols s")
    genParser.AddFlag("uppercase u")
    genParser.AddFlag("readable r")
    genParser.AddFlag("print p")

    // Register the 'import' command.
    importParser := parser.AddCmd("import", importHelp, importCallback)
    importParser.AddStr("file f", "")
    importParser.AddStr("masterpass", "")

    // Register the 'list' command.
    listParser := parser.AddCmd("list show", listHelp, listCallback)
    listParser.AddStr("file f", "")
    listParser.AddStr("masterpass", "")
    listParser.AddStr("tag t", "")
    listParser.AddFlag("verbose v")

    // Register the 'new' command.
    newParser := parser.AddCmd("new", newHelp, newCallback)
    newParser.AddStr("masterpass", "")

    // Register the 'pass' command.
    passParser := parser.AddCmd("pass", passHelp, passCallback)
    passParser.AddStr("file f", "")
    passParser.AddStr("masterpass", "")
    passParser.AddFlag("readable r")
    passParser.AddFlag("print p")

    // Register the 'purge' command.
    purgeParser := parser.AddCmd("purge", purgeHelp, purgeCallback)
    purgeParser.AddStr("file f", "")
    purgeParser.AddStr("masterpass", "")

    // Register the 'tags' command.
    tagsParser := parser.AddCmd("tags", tagsHelp, tagsCallback)
    tagsParser.AddStr("file f", "")
    tagsParser.AddStr("masterpass", "")

    // Register the 'user' command.
    userParser := parser.AddCmd("user", userHelp, userCallback)
    userParser.AddStr("file f", "")
    userParser.AddStr("masterpass", "")
    userParser.AddFlag("print p")

    // Parse the application's command line arguments.  If a command is found,
    // control will be passed to its callback function.
    parser.Parse()

    // If no command has been found, print the help text and exit.
    if !parser.HasCmd() {
        parser.Help()
    }
}
<commit_msg>Bump version to 0.14.0<commit_after>package main

import "github.com/dmulholland/clio/go/clio"

import (
    "fmt"
    "os"
    "path/filepath"
)

import (
    "github.com/dmulholland/ironclad/ironconfig"
)

// Application version number.
const version = "0.14.0"

// Application help text.
var helptext = fmt.Sprintf(`
Usage: %s [FLAGS] [COMMAND]

  A utility for creating and managing encrypted password databases.

Flags:
  --help            Print the application's help text and exit.
  --version         Print the application's version number and exit.

Commands:
  add               Add a new entry to a database.
  config            Set or print a configuration option.
  decrypt           Decrypt a file.
  delete            Delete entries from a database.
  dump              Dump a database's internal JSON data store.
  edit              Edit an existing database entry.
  encrypt           Encrypt a file.
  export            Export entries from a database.
  gen               Generate a new random password.
  import            Import entries into a database.
  list              List database entries.
  new               Create a new database.
  pass              Copy a password to the clipboard.
  purge             Purge deleted entries from a database.
  tags              List database tags.
  user              Copy a username to the clipboard.

Command Help:
  help <command>    Print the specified command's help text and exit.
`, filepath.Base(os.Args[0]))

// Path to the application's configuration directory.
var configdir = filepath.Join(os.Getenv("HOME"), ".config", "ironclad")

// Path to the application's configuration file.
var configfile = filepath.Join(configdir, "goconfig.toml")

// Default port for the cached-password server.
const defaultport = "54313"

// Application entry point.
func main() {

    // Set the location of the application's configuration file.
    ironconfig.ConfigFile = configfile

    // Instantiate an argument parser.
    parser := clio.NewParser(helptext, version)

    // Register the 'add' command.
    addParser := parser.AddCmd("add", addHelp, addCallback)
    addParser.AddStr("file f", "")
    addParser.AddStr("masterpass", "")

    // Register the 'cache' command.
    parser.AddCmd("cache", cacheHelp, cacheCallback)

    // Register the 'config' command.
    parser.AddCmd("config", configHelp, configCallback)

    // Register the 'decrypt' command.
    decryptParser := parser.AddCmd("decrypt", decryptHelp, decryptCallback)
    decryptParser.AddStr("out o", "")

    // Register the 'delete' command.
    deleteParser := parser.AddCmd("delete", deleteHelp, deleteCallback)
    deleteParser.AddStr("file f", "")
    deleteParser.AddStr("masterpass", "")

    // Register the 'dump' command.
    dumpParser := parser.AddCmd("dump", dumpHelp, dumpCallback)
    dumpParser.AddStr("file f", "")
    dumpParser.AddStr("masterpass", "")

    // Register the 'edit' command.
    editParser := parser.AddCmd("edit", editHelp, editCallback)
    editParser.AddStr("file f", "")
    editParser.AddStr("masterpass", "")
    editParser.AddFlag("title t")
    editParser.AddFlag("url l")
    editParser.AddFlag("username u")
    editParser.AddFlag("password p")
    editParser.AddFlag("notes n")
    editParser.AddFlag("tags s")
    editParser.AddFlag("email e")

    // Register the 'encrypt' command.
    encryptParser := parser.AddCmd("encrypt", encryptHelp, encryptCallback)
    encryptParser.AddStr("out o", "")

    // Register the 'export' command.
    exportParser := parser.AddCmd("export", exportHelp, exportCallback)
    exportParser.AddStr("file f", "")
    exportParser.AddStr("masterpass", "")
    exportParser.AddStr("tag t", "")

    // Register the 'gen' command.
    genParser := parser.AddCmd("gen", genHelp, genCallback)
    genParser.AddStr("file f", "")
    genParser.AddStr("masterpass", "")
    genParser.AddFlag("digits d")
    genParser.AddFlag("exclude-similar x")
    genParser.AddFlag("lowercase l")
    genParser.AddFlag("symbols s")
    genParser.AddFlag("uppercase u")
    genParser.AddFlag("readable r")
    genParser.AddFlag("print p")

    // Register the 'import' command.
    importParser := parser.AddCmd("import", importHelp, importCallback)
    importParser.AddStr("file f", "")
    importParser.AddStr("masterpass", "")

    // Register the 'list' command.
    listParser := parser.AddCmd("list show", listHelp, listCallback)
    listParser.AddStr("file f", "")
    listParser.AddStr("masterpass", "")
    listParser.AddStr("tag t", "")
    listParser.AddFlag("verbose v")

    // Register the 'new' command.
    newParser := parser.AddCmd("new", newHelp, newCallback)
    newParser.AddStr("masterpass", "")

    // Register the 'pass' command.
    passParser := parser.AddCmd("pass", passHelp, passCallback)
    passParser.AddStr("file f", "")
    passParser.AddStr("masterpass", "")
    passParser.AddFlag("readable r")
    passParser.AddFlag("print p")

    // Register the 'purge' command.
    purgeParser := parser.AddCmd("purge", purgeHelp, purgeCallback)
    purgeParser.AddStr("file f", "")
    purgeParser.AddStr("masterpass", "")

    // Register the 'tags' command.
    tagsParser := parser.AddCmd("tags", tagsHelp, tagsCallback)
    tagsParser.AddStr("file f", "")
    tagsParser.AddStr("masterpass", "")

    // Register the 'user' command.
    userParser := parser.AddCmd("user", userHelp, userCallback)
    userParser.AddStr("file f", "")
    userParser.AddStr("masterpass", "")
    userParser.AddFlag("print p")

    // Parse the application's command line arguments.  If a command is found,
    // control will be passed to its callback function.
    parser.Parse()

    // If no command has been found, print the help text and exit.
    if !parser.HasCmd() {
        parser.Help()
    }
}
<|endoftext|>


<commit_before>package amazon

import (
	"errors"
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/waitstate"
	"strings"

	"github.com/mitchellh/goamz/ec2"
	"golang.org/x/net/context"
)

func (a *Amazon) Start(ctx context.Context) (ec2.Instance, error) {
	// if we have eventer, use it
	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Starting machine",
			Status:     machinestate.Starting,
			Percentage: 10,
		})
	}

	_, err := a.Client.StartInstances(a.Id())
	if err != nil {
		return ec2.Instance{}, err
	}

	var instance ec2.Instance
	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err = a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "start",
		Start:     25,
		Finish:    60,
	}

	if err := ws.Wait(); err != nil {
		return ec2.Instance{}, err
	}

	return instance, nil
}

func (a *Amazon) Stop(ctx context.Context) error {
	// if we have eventer, use it
	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Stopping machine",
			Status:     machinestate.Stopping,
			Percentage: 10,
		})
	}

	_, err := a.Client.StopInstances(a.Id())
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "stop",
		Start:     25,
		Finish:    60,
	}

	return ws.Wait()
}

func (a *Amazon) Restart(ctx context.Context) error {
	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Restarting machine",
			Status:     machinestate.Rebooting,
			Percentage: 10,
		})
	}

	_, err := a.Client.RebootInstances(a.Id())
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "restart",
		Start:     25,
		Finish:    60,
	}

	return ws.Wait()
}

func (a *Amazon) Destroy(ctx context.Context, start, finish int) error {
	if a.Id() == "" {
		return errors.New("instance id is empty")
	}

	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Terminating machine",
			Status:     machinestate.Terminating,
			Percentage: start,
		})
	}

	_, err := a.Client.TerminateInstances([]string{a.Id()})
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "destroy",
		Start:     start,
		Finish:    finish,
	}

	return ws.Wait()
}

// StatusToState converts a amazon status to a sensible machinestate.State
// format
func StatusToState(status string) machinestate.State {
	status = strings.ToLower(status)

	// Valid values: pending | running | shutting-down | terminated | stopping | stopped

	switch status {
	case "pending":
		return machinestate.Starting
	case "running":
		return machinestate.Running
	case "stopped":
		return machinestate.Stopped
	case "stopping":
		return machinestate.Stopping
	case "shutting-down":
		return machinestate.Terminating
	case "terminated":
		return machinestate.Terminated
	default:
		return machinestate.Unknown
	}
}
<commit_msg>kloud/amazon: check id for all commands<commit_after>package amazon

import (
	"errors"
	"koding/kites/kloud/eventer"
	"koding/kites/kloud/machinestate"
	"koding/kites/kloud/waitstate"
	"strings"

	"github.com/mitchellh/goamz/ec2"
	"golang.org/x/net/context"
)

var (
	ErrInstanceIdEmpty = errors.New("instance id is empty")
)

func (a *Amazon) Start(ctx context.Context) (ec2.Instance, error) {
	if a.Id() == "" {
		return ec2.Instance{}, ErrInstanceIdEmpty
	}

	// if we have eventer, use it
	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Starting machine",
			Status:     machinestate.Starting,
			Percentage: 10,
		})
	}

	_, err := a.Client.StartInstances(a.Id())
	if err != nil {
		return ec2.Instance{}, err
	}

	var instance ec2.Instance
	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err = a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "start",
		Start:     25,
		Finish:    60,
	}

	if err := ws.Wait(); err != nil {
		return ec2.Instance{}, err
	}

	return instance, nil
}

func (a *Amazon) Stop(ctx context.Context) error {
	if a.Id() == "" {
		return ErrInstanceIdEmpty
	}

	// if we have eventer, use it
	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Stopping machine",
			Status:     machinestate.Stopping,
			Percentage: 10,
		})
	}

	_, err := a.Client.StopInstances(a.Id())
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "stop",
		Start:     25,
		Finish:    60,
	}

	return ws.Wait()
}

func (a *Amazon) Restart(ctx context.Context) error {
	if a.Id() == "" {
		return ErrInstanceIdEmpty
	}

	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Restarting machine",
			Status:     machinestate.Rebooting,
			Percentage: 10,
		})
	}

	_, err := a.Client.RebootInstances(a.Id())
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "restart",
		Start:     25,
		Finish:    60,
	}

	return ws.Wait()
}

func (a *Amazon) Destroy(ctx context.Context, start, finish int) error {
	if a.Id() == "" {
		return ErrInstanceIdEmpty
	}

	ev, withPush := eventer.FromContext(ctx)
	if withPush {
		ev.Push(&eventer.Event{
			Message:    "Terminating machine",
			Status:     machinestate.Terminating,
			Percentage: start,
		})
	}

	_, err := a.Client.TerminateInstances([]string{a.Id()})
	if err != nil {
		return err
	}

	stateFunc := func(currentPercentage int) (machinestate.State, error) {
		instance, err := a.Instance()
		if err != nil {
			return 0, err
		}

		return StatusToState(instance.State.Name), nil
	}

	ws := waitstate.WaitState{
		StateFunc: stateFunc,
		Eventer:   ev,
		Action:    "destroy",
		Start:     start,
		Finish:    finish,
	}

	return ws.Wait()
}

// StatusToState converts a amazon status to a sensible machinestate.State
// format
func StatusToState(status string) machinestate.State {
	status = strings.ToLower(status)

	// Valid values: pending | running | shutting-down | terminated | stopping | stopped

	switch status {
	case "pending":
		return machinestate.Starting
	case "running":
		return machinestate.Running
	case "stopped":
		return machinestate.Stopped
	case "stopping":
		return machinestate.Stopping
	case "shutting-down":
		return machinestate.Terminating
	case "terminated":
		return machinestate.Terminated
	default:
		return machinestate.Unknown
	}
}
<|endoftext|>


<commit_before>package models

var GroupChannelPermissions = map[string]Permission{
	REQUEST_NAME_MESSAGE_UPDATE: Permission{
		Name:           REQUEST_NAME_MESSAGE_UPDATE,
		StatusConstant: Permission_STATUS_ALLOWED,
	},

	REQUEST_NAME_MESSAGE_DELETE: Permission{
		Name:           REQUEST_NAME_MESSAGE_DELETE,
		StatusConstant: Permission_STATUS_ALLOWED,
	},

	REQUEST_NAME_MESSAGE_GET: Permission{
		Name:           REQUEST_NAME_MESSAGE_GET,
		StatusConstant: Permission_STATUS_ALLOWED,
	},
}

var DefaultPermissions = map[string]map[string]Permission{
	Channel_TYPE_GROUP: GroupChannelPermissions,
}

const (
	REQUEST_NAME_MESSAGE_UPDATE = "message-update"
	REQUEST_NAME_MESSAGE_DELETE = "message-delete"
	REQUEST_NAME_MESSAGE_GET    = "message-get"
)

const (
	ModerationChannelCreateLink = "moderation-channel-create-link"
	ModerationChannelGetLink    = "moderation-channel-get-link"
	ModerationChannelDeleteLink = "moderation-channel-delete-link"
	ModerationChannelBlacklist  = "moderation-channel-blacklist"
	ModerationChannelGetRoot    = "moderation-channel-get-root"
)
<commit_msg>socialapi: add handler constant<commit_after>package models

var GroupChannelPermissions = map[string]Permission{
	REQUEST_NAME_MESSAGE_UPDATE: Permission{
		Name:           REQUEST_NAME_MESSAGE_UPDATE,
		StatusConstant: Permission_STATUS_ALLOWED,
	},

	REQUEST_NAME_MESSAGE_DELETE: Permission{
		Name:           REQUEST_NAME_MESSAGE_DELETE,
		StatusConstant: Permission_STATUS_ALLOWED,
	},

	REQUEST_NAME_MESSAGE_GET: Permission{
		Name:           REQUEST_NAME_MESSAGE_GET,
		StatusConstant: Permission_STATUS_ALLOWED,
	},
}

var DefaultPermissions = map[string]map[string]Permission{
	Channel_TYPE_GROUP: GroupChannelPermissions,
}

const (
	REQUEST_NAME_MESSAGE_UPDATE = "message-update"
	REQUEST_NAME_MESSAGE_DELETE = "message-delete"
	REQUEST_NAME_MESSAGE_GET    = "message-get"
)

const (
	ModerationChannelCreateLink = "moderation-channel-create-link"
	ModerationChannelGetLink    = "moderation-channel-get-link"
	ModerationChannelDeleteLink = "moderation-channel-delete-link"
	ModerationChannelBlacklist  = "moderation-channel-blacklist"
	ModerationChannelGetRoot    = "moderation-channel-get-root"
)

const (
	DispatcherEvent = "dispatcher-event"
)
<|endoftext|>


<commit_before>/*
Copyright 2021 The Vitess Authors.

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 vreplication

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql"
)

func insertInitialDataIntoExternalCluster(t *testing.T, conn *mysql.Conn) {
	t.Run("insertInitialData", func(t *testing.T) {
		fmt.Printf("Inserting initial data\n")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(1, 1, 'review1');")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(2, 1, 'review2');")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(3, 2, 'review3');")
		execVtgateQuery(t, conn, "rating:0", "insert into rating(gid, pid, rating) values(1, 1, 4);")
		execVtgateQuery(t, conn, "rating:0", "insert into rating(gid, pid, rating) values(2, 2, 5);")
	})
}

// TestMigrate runs an e2e test for importing from an external cluster using the Mount and Migrate commands.
// We have an anti-pattern in Vitess: vt executables look for an environment variable VTDATAROOT for certain cluster parameters
// like the log directory when they are created. Until this test we just needed a single cluster for e2e tests.
// However now we need to create an external Vitess cluster. For this we need a different VTDATAROOT and
// hence the VTDATAROOT env variable gets overwritten.
// Each time we need to create vt processes in the "other" cluster we need to set the appropriate VTDATAROOT
func TestMigrate(t *testing.T) {
	defaultCellName := "zone1"
	cells := []string{"zone1"}
	allCellNames = "zone1"
	vc = NewVitessCluster(t, "TestMigrate", cells, mainClusterConfig)

	require.NotNil(t, vc)
	defaultReplicas = 0
	defaultRdonly = 0
	defer vc.TearDown(t)

	defaultCell = vc.Cells[defaultCellName]
	vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, defaultReplicas, defaultRdonly, 100)
	vtgate = defaultCell.Vtgates[0]
	require.NotNil(t, vtgate)
	vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.primary", "product", "0"), 1)

	vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort)
	defer vtgateConn.Close()
	verifyClusterHealth(t, vc)
	insertInitialData(t)

	// create external cluster
	extCell := "extcell1"
	extCells := []string{extCell}
	extVc := NewVitessCluster(t, "TestMigrateExternal", extCells, externalClusterConfig)
	require.NotNil(t, extVc)
	defer extVc.TearDown(t)

	extCell2 := extVc.Cells[extCell]
	extVc.AddKeyspace(t, []*Cell{extCell2}, "rating", "0", initialExternalVSchema, initialExternalSchema, 0, 0, 1000)
	extVtgate := extCell2.Vtgates[0]
	require.NotNil(t, extVtgate)

	extVtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.primary", "rating", "0"), 1)
	verifyClusterHealth(t, extVc)
	extVtgateConn := getConnection(t, extVc.ClusterConfig.hostname, extVc.ClusterConfig.vtgateMySQLPort)
	insertInitialDataIntoExternalCluster(t, extVtgateConn)

	var err error
	var output, expected string
	ksWorkflow := "product.e1"

	t.Run("mount external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-topo_type=etcd2",
			fmt.Sprintf("-topo_server=localhost:%d", extVc.ClusterConfig.topoPort), "-topo_root=/vitess/global", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-list"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = "ext1\n"
		require.Equal(t, expected, output)
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-show", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = `{"ClusterName":"ext1","topo_config":{"topo_type":"etcd2","server":"localhost:12379","root":"/vitess/global"}}` + "\n"
		require.Equal(t, expected, output)
	})

	t.Run("migrate from external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "-all", "-cells=extcell1",
			"-source=ext1.rating", "create", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 1)
		validateCount(t, vtgateConn, "product:0", "rating", 2)
		validateCount(t, vtgateConn, "product:0", "review", 3)
		execVtgateQuery(t, extVtgateConn, "rating", "insert into review(rid, pid, review) values(4, 1, 'review4');")
		execVtgateQuery(t, extVtgateConn, "rating", "insert into rating(gid, pid, rating) values(3, 1, 3);")
		time.Sleep(1 * time.Second) // wait for stream to find row
		validateCount(t, vtgateConn, "product:0", "rating", 3)
		validateCount(t, vtgateConn, "product:0", "review", 4)
		vdiff(t, ksWorkflow, "extcell1")

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "complete", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}

		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 0)
	})
	t.Run("cancel migrate workflow", func(t *testing.T) {
		execVtgateQuery(t, vtgateConn, "product", "drop table review,rating")

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "-all", "-auto_start=false", "-cells=extcell1",
			"-source=ext1.rating", "create", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 1)
		validateCount(t, vtgateConn, "product:0", "rating", 0)
		validateCount(t, vtgateConn, "product:0", "review", 0)
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "cancel", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 0)
		var found bool
		found, err = checkIfTableExists(t, vc, "zone1-100", "review")
		require.NoError(t, err)
		require.False(t, found)
		found, err = checkIfTableExists(t, vc, "zone1-100", "rating")
		require.NoError(t, err)
		require.False(t, found)
	})
	t.Run("unmount external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-unmount", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-list"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = "\n"
		require.Equal(t, expected, output)

		output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-show", "ext1")
		require.Errorf(t, err, "there is no vitess cluster named ext1")
	})
}
<commit_msg>Add delay to try to fix flaky vreplication_migrate<commit_after>/*
Copyright 2021 The Vitess Authors.

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 vreplication

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"vitess.io/vitess/go/mysql"
)

func insertInitialDataIntoExternalCluster(t *testing.T, conn *mysql.Conn) {
	t.Run("insertInitialData", func(t *testing.T) {
		fmt.Printf("Inserting initial data\n")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(1, 1, 'review1');")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(2, 1, 'review2');")
		execVtgateQuery(t, conn, "rating:0", "insert into review(rid, pid, review) values(3, 2, 'review3');")
		execVtgateQuery(t, conn, "rating:0", "insert into rating(gid, pid, rating) values(1, 1, 4);")
		execVtgateQuery(t, conn, "rating:0", "insert into rating(gid, pid, rating) values(2, 2, 5);")
	})
}

// TestMigrate runs an e2e test for importing from an external cluster using the Mount and Migrate commands.
// We have an anti-pattern in Vitess: vt executables look for an environment variable VTDATAROOT for certain cluster parameters
// like the log directory when they are created. Until this test we just needed a single cluster for e2e tests.
// However now we need to create an external Vitess cluster. For this we need a different VTDATAROOT and
// hence the VTDATAROOT env variable gets overwritten.
// Each time we need to create vt processes in the "other" cluster we need to set the appropriate VTDATAROOT
func TestMigrate(t *testing.T) {
	defaultCellName := "zone1"
	cells := []string{"zone1"}
	allCellNames = "zone1"
	vc = NewVitessCluster(t, "TestMigrate", cells, mainClusterConfig)

	require.NotNil(t, vc)
	defaultReplicas = 0
	defaultRdonly = 0
	defer vc.TearDown(t)

	defaultCell = vc.Cells[defaultCellName]
	vc.AddKeyspace(t, []*Cell{defaultCell}, "product", "0", initialProductVSchema, initialProductSchema, defaultReplicas, defaultRdonly, 100)
	vtgate = defaultCell.Vtgates[0]
	require.NotNil(t, vtgate)
	vtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.primary", "product", "0"), 1)

	vtgateConn = getConnection(t, vc.ClusterConfig.hostname, vc.ClusterConfig.vtgateMySQLPort)
	defer vtgateConn.Close()
	verifyClusterHealth(t, vc)
	insertInitialData(t)

	// create external cluster
	extCell := "extcell1"
	extCells := []string{extCell}
	extVc := NewVitessCluster(t, "TestMigrateExternal", extCells, externalClusterConfig)
	require.NotNil(t, extVc)
	defer extVc.TearDown(t)

	extCell2 := extVc.Cells[extCell]
	extVc.AddKeyspace(t, []*Cell{extCell2}, "rating", "0", initialExternalVSchema, initialExternalSchema, 0, 0, 1000)
	extVtgate := extCell2.Vtgates[0]
	require.NotNil(t, extVtgate)

	extVtgate.WaitForStatusOfTabletInShard(fmt.Sprintf("%s.%s.primary", "rating", "0"), 1)
	verifyClusterHealth(t, extVc)
	extVtgateConn := getConnection(t, extVc.ClusterConfig.hostname, extVc.ClusterConfig.vtgateMySQLPort)
	insertInitialDataIntoExternalCluster(t, extVtgateConn)

	var err error
	var output, expected string
	ksWorkflow := "product.e1"

	t.Run("mount external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-topo_type=etcd2",
			fmt.Sprintf("-topo_server=localhost:%d", extVc.ClusterConfig.topoPort), "-topo_root=/vitess/global", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-list"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = "ext1\n"
		require.Equal(t, expected, output)
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-show", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = `{"ClusterName":"ext1","topo_config":{"topo_type":"etcd2","server":"localhost:12379","root":"/vitess/global"}}` + "\n"
		require.Equal(t, expected, output)
	})

	t.Run("migrate from external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "-all", "-cells=extcell1",
			"-source=ext1.rating", "create", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		time.Sleep(1 * time.Second) // wait for migrate to run
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 1)
		validateCount(t, vtgateConn, "product:0", "rating", 2)
		validateCount(t, vtgateConn, "product:0", "review", 3)
		execVtgateQuery(t, extVtgateConn, "rating", "insert into review(rid, pid, review) values(4, 1, 'review4');")
		execVtgateQuery(t, extVtgateConn, "rating", "insert into rating(gid, pid, rating) values(3, 1, 3);")
		time.Sleep(1 * time.Second) // wait for stream to find row
		validateCount(t, vtgateConn, "product:0", "rating", 3)
		validateCount(t, vtgateConn, "product:0", "review", 4)
		vdiff(t, ksWorkflow, "extcell1")

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "complete", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}

		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 0)
	})
	t.Run("cancel migrate workflow", func(t *testing.T) {
		execVtgateQuery(t, vtgateConn, "product", "drop table review,rating")

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "-all", "-auto_start=false", "-cells=extcell1",
			"-source=ext1.rating", "create", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 1)
		validateCount(t, vtgateConn, "product:0", "rating", 0)
		validateCount(t, vtgateConn, "product:0", "review", 0)
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Migrate", "cancel", ksWorkflow); err != nil {
			t.Fatalf("Migrate command failed with %+v : %s\n", err, output)
		}
		expectNumberOfStreams(t, vtgateConn, "migrate", "e1", "product:0", 0)
		var found bool
		found, err = checkIfTableExists(t, vc, "zone1-100", "review")
		require.NoError(t, err)
		require.False(t, found)
		found, err = checkIfTableExists(t, vc, "zone1-100", "rating")
		require.NoError(t, err)
		require.False(t, found)
	})
	t.Run("unmount external cluster", func(t *testing.T) {
		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-unmount", "ext1"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}

		if output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-list"); err != nil {
			t.Fatalf("Mount command failed with %+v : %s\n", err, output)
		}
		expected = "\n"
		require.Equal(t, expected, output)

		output, err = vc.VtctlClient.ExecuteCommandWithOutput("Mount", "-type=vitess", "-show", "ext1")
		require.Errorf(t, err, "there is no vitess cluster named ext1")
	})
}
<|endoftext|>


<commit_before>// Package freeport provides a helper for allocating free ports across multiple
// processes on the same machine.
package freeport

import (
	"fmt"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/mitchellh/go-testing-interface"
)

const (
	// blockSize is the size of the allocated port block. ports are given out
	// consecutively from that block with roll-over for the lifetime of the
	// application/test run.
	blockSize = 500

	// maxBlocks is the number of available port blocks.
	// lowPort + maxBlocks * blockSize must be less than 65535.
	maxBlocks = 30

	// lowPort is the lowest port number that should be used.
	lowPort = 10000

	// attempts is how often we try to allocate a port block
	// before giving up.
	attempts = 10
)

var (
	// firstPort is the first port of the allocated block.
	firstPort int

	// lockLn is the system-wide mutex for the port block.
	lockLn net.Listener

	// mu guards nextPort
	mu sync.Mutex

	// port is the last allocated port.
	port int
)

func init() {
	if lowPort+maxBlocks*blockSize > 65535 {
		panic("freeport: block size too big or too many blocks requested")
	}

	rand.Seed(time.Now().UnixNano())
	firstPort, lockLn = alloc()
}

// alloc reserves a port block for exclusive use for the lifetime of the
// application. lockLn serves as a system-wide mutex for the port block and is
// implemented as a TCP listener which is bound to the firstPort and which will
// be automatically released when the application terminates.
func alloc() (int, net.Listener) {
	for i := 0; i < attempts; i++ {
		block := int(rand.Int31n(int32(maxBlocks)))
		firstPort := lowPort + block*blockSize
		ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", firstPort))
		if err != nil {
			continue
		}
		// log.Printf("[DEBUG] freeport: allocated port block %d (%d-%d)", block, firstPort, firstPort+blockSize-1)
		return firstPort, ln
	}
	panic("freeport: cannot allocate port block")
}

func tcpAddr(ip string, port int) *net.TCPAddr {
	return &net.TCPAddr{IP: net.ParseIP(ip), Port: port}
}

// Get wraps the Free function and panics on any failure retrieving ports.
func Get(n int) (ports []int) {
	ports, err := Free(n)
	if err != nil {
		panic(err)
	}

	return ports
}

// GetT is suitable for use when retrieving unused ports in tests. If there is
// an error retrieving free ports, the test will be failed.
func GetT(t testing.T, n int) (ports []int) {
	ports, err := Free(n)
	if err != nil {
		t.Fatalf("Failed retrieving free port: %v", err)
	}

	return ports
}

// Free returns a list of free ports from the allocated port block. It is safe
// to call this method concurrently. Ports have been tested to be available on
// 127.0.0.1 TCP but there is no guarantee that they will remain free in the
// future.
func Free(n int) (ports []int, err error) {
	mu.Lock()
	defer mu.Unlock()

	if n > blockSize-1 {
		return nil, fmt.Errorf("freeport: block size too small")
	}

	for len(ports) < n {
		port++

		// roll-over the port
		if port < firstPort+1 || port >= firstPort+blockSize {
			port = firstPort + 1
		}

		// if the port is in use then skip it
		ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", port))
		if err != nil {
			// log.Println("[DEBUG] freeport: port already in use: ", port)
			continue
		}
		ln.Close()

		ports = append(ports, port)
	}
	// log.Println("[DEBUG] freeport: free ports:", ports)
	return ports, nil
}
<commit_msg>Initialize freeport lazily to avoid runtime issues<commit_after>// Package freeport provides a helper for allocating free ports across multiple
// processes on the same machine.
package freeport

import (
	"fmt"
	"math/rand"
	"net"
	"sync"
	"time"

	"github.com/mitchellh/go-testing-interface"
)

const (
	// blockSize is the size of the allocated port block. ports are given out
	// consecutively from that block with roll-over for the lifetime of the
	// application/test run.
	blockSize = 500

	// maxBlocks is the number of available port blocks.
	// lowPort + maxBlocks * blockSize must be less than 65535.
	maxBlocks = 30

	// lowPort is the lowest port number that should be used.
	lowPort = 10000

	// attempts is how often we try to allocate a port block
	// before giving up.
	attempts = 10
)

var (
	// firstPort is the first port of the allocated block.
	firstPort int

	// lockLn is the system-wide mutex for the port block.
	lockLn net.Listener

	// mu guards nextPort
	mu sync.Mutex

	// once is used to do the initialization on the first call to retrieve free
	// ports
	once sync.Once

	// port is the last allocated port.
	port int
)

// initialize is used to initialize freeport.
func initialize() {
	if lowPort+maxBlocks*blockSize > 65535 {
		panic("freeport: block size too big or too many blocks requested")
	}

	rand.Seed(time.Now().UnixNano())
	firstPort, lockLn = alloc()
}

// alloc reserves a port block for exclusive use for the lifetime of the
// application. lockLn serves as a system-wide mutex for the port block and is
// implemented as a TCP listener which is bound to the firstPort and which will
// be automatically released when the application terminates.
func alloc() (int, net.Listener) {
	for i := 0; i < attempts; i++ {
		block := int(rand.Int31n(int32(maxBlocks)))
		firstPort := lowPort + block*blockSize
		ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", firstPort))
		if err != nil {
			continue
		}
		// log.Printf("[DEBUG] freeport: allocated port block %d (%d-%d)", block, firstPort, firstPort+blockSize-1)
		return firstPort, ln
	}
	panic("freeport: cannot allocate port block")
}

func tcpAddr(ip string, port int) *net.TCPAddr {
	return &net.TCPAddr{IP: net.ParseIP(ip), Port: port}
}

// Get wraps the Free function and panics on any failure retrieving ports.
func Get(n int) (ports []int) {
	ports, err := Free(n)
	if err != nil {
		panic(err)
	}

	return ports
}

// GetT is suitable for use when retrieving unused ports in tests. If there is
// an error retrieving free ports, the test will be failed.
func GetT(t testing.T, n int) (ports []int) {
	ports, err := Free(n)
	if err != nil {
		t.Fatalf("Failed retrieving free port: %v", err)
	}

	return ports
}

// Free returns a list of free ports from the allocated port block. It is safe
// to call this method concurrently. Ports have been tested to be available on
// 127.0.0.1 TCP but there is no guarantee that they will remain free in the
// future.
func Free(n int) (ports []int, err error) {
	mu.Lock()
	defer mu.Unlock()

	if n > blockSize-1 {
		return nil, fmt.Errorf("freeport: block size too small")
	}

	// Reserve a port block
	once.Do(initialize)

	for len(ports) < n {
		port++

		// roll-over the port
		if port < firstPort+1 || port >= firstPort+blockSize {
			port = firstPort + 1
		}

		// if the port is in use then skip it
		ln, err := net.ListenTCP("tcp", tcpAddr("127.0.0.1", port))
		if err != nil {
			// log.Println("[DEBUG] freeport: port already in use: ", port)
			continue
		}
		ln.Close()

		ports = append(ports, port)
	}
	// log.Println("[DEBUG] freeport: free ports:", ports)
	return ports, nil
}
<|endoftext|>