<commit_before>package gopush

import (
	"fmt"
	"reflect"
	"strings"
)

func newCodeStack(interpreter *Interpreter) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["="] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if reflect.DeepEqual(c1, c2) {
			interpreter.Stacks["boolean"].Push(true)
		} else {
			interpreter.Stacks["boolean"].Push(false)
		}
	}

	s.Functions["append"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if c1.Literal != "" {
			c1 = Code{Length: c1.Length, List: []Code{c1}}
		}

		if c2.Literal != "" {
			c2 = Code{Length: c2.Length, List: []Code{c2}}
		}

		combined := Code{Length: c1.Length + c2.Length, List: append(c2.List, c1.List...)}

		if combined.Length <= interpreter.Options.MaxPointsInProgram {
			interpreter.Stacks["code"].Push(combined)
		}
	}

	s.Functions["atom"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if c.Literal != "" {
			interpreter.Stacks["boolean"].Push(true)
		} else {
			interpreter.Stacks["boolean"].Push(false)
		}
	}

	s.Functions["car"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if len(c.List) == 0 {
			return
		}

		interpreter.Stacks["code"].Push(c.List[0])
	}

	s.Functions["cdr"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if len(c.List) == 0 {
			interpreter.Stacks["code"].Push(Code{})
		} else {
			cdr := Code{
				Length: c.Length - c.List[0].Length,
				List:   c.List[1:],
			}
			interpreter.Stacks["code"].Push(cdr)
		}
	}

	s.Functions["cons"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if c1.Literal != "" {
			c1 = Code{Length: 1, List: []Code{c1}}
		}

		if c2.Literal != "" {
			c2 = Code{Length: 1, List: []Code{c2}}
		}

		c := Code{
			Length: c1.Length + c2.Length,
			List:   append(c2.List, c1.List...),
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["container"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		c := c1.Container(c2)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["contains"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		interpreter.Stacks["boolean"].Push(c2.Contains(c1))
	}

	s.Functions["define"] = func() {
		if !interpreter.stackOK("name", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)
		c := interpreter.Stacks["code"].Pop().(Code)

		interpreter.define(n, c)
	}

	s.Functions["definition"] = func() {
		if !interpreter.stackOK("name", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)

		if c, ok := interpreter.Definitions[n]; ok {
			interpreter.Stacks["code"].Push(c)
		}
	}

	s.Functions["discrepancy"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("integer", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		u1 := c1.UniqueItems()
		u2 := c2.UniqueItems()

		keys := make(map[string]struct{}, 0)

		for k := range u1 {
			keys[k] = struct{}{}
		}

		for k := range u2 {
			keys[k] = struct{}{}
		}

		discrepancy := int64(0)
		for k := range keys {
			if u1[k] > u2[k] {
				discrepancy += u1[k] - u2[k]
			} else {
				discrepancy += u2[k] - u1[k]
			}
		}

		interpreter.Stacks["integer"].Push(discrepancy)
	}

	s.Functions["do"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		err := interpreter.runCode(c)
		if err != nil {
			panic(err)
		}

		interpreter.Stacks["code"].Pop()
	}

	s.Functions["do*"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)
		interpreter.Stacks["code"].Pop()

		err := interpreter.runCode(c)
		if err != nil {
			panic(err)
		}
	}

	s.Functions["do*count"] = func() {
		// TODO
	}

	s.Functions["do*range"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 2) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)
		dst := interpreter.Stacks["integer"].Pop().(int64)
		cur := interpreter.Stacks["integer"].Pop().(int64)

		if cur == dst {
			interpreter.Stacks["integer"].Push(cur)
			interpreter.Stacks["exec"].Push(c)
		} else {
			interpreter.Stacks["integer"].Push(cur)

			if dst < cur {
				cur--
			} else {
				cur++
			}

			interpreter.Stacks["code"].Push(c)
			interpreter.Stacks["exec"].Push(c)
			interpreter.Stacks["exec"].Push(Code{Length: 1, Literal: "CODE.DO*RANGE"})
			interpreter.Stacks["integer"].Push(cur)
			interpreter.Stacks["integer"].Push(dst)
		}
	}

	s.Functions["do*times"] = func() {
		// TODO
	}

	s.Functions["dup"] = func() {
		interpreter.Stacks["code"].Dup()
	}

	s.Functions["extract"] = func() {
		// TODO
	}

	s.Functions["flush"] = func() {
		interpreter.Stacks["code"].Flush()
	}

	s.Functions["fromboolean"] = func() {
		if !interpreter.stackOK("boolean", 1) {
			return
		}

		b := interpreter.Stacks["boolean"].Pop().(bool)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: fmt.Sprint(b)})
	}

	s.Functions["fromfloat"] = func() {
		if !interpreter.stackOK("float", 1) {
			return
		}

		f := interpreter.Stacks["float"].Pop().(float64)
		l := fmt.Sprint(f)
		if !strings.Contains(l, ".") {
			l += ".0"
		}
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: l})
	}

	s.Functions["frominteger"] = func() {
		if !interpreter.stackOK("integer", 1) {
			return
		}

		i := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: fmt.Sprint(i)})
	}

	s.Functions["fromname"] = func() {
		if !interpreter.stackOK("name", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: n})
	}

	s.Functions["if"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 1) {
			return
		}

		b := interpreter.Stacks["boolean"].Pop().(bool)
		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if b {
			interpreter.Stacks["exec"].Push(c2)
		} else {
			interpreter.Stacks["exec"].Push(c1)
		}
	}

	s.Functions["insert"] = func() {
		// TODO
	}

	s.Functions["instructions"] = func() {
		c := Code{List: make([]Code, 0, len(interpreter.listOfInstructions))}

		for _, instr := range interpreter.listOfInstructions {
			if instr == "NAME-ERC" || instr == "FLOAT-ERC" || instr == "INTEGER-ERC" {
				continue
			}

			c.Length++
			c.List = append(c.List, Code{Length: 1, Literal: instr})
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["length"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		if c.Literal != "" {
			interpreter.Stacks["integer"].Push(int64(1))
		} else {
			interpreter.Stacks["integer"].Push(int64(len(c.List)))
		}
	}

	s.Functions["list"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		c := Code{
			Length: c1.Length + c2.Length,
			List:   []Code{c1, c2},
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["member"] = func() {
		// TODO
	}

	s.Functions["noop"] = func() {
		// Does nothing
	}

	s.Functions["nth"] = func() {
		// TODO
	}

	s.Functions["nthcdr"] = func() {
		// TODO
	}

	s.Functions["null"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["boolean"].Push(c.Literal == "" && len(c.List) == 0)
	}

	s.Functions["pop"] = func() {
		// TODO
	}

	s.Functions["position"] = func() {
		// TODO
	}

	s.Functions["quote"] = func() {
		if !interpreter.stackOK("exec", 1) {
			return
		}

		c := interpreter.Stacks["exec"].Pop().(Code)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["rand"] = func() {
		if !interpreter.stackOK("integer", 1) {
			return
		}

		maxPoints := interpreter.Stacks["integer"].Pop().(int64)
		if maxPoints < 0 {
			maxPoints *= -1
		}

		if maxPoints > interpreter.Options.MaxPointsInRandomExpression {
			maxPoints = interpreter.Options.MaxPointsInRandomExpression
		}

		c := interpreter.RandomCode(maxPoints)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["rot"] = func() {
		interpreter.Stacks["code"].Rot()
	}

	s.Functions["shove"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["code"].Shove(c, idx)
		interpreter.Stacks["code"].Pop()
	}

	s.Functions["size"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["integer"].Push(c.Length)
	}

	s.Functions["stackdepth"] = func() {
		if !interpreter.stackOK("integer", 0) {
			return
		}

		interpreter.Stacks["integer"].Push(interpreter.Stacks["code"].Len())
	}

	s.Functions["subst"] = func() {
		// TODO
	}

	s.Functions["swap"] = func() {
		interpreter.Stacks["code"].Swap()
	}

	s.Functions["yank"] = func() {
		if !interpreter.stackOK("integer", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].Yank(idx)
	}

	s.Functions["yankdup"] = func() {
		if !interpreter.stackOK("integer", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].YankDup(idx)
	}

	return s
}
<commit_msg>Remove nonsensical parameter to make()<commit_after>package gopush

import (
	"fmt"
	"reflect"
	"strings"
)

func newCodeStack(interpreter *Interpreter) *Stack {
	s := &Stack{
		Functions: make(map[string]Instruction),
	}

	s.Functions["="] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if reflect.DeepEqual(c1, c2) {
			interpreter.Stacks["boolean"].Push(true)
		} else {
			interpreter.Stacks["boolean"].Push(false)
		}
	}

	s.Functions["append"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if c1.Literal != "" {
			c1 = Code{Length: c1.Length, List: []Code{c1}}
		}

		if c2.Literal != "" {
			c2 = Code{Length: c2.Length, List: []Code{c2}}
		}

		combined := Code{Length: c1.Length + c2.Length, List: append(c2.List, c1.List...)}

		if combined.Length <= interpreter.Options.MaxPointsInProgram {
			interpreter.Stacks["code"].Push(combined)
		}
	}

	s.Functions["atom"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if c.Literal != "" {
			interpreter.Stacks["boolean"].Push(true)
		} else {
			interpreter.Stacks["boolean"].Push(false)
		}
	}

	s.Functions["car"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if len(c.List) == 0 {
			return
		}

		interpreter.Stacks["code"].Push(c.List[0])
	}

	s.Functions["cdr"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		if len(c.List) == 0 {
			interpreter.Stacks["code"].Push(Code{})
		} else {
			cdr := Code{
				Length: c.Length - c.List[0].Length,
				List:   c.List[1:],
			}
			interpreter.Stacks["code"].Push(cdr)
		}
	}

	s.Functions["cons"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if c1.Literal != "" {
			c1 = Code{Length: 1, List: []Code{c1}}
		}

		if c2.Literal != "" {
			c2 = Code{Length: 1, List: []Code{c2}}
		}

		c := Code{
			Length: c1.Length + c2.Length,
			List:   append(c2.List, c1.List...),
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["container"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		c := c1.Container(c2)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["contains"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		interpreter.Stacks["boolean"].Push(c2.Contains(c1))
	}

	s.Functions["define"] = func() {
		if !interpreter.stackOK("name", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)
		c := interpreter.Stacks["code"].Pop().(Code)

		interpreter.define(n, c)
	}

	s.Functions["definition"] = func() {
		if !interpreter.stackOK("name", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)

		if c, ok := interpreter.Definitions[n]; ok {
			interpreter.Stacks["code"].Push(c)
		}
	}

	s.Functions["discrepancy"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("integer", 0) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		u1 := c1.UniqueItems()
		u2 := c2.UniqueItems()

		keys := make(map[string]struct{})

		for k := range u1 {
			keys[k] = struct{}{}
		}

		for k := range u2 {
			keys[k] = struct{}{}
		}

		discrepancy := int64(0)
		for k := range keys {
			if u1[k] > u2[k] {
				discrepancy += u1[k] - u2[k]
			} else {
				discrepancy += u2[k] - u1[k]
			}
		}

		interpreter.Stacks["integer"].Push(discrepancy)
	}

	s.Functions["do"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)

		err := interpreter.runCode(c)
		if err != nil {
			panic(err)
		}

		interpreter.Stacks["code"].Pop()
	}

	s.Functions["do*"] = func() {
		if !interpreter.stackOK("code", 1) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)
		interpreter.Stacks["code"].Pop()

		err := interpreter.runCode(c)
		if err != nil {
			panic(err)
		}
	}

	s.Functions["do*count"] = func() {
		// TODO
	}

	s.Functions["do*range"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 2) {
			return
		}

		c := interpreter.Stacks["code"].Pop().(Code)
		dst := interpreter.Stacks["integer"].Pop().(int64)
		cur := interpreter.Stacks["integer"].Pop().(int64)

		if cur == dst {
			interpreter.Stacks["integer"].Push(cur)
			interpreter.Stacks["exec"].Push(c)
		} else {
			interpreter.Stacks["integer"].Push(cur)

			if dst < cur {
				cur--
			} else {
				cur++
			}

			interpreter.Stacks["code"].Push(c)
			interpreter.Stacks["exec"].Push(c)
			interpreter.Stacks["exec"].Push(Code{Length: 1, Literal: "CODE.DO*RANGE"})
			interpreter.Stacks["integer"].Push(cur)
			interpreter.Stacks["integer"].Push(dst)
		}
	}

	s.Functions["do*times"] = func() {
		// TODO
	}

	s.Functions["dup"] = func() {
		interpreter.Stacks["code"].Dup()
	}

	s.Functions["extract"] = func() {
		// TODO
	}

	s.Functions["flush"] = func() {
		interpreter.Stacks["code"].Flush()
	}

	s.Functions["fromboolean"] = func() {
		if !interpreter.stackOK("boolean", 1) {
			return
		}

		b := interpreter.Stacks["boolean"].Pop().(bool)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: fmt.Sprint(b)})
	}

	s.Functions["fromfloat"] = func() {
		if !interpreter.stackOK("float", 1) {
			return
		}

		f := interpreter.Stacks["float"].Pop().(float64)
		l := fmt.Sprint(f)
		if !strings.Contains(l, ".") {
			l += ".0"
		}
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: l})
	}

	s.Functions["frominteger"] = func() {
		if !interpreter.stackOK("integer", 1) {
			return
		}

		i := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: fmt.Sprint(i)})
	}

	s.Functions["fromname"] = func() {
		if !interpreter.stackOK("name", 1) {
			return
		}

		n := interpreter.Stacks["name"].Pop().(string)
		interpreter.Stacks["code"].Push(Code{Length: 1, Literal: n})
	}

	s.Functions["if"] = func() {
		if !interpreter.stackOK("code", 2) || !interpreter.stackOK("boolean", 1) {
			return
		}

		b := interpreter.Stacks["boolean"].Pop().(bool)
		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		if b {
			interpreter.Stacks["exec"].Push(c2)
		} else {
			interpreter.Stacks["exec"].Push(c1)
		}
	}

	s.Functions["insert"] = func() {
		// TODO
	}

	s.Functions["instructions"] = func() {
		c := Code{List: make([]Code, 0, len(interpreter.listOfInstructions))}

		for _, instr := range interpreter.listOfInstructions {
			if instr == "NAME-ERC" || instr == "FLOAT-ERC" || instr == "INTEGER-ERC" {
				continue
			}

			c.Length++
			c.List = append(c.List, Code{Length: 1, Literal: instr})
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["length"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		if c.Literal != "" {
			interpreter.Stacks["integer"].Push(int64(1))
		} else {
			interpreter.Stacks["integer"].Push(int64(len(c.List)))
		}
	}

	s.Functions["list"] = func() {
		if !interpreter.stackOK("code", 2) {
			return
		}

		c1 := interpreter.Stacks["code"].Pop().(Code)
		c2 := interpreter.Stacks["code"].Pop().(Code)

		c := Code{
			Length: c1.Length + c2.Length,
			List:   []Code{c1, c2},
		}

		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["member"] = func() {
		// TODO
	}

	s.Functions["noop"] = func() {
		// Does nothing
	}

	s.Functions["nth"] = func() {
		// TODO
	}

	s.Functions["nthcdr"] = func() {
		// TODO
	}

	s.Functions["null"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("boolean", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["boolean"].Push(c.Literal == "" && len(c.List) == 0)
	}

	s.Functions["pop"] = func() {
		// TODO
	}

	s.Functions["position"] = func() {
		// TODO
	}

	s.Functions["quote"] = func() {
		if !interpreter.stackOK("exec", 1) {
			return
		}

		c := interpreter.Stacks["exec"].Pop().(Code)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["rand"] = func() {
		if !interpreter.stackOK("integer", 1) {
			return
		}

		maxPoints := interpreter.Stacks["integer"].Pop().(int64)
		if maxPoints < 0 {
			maxPoints *= -1
		}

		if maxPoints > interpreter.Options.MaxPointsInRandomExpression {
			maxPoints = interpreter.Options.MaxPointsInRandomExpression
		}

		c := interpreter.RandomCode(maxPoints)
		interpreter.Stacks["code"].Push(c)
	}

	s.Functions["rot"] = func() {
		interpreter.Stacks["code"].Rot()
	}

	s.Functions["shove"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["code"].Shove(c, idx)
		interpreter.Stacks["code"].Pop()
	}

	s.Functions["size"] = func() {
		if !interpreter.stackOK("code", 1) || !interpreter.stackOK("integer", 0) {
			return
		}

		c := interpreter.Stacks["code"].Peek().(Code)
		interpreter.Stacks["integer"].Push(c.Length)
	}

	s.Functions["stackdepth"] = func() {
		if !interpreter.stackOK("integer", 0) {
			return
		}

		interpreter.Stacks["integer"].Push(interpreter.Stacks["code"].Len())
	}

	s.Functions["subst"] = func() {
		// TODO
	}

	s.Functions["swap"] = func() {
		interpreter.Stacks["code"].Swap()
	}

	s.Functions["yank"] = func() {
		if !interpreter.stackOK("integer", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].Yank(idx)
	}

	s.Functions["yankdup"] = func() {
		if !interpreter.stackOK("integer", 1) || !interpreter.stackOK("code", 1) {
			return
		}

		idx := interpreter.Stacks["integer"].Pop().(int64)
		interpreter.Stacks["code"].YankDup(idx)
	}

	return s
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Heptio Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package client

import (
	"github.com/pkg/errors"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
)

// DynamicFactory contains methods for retrieving dynamic clients for GroupVersionResources and
// GroupVersionKinds.
type DynamicFactory interface {
	// ClientForGroupVersionResource returns a Dynamic client for the given group/version
	// and resource for the given namespace.
	ClientForGroupVersionResource(gv schema.GroupVersion, resource metav1.APIResource, namespace string) (Dynamic, error)
}

// dynamicFactory implements DynamicFactory.
type dynamicFactory struct {
	clientPool dynamic.ClientPool
}

// NewDynamicFactory returns a new ClientPool-based dynamic factory.
func NewDynamicFactory(clientPool dynamic.ClientPool) DynamicFactory {
	return &dynamicFactory{clientPool: clientPool}
}

func (f *dynamicFactory) ClientForGroupVersionResource(gv schema.GroupVersion, resource metav1.APIResource, namespace string) (Dynamic, error) {
	// client-go doesn't actually use the kind when getting the dynamic client from the client pool;
	// it only needs the group and version.
	dynamicClient, err := f.clientPool.ClientForGroupVersionKind(gv.WithKind(""))
	if err != nil {
		return nil, errors.Wrapf(err, "error getting client for GroupVersion %s, Resource %s", gv.String, resource.String())
	}

	return &dynamicResourceClient{
		resourceClient: dynamicClient.Resource(&resource, namespace),
	}, nil
}

// Creator creates an object.
type Creator interface {
	// Create creates an object.
	Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
}

// Lister lists objects.
type Lister interface {
	// List lists all the objects of a given resource.
	List(metav1.ListOptions) (runtime.Object, error)
}

// Watcher watches objects.
type Watcher interface {
	// Watch watches for changes to objects of a given resource.
	Watch(metav1.ListOptions) (watch.Interface, error)
}

// Getter gets an object.
type Getter interface {
	// Get fetches an object by name.
	Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error)
}

// Dynamic contains client methods that Ark needs for backing up and restoring resources.
type Dynamic interface {
	Creator
	Lister
	Watcher
	Getter
}

// dynamicResourceClient implements Dynamic.
type dynamicResourceClient struct {
	resourceClient *dynamic.ResourceClient
}

var _ Dynamic = &dynamicResourceClient{}

func (d *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
	return d.resourceClient.Create(obj)
}

func (d *dynamicResourceClient) List(options metav1.ListOptions) (runtime.Object, error) {
	return d.resourceClient.List(options)
}

func (d *dynamicResourceClient) Watch(options metav1.ListOptions) (watch.Interface, error) {
	return d.resourceClient.Watch(options)
}

func (d *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
	return d.resourceClient.Get(name, opts)
}
<commit_msg>dynamicResourceClient: fix resourceClient type<commit_after>/*
Copyright 2017 Heptio Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package client

import (
	"github.com/pkg/errors"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/watch"
	"k8s.io/client-go/dynamic"
)

// DynamicFactory contains methods for retrieving dynamic clients for GroupVersionResources and
// GroupVersionKinds.
type DynamicFactory interface {
	// ClientForGroupVersionResource returns a Dynamic client for the given group/version
	// and resource for the given namespace.
	ClientForGroupVersionResource(gv schema.GroupVersion, resource metav1.APIResource, namespace string) (Dynamic, error)
}

// dynamicFactory implements DynamicFactory.
type dynamicFactory struct {
	clientPool dynamic.ClientPool
}

// NewDynamicFactory returns a new ClientPool-based dynamic factory.
func NewDynamicFactory(clientPool dynamic.ClientPool) DynamicFactory {
	return &dynamicFactory{clientPool: clientPool}
}

func (f *dynamicFactory) ClientForGroupVersionResource(gv schema.GroupVersion, resource metav1.APIResource, namespace string) (Dynamic, error) {
	// client-go doesn't actually use the kind when getting the dynamic client from the client pool;
	// it only needs the group and version.
	dynamicClient, err := f.clientPool.ClientForGroupVersionKind(gv.WithKind(""))
	if err != nil {
		return nil, errors.Wrapf(err, "error getting client for GroupVersion %s, Resource %s", gv.String, resource.String())
	}

	return &dynamicResourceClient{
		resourceClient: dynamicClient.Resource(&resource, namespace),
	}, nil
}

// Creator creates an object.
type Creator interface {
	// Create creates an object.
	Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
}

// Lister lists objects.
type Lister interface {
	// List lists all the objects of a given resource.
	List(metav1.ListOptions) (runtime.Object, error)
}

// Watcher watches objects.
type Watcher interface {
	// Watch watches for changes to objects of a given resource.
	Watch(metav1.ListOptions) (watch.Interface, error)
}

// Getter gets an object.
type Getter interface {
	// Get fetches an object by name.
	Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error)
}

// Dynamic contains client methods that Ark needs for backing up and restoring resources.
type Dynamic interface {
	Creator
	Lister
	Watcher
	Getter
}

// dynamicResourceClient implements Dynamic.
type dynamicResourceClient struct {
	resourceClient dynamic.ResourceInterface
}

var _ Dynamic = &dynamicResourceClient{}

func (d *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
	return d.resourceClient.Create(obj)
}

func (d *dynamicResourceClient) List(options metav1.ListOptions) (runtime.Object, error) {
	return d.resourceClient.List(options)
}

func (d *dynamicResourceClient) Watch(options metav1.ListOptions) (watch.Interface, error) {
	return d.resourceClient.Watch(options)
}

func (d *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
	return d.resourceClient.Get(name, opts)
}
<|endoftext|>


<commit_before>package commands

import (
	"bufio"
	"fmt"
	"os"

	"github.com/QuentinPerez/c14-cli/pkg/api/auth"
	"github.com/juju/errors"

	"golang.org/x/crypto/ssh/terminal"
)

type login struct {
	Base
	loginFlags
}

type loginFlags struct {
}

// Login returns a new command "login"
func Login() Command {
	ret := &login{}
	ret.Init(Config{
		UsageLine:   "login",
		Description: "Log in to Online API",
		Help: `Generates a credentials file in $HOME/.c14rc
containing informations to generate a token`,
		Examples: `
    $ c14 login`,
	})
	return ret
}

func (l *login) GetName() string {
	return "login"
}

func (l *login) Run(args []string) (err error) {
	var (
		empty          string
		authentication auth.Authentication
		credentials    auth.Credentials
		clientID       = "38320_2wln446j992cgo0088g04coo8gswkcws0c4sww0oo0ggs8kos8"
	)

	if authentication, err = auth.GetVerificationURL(clientID); err != nil {
		return
	}
	if err = promptUser(fmt.Sprintf(`Please opens this link with your browser: %v
Then copy paste the code %v (enter when is done) : `, authentication.VerficationURL, authentication.UserCode), &empty, true); err != nil {
		return
	}
	if credentials, err = auth.GenerateCredentials(clientID, authentication.DeviceCode); err != nil {
		return
	}
	err = credentials.Save()
	return
}

func promptUser(prompt string, output *string, echo bool) (err error) {
	var b []byte

	fmt.Fprintf(os.Stdout, prompt)
	os.Stdout.Sync()
	if !echo {
		if b, err = terminal.ReadPassword(int(os.Stdin.Fd())); err != nil {
			err = errors.Annotate(err, "Unable to prompt for password")
			return
		}
		*output = string(b)
		fmt.Fprintf(os.Stdout, "\n")
	} else {
		reader := bufio.NewReader(os.Stdin)
		*output, err = reader.ReadString('\n')
	}
	return
}
<commit_msg>login: Don't ask to press enter<commit_after>package commands

import (
	"bufio"
	"fmt"
	"os"
	"time"

	"github.com/QuentinPerez/c14-cli/pkg/api/auth"
	"github.com/juju/errors"

	"golang.org/x/crypto/ssh/terminal"
)

type login struct {
	Base
	loginFlags
}

type loginFlags struct {
}

// Login returns a new command "login"
func Login() Command {
	ret := &login{}
	ret.Init(Config{
		UsageLine:   "login",
		Description: "Log in to Online API",
		Help: `Generates a credentials file in $HOME/.c14rc
containing informations to generate a token`,
		Examples: `
    $ c14 login`,
	})
	return ret
}

func (l *login) GetName() string {
	return "login"
}

func (l *login) Run(args []string) (err error) {
	var (
		authentication auth.Authentication
		credentials    auth.Credentials
		clientID       = "38320_2wln446j992cgo0088g04coo8gswkcws0c4sww0oo0ggs8kos8"
	)

	if authentication, err = auth.GetVerificationURL(clientID); err != nil {
		return
	}
	fmt.Printf(`Please opens this link with your browser: %v
Then copy paste the code %v
`, authentication.VerficationURL, authentication.UserCode)
	for i := 0; i < 1500; i++ {
		if credentials, err = auth.GenerateCredentials(clientID, authentication.DeviceCode); err == nil {
			break
		}
		time.Sleep(100 * time.Millisecond)
	}
	if err != nil {
		err = errors.Annotate(err, "Timeout")
		return
	}
	err = credentials.Save()
	return
}

func promptUser(prompt string, output *string, echo bool) (err error) {
	var b []byte

	fmt.Fprintf(os.Stdout, prompt)
	os.Stdout.Sync()
	if !echo {
		if b, err = terminal.ReadPassword(int(os.Stdin.Fd())); err != nil {
			err = errors.Annotate(err, "Unable to prompt for password")
			return
		}
		*output = string(b)
		fmt.Fprintf(os.Stdout, "\n")
	} else {
		reader := bufio.NewReader(os.Stdin)
		*output, err = reader.ReadString('\n')
	}
	return
}
<|endoftext|>


<commit_before>//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package azblob

import (
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
)

// SharedKeyCredential contains an account's name and its primary or secondary key.
type SharedKeyCredential = exported.SharedKeyCredential

// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
// storage account's name and either its primary or secondary key.
func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) {
	return exported.NewSharedKeyCredential(accountName, accountKey)
}

// ParsedConnectionString is parsed connection string
type ParsedConnectionString = shared.ParsedConnectionString

// ParseConnectionString returns ParsedConnectionString
func ParseConnectionString(connectionString string) (ParsedConnectionString, error) {
	return shared.ParseConnectionString(connectionString)
}

// IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator.
// Ex: "https://10.132.141.33/accountname/containername"
type IPEndpointStyleInfo = exported.IPEndpointStyleInfo

// BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You parse an
// existing URL into its parts by calling NewBlobURLParts(). You construct a URL from parts by calling URL().
// NOTE: Changing any SAS-related field requires computing a new SAS signature.
type BlobURLParts = exported.BlobURLParts

// ParseBlobURL parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other
// query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object.
func ParseBlobURL(u string) (BlobURLParts, error) {
	return exported.ParseBlobURL(u)
}
<commit_msg>Export types needed by BlobURLParts (#18858)<commit_after>//go:build go1.18
// +build go1.18

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

package azblob

import (
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/exported"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/internal/shared"
)

// SharedKeyCredential contains an account's name and its primary or secondary key.
type SharedKeyCredential = exported.SharedKeyCredential

// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
// storage account's name and either its primary or secondary key.
func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) {
	return exported.NewSharedKeyCredential(accountName, accountKey)
}

// ParsedConnectionString is parsed connection string
type ParsedConnectionString = shared.ParsedConnectionString

// ParseConnectionString returns ParsedConnectionString
func ParseConnectionString(connectionString string) (ParsedConnectionString, error) {
	return shared.ParseConnectionString(connectionString)
}

// IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator.
// Ex: "https://10.132.141.33/accountname/containername"
type IPEndpointStyleInfo = exported.IPEndpointStyleInfo

// BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You parse an
// existing URL into its parts by calling NewBlobURLParts(). You construct a URL from parts by calling URL().
// NOTE: Changing any SAS-related field requires computing a new SAS signature.
type BlobURLParts = exported.BlobURLParts

// ParseBlobURL parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other
// query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object.
func ParseBlobURL(u string) (BlobURLParts, error) {
	return exported.ParseBlobURL(u)
}

// SASQueryParameters object represents the components that make up an Azure Storage SAS' query parameters.
// You parse a map of query parameters into its fields by calling NewSASQueryParameters(). You add the components
// to a query parameter map by calling AddToValues().
// NOTE: Changing any field requires computing a new SAS signature using a XxxSASSignatureValues type.
// https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas
type SASQueryParameters = exported.SASQueryParameters

// SASProtocol indicates the protocal in use for the SAS URL (http/https).
type SASProtocol = exported.SASProtocol

// IPRange represents a SAS IP range's start IP and (optionally) end IP.
type IPRange = exported.IPRange
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013-2015 Oryx(ossrs)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// +build darwin dragonfly freebsd nacl netbsd openbsd solaris linux

package protocol

func (v *RtmpStack) fastSendMessages(iovs ...[]byte) (err error) {
	return v.slowSendMessages(iovs...)
}
<commit_msg>add comments about writev.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013-2015 Oryx(ossrs)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// +build darwin dragonfly freebsd nacl netbsd openbsd solaris linux

package protocol

func (v *RtmpStack) fastSendMessages(iovs ...[]byte) (err error) {
	// wait for golang to implements the writev.
	// @see https://github.com/golang/go/issues/13451
	return v.slowSendMessages(iovs...)
}
<|endoftext|>


<commit_before>// Copyright 2018 The Terraformer 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 aws

import (
	"github.com/GoogleCloudPlatform/terraformer/terraform_utils"
	"github.com/aws/aws-sdk-go/service/glue"
	"github.com/aws/aws-sdk-go/service/sts"
)

type GlueGenerator struct {
	AWSService
}

func (g *GlueGenerator) loadGlueCrawlers(svc *glue.Glue) error {
	var GlueCrawlerAllowEmptyValues = []string{"tags."}
	crawlers, err := svc.GetCrawlers(&glue.GetCrawlersInput{})
	if err != nil {
		return err
	}

	for _, crawler := range crawlers.Crawlers {
		resource := terraform_utils.NewSimpleResource(*crawler.Name, *crawler.Name,
			"aws_glue_crawler",
			"aws",
			GlueCrawlerAllowEmptyValues)
		g.Resources = append(g.Resources, resource)
	}
	return nil
}

func (g *GlueGenerator) loadGlueCatalogDatabase(svc *glue.Glue, accont *string) error {
	var GlueCatalogDatabaseAllowEmptyValues = []string{"tags."}
	catalogDatabases, err := svc.GetDatabases(&glue.GetDatabasesInput{})
	if err != nil {
		return err
	}

	for _, catalogDatabase := range catalogDatabases.DatabaseList {
		// format of ID is "CATALOG-ID:DATABASE-NAME".
		// CATALOG-ID is AWS Account ID
		// https://docs.aws.amazon.com/cli/latest/reference/glue/create-database.html#options
		id := *accont + ":" + *catalogDatabase.Name
		resource := terraform_utils.NewSimpleResource(id, *catalogDatabase.Name,
			"aws_glue_catalog_database",
			"aws",
			GlueCatalogDatabaseAllowEmptyValues)
		g.Resources = append(g.Resources, resource)
	}

	return nil
}

// Generate TerraformResources from AWS API,
// from each database create 1 TerraformResource.
// Need only database name as ID for terraform resource
// AWS api support paging
func (g *GlueGenerator) InitResources() error {
	sess := g.generateSession()
	svc := glue.New(sess)

	stsSvc := sts.New(sess)
	identity, err := stsSvc.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		return err
	}
	account := identity.Account

	if err := g.loadGlueCrawlers(svc); err != nil {
		return err
	}
	if err := g.loadGlueCatalogDatabase(svc, account); err != nil {
		return err
	}
	return nil
}
<commit_msg>implement aws_glue_database<commit_after>// Copyright 2018 The Terraformer 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 aws

import (
	"github.com/GoogleCloudPlatform/terraformer/terraform_utils"
	"github.com/aws/aws-sdk-go/service/glue"
	"github.com/aws/aws-sdk-go/service/sts"
)

type GlueGenerator struct {
	AWSService
}

func (g *GlueGenerator) loadGlueCrawlers(svc *glue.Glue) error {
	var GlueCrawlerAllowEmptyValues = []string{"tags."}
	crawlers, err := svc.GetCrawlers(&glue.GetCrawlersInput{})
	if err != nil {
		return err
	}

	for _, crawler := range crawlers.Crawlers {
		resource := terraform_utils.NewSimpleResource(*crawler.Name, *crawler.Name,
			"aws_glue_crawler",
			"aws",
			GlueCrawlerAllowEmptyValues)
		g.Resources = append(g.Resources, resource)
	}
	return nil
}

func (g *GlueGenerator) loadGlueCatalogDatabase(svc *glue.Glue, account *string) (DatabaseNames []*string, error error) {
	var GlueCatalogDatabaseAllowEmptyValues = []string{"tags."}
	catalogDatabases, err := svc.GetDatabases(&glue.GetDatabasesInput{})
	if err != nil {
		return nil, err
	}

	for _, catalogDatabase := range catalogDatabases.DatabaseList {
		// format of ID is "CATALOG-ID:DATABASE-NAME".
		// CATALOG-ID is AWS Account ID
		// https://docs.aws.amazon.com/cli/latest/reference/glue/create-database.html#options
		id := *account + ":" + *catalogDatabase.Name
		resource := terraform_utils.NewSimpleResource(id, *catalogDatabase.Name,
			"aws_glue_catalog_database",
			"aws",
			GlueCatalogDatabaseAllowEmptyValues)
		g.Resources = append(g.Resources, resource)
		DatabaseNames = append(DatabaseNames, catalogDatabase.Name)
	}
	return DatabaseNames, nil
}

func (g *GlueGenerator) loadGlueCatalogTable(svc *glue.Glue, account *string, databaseName *string) error {
	// format of ID is "CATALOG-ID:DATABASE-NAME:TABLE-NAME".
	// CATALOG-ID is AWS Account ID
	// https://docs.aws.amazon.com/cli/latest/reference/glue/create-database.html#options

	catalogTables, err := svc.GetTables(&glue.GetTablesInput{DatabaseName: databaseName})
	if err != nil {
		return err
	}
	var GlueCatalogTableAllowEmptyValues = []string{"tags."}

	for _, catalogTable := range catalogTables.TableList {
		id := *account + ":" + *databaseName + ":" + *catalogTable.Name
		resource := terraform_utils.NewSimpleResource(id, *catalogTable.Name,
			"aws_glue_catalog_table",
			"aws",
			GlueCatalogTableAllowEmptyValues)
		g.Resources = append(g.Resources, resource)
	}
	return nil
}

// Generate TerraformResources from AWS API,
// from each database create 1 TerraformResource.
// Need only database name as ID for terraform resource
// AWS api support paging
func (g *GlueGenerator) InitResources() error {
	sess := g.generateSession()
	svc := glue.New(sess)

	stsSvc := sts.New(sess)
	identity, err := stsSvc.GetCallerIdentity(&sts.GetCallerIdentityInput{})
	if err != nil {
		return err
	}
	account := identity.Account

	if err := g.loadGlueCrawlers(svc); err != nil {
		return err
	}
	var DatabaseNames []*string
	if DatabaseNames, err = g.loadGlueCatalogDatabase(svc, account); err != nil {
		return err
	}
	for _, DatabaseName := range DatabaseNames {
		if err := g.loadGlueCatalogTable(svc, account, DatabaseName); err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package proxmox

import (
	"encoding/json"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// LXC options for the Proxmox API
type ConfigLxc struct {
	Ostemplate         string      `json:"ostemplate"`
	Arch               string      `json:"arch"`
	BWLimit            int         `json:"bwlimit,omitempty"`
	CMode              string      `json:"cmode"`
	Console            bool        `json:"console"`
	Cores              int         `json:"cores,omitempty"`
	CPULimit           int         `json:"cpulimit"`
	CPUUnits           int         `json:"cpuunits"`
	Description        string      `json:"description,omitempty"`
	Features           QemuDevice  `json:"features,omitempty"`
	Force              bool        `json:"force,omitempty"`
	HaState            string      `json:"hastate,omitempty"`
	Hookscript         string      `json:"hookscript,omitempty"`
	Hostname           string      `json:"hostname,omitempty"`
	IgnoreUnpackErrors bool        `json:"ignore-unpack-errors,omitempty"`
	Lock               string      `json:"lock,omitempty"`
	Memory             int         `json:"memory"`
	Mountpoints        QemuDevices `json:"mountpoints,omitempty"`
	Nameserver         string      `json:"nameserver,omitempty"`
	Networks           QemuDevices `json:"networks,omitempty"`
	OnBoot             bool        `json:"onboot"`
	OsType             string      `json:"ostype,omitempty"`
	Password           string      `json:"password,omitempty"`
	Pool               string      `json:"pool,omitempty"`
	Protection         bool        `json:"protection"`
	Restore            bool        `json:"restore,omitempty"`
	RootFs             QemuDevice  `json:"rootfs,omitempty"`
	SearchDomain       string      `json:"searchdomain,omitempty"`
	SSHPublicKeys      string      `json:"ssh-public-keys,omitempty"`
	Start              bool        `json:"start"`
	Startup            string      `json:"startup,omitempty"`
	Storage            string      `json:"storage"`
	Swap               int         `json:"swap"`
	Template           bool        `json:"template,omitempty"`
	Tty                int         `json:"tty"`
	Unique             bool        `json:"unique,omitempty"`
	Unprivileged       bool        `json:"unprivileged"`
	Tags               string      `json:"tags"`
	Unused             []string    `json:"unused,omitempty"`
}

func NewConfigLxc() ConfigLxc {
	return ConfigLxc{
		Arch:         "amd64",
		CMode:        "tty",
		Console:      true,
		CPULimit:     0,
		CPUUnits:     1024,
		Memory:       512,
		OnBoot:       false,
		Protection:   false,
		Start:        false,
		Storage:      "local",
		Swap:         512,
		Template:     false,
		Tty:          2,
		Unprivileged: false,
	}
}

func NewConfigLxcFromJson(io io.Reader) (config ConfigLxc, err error) {
	config = NewConfigLxc()
	err = json.NewDecoder(io).Decode(config)
	return config, err
}

func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *ConfigLxc, err error) {
	// prepare json map to receive the information from the api
	var lxcConfig map[string]interface{}
	lxcConfig, err = client.GetVmConfig(vmr)
	if err != nil {
		return nil, err
	}

	// prepare a new lxc config to store and return\
	// the information from api
	newConfig := NewConfigLxc()
	config = &newConfig

	arch := ""
	if _, isSet := lxcConfig["arch"]; isSet {
		arch = lxcConfig["arch"].(string)
	}
	cmode := ""
	if _, isSet := lxcConfig["cmode"]; isSet {
		cmode = lxcConfig["cmode"].(string)
	}
	console := true
	if _, isSet := lxcConfig["console"]; isSet {
		console = Itob(int(lxcConfig["console"].(float64)))
	}
	cores := 0
	if _, isSet := lxcConfig["cores"]; isSet {
		cores = int(lxcConfig["cores"].(float64))
	}
	cpulimit := 0
	if _, isSet := lxcConfig["cpulimit"]; isSet {
		cpulimit, _ = strconv.Atoi(lxcConfig["cpulimit"].(string))
	}
	cpuunits := 1024
	if _, isSet := lxcConfig["cpuunits"]; isSet {
		cpuunits = int(lxcConfig["cpuunits"].(float64))
	}
	description := ""
	if _, isSet := lxcConfig["description"]; isSet {
		description = lxcConfig["description"].(string)
	}

	// add features, if any
	if features, isSet := lxcConfig["features"]; isSet {
		featureList := strings.Split(features.(string), ",")

		// create new device map to store features
		featureMap := QemuDevice{}
		// add all features to device map
		featureMap.readDeviceConfig(featureList)
		// prepare empty feature map
		if config.Features == nil {
			config.Features = QemuDevice{}
		}
		// and device config to networks
		if len(featureMap) > 0 {
			config.Features = featureMap
		}
	}

	hastate := ""
	if _, isSet := lxcConfig["hastate"]; isSet {
		hastate = lxcConfig["hastate"].(string)
	}
	hookscript := ""
	if _, isSet := lxcConfig["hookscript"]; isSet {
		hookscript = lxcConfig["hookscript"].(string)
	}
	hostname := ""
	if _, isSet := lxcConfig["hostname"]; isSet {
		hostname = lxcConfig["hostname"].(string)
	}
	lock := ""
	if _, isSet := lxcConfig["lock"]; isSet {
		lock = lxcConfig["lock"].(string)
	}
	memory := 512
	if _, isSet := lxcConfig["memory"]; isSet {
		memory = int(lxcConfig["memory"].(float64))
	}

	// add rootfs
	rootfs := QemuDevice{}
	if rootfsStr, isSet := lxcConfig["rootfs"]; isSet {
		rootfs = ParsePMConf(rootfsStr.(string), "volume")
	}

	// add mountpoints
	mpNames := []string{}

	for k, _ := range lxcConfig {
		if mpName := rxMpName.FindStringSubmatch(k); len(mpName) > 0 {
			mpNames = append(mpNames, mpName[0])
		}
	}

	for _, mpName := range mpNames {
		mpConfStr := lxcConfig[mpName].(string)
		mpConfMap := ParseLxcDisk(mpConfStr)

		// add mp id
		id := rxDeviceID.FindStringSubmatch(mpName)
		mpID, _ := strconv.Atoi(id[0])
		mpConfMap["slot"] = mpID

		// prepare empty mountpoint map
		if config.Mountpoints == nil {
			config.Mountpoints = QemuDevices{}
		}
		// and device config to mountpoints
		if len(mpConfMap) > 0 {
			config.Mountpoints[mpID] = mpConfMap
		}
	}

	nameserver := ""
	if _, isSet := lxcConfig["nameserver"]; isSet {
		nameserver = lxcConfig["nameserver"].(string)
	}

	// add networks
	nicNames := []string{}

	for k, _ := range lxcConfig {
		if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 {
			nicNames = append(nicNames, nicName[0])
		}
	}

	for _, nicName := range nicNames {
		nicConfStr := lxcConfig[nicName]
		nicConfList := strings.Split(nicConfStr.(string), ",")

		id := rxDeviceID.FindStringSubmatch(nicName)
		nicID, _ := strconv.Atoi(id[0])
		// add nic id
		nicConfMap := QemuDevice{
			"id": nicID,
		}
		// add rest of device config
		nicConfMap.readDeviceConfig(nicConfList)

		if nicConfMap["firewall"] == 1 {
			nicConfMap["firewall"] = true
		} else if nicConfMap["firewall"] == 0 {
			nicConfMap["firewall"] = false
		}

		// prepare empty network map
		if config.Networks == nil {
			config.Networks = QemuDevices{}
		}
		// and device config to networks
		if len(nicConfMap) > 0 {
			config.Networks[nicID] = nicConfMap
		}
	}

	onboot := false
	if _, isSet := lxcConfig["onboot"]; isSet {
		onboot = Itob(int(lxcConfig["onboot"].(float64)))
	}
	ostype := ""
	if _, isSet := lxcConfig["ostype"]; isSet {
		ostype = lxcConfig["ostype"].(string)
	}
	protection := false
	if _, isSet := lxcConfig["protection"]; isSet {
		protection = Itob(int(lxcConfig["protection"].(float64)))
	}
	searchdomain := ""
	if _, isSet := lxcConfig["searchdomain"]; isSet {
		searchdomain = lxcConfig["searchdomain"].(string)
	}
	startup := ""
	if _, isSet := lxcConfig["startup"]; isSet {
		startup = lxcConfig["startup"].(string)
	}
	swap := 512
	if _, isSet := lxcConfig["swap"]; isSet {
		swap = int(lxcConfig["swap"].(float64))
	}
	template := false
	if _, isSet := lxcConfig["template"]; isSet {
		template = Itob(int(lxcConfig["template"].(float64)))
	}
	tty := 2
	if _, isSet := lxcConfig["tty"]; isSet {
		tty = int(lxcConfig["tty"].(float64))
	}
	unprivileged := false
	if _, isset := lxcConfig["unprivileged"]; isset {
		unprivileged = Itob(int(lxcConfig["unprivileged"].(float64)))
	}
	tags := ""
	if _, isSet := lxcConfig["tags"]; isSet {
		tags = lxcConfig["tags"].(string)
	}
	var unused []string
	if _, isset := lxcConfig["unused"]; isset {
		unused = lxcConfig["unused"].([]string)
	}

	config.Arch = arch
	config.CMode = cmode
	config.Console = console
	config.Cores = cores
	config.CPULimit = cpulimit
	config.CPUUnits = cpuunits
	config.Description = description
	config.OnBoot = onboot
	config.HaState = hastate
	config.Hookscript = hookscript
	config.Hostname = hostname
	config.Lock = lock
	config.Memory = memory
	config.Nameserver = nameserver
	config.OnBoot = onboot
	config.OsType = ostype
	config.Protection = protection
	config.RootFs = rootfs
	config.SearchDomain = searchdomain
	config.Startup = startup
	config.Swap = swap
	config.Template = template
	config.Tty = tty
	config.Unprivileged = unprivileged
	config.Unused = unused
	config.Tags = tags

	return
}

// create LXC container using the Proxmox API
func (config ConfigLxc) CreateLxc(vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("lxc")
	paramMap := config.mapToAPIParams()

	// amend vmid
	paramMap["vmid"] = vmr.vmId

	exitStatus, err := client.CreateLxcContainer(vmr.node, paramMap)
	if err != nil {
		params, _ := json.Marshal(&paramMap)
		return fmt.Errorf("Error creating LXC container: %v, error status: %s (params: %v)", err, exitStatus, string(params))
	}

	_, err = client.UpdateVMHA(vmr, config.HaState)
	if err != nil {
		return fmt.Errorf("[ERROR] %q", err)
	}

	return
}

func (config ConfigLxc) UpdateConfig(vmr *VmRef, client *Client) (err error) {
	paramMap := config.mapToAPIParams()

	// delete parameters wich are not supported in updated operations
	delete(paramMap, "pool")
	delete(paramMap, "storage")
	delete(paramMap, "password")
	delete(paramMap, "ostemplate")
	delete(paramMap, "start")

	// even though it is listed as a PUT option in the API documentation
	// we remove it here because "it should not be modified manually";
	// also, error "500 unable to modify read-only option: 'unprivileged'"
	delete(paramMap, "unprivileged")

	_, err = client.UpdateVMHA(vmr, config.HaState)
	if err != nil {
		return err
	}

	_, err = client.SetLxcConfig(vmr, paramMap)
	return err
}

func ParseLxcDisk(diskStr string) QemuDevice {
	disk := ParsePMConf(diskStr, "volume")

	// add features, if any
	if mountoptions, isSet := disk["mountoptions"]; isSet {
		moList := strings.Split(mountoptions.(string), ";")
		moMap := map[string]bool{}
		for _, mo := range moList {
			moMap[mo] = true
		}
		disk["mountoptions"] = moMap
	}

	storageName, fileName := ParseSubConf(disk["volume"].(string), ":")
	disk["storage"] = storageName
	disk["file"] = fileName

	return disk
}

func (config ConfigLxc) mapToAPIParams() map[string]interface{} {
	// convert config to map
	params, _ := json.Marshal(&config)
	var paramMap map[string]interface{}
	json.Unmarshal(params, &paramMap)

	// build list of features
	// add features as parameter list to lxc parameters
	// this overwrites the orginal formatting with a
	// comma separated list of "key=value" pairs
	paramMap["features"] = formatDeviceParam(config.Features)

	// format rootfs params as expected
	if rootfs := config.RootFs; rootfs != nil {
		paramMap["rootfs"] = FormatDiskParam(rootfs)
	}

	// build list of mountpoints
	// this does the same as for the feature list
	// except that there can be multiple of these mountpoint sets
	// and each mountpoint set comes with a new id
	for _, mpConfMap := range config.Mountpoints {
		// add mp to lxc parameters
		mpID := mpConfMap["slot"]
		mpName := fmt.Sprintf("mp%v", mpID)
		paramMap[mpName] = FormatDiskParam(mpConfMap)
	}

	// build list of network parameters
	for nicID, nicConfMap := range config.Networks {
		// add nic to lxc parameters
		nicName := fmt.Sprintf("net%v", nicID)
		paramMap[nicName] = formatDeviceParam(nicConfMap)
	}

	// build list of unused volumes for sake of completeness,
	// even if it is not recommended to change these volumes manually
	for volID, vol := range config.Unused {
		// add volume to lxc parameters
		volName := fmt.Sprintf("unused%v", volID)
		paramMap[volName] = vol
	}

	// now that we concatenated the key value parameter
	// list for the networks, mountpoints and unused volumes,
	// remove the original keys, since the Proxmox API does
	// not know how to handle this key
	delete(paramMap, "networks")
	delete(paramMap, "mountpoints")
	delete(paramMap, "unused")

	// also delete the hastate key which is used elsewhere
	delete(paramMap, "hastate")

	return paramMap
}
<commit_msg>LXC mountpount int to boolean conversion<commit_after>package proxmox

import (
	"encoding/json"
	"fmt"
	"io"
	"strconv"
	"strings"
)

// LXC options for the Proxmox API
type ConfigLxc struct {
	Ostemplate         string      `json:"ostemplate"`
	Arch               string      `json:"arch"`
	BWLimit            int         `json:"bwlimit,omitempty"`
	CMode              string      `json:"cmode"`
	Console            bool        `json:"console"`
	Cores              int         `json:"cores,omitempty"`
	CPULimit           int         `json:"cpulimit"`
	CPUUnits           int         `json:"cpuunits"`
	Description        string      `json:"description,omitempty"`
	Features           QemuDevice  `json:"features,omitempty"`
	Force              bool        `json:"force,omitempty"`
	HaState            string      `json:"hastate,omitempty"`
	Hookscript         string      `json:"hookscript,omitempty"`
	Hostname           string      `json:"hostname,omitempty"`
	IgnoreUnpackErrors bool        `json:"ignore-unpack-errors,omitempty"`
	Lock               string      `json:"lock,omitempty"`
	Memory             int         `json:"memory"`
	Mountpoints        QemuDevices `json:"mountpoints,omitempty"`
	Nameserver         string      `json:"nameserver,omitempty"`
	Networks           QemuDevices `json:"networks,omitempty"`
	OnBoot             bool        `json:"onboot"`
	OsType             string      `json:"ostype,omitempty"`
	Password           string      `json:"password,omitempty"`
	Pool               string      `json:"pool,omitempty"`
	Protection         bool        `json:"protection"`
	Restore            bool        `json:"restore,omitempty"`
	RootFs             QemuDevice  `json:"rootfs,omitempty"`
	SearchDomain       string      `json:"searchdomain,omitempty"`
	SSHPublicKeys      string      `json:"ssh-public-keys,omitempty"`
	Start              bool        `json:"start"`
	Startup            string      `json:"startup,omitempty"`
	Storage            string      `json:"storage"`
	Swap               int         `json:"swap"`
	Template           bool        `json:"template,omitempty"`
	Tty                int         `json:"tty"`
	Unique             bool        `json:"unique,omitempty"`
	Unprivileged       bool        `json:"unprivileged"`
	Tags               string      `json:"tags"`
	Unused             []string    `json:"unused,omitempty"`
}

func NewConfigLxc() ConfigLxc {
	return ConfigLxc{
		Arch:         "amd64",
		CMode:        "tty",
		Console:      true,
		CPULimit:     0,
		CPUUnits:     1024,
		Memory:       512,
		OnBoot:       false,
		Protection:   false,
		Start:        false,
		Storage:      "local",
		Swap:         512,
		Template:     false,
		Tty:          2,
		Unprivileged: false,
	}
}

func NewConfigLxcFromJson(io io.Reader) (config ConfigLxc, err error) {
	config = NewConfigLxc()
	err = json.NewDecoder(io).Decode(config)
	return config, err
}

func NewConfigLxcFromApi(vmr *VmRef, client *Client) (config *ConfigLxc, err error) {
	// prepare json map to receive the information from the api
	var lxcConfig map[string]interface{}
	lxcConfig, err = client.GetVmConfig(vmr)
	if err != nil {
		return nil, err
	}

	// prepare a new lxc config to store and return\
	// the information from api
	newConfig := NewConfigLxc()
	config = &newConfig

	arch := ""
	if _, isSet := lxcConfig["arch"]; isSet {
		arch = lxcConfig["arch"].(string)
	}
	cmode := ""
	if _, isSet := lxcConfig["cmode"]; isSet {
		cmode = lxcConfig["cmode"].(string)
	}
	console := true
	if _, isSet := lxcConfig["console"]; isSet {
		console = Itob(int(lxcConfig["console"].(float64)))
	}
	cores := 0
	if _, isSet := lxcConfig["cores"]; isSet {
		cores = int(lxcConfig["cores"].(float64))
	}
	cpulimit := 0
	if _, isSet := lxcConfig["cpulimit"]; isSet {
		cpulimit, _ = strconv.Atoi(lxcConfig["cpulimit"].(string))
	}
	cpuunits := 1024
	if _, isSet := lxcConfig["cpuunits"]; isSet {
		cpuunits = int(lxcConfig["cpuunits"].(float64))
	}
	description := ""
	if _, isSet := lxcConfig["description"]; isSet {
		description = lxcConfig["description"].(string)
	}

	// add features, if any
	if features, isSet := lxcConfig["features"]; isSet {
		featureList := strings.Split(features.(string), ",")

		// create new device map to store features
		featureMap := QemuDevice{}
		// add all features to device map
		featureMap.readDeviceConfig(featureList)
		// prepare empty feature map
		if config.Features == nil {
			config.Features = QemuDevice{}
		}
		// and device config to networks
		if len(featureMap) > 0 {
			config.Features = featureMap
		}
	}

	hastate := ""
	if _, isSet := lxcConfig["hastate"]; isSet {
		hastate = lxcConfig["hastate"].(string)
	}
	hookscript := ""
	if _, isSet := lxcConfig["hookscript"]; isSet {
		hookscript = lxcConfig["hookscript"].(string)
	}
	hostname := ""
	if _, isSet := lxcConfig["hostname"]; isSet {
		hostname = lxcConfig["hostname"].(string)
	}
	lock := ""
	if _, isSet := lxcConfig["lock"]; isSet {
		lock = lxcConfig["lock"].(string)
	}
	memory := 512
	if _, isSet := lxcConfig["memory"]; isSet {
		memory = int(lxcConfig["memory"].(float64))
	}

	// add rootfs
	rootfs := QemuDevice{}
	if rootfsStr, isSet := lxcConfig["rootfs"]; isSet {
		rootfs = ParsePMConf(rootfsStr.(string), "volume")
	}

	// add mountpoints
	mpNames := []string{}

	for k, _ := range lxcConfig {
		if mpName := rxMpName.FindStringSubmatch(k); len(mpName) > 0 {
			mpNames = append(mpNames, mpName[0])
		}
	}

	for _, mpName := range mpNames {
		mpConfStr := lxcConfig[mpName].(string)
		mpConfMap := ParseLxcDisk(mpConfStr)

		// add mp id
		id := rxDeviceID.FindStringSubmatch(mpName)
		mpID, _ := strconv.Atoi(id[0])
		mpConfMap["slot"] = mpID

		mpConfMap["backup"] = mpConfMap["backup"] != 0

		// prepare empty mountpoint map
		if config.Mountpoints == nil {
			config.Mountpoints = QemuDevices{}
		}
		// and device config to mountpoints
		if len(mpConfMap) > 0 {
			config.Mountpoints[mpID] = mpConfMap
		}
	}

	nameserver := ""
	if _, isSet := lxcConfig["nameserver"]; isSet {
		nameserver = lxcConfig["nameserver"].(string)
	}

	// add networks
	nicNames := []string{}

	for k, _ := range lxcConfig {
		if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 {
			nicNames = append(nicNames, nicName[0])
		}
	}

	for _, nicName := range nicNames {
		nicConfStr := lxcConfig[nicName]
		nicConfList := strings.Split(nicConfStr.(string), ",")

		id := rxDeviceID.FindStringSubmatch(nicName)
		nicID, _ := strconv.Atoi(id[0])
		// add nic id
		nicConfMap := QemuDevice{
			"id": nicID,
		}
		// add rest of device config
		nicConfMap.readDeviceConfig(nicConfList)

		nicConfMap["firewall"] = nicConfMap["firewall"] != 0

		// prepare empty network map
		if config.Networks == nil {
			config.Networks = QemuDevices{}
		}
		// and device config to networks
		if len(nicConfMap) > 0 {
			config.Networks[nicID] = nicConfMap
		}
	}

	onboot := false
	if _, isSet := lxcConfig["onboot"]; isSet {
		onboot = Itob(int(lxcConfig["onboot"].(float64)))
	}
	ostype := ""
	if _, isSet := lxcConfig["ostype"]; isSet {
		ostype = lxcConfig["ostype"].(string)
	}
	protection := false
	if _, isSet := lxcConfig["protection"]; isSet {
		protection = Itob(int(lxcConfig["protection"].(float64)))
	}
	searchdomain := ""
	if _, isSet := lxcConfig["searchdomain"]; isSet {
		searchdomain = lxcConfig["searchdomain"].(string)
	}
	startup := ""
	if _, isSet := lxcConfig["startup"]; isSet {
		startup = lxcConfig["startup"].(string)
	}
	swap := 512
	if _, isSet := lxcConfig["swap"]; isSet {
		swap = int(lxcConfig["swap"].(float64))
	}
	template := false
	if _, isSet := lxcConfig["template"]; isSet {
		template = Itob(int(lxcConfig["template"].(float64)))
	}
	tty := 2
	if _, isSet := lxcConfig["tty"]; isSet {
		tty = int(lxcConfig["tty"].(float64))
	}
	unprivileged := false
	if _, isset := lxcConfig["unprivileged"]; isset {
		unprivileged = Itob(int(lxcConfig["unprivileged"].(float64)))
	}
	tags := ""
	if _, isSet := lxcConfig["tags"]; isSet {
		tags = lxcConfig["tags"].(string)
	}
	var unused []string
	if _, isset := lxcConfig["unused"]; isset {
		unused = lxcConfig["unused"].([]string)
	}

	config.Arch = arch
	config.CMode = cmode
	config.Console = console
	config.Cores = cores
	config.CPULimit = cpulimit
	config.CPUUnits = cpuunits
	config.Description = description
	config.OnBoot = onboot
	config.HaState = hastate
	config.Hookscript = hookscript
	config.Hostname = hostname
	config.Lock = lock
	config.Memory = memory
	config.Nameserver = nameserver
	config.OnBoot = onboot
	config.OsType = ostype
	config.Protection = protection
	config.RootFs = rootfs
	config.SearchDomain = searchdomain
	config.Startup = startup
	config.Swap = swap
	config.Template = template
	config.Tty = tty
	config.Unprivileged = unprivileged
	config.Unused = unused
	config.Tags = tags

	return
}

// create LXC container using the Proxmox API
func (config ConfigLxc) CreateLxc(vmr *VmRef, client *Client) (err error) {
	vmr.SetVmType("lxc")
	paramMap := config.mapToAPIParams()

	// amend vmid
	paramMap["vmid"] = vmr.vmId

	exitStatus, err := client.CreateLxcContainer(vmr.node, paramMap)
	if err != nil {
		params, _ := json.Marshal(&paramMap)
		return fmt.Errorf("Error creating LXC container: %v, error status: %s (params: %v)", err, exitStatus, string(params))
	}

	_, err = client.UpdateVMHA(vmr, config.HaState)
	if err != nil {
		return fmt.Errorf("[ERROR] %q", err)
	}

	return
}

func (config ConfigLxc) UpdateConfig(vmr *VmRef, client *Client) (err error) {
	paramMap := config.mapToAPIParams()

	// delete parameters wich are not supported in updated operations
	delete(paramMap, "pool")
	delete(paramMap, "storage")
	delete(paramMap, "password")
	delete(paramMap, "ostemplate")
	delete(paramMap, "start")

	// even though it is listed as a PUT option in the API documentation
	// we remove it here because "it should not be modified manually";
	// also, error "500 unable to modify read-only option: 'unprivileged'"
	delete(paramMap, "unprivileged")

	_, err = client.UpdateVMHA(vmr, config.HaState)
	if err != nil {
		return err
	}

	_, err = client.SetLxcConfig(vmr, paramMap)
	return err
}

func ParseLxcDisk(diskStr string) QemuDevice {
	disk := ParsePMConf(diskStr, "volume")

	// add features, if any
	if mountoptions, isSet := disk["mountoptions"]; isSet {
		moList := strings.Split(mountoptions.(string), ";")
		moMap := map[string]bool{}
		for _, mo := range moList {
			moMap[mo] = true
		}
		disk["mountoptions"] = moMap
	}

	storageName, fileName := ParseSubConf(disk["volume"].(string), ":")
	disk["storage"] = storageName
	disk["file"] = fileName

	return disk
}

func (config ConfigLxc) mapToAPIParams() map[string]interface{} {
	// convert config to map
	params, _ := json.Marshal(&config)
	var paramMap map[string]interface{}
	json.Unmarshal(params, &paramMap)

	// build list of features
	// add features as parameter list to lxc parameters
	// this overwrites the orginal formatting with a
	// comma separated list of "key=value" pairs
	paramMap["features"] = formatDeviceParam(config.Features)

	// format rootfs params as expected
	if rootfs := config.RootFs; rootfs != nil {
		paramMap["rootfs"] = FormatDiskParam(rootfs)
	}

	// build list of mountpoints
	// this does the same as for the feature list
	// except that there can be multiple of these mountpoint sets
	// and each mountpoint set comes with a new id
	for _, mpConfMap := range config.Mountpoints {
		// add mp to lxc parameters
		mpID := mpConfMap["slot"]
		mpName := fmt.Sprintf("mp%v", mpID)
		paramMap[mpName] = FormatDiskParam(mpConfMap)
	}

	// build list of network parameters
	for nicID, nicConfMap := range config.Networks {
		// add nic to lxc parameters
		nicName := fmt.Sprintf("net%v", nicID)
		paramMap[nicName] = formatDeviceParam(nicConfMap)
	}

	// build list of unused volumes for sake of completeness,
	// even if it is not recommended to change these volumes manually
	for volID, vol := range config.Unused {
		// add volume to lxc parameters
		volName := fmt.Sprintf("unused%v", volID)
		paramMap[volName] = vol
	}

	// now that we concatenated the key value parameter
	// list for the networks, mountpoints and unused volumes,
	// remove the original keys, since the Proxmox API does
	// not know how to handle this key
	delete(paramMap, "networks")
	delete(paramMap, "mountpoints")
	delete(paramMap, "unused")

	// also delete the hastate key which is used elsewhere
	delete(paramMap, "hastate")

	return paramMap
}
<|endoftext|>


<commit_before>package events

import (
	"context"
	"fmt"

	"github.com/hashicorp/nomad/api"
	"github.com/hashicorp/nomad/e2e/e2eutil"
	"github.com/hashicorp/nomad/e2e/framework"
	"github.com/hashicorp/nomad/helper/uuid"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

type EventsTest struct {
	framework.TC
	jobIDs []string
}

func init() {
	framework.AddSuites(&framework.TestSuite{
		Component:   "Events",
		CanRunLocal: true,
		Cases: []framework.TestCase{
			new(EventsTest),
		},
	})
}

func (tc *EventsTest) BeforeAll(f *framework.F) {
	e2eutil.WaitForLeader(f.T(), tc.Nomad())
}

func (tc *EventsTest) AfterEach(f *framework.F) {
	nomadClient := tc.Nomad()
	j := nomadClient.Jobs()

	for _, id := range tc.jobIDs {
		j.Deregister(id, true, nil)
	}
	_, err := e2eutil.Command("nomad", "system", "gc")
	f.NoError(err)
}

// TestDeploymentEvents registers a job then applies a change
// An event stream listening to Deployment Events asserts that
// a DeploymentPromotion event is emitted
func (tc *EventsTest) TestDeploymentEvents(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("deployment-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	topics := map[api.Topic][]string{
		api.TopicDeployment: {jobID},
	}

	var deployEvents []api.Event
	streamCh, err := events.Stream(ctx, topics, 0, nil)
	require.NoError(t, err)

	// gather deployment events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event := <-streamCh:
				if event.IsHeartbeat() {
					continue
				}

				deployEvents = append(deployEvents, event.Events...)
			}
		}
	}()

	// register job
	e2eutil.RegisterAndWaitForAllocs(t, nomadClient, "events/input/initial.nomad", jobID, "")

	// update job
	e2eutil.RegisterAllocs(t, nomadClient, "events/input/deploy.nomad", jobID, "")

	ds := e2eutil.DeploymentsForJob(t, nomadClient, jobID)
	require.Equal(t, 2, len(ds))
	deploy := ds[0]

	// wait for deployment to be running and ready for auto promote
	e2eutil.WaitForDeployment(t, nomadClient, deploy.ID, structs.DeploymentStatusRunning, structs.DeploymentStatusDescriptionRunningAutoPromotion)

	// ensure there is a deployment promotion event
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range deployEvents {
			if e.Type == "DeploymentPromotion" {
				return true, nil
			}
		}
		var got []string
		for _, e := range deployEvents {
			got = append(got, e.Type)
		}
		return false, fmt.Errorf("expected to receive deployment promotion event, got: %#v", got)
	}, func(e error) {
		f.NoError(e)
	})
}

// TestBlockedEvalEvents applies a job with a large memory requirement. The
// event stream checks for a failed task group alloc
func (tc *EventsTest) TestBlockedEvalEvents(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("blocked-deploy-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	topics := map[api.Topic][]string{
		api.TopicEvaluation: {"*"},
	}

	var evalEvents []api.Event
	streamCh, err := events.Stream(ctx, topics, 0, nil)
	require.NoError(t, err)

	// gather deployment events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event := <-streamCh:
				if event.IsHeartbeat() {
					continue
				}

				evalEvents = append(evalEvents, event.Events...)
			}
		}
	}()

	// register job
	e2eutil.Register(jobID, "events/input/large-job.nomad")

	// ensure there is a deployment promotion event
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range evalEvents {
			eval, err := e.Evaluation()
			if err != nil {
				return false, fmt.Errorf("event was not an evaluation %w", err)
			}

			ftg := eval.FailedTGAllocs

			tg, ok := ftg["one"]
			if !ok {
				continue
			}

			mem := tg.DimensionExhausted["memory"]
			require.NotNil(t, mem, "memory dimension was nil")
			require.Greater(t, mem, 0, "memory dimension was zero")
			return true, nil

		}
		return false, fmt.Errorf("expected blocked eval with memory exhausted, got: %#v", evalEvents)
	}, func(e error) {
		require.NoError(t, e)
	})
}

// TestStartIndex applies a job, then connects to the stream with a start
// index to verify that the events from before the job are not included.
func (tc *EventsTest) TestStartIndex(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("deployment-%s", uuid[0:8])
	jobID2 := fmt.Sprintf("deployment2-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID, jobID2)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// register job
	err := e2eutil.Register(jobID, "events/input/initial.nomad")
	require.NoError(t, err)
	job, _, err := nomadClient.Jobs().Info(jobID, nil)
	require.NoError(t, err)
	startIndex := *job.JobModifyIndex + 1

	topics := map[api.Topic][]string{
		api.TopicJob: {"*"},
	}

	// starting at Job.ModifyIndex + 1, the next (and only) JobRegistered event that we see
	// should be from a different job registration
	streamCh, err := events.Stream(ctx, topics, startIndex, nil)
	require.NoError(t, err)

	var jobEvents []api.Event
	// gather job register events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event := <-streamCh:
				if event.IsHeartbeat() {
					continue
				}
				jobEvents = append(jobEvents, event.Events...)
			}
		}
	}()

	// new job (to make sure we get a JobRegistered event)
	err = e2eutil.Register(jobID2, "events/input/deploy.nomad")
	require.NoError(t, err)

	// ensure there is a deployment promotion event
	foundUnexpected := false
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range jobEvents {
			if e.Type == "JobRegistered" {
				if e.Index <= startIndex {
					foundUnexpected = true
				}
				if e.Index >= startIndex {
					return true, nil
				}
			}
		}
		return false, fmt.Errorf("expected to receive JobRegistered event for index at least %v", startIndex)
	}, func(e error) {
		f.NoError(e)
	})
	require.False(t, foundUnexpected, "found events from earlier-than-expected indices")
}
<commit_msg>e2e: deflake events<commit_after>package events

import (
	"context"
	"fmt"

	"github.com/hashicorp/nomad/api"
	"github.com/hashicorp/nomad/e2e/e2eutil"
	"github.com/hashicorp/nomad/e2e/framework"
	"github.com/hashicorp/nomad/helper/uuid"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/hashicorp/nomad/testutil"
	"github.com/stretchr/testify/require"
)

type EventsTest struct {
	framework.TC
	jobIDs []string
}

func init() {
	framework.AddSuites(&framework.TestSuite{
		Component:   "Events",
		CanRunLocal: true,
		Cases: []framework.TestCase{
			new(EventsTest),
		},
	})
}

func (tc *EventsTest) BeforeAll(f *framework.F) {
	e2eutil.WaitForLeader(f.T(), tc.Nomad())
}

func (tc *EventsTest) AfterEach(f *framework.F) {
	nomadClient := tc.Nomad()
	j := nomadClient.Jobs()

	for _, id := range tc.jobIDs {
		j.Deregister(id, true, nil)
	}
	_, err := e2eutil.Command("nomad", "system", "gc")
	f.NoError(err)
}

// TestDeploymentEvents registers a job then applies a change
// An event stream listening to Deployment Events asserts that
// a DeploymentPromotion event is emitted
func (tc *EventsTest) TestDeploymentEvents(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("deployment-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	topics := map[api.Topic][]string{
		api.TopicDeployment: {jobID},
	}

	var deployEvents []api.Event
	streamCh, err := events.Stream(ctx, topics, 0, nil)
	require.NoError(t, err)

	// gather deployment events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event := <-streamCh:
				if event.IsHeartbeat() {
					continue
				}

				deployEvents = append(deployEvents, event.Events...)
			}
		}
	}()

	// register job
	e2eutil.RegisterAndWaitForAllocs(t, nomadClient, "events/input/initial.nomad", jobID, "")

	// update job
	e2eutil.RegisterAllocs(t, nomadClient, "events/input/deploy.nomad", jobID, "")

	ds := e2eutil.DeploymentsForJob(t, nomadClient, jobID)
	require.Equal(t, 2, len(ds))
	deploy := ds[0]

	// wait for deployment to be running and ready for auto promote
	e2eutil.WaitForDeployment(t, nomadClient, deploy.ID, structs.DeploymentStatusRunning, structs.DeploymentStatusDescriptionRunningAutoPromotion)

	// ensure there is a deployment promotion event
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range deployEvents {
			if e.Type == "DeploymentPromotion" {
				return true, nil
			}
		}
		var got []string
		for _, e := range deployEvents {
			got = append(got, e.Type)
		}
		return false, fmt.Errorf("expected to receive deployment promotion event, got: %#v", got)
	}, func(e error) {
		f.NoError(e)
	})
}

// TestBlockedEvalEvents applies a job with a large memory requirement. The
// event stream checks for a failed task group alloc
func (tc *EventsTest) TestBlockedEvalEvents(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("blocked-deploy-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	topics := map[api.Topic][]string{
		api.TopicEvaluation: {"*"},
	}

	var evalEvents []api.Event
	streamCh, err := events.Stream(ctx, topics, 0, nil)
	require.NoError(t, err)

	// gather deployment events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event := <-streamCh:
				if event.IsHeartbeat() {
					continue
				}

				evalEvents = append(evalEvents, event.Events...)
			}
		}
	}()

	// register job
	e2eutil.Register(jobID, "events/input/large-job.nomad")

	// ensure there is a deployment promotion event
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range evalEvents {
			eval, err := e.Evaluation()
			if err != nil {
				return false, fmt.Errorf("event was not an evaluation %w", err)
			}

			ftg := eval.FailedTGAllocs

			tg, ok := ftg["one"]
			if !ok {
				continue
			}

			mem := tg.DimensionExhausted["memory"]
			require.NotNil(t, mem, "memory dimension was nil")
			require.Greater(t, mem, 0, "memory dimension was zero")
			return true, nil

		}
		return false, fmt.Errorf("expected blocked eval with memory exhausted, got: %#v", evalEvents)
	}, func(e error) {
		require.NoError(t, e)
	})
}

// TestStartIndex applies a job, then connects to the stream with a start
// index to verify that the events from before the job are not included.
func (tc *EventsTest) TestStartIndex(f *framework.F) {
	t := f.T()

	nomadClient := tc.Nomad()
	events := nomadClient.EventStream()

	uuid := uuid.Generate()
	jobID := fmt.Sprintf("deployment-%s", uuid[0:8])
	jobID2 := fmt.Sprintf("deployment2-%s", uuid[0:8])
	tc.jobIDs = append(tc.jobIDs, jobID, jobID2)
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// register job
	err := e2eutil.Register(jobID, "events/input/initial.nomad")
	require.NoError(t, err)
	job, _, err := nomadClient.Jobs().Info(jobID, nil)
	require.NoError(t, err)
	startIndex := *job.JobModifyIndex + 1

	topics := map[api.Topic][]string{
		api.TopicJob: {"*"},
	}

	// starting at Job.ModifyIndex + 1, the next (and only) JobRegistered event that we see
	// should be from a different job registration
	streamCh, err := events.Stream(ctx, topics, startIndex, nil)
	require.NoError(t, err)

	var jobEvents []api.Event
	// gather job register events
	go func() {
		for {
			select {
			case <-ctx.Done():
				return
			case event, ok := <-streamCh:
				if !ok {
					return
				}
				if event.IsHeartbeat() {
					continue
				}
				jobEvents = append(jobEvents, event.Events...)
			}
		}
	}()

	// new job (to make sure we get a JobRegistered event)
	err = e2eutil.Register(jobID2, "events/input/deploy.nomad")
	require.NoError(t, err)

	// ensure there is a deployment promotion event
	foundUnexpected := false
	testutil.WaitForResult(func() (bool, error) {
		for _, e := range jobEvents {
			if e.Type == "JobRegistered" {
				if e.Index <= startIndex {
					foundUnexpected = true
				}
				if e.Index >= startIndex {
					return true, nil
				}
			}
		}
		return false, fmt.Errorf("expected to receive JobRegistered event for index at least %v", startIndex)
	}, func(e error) {
		f.NoError(e)
	})
	require.False(t, foundUnexpected, "found events from earlier-than-expected indices")
}
<|endoftext|>


<commit_before>package main

import "bufio"
import "fmt"
import "encoding/json"
import "net/http"
import "os"
import "strings"

func getData(url string) (data []string) {
	resp, err := http.Get(url)
	if err != nil {
		os.Stderr.Write([]byte("Error: " + err.Error()))
		os.Exit(1)
	}

	defer resp.Body.Close()

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		data = append(data, strings.TrimRight(scanner.Text(), "\n"))
		if err != nil {
			break
		}
	}
	return
}

func crawlData(url string) map[string]interface{} {
	data := make(map[string]interface{})
	urlData := getData(url)

	for _, line := range urlData {
		switch {
		default:
			data[line] = getData(url + line)[0]
		case line == "dynamic":
			break
		case line == "meta-data":
			data[line] = crawlData(url + line + "/")
		case line == "user-data":
			data[line] = strings.Join(getData(url+line+"/"), "")
		case strings.HasSuffix(line, "/"):
			data[line[:len(line)-1]] = crawlData(url + line)
		case strings.HasSuffix(url, "public-keys/"):
			keyId := strings.SplitN(line, "=", 2)[0]
			data[line] = crawlData(url + keyId + "/")
		}
	}
	return data
}

func jsonData(url string) string {
	data, err := json.MarshalIndent(crawlData(url), "", "    ")
	if err != nil {
		os.Stderr.Write([]byte("Error: " + err.Error()))
		os.Exit(1)
	}
	return string(data)
}

func main() {
	url := "http://169.254.169.254/latest/"

	os.Stdout.WriteString(jsonData(url))
	fmt.Println("")
}
<commit_msg>minor refactor<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"
)

func getData(url string) (data []string) {
	resp, err := http.Get(url)
	if err != nil {
		os.Stderr.Write([]byte("Error: " + err.Error()))
		os.Exit(1)
	}

	defer resp.Body.Close()

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		data = append(data, strings.TrimRight(scanner.Text(), "\n"))
		if err != nil {
			break
		}
	}
	return
}

func crawlData(url string) map[string]interface{} {
	data := make(map[string]interface{})
	urlData := getData(url)

	for _, line := range urlData {
		switch {
		default:
			data[line] = getData(url + line)[0]
		case line == "dynamic":
			break
		case line == "meta-data":
			data[line] = crawlData(url + line + "/")
		case line == "user-data":
			data[line] = strings.Join(getData(url+line+"/"), "")
		case strings.HasSuffix(line, "/"):
			data[line[:len(line)-1]] = crawlData(url + line)
		case strings.HasSuffix(url, "public-keys/"):
			keyId := strings.SplitN(line, "=", 2)[0]
			data[line] = crawlData(url + keyId + "/")
		}
	}
	return data
}

func jsonData(url string) string {
	data, err := json.MarshalIndent(crawlData(url), "", "    ")
	if err != nil {
		os.Stderr.Write([]byte("Error: " + err.Error()))
		os.Exit(1)
	}
	return string(data)
}

func main() {
	url := "http://169.254.169.254/latest/"

	os.Stdout.WriteString(jsonData(url))
	fmt.Println("")
}
<|endoftext|>


<commit_before>package edit

import (
	"testing"

	"github.com/elves/elvish/edit/ui"
)

var (
	theLine    = "qw search 'foo bar ~y'"
	theLastCmd = newLastCmd(theLine)

	lastcmdFilterTests = []listingFilterTestCases{
		{"", []shown{
			{"M-,", ui.Unstyled(theLine)},
			{"0", ui.Unstyled("qw")},
			{"1", ui.Unstyled("search")},
			{"2", ui.Unstyled("'foo bar ~y'")}}},
		{"1", []shown{{"1", ui.Unstyled("search")}}},
		{"-", []shown{
			{"M-,", ui.Unstyled(theLine)},
			{"-3", ui.Unstyled("qw")},
			{"-2", ui.Unstyled("search")},
			{"-1", ui.Unstyled("'foo bar ~y'")}}},
		{"-1", []shown{{"-1", ui.Unstyled("'foo bar ~y'")}}},
	}
)

func TestLastCmd(t *testing.T) {
	testListingFilter(t, "theLastCmd", theLastCmd, lastcmdFilterTests)
}
<commit_msg>Fix test for lastcmd mode.<commit_after>package edit

import (
	"testing"

	"github.com/elves/elvish/edit/ui"
)

var (
	theLine    = "qw search 'foo bar ~y'"
	theLastCmd = newLastCmd(theLine)

	lastcmdFilterTests = []listingFilterTestCases{
		{"", []shown{
			{"M-1", ui.Unstyled(theLine)},
			{"0", ui.Unstyled("qw")},
			{"1", ui.Unstyled("search")},
			{"2", ui.Unstyled("'foo bar ~y'")}}},
		{"1", []shown{{"1", ui.Unstyled("search")}}},
		{"-", []shown{
			{"M-1", ui.Unstyled(theLine)},
			{"-3", ui.Unstyled("qw")},
			{"-2", ui.Unstyled("search")},
			{"-1", ui.Unstyled("'foo bar ~y'")}}},
		{"-1", []shown{{"-1", ui.Unstyled("'foo bar ~y'")}}},
	}
)

func TestLastCmd(t *testing.T) {
	testListingFilter(t, "theLastCmd", theLastCmd, lastcmdFilterTests)
}
<|endoftext|>