<commit_before>package govaluate

import (
	"testing"
)

/*
	Represents a test of correctly creating a SQL query string from an expression.
*/
type QueryTest struct {

	Name string
	Input string
	Expected string
}

func TestSQLSerialization(test *testing.T) {

	testCases := []QueryTest {

		QueryTest {

			Name: "Single GT",
			Input: "1 > 0",
			Expected: "1 > 0",
		},
		QueryTest {

			Name: "Single LT",
			Input: "0 < 1",
			Expected: "0 < 1",
		},
		QueryTest {

			Name: "Single GTE",
			Input: "1 >= 0",
			Expected: "1 >= 0",
		},
		QueryTest {

			Name: "Single LTE",
			Input: "0 <= 1",
			Expected: "0 <= 1",
		},
		QueryTest {

			Name: "Single EQ",
			Input: "1 == 0",
			Expected: "1 = 0",
		},
		QueryTest {

			Name: "Single NEQ",
			Input: "1 != 0",
			Expected: "1 <> 0",
		},

		QueryTest {

			Name: "Parameter names",
			Input: "foo == bar",
			Expected: "[foo] = [bar]",
		},
		QueryTest {

			Name: "Strings",
			Input: "'foo'",
			Expected: "'foo'",
		},
		QueryTest {

			Name: "Date format",
			Input: "'2014-07-04'",
			Expected: "'2014-07-04T00:00:00Z'",
		},
		QueryTest {

			Name: "Clauses",
			Input: "10 + (foo + bar)",
			Expected: "10 + ( [foo] + [bar] )",
		},
	}

	runQueryTests(testCases, test);
}

func runQueryTests(testCases []QueryTest, test *testing.T) {

	var expression *EvaluableExpression
	var actualQuery string;
	var err error;

	// Run the test cases.
	for _, testCase := range testCases {

		expression, err = NewEvaluableExpression(testCase.Input)

		if(err != nil) {

			test.Logf("Test '%s' failed to parse: %s", testCase.Name, err)
			test.Logf("Expression: '%s'", testCase.Input);
			test.Fail()
			continue
		}

		actualQuery, err = expression.ToSQLQuery();

		if(err != nil) {

			test.Logf("Test '%s' failed to create query: %s", testCase.Name, err)
			test.Logf("Expression: '%s'", testCase.Input);
			test.Fail()
			continue
		}

		if(actualQuery != testCase.Expected) {

			test.Logf("Test '%s' did not create expected query. Actual: '%s'", testCase.Name, actualQuery)
			test.Logf("Actual: '%s', expected '%s'", actualQuery, testCase.Expected);
			test.Fail()
			continue
		}
	}
}
<commit_msg>Added tests to round out sql construction<commit_after>package govaluate

import (
	"testing"
)

/*
	Represents a test of correctly creating a SQL query string from an expression.
*/
type QueryTest struct {

	Name string
	Input string
	Expected string
}

func TestSQLSerialization(test *testing.T) {

	testCases := []QueryTest {

		QueryTest {

			Name: "Single GT",
			Input: "1 > 0",
			Expected: "1 > 0",
		},
		QueryTest {

			Name: "Single LT",
			Input: "0 < 1",
			Expected: "0 < 1",
		},
		QueryTest {

			Name: "Single GTE",
			Input: "1 >= 0",
			Expected: "1 >= 0",
		},
		QueryTest {

			Name: "Single LTE",
			Input: "0 <= 1",
			Expected: "0 <= 1",
		},
		QueryTest {

			Name: "Single EQ",
			Input: "1 == 0",
			Expected: "1 = 0",
		},
		QueryTest {

			Name: "Single NEQ",
			Input: "1 != 0",
			Expected: "1 <> 0",
		},

		QueryTest {

			Name: "Parameter names",
			Input: "foo == bar",
			Expected: "[foo] = [bar]",
		},
		QueryTest {

			Name: "Strings",
			Input: "'foo'",
			Expected: "'foo'",
		},
		QueryTest {

			Name: "Date format",
			Input: "'2014-07-04'",
			Expected: "'2014-07-04T00:00:00Z'",
		},
		QueryTest {

			Name: "Single PLUS",
			Input: "10 + 10",
			Expected: "10 + 10",
		},
		QueryTest {

			Name: "Single MINUS",
			Input: "10 - 10",
			Expected: "10 - 10",
		},
		QueryTest {

			Name: "Single MULTIPLY",
			Input: "10 * 10",
			Expected: "10 * 10",
		},
		QueryTest {

			Name: "Single DIVIDE",
			Input: "10 / 10",
			Expected: "10 / 10",
		},
		QueryTest {

			Name: "Single true bool",
			Input: "true",
			Expected: "1",
		},
		QueryTest {

			Name: "Single false bool",
			Input: "false",
			Expected: "0",
		},
		QueryTest {

			Name: "Single AND",
			Input: "true && true",
			Expected: "1 AND 1",
		},
		QueryTest {

			Name: "Single OR",
			Input: "true || true",
			Expected: "1 OR 1",
		},
		QueryTest {

			Name: "Clauses",
			Input: "10 + (foo + bar)",
			Expected: "10 + ( [foo] + [bar] )",
		},
	}

	runQueryTests(testCases, test);
}

func runQueryTests(testCases []QueryTest, test *testing.T) {

	var expression *EvaluableExpression
	var actualQuery string;
	var err error;

	// Run the test cases.
	for _, testCase := range testCases {

		expression, err = NewEvaluableExpression(testCase.Input)

		if(err != nil) {

			test.Logf("Test '%s' failed to parse: %s", testCase.Name, err)
			test.Logf("Expression: '%s'", testCase.Input);
			test.Fail()
			continue
		}

		actualQuery, err = expression.ToSQLQuery();

		if(err != nil) {

			test.Logf("Test '%s' failed to create query: %s", testCase.Name, err)
			test.Logf("Expression: '%s'", testCase.Input);
			test.Fail()
			continue
		}

		if(actualQuery != testCase.Expected) {

			test.Logf("Test '%s' did not create expected query. Actual: '%s'", testCase.Name, actualQuery)
			test.Logf("Actual: '%s', expected '%s'", actualQuery, testCase.Expected);
			test.Fail()
			continue
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"image"
	"image/color"
	"image/gif"
	"io"
	"math"
	"math/rand"
	"os"
)

var palette = []color.Color{color.White, color.Black}

const (
	whiteIndex = 0
	blackIndex = 1
)

func main() {
	lissajous(os.Stdout)
}

func lissajous(out io.Writer) {
	const (
		cycles  = 5
		res     = 0.001
		size    = 100
		nframes = 64
		delay   = 8
	)
	freq := rand.Float64() * 3.0
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < cycles*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), blackIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	gif.EncodeAll(out, &anim)
}
<commit_msg>turn the GIF into something more authentic ex 1.5<commit_after>package main

import (
	"image"
	"image/color"
	"image/gif"
	"io"
	"math"
	"math/rand"
	"os"
)

var palette = []color.Color{color.Black, color.RGBA{0x00, 0xff, 0x00, 0xff}}

const (
	blackIndex = 0
	greenIndex = 1
)

func main() {
	lissajous(os.Stdout)
}

func lissajous(out io.Writer) {
	const (
		cycles  = 5
		res     = 0.001
		size    = 100
		nframes = 64
		delay   = 8
	)
	freq := rand.Float64() * 3.0
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < cycles*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5), greenIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	gif.EncodeAll(out, &anim)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
	kval "github.com/kval-access-language/kval-boltdb"
	"github.com/olekukonko/tablewriter"
)

func main() {
	var file string
	var bucket string
	var machineFriendly bool

	cli.AppHelpTemplate = `NAME:
  {{.Name}} - {{.Usage}}

VERSION:
  {{.Version}}

USAGE:
  {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}

GLOBAL OPTIONS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
AUTHOR:
  {{range .Authors}}{{ . }}{{end}}
`
	app := cli.NewApp()
	app.Name = "bolter"
	app.Usage = "view boltdb file in your terminal"
	app.Version = "1.0.0"
	app.Author = "Hasit Mistry"
	app.Email = "hasitnm@gmail.com"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "file, f",
			Usage:       "boltdb `FILE` to view",
			Destination: &file,
		},
		cli.StringFlag{
			Name:        "bucket, b",
			Usage:       "boltdb `BUCKET` to view",
			Destination: &bucket,
		},
		cli.BoolFlag{
			Name:        "machine, m",
			Usage:       "key=value format",
			Destination: &machineFriendly,
		},
	}
	app.Action = func(c *cli.Context) error {
		if file == "" {
			cli.ShowAppHelp(c)
			return nil
		}

		var i impl
		if machineFriendly {
			i = impl{fmt: &machineFormatter{}}
		} else {
			i = impl{fmt: &tableFormatter{}}
		}
		if _, err := os.Stat(file); os.IsNotExist(err) {
			log.Fatal(err)
			return err
		}
		i.initDB(file)
		defer i.DB.Close()
		if bucket != "" {
			i.listBucketItems(bucket)
		} else {
			i.listBuckets()
		}
		return nil
	}
	app.Run(os.Args)
}

type formatter interface {
	DumpBuckets([]bucket)
	DumpBucketItems(string, []item)
}

type impl struct {
	KV  kval.Kvalboltdb
	DB  *bolt.DB
	fmt formatter
}

type item struct {
	Key   string `json:"Key"`
	Value string `json:"Value"`
}

type bucket struct {
	Name string `json:"Name"`
}

func (i *impl) initDB(file string) {
	var err error
	// Read-only permission, should be equiv. bolt.Open(file, 0400, nil)
	i.KV, err = kval.Connect(file)
	i.DB = kval.GetBolt(i.KV)
	if err != nil {
		log.Fatal(err)
	}
}

func (i *impl) listBucketItems(bucket string) {
	items := []item{}
	getItems := "GET " + bucket
	res, err := kval.Query(i.KV, getItems)
	if err != nil {
		log.Fatal(err)
	}
	for k, v := range res.Result {
		if v == kval.Nestedbucket {
			k = k + "*"
			v = ""
		}
		items = append(items, item{Key: string(k), Value: string(v)})
	}

	i.fmt.DumpBucketItems(bucket, items)
}

func (i *impl) listBuckets() {
	buckets := []bucket{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(bucketname []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, bucket{Name: string(bucketname)})
			return nil
		})
	})
	if err != nil {
		log.Fatal(err)
	}
	i.fmt.DumpBuckets(buckets)
}

type tableFormatter struct{}

func (tf tableFormatter) DumpBuckets(buckets []bucket) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Buckets"})
	for _, b := range buckets {
		row := []string{b.Name}
		table.Append(row)
	}
	table.Render()
}

func (tf tableFormatter) DumpBucketItems(bucket string, items []item) {
	fmt.Printf("Bucket: %s\n", bucket)
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Key", "Value"})
	for _, item := range items {
		row := []string{item.Key, item.Value}
		table.Append(row)
	}
	table.Render()
}

type machineFormatter struct{}

func (mf machineFormatter) DumpBuckets(buckets []bucket) {
	for _, b := range buckets {
		fmt.Println(b.Name)
	}
}

func (mf machineFormatter) DumpBucketItems(_ string, items []item) {
	for _, item := range items {
		fmt.Printf("%s=%s\n", item.Key, item.Value)
	}
}
<commit_msg>[feature] We can move forward through tables.<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
	kval "github.com/kval-access-language/kval-boltdb"
	"github.com/olekukonko/tablewriter"
)

func main() {
	var file string
	var bucket string
	var machineFriendly bool

	cli.AppHelpTemplate = `NAME:
  {{.Name}} - {{.Usage}}

VERSION:
  {{.Version}}

USAGE:
  {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}

GLOBAL OPTIONS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
AUTHOR:
  {{range .Authors}}{{ . }}{{end}}
`
	app := cli.NewApp()
	app.Name = "bolter"
	app.Usage = "view boltdb file in your terminal"
	app.Version = "1.0.0"
	app.Author = "Hasit Mistry"
	app.Email = "hasitnm@gmail.com"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "file, f",
			Usage:       "boltdb `FILE` to view",
			Destination: &file,
		},
		cli.StringFlag{
			Name:        "bucket, b",
			Usage:       "boltdb `BUCKET` to view",
			Destination: &bucket,
		},
		cli.BoolFlag{
			Name:        "machine, m",
			Usage:       "key=value format",
			Destination: &machineFriendly,
		},
	}
	app.Action = func(c *cli.Context) error {
		if file == "" {
			cli.ShowAppHelp(c)
			return nil
		}

		var i impl
		if machineFriendly {
			i = impl{fmt: &machineFormatter{}}
		} else {
			i = impl{fmt: &tableFormatter{}}
		}
		if _, err := os.Stat(file); os.IsNotExist(err) {
			log.Fatal(err)
			return err
		}
		i.initDB(file)
		defer i.DB.Close()

		i.readInput()

		return nil
	}
	app.Run(os.Args)
}

func (i *impl) readInput() {
	fmt.Fprint(os.Stdout, "DB Layout:\n\n")
	i.listBuckets()
	scanner := bufio.NewScanner(os.Stdin)
	fmt.Fprint(os.Stdout, "\nEnter bucket to explore (q to quit, m to print):\n\n")
	for scanner.Scan() {
		bucket := scanner.Text()
		fmt.Fprintln(os.Stdout, "")
		switch(bucket) {
		case "q":
			fallthrough
		case "quit":
			return
		case "":
			i.listBuckets()
		default:
			i.listBucketItems(bucket)
		}
	}
}

type formatter interface {
	DumpBuckets([]bucket)
	DumpBucketItems(string, []item)
}

type impl struct {
	KV  kval.Kvalboltdb
	DB  *bolt.DB
	fmt formatter
	loc string		// where we are in the structure
}

type item struct {
	Key   string `json:"Key"`
	Value string `json:"Value"`
}

type bucket struct {
	Name string `json:"Name"`
}

func (i *impl) initDB(file string) {
	var err error
	// Read-only permission, should be equiv. bolt.Open(file, 0400, nil)
	i.KV, err = kval.Connect(file)
	i.DB = kval.GetBolt(i.KV)
	if err != nil {
		log.Fatal(err)
	}
}

func (i *impl) updateLoc(bucket string) string {
	if i.loc == "" {
		i.loc = "GET " + bucket
	} else {
		i.loc = i.loc + " >> " + bucket
	}
	return i.loc
}

func (i *impl) listBucketItems(bucket string) {
	items := []item{}
	getItems := i.updateLoc(bucket)
	fmt.Fprintf(os.Stderr, "Query: " + i.loc + "\n\n")
	res, err := kval.Query(i.KV, getItems)
	if err != nil {
		if err.Error() != "Cannot GOTO bucket, bucket not found" {
			log.Fatal(err)
		} else {
			fmt.Fprintln(os.Stderr, "Bucket not found")
			fmt.Println(getItems)
		}
	}
	for k, v := range res.Result {
		if v == kval.Nestedbucket {
			k = k + "*"
			v = ""
		}
		items = append(items, item{Key: string(k), Value: string(v)})
	}

	i.fmt.DumpBucketItems(bucket, items)
}

func (i *impl) listBuckets() {
	buckets := []bucket{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(bucketname []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, bucket{Name: string(bucketname)})
			return nil
		})
	})
	if err != nil {
		log.Fatal(err)
	}
	i.fmt.DumpBuckets(buckets)
}

type tableFormatter struct{}

func (tf tableFormatter) DumpBuckets(buckets []bucket) {
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Buckets"})
	for _, b := range buckets {
		row := []string{b.Name}
		table.Append(row)
	}
	table.Render()
	fmt.Println()
}

func (tf tableFormatter) DumpBucketItems(bucket string, items []item) {
	fmt.Printf("Bucket: %s\n", bucket)
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Key", "Value"})
	for _, item := range items {
		row := []string{item.Key, item.Value}
		table.Append(row)
	}
	table.Render()
	fmt.Println()
}

type machineFormatter struct{}

func (mf machineFormatter) DumpBuckets(buckets []bucket) {
	for _, b := range buckets {
		fmt.Println(b.Name)
	}
}

func (mf machineFormatter) DumpBucketItems(_ string, items []item) {
	for _, item := range items {
		fmt.Printf("%s=%s\n", item.Key, item.Value)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
)

func main() {
	var file string
	var bucket string
	i := impl{}

	app := cli.NewApp()
	app.Name = "bolter"
	app.Usage = "view boltdb file in your terminal"
	app.Version = "1.0.0"
	app.Author = "Hasit Mistry"
	app.Email = "hasit@uw.edu"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "file, f",
			Usage:       "BoltDB file to view `FILE`",
			Destination: &file,
		},
		cli.StringFlag{
			Name:        "bucket, b",
			Usage:       "Bucket to view `BUCKET`",
			Destination: &bucket,
		},
	}
	app.Action = func(c *cli.Context) error {
		if file != "" {
			if _, err := os.Stat(file); os.IsNotExist(err) {
				log.Fatal(err)
				return err
			}
			i.initDB(file)
			defer i.DB.Close()
			if bucket != "" {
				i.listBucketItems(bucket)
			} else {
				i.listBuckets()
			}
		} else {
			cli.ShowAppHelp(c)
		}
		return nil
	}
	app.Run(os.Args)
}

type impl struct {
	DB *bolt.DB
}

type item struct {
	Key   string `json:"Key"`
	Value string `json:"Value"`
}

type bucket struct {
	Name string `json:"Name"`
}

func (i *impl) initDB(file string) {
	var err error
	// Read-only permission
	i.DB, err = bolt.Open(file, 0400, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func (i *impl) listBucketItems(bucket string) {
	items := []item{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucket))
		c := b.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			items = append(items, item{Key: string(k), Value: string(v)})
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Key\tValue:\n")
	for _, item := range items {
		fmt.Printf("%s\t%s\n", item.Key, item.Value)
	}
}

func (i *impl) listBuckets() {
	buckets := []bucket{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(bucketname []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, bucket{Name: string(bucketname)})
			return nil
		})
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Buckets:\n")
	for _, b := range buckets {
		fmt.Printf("%s\n", b.Name)
	}
}
<commit_msg>Print information using tablewriter<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/boltdb/bolt"
	"github.com/codegangsta/cli"
	"github.com/olekukonko/tablewriter"
)

func main() {
	var file string
	var bucket string
	i := impl{}

	app := cli.NewApp()
	app.Name = "bolter"
	app.Usage = "view boltdb file in your terminal"
	app.Version = "1.0.0"
	app.Author = "Hasit Mistry"
	app.Email = "hasit@uw.edu"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "file, f",
			Usage:       "BoltDB file to view `FILE`",
			Destination: &file,
		},
		cli.StringFlag{
			Name:        "bucket, b",
			Usage:       "Bucket to view `BUCKET`",
			Destination: &bucket,
		},
	}
	app.Action = func(c *cli.Context) error {
		if file != "" {
			if _, err := os.Stat(file); os.IsNotExist(err) {
				log.Fatal(err)
				return err
			}
			i.initDB(file)
			defer i.DB.Close()
			if bucket != "" {
				i.listBucketItems(bucket)
			} else {
				i.listBuckets()
			}
		} else {
			cli.ShowAppHelp(c)
		}
		return nil
	}
	app.Run(os.Args)
}

type impl struct {
	DB *bolt.DB
}

type item struct {
	Key   string `json:"Key"`
	Value string `json:"Value"`
}

type bucket struct {
	Name string `json:"Name"`
}

func (i *impl) initDB(file string) {
	var err error
	// Read-only permission
	i.DB, err = bolt.Open(file, 0400, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func (i *impl) listBucketItems(bucket string) {
	items := []item{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucket))
		c := b.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			items = append(items, item{Key: string(k), Value: string(v)})
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Bucket: %s\n", bucket)
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Key", "Value"})
	for _, item := range items {
		row := []string{item.Key, item.Value}
		table.Append(row)
	}
	table.Render()
}

func (i *impl) listBuckets() {
	buckets := []bucket{}
	err := i.DB.View(func(tx *bolt.Tx) error {
		return tx.ForEach(func(bucketname []byte, _ *bolt.Bucket) error {
			buckets = append(buckets, bucket{Name: string(bucketname)})
			return nil
		})
	})
	if err != nil {
		log.Fatal(err)
	}
	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Buckets"})
	for _, b := range buckets {
		row := []string{b.Name}
		table.Append(row)
	}
	table.Render()
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"

	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/ui"
	"github.com/loadimpact/k6/ui/pb"
)

const (
	// Max length of left-side progress bar text before trimming is forced
	maxLeftLength = 30
	// Amount of padding in chars between rendered progress
	// bar text and right-side terminal window edge.
	termPadding      = 1
	defaultTermWidth = 80
)

// A writer that syncs writes with a mutex and, if the output is a TTY, clears before newlines.
type consoleWriter struct {
	Writer io.Writer
	IsTTY  bool
	Mutex  *sync.Mutex

	// Used for flicker-free persistent objects like the progressbars
	PersistentText func()
}

func (w *consoleWriter) Write(p []byte) (n int, err error) {
	origLen := len(p)
	if w.IsTTY {
		// Add a TTY code to erase till the end of line with each new line
		// TODO: check how cross-platform this is...
		p = bytes.Replace(p, []byte{'\n'}, []byte{'\x1b', '[', '0', 'K', '\n'}, -1)
	}

	w.Mutex.Lock()
	n, err = w.Writer.Write(p)
	if w.PersistentText != nil {
		w.PersistentText()
	}
	w.Mutex.Unlock()

	if err != nil && n < origLen {
		return n, err
	}
	return origLen, err
}

func printBar(bar *pb.ProgressBar) {
	end := "\n"
	if stdout.IsTTY {
		// If we're in a TTY, instead of printing the bar and going to the next
		// line, erase everything till the end of the line and return to the
		// start, so that the next print will overwrite the same line.
		//
		// TODO: check for cross platform support
		end = "\x1b[0K\r"
	}
	rendered := bar.Render(0, 0)
	// Only output the left and middle part of the progress bar
	fprintf(stdout, "%s%s", rendered.String(), end)
}

func modifyAndPrintBar(bar *pb.ProgressBar, options ...pb.ProgressBarOption) {
	bar.Modify(options...)
	printBar(bar)
}

// Print execution description for both cloud and local execution.
// TODO: Clean this up as part of #1499 or #1427
func printExecutionDescription(
	execution, filename, output string, conf Config, et *lib.ExecutionTuple,
	execPlan []lib.ExecutionStep, collectors []lib.Collector,
) {
	fprintf(stdout, "  execution: %s\n", ui.ValueColor.Sprint(execution))
	fprintf(stdout, "     script: %s\n", ui.ValueColor.Sprint(filename))

	if execution == "local" {
		out := "-"
		link := ""

		for idx, collector := range collectors {
			if out != "-" {
				out = out + "; " + conf.Out[idx]
			} else {
				out = conf.Out[idx]
			}

			if l := collector.Link(); l != "" {
				link = link + " (" + l + ")"
			}
		}
		fprintf(stdout, "     output: %s%s\n", ui.ValueColor.Sprint(out), ui.ExtraColor.Sprint(link))
	} else {
		fprintf(stdout, "     output: %s\n", ui.ValueColor.Sprint(output))
	}
	fprintf(stdout, "\n")

	maxDuration, _ := lib.GetEndOffset(execPlan)
	executorConfigs := conf.Scenarios.GetSortedConfigs()

	fprintf(stdout, "  scenarios: %s\n", ui.ValueColor.Sprintf(
		"(%.2f%%) %d executors, %d max VUs, %s max duration (incl. graceful stop):",
		conf.ExecutionSegment.FloatLength()*100, len(executorConfigs),
		lib.GetMaxPossibleVUs(execPlan), maxDuration.Round(100*time.Millisecond)),
	)
	for _, ec := range executorConfigs {
		fprintf(stdout, "           * %s: %s\n",
			ec.GetName(), ec.GetDescription(et))
	}
	fprintf(stdout, "\n")
}

//nolint: funlen
func renderMultipleBars(
	isTTY, goBack bool, maxLeft, termWidth, widthDelta int, pbs []*pb.ProgressBar,
) (string, int) {
	lineEnd := "\n"
	if isTTY {
		//TODO: check for cross platform support
		lineEnd = "\x1b[K\n" // erase till end of line
	}

	var (
		// Amount of times line lengths exceed termWidth.
		// Needed to factor into the amount of lines to jump
		// back with [A and avoid scrollback issues.
		lineBreaks  int
		longestLine int
		// Maximum length of each right side column except last,
		// used to calculate the padding between columns.
		maxRColumnLen = make([]int, 2)
		pbsCount      = len(pbs)
		rendered      = make([]pb.ProgressBarRender, pbsCount)
		result        = make([]string, pbsCount+2)
	)

	result[0] = lineEnd // start with an empty line

	// First pass to render all progressbars and get the maximum
	// lengths of right-side columns.
	for i, pb := range pbs {
		rend := pb.Render(maxLeft, widthDelta)
		for i := range rend.Right {
			// Skip last column, since there's nothing to align after it (yet?).
			if i == len(rend.Right)-1 {
				break
			}
			if len(rend.Right[i]) > maxRColumnLen[i] {
				maxRColumnLen[i] = len(rend.Right[i])
			}
		}
		rendered[i] = rend
	}

	// Second pass to render final output, applying padding where needed
	for i := range rendered {
		rend := rendered[i]
		if rend.Hijack != "" {
			result[i+1] = rend.Hijack + lineEnd
			runeCount := utf8.RuneCountInString(rend.Hijack)
			lineBreaks += (runeCount - termPadding) / termWidth
			continue
		}
		var leftText, rightText string
		leftPadFmt := fmt.Sprintf("%%-%ds", maxLeft)
		leftText = fmt.Sprintf(leftPadFmt, rend.Left)
		for i := range rend.Right {
			rpad := 0
			if len(maxRColumnLen) > i {
				rpad = maxRColumnLen[i]
			}
			rightPadFmt := fmt.Sprintf(" %%-%ds", rpad+1)
			rightText += fmt.Sprintf(rightPadFmt, rend.Right[i])
		}
		// Get visible line length, without ANSI escape sequences (color)
		status := fmt.Sprintf(" %s ", rend.Status())
		line := leftText + status + rend.Progress() + rightText
		lineRuneCount := utf8.RuneCountInString(line)
		if lineRuneCount > longestLine {
			longestLine = lineRuneCount
		}
		lineBreaks += (lineRuneCount - termPadding) / termWidth
		if !noColor {
			rend.Color = true
			status = fmt.Sprintf(" %s ", rend.Status())
			line = fmt.Sprintf(leftPadFmt+"%s%s%s",
				rend.Left, status, rend.Progress(), rightText)
		}
		result[i+1] = line + lineEnd
	}

	if isTTY && goBack {
		// Clear screen and go back to the beginning
		//TODO: check for cross platform support
		result[pbsCount+1] = fmt.Sprintf("\r\x1b[J\x1b[%dA", pbsCount+lineBreaks+1)
	} else {
		result[pbsCount+1] = lineEnd
	}

	return strings.Join(result, ""), longestLine
}

//TODO: show other information here?
//TODO: add a no-progress option that will disable these
//TODO: don't use global variables...
// nolint:funlen
func showProgress(
	ctx context.Context, conf Config,
	execScheduler *local.ExecutionScheduler, logger *logrus.Logger,
) {
	if quiet || conf.HTTPDebug.Valid && conf.HTTPDebug.String != "" {
		return
	}

	pbs := []*pb.ProgressBar{execScheduler.GetInitProgressBar()}
	for _, s := range execScheduler.GetExecutors() {
		pbs = append(pbs, s.GetProgress())
	}

	var errTermGetSize bool
	termWidth, _, err := terminal.GetSize(int(os.Stdout.Fd()))
	if err != nil && stdoutTTY {
		logger.WithError(err).Warn("error getting terminal size")
		termWidth = defaultTermWidth
		errTermGetSize = true
	}

	// Get the longest left side string length, to align progress bars
	// horizontally and trim excess text.
	var leftLen int64
	for _, pb := range pbs {
		l := pb.Left()
		leftLen = lib.Max(int64(len(l)), leftLen)
	}
	// Limit to maximum left text length
	maxLeft := int(lib.Min(leftLen, maxLeftLength))

	var progressBarsLastRender []byte

	printProgressBars := func() {
		_, _ = stdout.Writer.Write(progressBarsLastRender)
	}

	var widthDelta int
	// Default to responsive progress bars when in an interactive terminal
	renderProgressBars := func(goBack bool) {
		barText, longestLine := renderMultipleBars(stdoutTTY, goBack, maxLeft, termWidth, widthDelta, pbs)
		widthDelta = termWidth - longestLine - termPadding
		progressBarsLastRender = []byte(barText)
	}

	// Otherwise fallback to fixed compact progress bars
	if !stdoutTTY {
		widthDelta = -pb.DefaultWidth
		renderProgressBars = func(goBack bool) {
			barText, _ := renderMultipleBars(stdoutTTY, goBack, maxLeft, termWidth, widthDelta, pbs)
			progressBarsLastRender = []byte(barText)
		}
	}

	//TODO: make configurable?
	updateFreq := 1 * time.Second
	//TODO: remove !noColor after we fix how we handle colors (see the related
	//description in the TODO message in cmd/root.go)
	if stdoutTTY && !noColor {
		updateFreq = 100 * time.Millisecond
		outMutex.Lock()
		stdout.PersistentText = printProgressBars
		stderr.PersistentText = printProgressBars
		outMutex.Unlock()
		defer func() {
			outMutex.Lock()
			stdout.PersistentText = nil
			stderr.PersistentText = nil
			outMutex.Unlock()
		}()
	}

	var (
		fd     = int(os.Stdout.Fd())
		ticker = time.NewTicker(updateFreq)
	)

	var winch chan os.Signal
	if sig := getWinchSignal(); sig != nil {
		winch = make(chan os.Signal, 1)
		signal.Notify(winch, sig)
	}

	ctxDone := ctx.Done()
	for {
		select {
		case <-ctxDone:
			renderProgressBars(false)
			outMutex.Lock()
			printProgressBars()
			outMutex.Unlock()
			return
		case <-winch:
			if !errTermGetSize {
				// More responsive progress bar resizing on platforms with SIGWINCH (*nix)
				termWidth, _, err = terminal.GetSize(fd)
				if err != nil {
					termWidth = defaultTermWidth
				}
			}
		case <-ticker.C:
			// Default ticker-based progress bar resizing
			if !errTermGetSize && winch == nil {
				termWidth, _, err = terminal.GetSize(fd)
				if err != nil {
					termWidth = defaultTermWidth
				}
			}
		}
		renderProgressBars(true)
		outMutex.Lock()
		printProgressBars()
		outMutex.Unlock()
	}
}
<commit_msg>Fix panic getting terminal width in some CI environments<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"

	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/ui"
	"github.com/loadimpact/k6/ui/pb"
)

const (
	// Max length of left-side progress bar text before trimming is forced
	maxLeftLength = 30
	// Amount of padding in chars between rendered progress
	// bar text and right-side terminal window edge.
	termPadding      = 1
	defaultTermWidth = 80
)

// A writer that syncs writes with a mutex and, if the output is a TTY, clears before newlines.
type consoleWriter struct {
	Writer io.Writer
	IsTTY  bool
	Mutex  *sync.Mutex

	// Used for flicker-free persistent objects like the progressbars
	PersistentText func()
}

func (w *consoleWriter) Write(p []byte) (n int, err error) {
	origLen := len(p)
	if w.IsTTY {
		// Add a TTY code to erase till the end of line with each new line
		// TODO: check how cross-platform this is...
		p = bytes.Replace(p, []byte{'\n'}, []byte{'\x1b', '[', '0', 'K', '\n'}, -1)
	}

	w.Mutex.Lock()
	n, err = w.Writer.Write(p)
	if w.PersistentText != nil {
		w.PersistentText()
	}
	w.Mutex.Unlock()

	if err != nil && n < origLen {
		return n, err
	}
	return origLen, err
}

func printBar(bar *pb.ProgressBar) {
	end := "\n"
	if stdout.IsTTY {
		// If we're in a TTY, instead of printing the bar and going to the next
		// line, erase everything till the end of the line and return to the
		// start, so that the next print will overwrite the same line.
		//
		// TODO: check for cross platform support
		end = "\x1b[0K\r"
	}
	rendered := bar.Render(0, 0)
	// Only output the left and middle part of the progress bar
	fprintf(stdout, "%s%s", rendered.String(), end)
}

func modifyAndPrintBar(bar *pb.ProgressBar, options ...pb.ProgressBarOption) {
	bar.Modify(options...)
	printBar(bar)
}

// Print execution description for both cloud and local execution.
// TODO: Clean this up as part of #1499 or #1427
func printExecutionDescription(
	execution, filename, output string, conf Config, et *lib.ExecutionTuple,
	execPlan []lib.ExecutionStep, collectors []lib.Collector,
) {
	fprintf(stdout, "  execution: %s\n", ui.ValueColor.Sprint(execution))
	fprintf(stdout, "     script: %s\n", ui.ValueColor.Sprint(filename))

	if execution == "local" {
		out := "-"
		link := ""

		for idx, collector := range collectors {
			if out != "-" {
				out = out + "; " + conf.Out[idx]
			} else {
				out = conf.Out[idx]
			}

			if l := collector.Link(); l != "" {
				link = link + " (" + l + ")"
			}
		}
		fprintf(stdout, "     output: %s%s\n", ui.ValueColor.Sprint(out), ui.ExtraColor.Sprint(link))
	} else {
		fprintf(stdout, "     output: %s\n", ui.ValueColor.Sprint(output))
	}
	fprintf(stdout, "\n")

	maxDuration, _ := lib.GetEndOffset(execPlan)
	executorConfigs := conf.Scenarios.GetSortedConfigs()

	fprintf(stdout, "  scenarios: %s\n", ui.ValueColor.Sprintf(
		"(%.2f%%) %d executors, %d max VUs, %s max duration (incl. graceful stop):",
		conf.ExecutionSegment.FloatLength()*100, len(executorConfigs),
		lib.GetMaxPossibleVUs(execPlan), maxDuration.Round(100*time.Millisecond)),
	)
	for _, ec := range executorConfigs {
		fprintf(stdout, "           * %s: %s\n",
			ec.GetName(), ec.GetDescription(et))
	}
	fprintf(stdout, "\n")
}

//nolint: funlen
func renderMultipleBars(
	isTTY, goBack bool, maxLeft, termWidth, widthDelta int, pbs []*pb.ProgressBar,
) (string, int) {
	lineEnd := "\n"
	if isTTY {
		//TODO: check for cross platform support
		lineEnd = "\x1b[K\n" // erase till end of line
	}

	var (
		// Amount of times line lengths exceed termWidth.
		// Needed to factor into the amount of lines to jump
		// back with [A and avoid scrollback issues.
		lineBreaks  int
		longestLine int
		// Maximum length of each right side column except last,
		// used to calculate the padding between columns.
		maxRColumnLen = make([]int, 2)
		pbsCount      = len(pbs)
		rendered      = make([]pb.ProgressBarRender, pbsCount)
		result        = make([]string, pbsCount+2)
	)

	result[0] = lineEnd // start with an empty line

	// First pass to render all progressbars and get the maximum
	// lengths of right-side columns.
	for i, pb := range pbs {
		rend := pb.Render(maxLeft, widthDelta)
		for i := range rend.Right {
			// Skip last column, since there's nothing to align after it (yet?).
			if i == len(rend.Right)-1 {
				break
			}
			if len(rend.Right[i]) > maxRColumnLen[i] {
				maxRColumnLen[i] = len(rend.Right[i])
			}
		}
		rendered[i] = rend
	}

	// Second pass to render final output, applying padding where needed
	for i := range rendered {
		rend := rendered[i]
		if rend.Hijack != "" {
			result[i+1] = rend.Hijack + lineEnd
			runeCount := utf8.RuneCountInString(rend.Hijack)
			lineBreaks += (runeCount - termPadding) / termWidth
			continue
		}
		var leftText, rightText string
		leftPadFmt := fmt.Sprintf("%%-%ds", maxLeft)
		leftText = fmt.Sprintf(leftPadFmt, rend.Left)
		for i := range rend.Right {
			rpad := 0
			if len(maxRColumnLen) > i {
				rpad = maxRColumnLen[i]
			}
			rightPadFmt := fmt.Sprintf(" %%-%ds", rpad+1)
			rightText += fmt.Sprintf(rightPadFmt, rend.Right[i])
		}
		// Get visible line length, without ANSI escape sequences (color)
		status := fmt.Sprintf(" %s ", rend.Status())
		line := leftText + status + rend.Progress() + rightText
		lineRuneCount := utf8.RuneCountInString(line)
		if lineRuneCount > longestLine {
			longestLine = lineRuneCount
		}
		lineBreaks += (lineRuneCount - termPadding) / termWidth
		if !noColor {
			rend.Color = true
			status = fmt.Sprintf(" %s ", rend.Status())
			line = fmt.Sprintf(leftPadFmt+"%s%s%s",
				rend.Left, status, rend.Progress(), rightText)
		}
		result[i+1] = line + lineEnd
	}

	if isTTY && goBack {
		// Clear screen and go back to the beginning
		//TODO: check for cross platform support
		result[pbsCount+1] = fmt.Sprintf("\r\x1b[J\x1b[%dA", pbsCount+lineBreaks+1)
	} else {
		result[pbsCount+1] = lineEnd
	}

	return strings.Join(result, ""), longestLine
}

//TODO: show other information here?
//TODO: add a no-progress option that will disable these
//TODO: don't use global variables...
// nolint:funlen
func showProgress(
	ctx context.Context, conf Config,
	execScheduler *local.ExecutionScheduler, logger *logrus.Logger,
) {
	if quiet || conf.HTTPDebug.Valid && conf.HTTPDebug.String != "" {
		return
	}

	pbs := []*pb.ProgressBar{execScheduler.GetInitProgressBar()}
	for _, s := range execScheduler.GetExecutors() {
		pbs = append(pbs, s.GetProgress())
	}

	var errTermGetSize bool
	termWidth := defaultTermWidth
	if stdoutTTY {
		tw, _, err := terminal.GetSize(int(os.Stdout.Fd()))
		if !(tw > 0) || err != nil {
			errTermGetSize = true
			logger.WithError(err).Warn("error getting terminal size")
		} else {
			termWidth = tw
		}
	}

	// Get the longest left side string length, to align progress bars
	// horizontally and trim excess text.
	var leftLen int64
	for _, pb := range pbs {
		l := pb.Left()
		leftLen = lib.Max(int64(len(l)), leftLen)
	}
	// Limit to maximum left text length
	maxLeft := int(lib.Min(leftLen, maxLeftLength))

	var progressBarsLastRender []byte

	printProgressBars := func() {
		_, _ = stdout.Writer.Write(progressBarsLastRender)
	}

	var widthDelta int
	// Default to responsive progress bars when in an interactive terminal
	renderProgressBars := func(goBack bool) {
		barText, longestLine := renderMultipleBars(stdoutTTY, goBack, maxLeft, termWidth, widthDelta, pbs)
		widthDelta = termWidth - longestLine - termPadding
		progressBarsLastRender = []byte(barText)
	}

	// Otherwise fallback to fixed compact progress bars
	if !stdoutTTY {
		widthDelta = -pb.DefaultWidth
		renderProgressBars = func(goBack bool) {
			barText, _ := renderMultipleBars(stdoutTTY, goBack, maxLeft, termWidth, widthDelta, pbs)
			progressBarsLastRender = []byte(barText)
		}
	}

	//TODO: make configurable?
	updateFreq := 1 * time.Second
	//TODO: remove !noColor after we fix how we handle colors (see the related
	//description in the TODO message in cmd/root.go)
	if stdoutTTY && !noColor {
		updateFreq = 100 * time.Millisecond
		outMutex.Lock()
		stdout.PersistentText = printProgressBars
		stderr.PersistentText = printProgressBars
		outMutex.Unlock()
		defer func() {
			outMutex.Lock()
			stdout.PersistentText = nil
			stderr.PersistentText = nil
			outMutex.Unlock()
		}()
	}

	var (
		fd     = int(os.Stdout.Fd())
		ticker = time.NewTicker(updateFreq)
	)

	var winch chan os.Signal
	if sig := getWinchSignal(); sig != nil {
		winch = make(chan os.Signal, 1)
		signal.Notify(winch, sig)
	}

	ctxDone := ctx.Done()
	for {
		select {
		case <-ctxDone:
			renderProgressBars(false)
			outMutex.Lock()
			printProgressBars()
			outMutex.Unlock()
			return
		case <-winch:
			if stdoutTTY && !errTermGetSize {
				// More responsive progress bar resizing on platforms with SIGWINCH (*nix)
				tw, _, err := terminal.GetSize(fd)
				if tw > 0 && err == nil {
					termWidth = tw
				}
			}
		case <-ticker.C:
			// Default ticker-based progress bar resizing
			if stdoutTTY && !errTermGetSize && winch == nil {
				tw, _, err := terminal.GetSize(fd)
				if tw > 0 && err == nil {
					termWidth = tw
				}
			}
		}
		renderProgressBars(true)
		outMutex.Lock()
		printProgressBars()
		outMutex.Unlock()
	}
}
<|endoftext|>


<commit_before>// Copyright © 2017 Aidan Steele <aidan.steele@glassechidna.com.au>
//
// 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 cmd

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/glassechidna/stackit/pkg/stackit"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"io/ioutil"
	"os"
	"strings"
)

// up --stack-name stackit-test --template sample.yml --param-value DockerImage=nginx --param-value Cluster=app-cluster-Cluster-1C2I18JXK9QNM --tag MyTag=Cool

var paramValues []string
var previousParamValues []string
var tags []string
var notificationArns []string

var upCmd = &cobra.Command{
	Use:   "up",
	Short: "Bring stack up to date",
	Run: func(cmd *cobra.Command, args []string) {
		region := viper.GetString("region")
		profile := viper.GetString("profile")
		stackName := viper.GetString("stack-name")

		serviceRole := viper.GetString("service-role")
		stackPolicy := viper.GetString("stack-policy")
		template := viper.GetString("template")
		previousTemplate := viper.GetBool("previous-template")
		alwaysSucceed := viper.GetBool("always-succeed")
		//noDestroy := viper.GetBool("no-destroy")
		//cancelOnExit := !viper.GetBool("no-cancel-on-exit")

		showTimestamps := !viper.GetBool("no-timestamps")
		showColor := !viper.GetBool("no-color")
		printer := stackit.NewTailPrinterWithOptions(showTimestamps, showColor, cmd.OutOrStderr())

		parsed := parseCLIInput(
			serviceRole,
			stackPolicy,
			template,
			paramValues,
			previousParamValues,
			tags,
			notificationArns,
			previousTemplate)

		parsed.StackName = stackName

		events := make(chan stackit.TailStackEvent)

		sess := awsSession(profile, region)
		sit := stackit.NewStackit(cloudformation.New(sess), sts.New(sess))

		go func() {
			for tailEvent := range events {
				printer.PrintTailEvent(tailEvent)
			}
		}()

		prepared, err := sit.Prepare(parsed, events)
		if err != nil {
			panic(err)
		}

		if prepared == nil {
			return // no-op change set
		}

		err = sit.Execute(*prepared.Output.StackId, *prepared.Output.Id, events)
		if err != nil {
			panic(err)
		}

		stackId := *prepared.Output.StackId
		if success, _ := sit.IsSuccessfulState(stackId); !success && !alwaysSucceed {
			os.Exit(1)
		}

		sit.PrintOutputs(stackId, cmd.OutOrStdout())
	},
}

func keyvalSliceToMap(slice []string) map[string]string {
	theMap := map[string]string{}

	for _, paramPair := range slice {
		parts := strings.SplitN(paramPair, "=", 2)
		name, value := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
		theMap[name] = value
	}

	return theMap
}

func parseCLIInput(
	serviceRole,
	stackPolicy,
	template string,
	cliParamValues,
	previousParamValues,
	tags,
	notificationArns []string,
	previousTemplate bool) stackit.StackitUpInput {
	input := stackit.StackitUpInput{
		PopulateMissing: true,
	}

	if len(serviceRole) > 0 {
		input.RoleARN = serviceRole
	}

	if len(stackPolicy) > 0 {
		policyBody, err := ioutil.ReadFile(stackPolicy)
		if err != nil {

		} else {
			input.StackPolicyBody = string(policyBody)
		}
	}

	if len(template) > 0 {
		templateBody, err := ioutil.ReadFile(template)
		if err != nil {

		} else {
			input.TemplateBody = string(templateBody)
		}
	}

	input.PreviousTemplate = previousTemplate

	paramMap := keyvalSliceToMap(viper.GetStringSlice("parameters"))
	for key, val := range keyvalSliceToMap(cliParamValues) {
		paramMap[key] = val
	}

	params := []*cloudformation.Parameter{}
	for name, value := range paramMap {
		params = append(params, &cloudformation.Parameter{
			ParameterKey:   aws.String(name),
			ParameterValue: aws.String(value),
		})
	}

	for _, param := range previousParamValues {
		params = append(params, &cloudformation.Parameter{
			ParameterKey:     aws.String(param),
			UsePreviousValue: aws.Bool(true),
		})
	}

	input.Parameters = params
	input.NotificationARNs = notificationArns

	if len(tags) > 0 {
		input.Tags = keyvalSliceToMap(tags)
	}

	return input
}

func init() {
	RootCmd.AddCommand(upCmd)

	upCmd.PersistentFlags().String("service-role", "", "")
	upCmd.PersistentFlags().String("stack-policy", "", "")
	upCmd.PersistentFlags().String("template", "", "")
	upCmd.PersistentFlags().StringArrayVar(&paramValues, "param-value", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&previousParamValues, "previous-param-value", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&tags, "tag", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&notificationArns, "notification-arn", []string{}, "")
	upCmd.PersistentFlags().Bool("previous-template", false, "")
	upCmd.PersistentFlags().Bool("no-destroy", false, "")
	upCmd.PersistentFlags().Bool("no-cancel-on-exit", false, "")
	upCmd.PersistentFlags().Bool("no-timestamps", false, "")
	upCmd.PersistentFlags().Bool("no-color", false, "")
	upCmd.PersistentFlags().Bool("always-succeed", false, "Typically stackit will return a nonzero exit code on failure. This disables that.")

	viper.BindPFlags(upCmd.PersistentFlags())
}
<commit_msg>Removed never-used code<commit_after>// Copyright © 2017 Aidan Steele <aidan.steele@glassechidna.com.au>
//
// 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 cmd

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/cloudformation"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/glassechidna/stackit/pkg/stackit"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"io/ioutil"
	"os"
	"strings"
)

// up --stack-name stackit-test --template sample.yml --param-value DockerImage=nginx --param-value Cluster=app-cluster-Cluster-1C2I18JXK9QNM --tag MyTag=Cool

var paramValues []string
var previousParamValues []string
var tags []string
var notificationArns []string

var upCmd = &cobra.Command{
	Use:   "up",
	Short: "Bring stack up to date",
	Run: func(cmd *cobra.Command, args []string) {
		region := viper.GetString("region")
		profile := viper.GetString("profile")
		stackName := viper.GetString("stack-name")

		serviceRole := viper.GetString("service-role")
		stackPolicy := viper.GetString("stack-policy")
		template := viper.GetString("template")
		previousTemplate := viper.GetBool("previous-template")
		alwaysSucceed := viper.GetBool("always-succeed")

		showTimestamps := !viper.GetBool("no-timestamps")
		showColor := !viper.GetBool("no-color")
		printer := stackit.NewTailPrinterWithOptions(showTimestamps, showColor, cmd.OutOrStderr())

		parsed := parseCLIInput(
			serviceRole,
			stackPolicy,
			template,
			paramValues,
			previousParamValues,
			tags,
			notificationArns,
			previousTemplate)

		parsed.StackName = stackName

		events := make(chan stackit.TailStackEvent)

		sess := awsSession(profile, region)
		sit := stackit.NewStackit(cloudformation.New(sess), sts.New(sess))

		go func() {
			for tailEvent := range events {
				printer.PrintTailEvent(tailEvent)
			}
		}()

		prepared, err := sit.Prepare(parsed, events)
		if err != nil {
			panic(err)
		}

		if prepared == nil {
			return // no-op change set
		}

		err = sit.Execute(*prepared.Output.StackId, *prepared.Output.Id, events)
		if err != nil {
			panic(err)
		}

		stackId := *prepared.Output.StackId
		if success, _ := sit.IsSuccessfulState(stackId); !success && !alwaysSucceed {
			os.Exit(1)
		}

		sit.PrintOutputs(stackId, cmd.OutOrStdout())
	},
}

func keyvalSliceToMap(slice []string) map[string]string {
	theMap := map[string]string{}

	for _, paramPair := range slice {
		parts := strings.SplitN(paramPair, "=", 2)
		name, value := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
		theMap[name] = value
	}

	return theMap
}

func parseCLIInput(
	serviceRole,
	stackPolicy,
	template string,
	cliParamValues,
	previousParamValues,
	tags,
	notificationArns []string,
	previousTemplate bool) stackit.StackitUpInput {
	input := stackit.StackitUpInput{
		PopulateMissing: true,
	}

	if len(serviceRole) > 0 {
		input.RoleARN = serviceRole
	}

	if len(stackPolicy) > 0 {
		policyBody, err := ioutil.ReadFile(stackPolicy)
		if err != nil {

		} else {
			input.StackPolicyBody = string(policyBody)
		}
	}

	if len(template) > 0 {
		templateBody, err := ioutil.ReadFile(template)
		if err != nil {

		} else {
			input.TemplateBody = string(templateBody)
		}
	}

	input.PreviousTemplate = previousTemplate

	paramMap := keyvalSliceToMap(viper.GetStringSlice("parameters"))
	for key, val := range keyvalSliceToMap(cliParamValues) {
		paramMap[key] = val
	}

	params := []*cloudformation.Parameter{}
	for name, value := range paramMap {
		params = append(params, &cloudformation.Parameter{
			ParameterKey:   aws.String(name),
			ParameterValue: aws.String(value),
		})
	}

	for _, param := range previousParamValues {
		params = append(params, &cloudformation.Parameter{
			ParameterKey:     aws.String(param),
			UsePreviousValue: aws.Bool(true),
		})
	}

	input.Parameters = params
	input.NotificationARNs = notificationArns

	if len(tags) > 0 {
		input.Tags = keyvalSliceToMap(tags)
	}

	return input
}

func init() {
	RootCmd.AddCommand(upCmd)

	upCmd.PersistentFlags().String("service-role", "", "")
	upCmd.PersistentFlags().String("stack-policy", "", "")
	upCmd.PersistentFlags().String("template", "", "")
	upCmd.PersistentFlags().StringArrayVar(&paramValues, "param-value", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&previousParamValues, "previous-param-value", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&tags, "tag", []string{}, "")
	upCmd.PersistentFlags().StringArrayVar(&notificationArns, "notification-arn", []string{}, "")
	upCmd.PersistentFlags().Bool("previous-template", false, "")
	upCmd.PersistentFlags().Bool("no-timestamps", false, "")
	upCmd.PersistentFlags().Bool("no-color", false, "")
	upCmd.PersistentFlags().Bool("always-succeed", false, "Typically stackit will return a nonzero exit code on failure. This disables that.")

	viper.BindPFlags(upCmd.PersistentFlags())
}
<|endoftext|>


<commit_before>package rational

import (
	"fmt"
	"math/big"
	"strings"
)

var symbCockle = [4]string{"", "i₁", "s₂", "s₃"}

// A Cockle represents a rational Cockle quaternion.
type Cockle struct {
	re, sp *Complex
}

// Re returns the Cayley-Dickson real part of z, a pointer to a Complex value.
func (z *Cockle) Re() *Complex {
	return z.re
}

// Sp returns the Cayley-Dickson split part of z, a pointer to a Complex
// value.
func (z *Cockle) Sp() *Complex {
	return z.sp
}

// SetRe sets the Cayley-Dickson real part of z equal to a.
func (z *Cockle) SetRe(a *Complex) {
	z.re = a
}

// SetSp sets the Cayley-Dickson split part of z equal to b.
func (z *Cockle) SetSp(b *Complex) {
	z.sp = b
}

// Cartesian returns the four Cartesian components of z.
func (z *Cockle) Cartesian() (a, b, c, d *big.Rat) {
	a, b = z.Re().Cartesian()
	c, d = z.Sp().Cartesian()
	return
}

// String returns the string representation of a Cockle value.
// If z corresponds to a + bi₁ + cs₂ + ds₃, then the string is "(a+bi₁+cs₂+ds₃)",
// similar to complex128 values.
func (z *Cockle) String() string {
	v := make([]*big.Rat, 4)
	v[0], v[1] = z.Re().Cartesian()
	v[2], v[3] = z.Sp().Cartesian()
	a := make([]string, 9)
	a[0] = "("
	a[1] = fmt.Sprintf("%v", v[0])
	i := 1
	for j := 2; j < 8; j = j + 2 {
		if v[i].Sign() == -1 {
			a[j] = fmt.Sprintf("%v", v[i])
		} else {
			a[j] = fmt.Sprintf("+%v", v[i])
		}
		a[j+1] = symbCockle[i]
		i++
	}
	a[8] = ")"
	return strings.Join(a, "")
}

// Equals returns true if y and z are equal.
func (z *Cockle) Equals(y *Cockle) bool {
	if !z.Re().Equals(y.Re()) || !z.Sp().Equals(y.Sp()) {
		return false
	}
	return true
}

// Copy copies y onto z, and returns z.
func (z *Cockle) Copy(y *Cockle) *Cockle {
	z.SetRe(y.Re())
	z.SetSp(y.Sp())
	return z
}

// NewCockle returns a pointer to a Cockle value made from four given pointers
// to big.Rat values.
func NewCockle(a, b, c, d *big.Rat) *Cockle {
	z := new(Cockle)
	z.SetRe(NewComplex(a, b))
	z.SetSp(NewComplex(c, d))
	return z
}

// Scal sets z equal to y scaled by a, and returns z.
func (z *Cockle) Scal(y *Cockle, a *big.Rat) *Cockle {
	z.SetRe(new(Complex).Scal(y.Re(), a))
	z.SetSp(new(Complex).Scal(y.Sp(), a))
	return z
}

// Neg sets z equal to the negative of y, and returns z.
func (z *Cockle) Neg(y *Cockle) *Cockle {
	z.SetRe(new(Complex).Neg(y.Re()))
	z.SetSp(new(Complex).Neg(y.Sp()))
	return z
}

// Conj sets z equal to the conjugate of y, and returns z.
func (z *Cockle) Conj(y *Cockle) *Cockle {
	z.SetRe(new(Complex).Conj(y.Re()))
	z.SetSp(new(Complex).Neg(y.Sp()))
	return z
}

// Add sets z equal to the sum of x and y, and returns z.
func (z *Cockle) Add(x, y *Cockle) *Cockle {
	z.SetRe(new(Complex).Add(x.Re(), y.Re()))
	z.SetSp(new(Complex).Add(x.Sp(), y.Sp()))
	return z
}

// Sub sets z equal to the difference of x and y, and returns z.
func (z *Cockle) Sub(x, y *Cockle) *Cockle {
	z.SetRe(new(Complex).Sub(x.Re(), y.Re()))
	z.SetSp(new(Complex).Sub(x.Sp(), y.Sp()))
	return z
}

// Mul sets z equal to the product of x and y, and returns z.
//
// The multiplication rules are:
// 		Mul(i₁, i₁) = -1
// 		Mul(s₂, s₂) = Mul(s₃, s₃) = +1
// 		Mul(i₁, s₂) = -Mul(s₂, i₁) = +s₃
// 		Mul(s₂, s₃) = -Mul(s₃, s₂) = -i₁
// 		Mul(s₃, i₁) = -Mul(i₁, s₃) = +s₂
// This binary operation is noncommutative but associative.
func (z *Cockle) Mul(x, y *Cockle) *Cockle {
	p := new(Cockle).Copy(x)
	q := new(Cockle).Copy(y)
	z.SetRe(new(Complex).Add(
		new(Complex).Mul(p.Re(), q.Re()),
		new(Complex).Mul(new(Complex).Conj(q.Sp()), p.Sp()),
	))
	z.SetSp(new(Complex).Add(
		new(Complex).Mul(p.Re(), q.Sp()),
		new(Complex).Mul(p.Sp(), new(Complex).Conj(q.Re())),
	))
	return z
}

// Commutator sets z equal to the commutator of x and y, and returns z.
func (z *Cockle) Commutator(x, y *Cockle) *Cockle {
	return z.Sub(
		new(Cockle).Mul(x, y),
		new(Cockle).Mul(y, x),
	)
}

// Quad returns the quadrance of z, a pointer to a big.Rat value.
func (z *Cockle) Quad() *big.Rat {
	return new(big.Rat).Sub(
		z.Re().Quad(),
		z.Sp().Quad(),
	)
}

// IsZeroDiv returns true if z is a zero divisor.
func (z *Cockle) IsZeroDiv() bool {
	return z.Re().Quad().Cmp(z.Sp().Quad()) == 0
}

// Inv sets z equal to the inverse of y, and returns z.
func (z *Cockle) Inv(y *Cockle) *Cockle {
	if y.IsZeroDiv() {
		panic("zero divisor inverse")
	}
	return z.Scal(new(Cockle).Conj(y), new(big.Rat).Inv(y.Quad()))
}

// Quo sets z equal to the quotient of x and y, and returns z.
func (z *Cockle) Quo(x, y *Cockle) *Cockle {
	if y.IsZeroDiv() {
		panic("zero divisor denominator")
	}
	return z.Mul(x, new(Cockle).Inv(y))
}
<commit_msg>Add IsNilpotent method to Cockle type<commit_after>package rational

import (
	"fmt"
	"math/big"
	"strings"
)

var symbCockle = [4]string{"", "i₁", "s₂", "s₃"}

// A Cockle represents a rational Cockle quaternion.
type Cockle struct {
	re, sp *Complex
}

// Re returns the Cayley-Dickson real part of z, a pointer to a Complex value.
func (z *Cockle) Re() *Complex {
	return z.re
}

// Sp returns the Cayley-Dickson split part of z, a pointer to a Complex
// value.
func (z *Cockle) Sp() *Complex {
	return z.sp
}

// SetRe sets the Cayley-Dickson real part of z equal to a.
func (z *Cockle) SetRe(a *Complex) {
	z.re = a
}

// SetSp sets the Cayley-Dickson split part of z equal to b.
func (z *Cockle) SetSp(b *Complex) {
	z.sp = b
}

// Cartesian returns the four Cartesian components of z.
func (z *Cockle) Cartesian() (a, b, c, d *big.Rat) {
	a, b = z.Re().Cartesian()
	c, d = z.Sp().Cartesian()
	return
}

// String returns the string representation of a Cockle value.
// If z corresponds to a + bi₁ + cs₂ + ds₃, then the string is "(a+bi₁+cs₂+ds₃)",
// similar to complex128 values.
func (z *Cockle) String() string {
	v := make([]*big.Rat, 4)
	v[0], v[1] = z.Re().Cartesian()
	v[2], v[3] = z.Sp().Cartesian()
	a := make([]string, 9)
	a[0] = "("
	a[1] = fmt.Sprintf("%v", v[0])
	i := 1
	for j := 2; j < 8; j = j + 2 {
		if v[i].Sign() == -1 {
			a[j] = fmt.Sprintf("%v", v[i])
		} else {
			a[j] = fmt.Sprintf("+%v", v[i])
		}
		a[j+1] = symbCockle[i]
		i++
	}
	a[8] = ")"
	return strings.Join(a, "")
}

// Equals returns true if y and z are equal.
func (z *Cockle) Equals(y *Cockle) bool {
	if !z.Re().Equals(y.Re()) || !z.Sp().Equals(y.Sp()) {
		return false
	}
	return true
}

// Copy copies y onto z, and returns z.
func (z *Cockle) Copy(y *Cockle) *Cockle {
	z.SetRe(y.Re())
	z.SetSp(y.Sp())
	return z
}

// NewCockle returns a pointer to a Cockle value made from four given pointers
// to big.Rat values.
func NewCockle(a, b, c, d *big.Rat) *Cockle {
	z := new(Cockle)
	z.SetRe(NewComplex(a, b))
	z.SetSp(NewComplex(c, d))
	return z
}

// Scal sets z equal to y scaled by a, and returns z.
func (z *Cockle) Scal(y *Cockle, a *big.Rat) *Cockle {
	z.SetRe(new(Complex).Scal(y.Re(), a))
	z.SetSp(new(Complex).Scal(y.Sp(), a))
	return z
}

// Neg sets z equal to the negative of y, and returns z.
func (z *Cockle) Neg(y *Cockle) *Cockle {
	z.SetRe(new(Complex).Neg(y.Re()))
	z.SetSp(new(Complex).Neg(y.Sp()))
	return z
}

// Conj sets z equal to the conjugate of y, and returns z.
func (z *Cockle) Conj(y *Cockle) *Cockle {
	z.SetRe(new(Complex).Conj(y.Re()))
	z.SetSp(new(Complex).Neg(y.Sp()))
	return z
}

// Add sets z equal to the sum of x and y, and returns z.
func (z *Cockle) Add(x, y *Cockle) *Cockle {
	z.SetRe(new(Complex).Add(x.Re(), y.Re()))
	z.SetSp(new(Complex).Add(x.Sp(), y.Sp()))
	return z
}

// Sub sets z equal to the difference of x and y, and returns z.
func (z *Cockle) Sub(x, y *Cockle) *Cockle {
	z.SetRe(new(Complex).Sub(x.Re(), y.Re()))
	z.SetSp(new(Complex).Sub(x.Sp(), y.Sp()))
	return z
}

// Mul sets z equal to the product of x and y, and returns z.
//
// The multiplication rules are:
// 		Mul(i₁, i₁) = -1
// 		Mul(s₂, s₂) = Mul(s₃, s₃) = +1
// 		Mul(i₁, s₂) = -Mul(s₂, i₁) = +s₃
// 		Mul(s₂, s₃) = -Mul(s₃, s₂) = -i₁
// 		Mul(s₃, i₁) = -Mul(i₁, s₃) = +s₂
// This binary operation is noncommutative but associative.
func (z *Cockle) Mul(x, y *Cockle) *Cockle {
	p := new(Cockle).Copy(x)
	q := new(Cockle).Copy(y)
	z.SetRe(new(Complex).Add(
		new(Complex).Mul(p.Re(), q.Re()),
		new(Complex).Mul(new(Complex).Conj(q.Sp()), p.Sp()),
	))
	z.SetSp(new(Complex).Add(
		new(Complex).Mul(p.Re(), q.Sp()),
		new(Complex).Mul(p.Sp(), new(Complex).Conj(q.Re())),
	))
	return z
}

// Commutator sets z equal to the commutator of x and y, and returns z.
func (z *Cockle) Commutator(x, y *Cockle) *Cockle {
	return z.Sub(
		new(Cockle).Mul(x, y),
		new(Cockle).Mul(y, x),
	)
}

// Quad returns the quadrance of z, a pointer to a big.Rat value.
func (z *Cockle) Quad() *big.Rat {
	return new(big.Rat).Sub(
		z.Re().Quad(),
		z.Sp().Quad(),
	)
}

// IsZeroDiv returns true if z is a zero divisor.
func (z *Cockle) IsZeroDiv() bool {
	return z.Re().Quad().Cmp(z.Sp().Quad()) == 0
}

// Inv sets z equal to the inverse of y, and returns z.
func (z *Cockle) Inv(y *Cockle) *Cockle {
	if y.IsZeroDiv() {
		panic("zero divisor inverse")
	}
	return z.Scal(new(Cockle).Conj(y), new(big.Rat).Inv(y.Quad()))
}

// Quo sets z equal to the quotient of x and y, and returns z.
func (z *Cockle) Quo(x, y *Cockle) *Cockle {
	if y.IsZeroDiv() {
		panic("zero divisor denominator")
	}
	return z.Mul(x, new(Cockle).Inv(y))
}

// IsNilpotent returns true if z raised to the nth power vanishes.
func (z *Cockle) IsNilpotent(n int) bool {
	zeroRat := big.NewRat(0, 1)
	zero := NewCockle(zeroRat, zeroRat, zeroRat, zeroRat)
	if z.Equals(zero) {
		return true
	}
	p := NewCockle(big.NewRat(1, 1), zeroRat, zeroRat, zeroRat)
	for i := 0; i < n; i++ {
		p.Mul(p, z)
		if p.Equals(zero) {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>//  Copyright 2015 Walter Schulze
//
//  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 xml

import (
	"bytes"
	"fmt"
	"github.com/katydid/katydid/serialize"
	"io"
	"regexp"
	"strconv"
	"strings"
)

type parser struct {
	buf       []byte
	dec       *Decoder
	tok       Token
	attrs     []Attr
	attrIndex int
	attrValue bool
	attrFirst bool
}

func NewXMLParser() *parser {
	return &parser{}
}

var procInstPattern = regexp.MustCompile(`<\?.*\?>`)

func (p *parser) Init(buf []byte) error {
	buf = procInstPattern.ReplaceAll(buf, []byte{})
	buf = bytes.TrimSpace(buf)
	p.buf = buf
	p.dec = NewDecoder(NewBuffer(buf))
	p.dec.Strict = false
	return nil
}

func (p *parser) Copy() serialize.Parser {
	return &parser{
		buf:       p.buf,
		dec:       p.dec.Copy(),
		tok:       CopyToken(p.tok),
		attrs:     copyAttrs(p.attrs),
		attrIndex: p.attrIndex,
		attrValue: p.attrValue,
		attrFirst: p.attrFirst,
	}
}

func hasContent(c CharData) bool {
	return len(string(c)) > 0
}

func (p *parser) Next() (err error) {
	if p.attrValue {
		if p.attrFirst {
			p.attrFirst = false
			return nil
		} else {
			return io.EOF
		}
	}
	if p.tok == nil {
		if p.attrs != nil {
			p.attrIndex++
			if p.attrIndex < len(p.attrs) {
				return nil
			}
		}
	}
	if p.tok != nil {
		for {
			if _, ok := p.tok.(StartElement); ok {
				//fmt.Printf("Skipping %s\n", s.Name)
				if err := p.dec.Skip(); err != nil {
					//fmt.Printf("Skip err = %v\n", err)
					return err
				}
				break
			} else if _, ok := p.tok.(EndElement); ok {
				return io.EOF
			} else if c, ok := p.tok.(CharData); ok {
				if hasContent(c) {
					break
				}
			} else if _, ok := p.tok.(Comment); ok {
				p.tok, err = p.dec.Token()
				//fmt.Printf("Comment Next Token %#v, err = %v\n", p.tok, err)
				if err != nil {
					return err
				}
			} else {
				panic(fmt.Sprintf("unknown token %T", p.tok))
			}
		}
	}
	p.tok, err = p.dec.Token()
	//fmt.Printf("Next Token %#v, err %v\n", p.tok, err)
	for err == nil {
		if _, ok := p.tok.(StartElement); ok {
			break
		} else if c, ok := p.tok.(CharData); ok {
			if hasContent(c) {
				break
			}
		} else if _, ok := p.tok.(EndElement); ok {
			return io.EOF
		}
		p.tok, err = p.dec.Token()
		//fmt.Printf("Next Next Token %#v, err = %v\n", p.tok, err)
	}
	return err
}

func (p *parser) IsLeaf() bool {
	if p.tok == nil {
		if p.attrValue {
			return true
		}
		return false
	}
	_, ok := p.tok.(CharData)
	fmt.Printf("IsLeaf %#v\n", p.tok)
	return ok
}

func (p *parser) getValue() string {
	if p.tok == nil && p.attrValue {
		return p.attrs[p.attrIndex].Value
	}
	if c, ok := p.tok.(CharData); ok {
		return string(c)
	}
	return ""
}

func (p *parser) Double() (float64, error) {
	return strconv.ParseFloat(p.getValue(), 64)
}

func (p *parser) Int() (int64, error) {
	i, err := strconv.ParseInt(p.getValue(), 10, 64)
	return int64(i), err
}

func (p *parser) Uint() (uint64, error) {
	i, err := strconv.ParseUint(p.getValue(), 10, 64)
	return uint64(i), err
}

func (p *parser) Bool() (bool, error) {
	return strconv.ParseBool(strings.TrimSpace(p.getValue()))
}

func (p *parser) String() (string, error) {
	if p.tok == nil && p.attrIndex < len(p.attrs) {
		if p.attrValue {
			return p.attrs[p.attrIndex].Value, nil
		} else {
			return "@" + p.attrs[p.attrIndex].Name.Local, nil
		}
	}
	if s, ok := p.tok.(StartElement); ok {
		return s.Name.Local, nil
	}
	if c, ok := p.tok.(CharData); ok {
		return string(c), nil
	}
	return "", serialize.ErrNotString
}

func (p *parser) Bytes() ([]byte, error) {
	if c, ok := p.tok.(CharData); ok {
		return []byte(c), nil
	}
	return nil, serialize.ErrNotBytes
}

func (p *parser) Up() {
	if p.tok == nil {
		if p.attrValue {
			p.attrValue = false
			p.attrFirst = false
			return
		}
	}
	if _, ok := p.tok.(EndElement); ok {
		p.tok = nil
		p.attrs = nil
		p.attrIndex = 0
		return
	}
	if err := p.dec.Skip(); err != nil {
		if err != io.EOF {
			panic(err)
		}
	}
}

func (p *parser) Down() {
	if p.tok == nil {
		if p.attrIndex < len(p.attrs) {
			p.attrValue = true
			p.attrFirst = true
			return
		}
	}
	if s, ok := p.tok.(StartElement); ok {
		p.tok = nil
		p.attrs = s.Attr
		p.attrIndex = -1
		return
	}
	panic(fmt.Sprintf("not a start element %T", p.tok))
}
<commit_msg>comment output in xml<commit_after>//  Copyright 2015 Walter Schulze
//
//  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 xml

import (
	"bytes"
	"fmt"
	"github.com/katydid/katydid/serialize"
	"io"
	"regexp"
	"strconv"
	"strings"
)

type parser struct {
	buf       []byte
	dec       *Decoder
	tok       Token
	attrs     []Attr
	attrIndex int
	attrValue bool
	attrFirst bool
}

func NewXMLParser() *parser {
	return &parser{}
}

var procInstPattern = regexp.MustCompile(`<\?.*\?>`)

func (p *parser) Init(buf []byte) error {
	buf = procInstPattern.ReplaceAll(buf, []byte{})
	buf = bytes.TrimSpace(buf)
	p.buf = buf
	p.dec = NewDecoder(NewBuffer(buf))
	p.dec.Strict = false
	return nil
}

func (p *parser) Copy() serialize.Parser {
	return &parser{
		buf:       p.buf,
		dec:       p.dec.Copy(),
		tok:       CopyToken(p.tok),
		attrs:     copyAttrs(p.attrs),
		attrIndex: p.attrIndex,
		attrValue: p.attrValue,
		attrFirst: p.attrFirst,
	}
}

func hasContent(c CharData) bool {
	return len(string(c)) > 0
}

func (p *parser) Next() (err error) {
	if p.attrValue {
		if p.attrFirst {
			p.attrFirst = false
			return nil
		} else {
			return io.EOF
		}
	}
	if p.tok == nil {
		if p.attrs != nil {
			p.attrIndex++
			if p.attrIndex < len(p.attrs) {
				return nil
			}
		}
	}
	if p.tok != nil {
		for {
			if _, ok := p.tok.(StartElement); ok {
				//fmt.Printf("Skipping %s\n", s.Name)
				if err := p.dec.Skip(); err != nil {
					//fmt.Printf("Skip err = %v\n", err)
					return err
				}
				break
			} else if _, ok := p.tok.(EndElement); ok {
				return io.EOF
			} else if c, ok := p.tok.(CharData); ok {
				if hasContent(c) {
					break
				}
			} else if _, ok := p.tok.(Comment); ok {
				p.tok, err = p.dec.Token()
				//fmt.Printf("Comment Next Token %#v, err = %v\n", p.tok, err)
				if err != nil {
					return err
				}
			} else {
				panic(fmt.Sprintf("unknown token %T", p.tok))
			}
		}
	}
	p.tok, err = p.dec.Token()
	//fmt.Printf("Next Token %#v, err %v\n", p.tok, err)
	for err == nil {
		if _, ok := p.tok.(StartElement); ok {
			break
		} else if c, ok := p.tok.(CharData); ok {
			if hasContent(c) {
				break
			}
		} else if _, ok := p.tok.(EndElement); ok {
			return io.EOF
		}
		p.tok, err = p.dec.Token()
		//fmt.Printf("Next Next Token %#v, err = %v\n", p.tok, err)
	}
	return err
}

func (p *parser) IsLeaf() bool {
	if p.tok == nil {
		if p.attrValue {
			return true
		}
		return false
	}
	_, ok := p.tok.(CharData)
	//fmt.Printf("IsLeaf %#v\n", p.tok)
	return ok
}

func (p *parser) getValue() string {
	if p.tok == nil && p.attrValue {
		return p.attrs[p.attrIndex].Value
	}
	if c, ok := p.tok.(CharData); ok {
		return string(c)
	}
	return ""
}

func (p *parser) Double() (float64, error) {
	return strconv.ParseFloat(p.getValue(), 64)
}

func (p *parser) Int() (int64, error) {
	i, err := strconv.ParseInt(p.getValue(), 10, 64)
	return int64(i), err
}

func (p *parser) Uint() (uint64, error) {
	i, err := strconv.ParseUint(p.getValue(), 10, 64)
	return uint64(i), err
}

func (p *parser) Bool() (bool, error) {
	return strconv.ParseBool(strings.TrimSpace(p.getValue()))
}

func (p *parser) String() (string, error) {
	if p.tok == nil && p.attrIndex < len(p.attrs) {
		if p.attrValue {
			return p.attrs[p.attrIndex].Value, nil
		} else {
			return "@" + p.attrs[p.attrIndex].Name.Local, nil
		}
	}
	if s, ok := p.tok.(StartElement); ok {
		return s.Name.Local, nil
	}
	if c, ok := p.tok.(CharData); ok {
		return string(c), nil
	}
	return "", serialize.ErrNotString
}

func (p *parser) Bytes() ([]byte, error) {
	if c, ok := p.tok.(CharData); ok {
		return []byte(c), nil
	}
	return nil, serialize.ErrNotBytes
}

func (p *parser) Up() {
	if p.tok == nil {
		if p.attrValue {
			p.attrValue = false
			p.attrFirst = false
			return
		}
	}
	if _, ok := p.tok.(EndElement); ok {
		p.tok = nil
		p.attrs = nil
		p.attrIndex = 0
		return
	}
	if err := p.dec.Skip(); err != nil {
		if err != io.EOF {
			panic(err)
		}
	}
}

func (p *parser) Down() {
	if p.tok == nil {
		if p.attrIndex < len(p.attrs) {
			p.attrValue = true
			p.attrFirst = true
			return
		}
	}
	if s, ok := p.tok.(StartElement); ok {
		p.tok = nil
		p.attrs = s.Attr
		p.attrIndex = -1
		return
	}
	panic(fmt.Sprintf("not a start element %T", p.tok))
}
<|endoftext|>


<commit_before>package chlib

import (
	"bytes"
	"chkit-v2/chlib/dbconfig"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	jww "github.com/spf13/jwalterweatherman"
)

type HttpApiHandler struct {
	cfg     dbconfig.HttpApiConfig
	headers map[string]string
	np      *jww.Notepad
}

type HttpApiResult map[string]interface{}

func NewHttpApiHandler(cfg dbconfig.HttpApiConfig, uuid, token string, np *jww.Notepad) *HttpApiHandler {
	handler := HttpApiHandler{
		cfg: cfg,
		np:  np,
	}
	handler.headers = make(map[string]string)
	handler.headers["Channel"] = uuid
	handler.headers["Authorization"] = token
	return &handler
}

func (h *HttpApiHandler) makeRequest(url, method string, jsonToSend GenericJson) (result HttpApiResult, err error) {
	h.np.SetPrefix("HTTP")
	client := http.Client{Timeout: h.cfg.Timeout}
	marshalled, _ := json.Marshal(jsonToSend)
	h.np.DEBUG.Printf("%s %s\n", method, url)
	request, err := http.NewRequest(method, url, bytes.NewBuffer(marshalled))
	for k, v := range h.headers {
		request.Header.Add(k, v)
	}
	if err != nil {
		return result, fmt.Errorf("http request create error: %s", err)
	}
	resp, err := client.Do(request)
	if err != nil {
		return result, fmt.Errorf("http request execute error: %s", err)
	}
	h.np.DEBUG.Println("Result", resp.Status)
	defer resp.Body.Close()
	err = json.NewDecoder(resp.Body).Decode(&result)
	return result, err
}

func (h *HttpApiHandler) Create(jsonToSend GenericJson, kind, nameSpace string) (result HttpApiResult, err error) {
	kind = fmt.Sprintf("%ss", strings.ToLower(kind))
	url := fmt.Sprintf("%s/namespaces/%s/%s", h.cfg.Server, nameSpace, kind)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Expose(jsonToSend GenericJson, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/services", h.cfg.Server, nameSpace)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Login(jsonToSend GenericJson) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/session/login", h.cfg.Server)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) SetForContainer(jsonToSend GenericJson, containerName, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/container/%s", h.cfg.Server, nameSpace, containerName)
	return h.makeRequest(url, http.MethodPatch, jsonToSend)
}

func (h *HttpApiHandler) SetForDeploy(jsonToSend GenericJson, deploy, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/deployments/%s/spec", h.cfg.Server, nameSpace, deploy)
	return h.makeRequest(url, http.MethodPatch, jsonToSend)
}

func (h *HttpApiHandler) Replace(jsonToSend GenericJson, nameSpace, kind string) (result HttpApiResult, err error) {
	kindI, hasKind := jsonToSend["kind"]
	if !hasKind {
		return result, fmt.Errorf("replace: kind not specified")
	}
	kind, ok := kindI.(string)
	if !ok {
		return result, fmt.Errorf("replace: kind is not a string")
	}
	metadataI, hasMd := jsonToSend["metadata"]
	if !hasMd {
		return result, fmt.Errorf("replace: metadata not specified")
	}
	metadata, ok := metadataI.(map[string]interface{})
	if !ok {
		return result, fmt.Errorf("replace: metadata is not object")
	}
	nameI, hasName := metadata["name"]
	if !hasName {
		return result, fmt.Errorf("replace: metadata has no name attrubute")
	}
	name, ok := nameI.(string)
	if !ok {
		return result, fmt.Errorf("repace: name is not a string")
	}
	url := fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	return h.makeRequest(url, http.MethodPut, jsonToSend)
}

func (h *HttpApiHandler) ReplaceNameSpaces(jsonToSend GenericJson) (result HttpApiResult, err error) {
	metadataI, hasMd := jsonToSend["metadata"]
	if !hasMd {
		return result, fmt.Errorf("replaceNameSpace: metadata not specified")
	}
	metadata, ok := metadataI.(map[string]interface{})
	if !ok {
		return result, fmt.Errorf("replaceNameSpace: metadata is not object")
	}
	nameI, hasName := metadata["name"]
	if !hasName {
		return result, fmt.Errorf("replaceNameSpace: metadata has no name attrubute")
	}
	name, ok := nameI.(string)
	if !ok {
		return result, fmt.Errorf("repaceNameSpace: name is not a string")
	}

	url := fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	return h.makeRequest(url, http.MethodPut, jsonToSend)
}

func (h *HttpApiHandler) Run(jsonToSend GenericJson, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/deployments", h.cfg.Server, nameSpace)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Delete(kind, name, nameSpace string, allPods bool) (result HttpApiResult, err error) {
	var url string
	if kind == KindDeployments && allPods {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s/pods", h.cfg.Server, nameSpace, kind, name)
	} else {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	}
	return h.makeRequest(url, http.MethodDelete, nil)
}

func (h *HttpApiHandler) DeleteNameSpaces(name string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	result, err = h.makeRequest(url, http.MethodDelete, nil)
	return
}

func (h *HttpApiHandler) Get(kind, name, nameSpace string) (result HttpApiResult, err error) {
	var url string
	if name != "" {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	} else {
		url = fmt.Sprintf("%s/namespaces/%s/%s", h.cfg.Server, nameSpace, kind)
	}
	return h.makeRequest(url, http.MethodGet, nil)
}

func (h *HttpApiHandler) GetNameSpaces(name string) (result HttpApiResult, err error) {
	var url string
	if name != "" {
		url = fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	} else {
		url = fmt.Sprintf("%s/namespaces", h.cfg.Server)
	}
	return h.makeRequest(url, http.MethodGet, nil)
}

func (apiResult *HttpApiResult) HandleApiResult() error {
	if apiResult == nil {
		return nil
	}
	errCont, hasErr := (*apiResult)["error"]
	if hasErr {
		return fmt.Errorf("api error: %v", errCont)
	}
	return nil
}
<commit_msg>Fix HTTP error forming if result is not JSON<commit_after>package chlib

import (
	"bytes"
	"chkit-v2/chlib/dbconfig"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	jww "github.com/spf13/jwalterweatherman"
)

type HttpApiHandler struct {
	cfg     dbconfig.HttpApiConfig
	headers map[string]string
	np      *jww.Notepad
}

type HttpApiResult map[string]interface{}

func NewHttpApiHandler(cfg dbconfig.HttpApiConfig, uuid, token string, np *jww.Notepad) *HttpApiHandler {
	handler := HttpApiHandler{
		cfg: cfg,
		np:  np,
	}
	handler.headers = make(map[string]string)
	handler.headers["Channel"] = uuid
	handler.headers["Authorization"] = token
	return &handler
}

func (h *HttpApiHandler) makeRequest(url, method string, jsonToSend GenericJson) (result HttpApiResult, err error) {
	h.np.SetPrefix("HTTP")
	client := http.Client{Timeout: h.cfg.Timeout}
	marshalled, _ := json.Marshal(jsonToSend)
	h.np.DEBUG.Printf("%s %s\n", method, url)
	request, err := http.NewRequest(method, url, bytes.NewBuffer(marshalled))
	for k, v := range h.headers {
		request.Header.Add(k, v)
	}
	if err != nil {
		return result, fmt.Errorf("http request create error: %s", err)
	}
	resp, err := client.Do(request)
	if err != nil {
		return result, fmt.Errorf("http request execute error: %s", err)
	}
	h.np.DEBUG.Println("Result", resp.Status)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return result, err
	}
	err = json.Unmarshal(body, &result)
	if err != nil {
		err = fmt.Errorf("Received error: %s", body)
	}
	return result, err
}

func (h *HttpApiHandler) Create(jsonToSend GenericJson, kind, nameSpace string) (result HttpApiResult, err error) {
	kind = fmt.Sprintf("%ss", strings.ToLower(kind))
	url := fmt.Sprintf("%s/namespaces/%s/%s", h.cfg.Server, nameSpace, kind)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Expose(jsonToSend GenericJson, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/services", h.cfg.Server, nameSpace)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Login(jsonToSend GenericJson) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/session/login", h.cfg.Server)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) SetForContainer(jsonToSend GenericJson, containerName, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/container/%s", h.cfg.Server, nameSpace, containerName)
	return h.makeRequest(url, http.MethodPatch, jsonToSend)
}

func (h *HttpApiHandler) SetForDeploy(jsonToSend GenericJson, deploy, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/deployments/%s/spec", h.cfg.Server, nameSpace, deploy)
	return h.makeRequest(url, http.MethodPatch, jsonToSend)
}

func (h *HttpApiHandler) Replace(jsonToSend GenericJson, nameSpace, kind string) (result HttpApiResult, err error) {
	kindI, hasKind := jsonToSend["kind"]
	if !hasKind {
		return result, fmt.Errorf("replace: kind not specified")
	}
	kind, ok := kindI.(string)
	if !ok {
		return result, fmt.Errorf("replace: kind is not a string")
	}
	metadataI, hasMd := jsonToSend["metadata"]
	if !hasMd {
		return result, fmt.Errorf("replace: metadata not specified")
	}
	metadata, ok := metadataI.(map[string]interface{})
	if !ok {
		return result, fmt.Errorf("replace: metadata is not object")
	}
	nameI, hasName := metadata["name"]
	if !hasName {
		return result, fmt.Errorf("replace: metadata has no name attrubute")
	}
	name, ok := nameI.(string)
	if !ok {
		return result, fmt.Errorf("repace: name is not a string")
	}
	url := fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	return h.makeRequest(url, http.MethodPut, jsonToSend)
}

func (h *HttpApiHandler) ReplaceNameSpaces(jsonToSend GenericJson) (result HttpApiResult, err error) {
	metadataI, hasMd := jsonToSend["metadata"]
	if !hasMd {
		return result, fmt.Errorf("replaceNameSpace: metadata not specified")
	}
	metadata, ok := metadataI.(map[string]interface{})
	if !ok {
		return result, fmt.Errorf("replaceNameSpace: metadata is not object")
	}
	nameI, hasName := metadata["name"]
	if !hasName {
		return result, fmt.Errorf("replaceNameSpace: metadata has no name attrubute")
	}
	name, ok := nameI.(string)
	if !ok {
		return result, fmt.Errorf("repaceNameSpace: name is not a string")
	}

	url := fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	return h.makeRequest(url, http.MethodPut, jsonToSend)
}

func (h *HttpApiHandler) Run(jsonToSend GenericJson, nameSpace string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s/deployments", h.cfg.Server, nameSpace)
	return h.makeRequest(url, http.MethodPost, jsonToSend)
}

func (h *HttpApiHandler) Delete(kind, name, nameSpace string, allPods bool) (result HttpApiResult, err error) {
	var url string
	if kind == KindDeployments && allPods {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s/pods", h.cfg.Server, nameSpace, kind, name)
	} else {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	}
	return h.makeRequest(url, http.MethodDelete, nil)
}

func (h *HttpApiHandler) DeleteNameSpaces(name string) (result HttpApiResult, err error) {
	url := fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	result, err = h.makeRequest(url, http.MethodDelete, nil)
	return
}

func (h *HttpApiHandler) Get(kind, name, nameSpace string) (result HttpApiResult, err error) {
	var url string
	if name != "" {
		url = fmt.Sprintf("%s/namespaces/%s/%s/%s", h.cfg.Server, nameSpace, kind, name)
	} else {
		url = fmt.Sprintf("%s/namespaces/%s/%s", h.cfg.Server, nameSpace, kind)
	}
	return h.makeRequest(url, http.MethodGet, nil)
}

func (h *HttpApiHandler) GetNameSpaces(name string) (result HttpApiResult, err error) {
	var url string
	if name != "" {
		url = fmt.Sprintf("%s/namespaces/%s", h.cfg.Server, name)
	} else {
		url = fmt.Sprintf("%s/namespaces", h.cfg.Server)
	}
	return h.makeRequest(url, http.MethodGet, nil)
}

func (apiResult *HttpApiResult) HandleApiResult() error {
	if apiResult == nil {
		return nil
	}
	errCont, hasErr := (*apiResult)["error"]
	if hasErr {
		return fmt.Errorf("api error: %v", errCont)
	}
	return nil
}
<|endoftext|>


<commit_before>package config

type Repo struct {
	Path   string   `json:"path"`
	Name   string   `json:"name"`
	Refs   []string `json:"refs"`
	Github string   `json:"github"`
}

type Backend struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Addr      string `json:"addr"`
	IndexPath string `json:"index"`
	Repos     []Repo `json:"repos"`
}

type Config struct {
	DocRoot  string
	Feedback struct {
		MailTo string `json:"mailto"`
	} `json:"feedback"`

	GoogleAnalyticsId string `json:"google_analytics_id"`
	// Should we respect X-Real-Ip, X-Real-Proto, and X-Forwarded-Host?
	ReverseProxy bool `json:"reverse_proxy"`

	Backends []Backend `json:"backends"`
}
<commit_msg>Some comments in `config.go'.<commit_after>package config

type Repo struct {
	Path   string   `json:"path"`
	Name   string   `json:"name"`
	Refs   []string `json:"refs"`
	Github string   `json:"github"`
}

type Backend struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	Addr      string `json:"addr"`
	IndexPath string `json:"index"`
	Repos     []Repo `json:"repos"`
}

type Config struct {
	// Location of the directory containing templates and static
	// assets. This should point at the "web" directory of the
	// repository.
	DocRoot string `json:"docroot"`

	Feedback struct {
		// The mailto address for the "feedback" url.
		Mailto string `json:"mailto"`
	} `json:"feedback"`

	GoogleAnalyticsId string `json:"google_analytics_id"`
	// Should we respect X-Real-Ip, X-Real-Proto, and X-Forwarded-Host?
	ReverseProxy bool `json:"reverse_proxy"`

	// List of backends to connect to. Each backend must minimally
	// include the "id" and "addr" fields; All other fields are
	// optional and will be replaced by values reported by the
	// backend server once we successfully connect.
	Backends []Backend `json:"backends"`
}
<|endoftext|>


<commit_before>package container

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/integration-cli/daemon"
)

func TestDaemonRestartKillContainers(t *testing.T) {
	type testCase struct {
		desc       string
		config     *container.Config
		hostConfig *container.HostConfig

		xRunning            bool
		xRunningLiveRestore bool
	}

	for _, c := range []testCase{
		{
			desc:                "container without restart policy",
			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
			xRunningLiveRestore: true,
		},
		{
			desc:                "container with restart=always",
			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
			hostConfig:          &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
			xRunning:            true,
			xRunningLiveRestore: true,
		},
	} {
		for _, liveRestoreEnabled := range []bool{false, true} {
			for fnName, stopDaemon := range map[string]func(*testing.T, *daemon.Daemon){
				"kill-daemon": func(t *testing.T, d *daemon.Daemon) {
					if err := d.Kill(); err != nil {
						t.Fatal(err)
					}
				},
				"stop-daemon": func(t *testing.T, d *daemon.Daemon) {
					d.Stop(t)
				},
			} {
				t.Run(fmt.Sprintf("live-restore=%v/%s/%s", liveRestoreEnabled, c.desc, fnName), func(t *testing.T) {
					c := c
					liveRestoreEnabled := liveRestoreEnabled
					stopDaemon := stopDaemon

					t.Parallel()

					d := daemon.New(t, "", "dockerd", daemon.Config{})
					client, err := d.NewClient()
					if err != nil {
						t.Fatal(err)
					}

					var args []string
					if liveRestoreEnabled {
						args = []string{"--live-restore"}
					}

					d.StartWithBusybox(t, args...)
					defer d.Stop(t)
					ctx := context.Background()

					resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, "")
					if err != nil {
						t.Fatal(err)
					}
					defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})

					if err := client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
						t.Fatal(err)
					}

					stopDaemon(t, d)
					d.Start(t, args...)

					expected := c.xRunning
					if liveRestoreEnabled {
						expected = c.xRunningLiveRestore
					}

					var running bool
					for i := 0; i < 30; i++ {
						inspect, err := client.ContainerInspect(ctx, resp.ID)
						if err != nil {
							t.Fatal(err)
						}

						running = inspect.State.Running
						if running == expected {
							break
						}
						time.Sleep(2 * time.Second)

					}

					if running != expected {
						t.Fatalf("got unexpected running state, expected %v, got: %v", expected, running)
					}
					// TODO(cpuguy83): test pause states... this seems to be rather undefined currently
				})
			}
		}
	}
}
<commit_msg>Fix race with concurrent daemon startup in tests<commit_after>package container

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/integration-cli/daemon"
)

func TestDaemonRestartKillContainers(t *testing.T) {
	type testCase struct {
		desc       string
		config     *container.Config
		hostConfig *container.HostConfig

		xRunning            bool
		xRunningLiveRestore bool
	}

	for _, c := range []testCase{
		{
			desc:                "container without restart policy",
			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
			xRunningLiveRestore: true,
		},
		{
			desc:                "container with restart=always",
			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
			hostConfig:          &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
			xRunning:            true,
			xRunningLiveRestore: true,
		},
	} {
		for _, liveRestoreEnabled := range []bool{false, true} {
			for fnName, stopDaemon := range map[string]func(*testing.T, *daemon.Daemon){
				"kill-daemon": func(t *testing.T, d *daemon.Daemon) {
					if err := d.Kill(); err != nil {
						t.Fatal(err)
					}
				},
				"stop-daemon": func(t *testing.T, d *daemon.Daemon) {
					d.Stop(t)
				},
			} {
				t.Run(fmt.Sprintf("live-restore=%v/%s/%s", liveRestoreEnabled, c.desc, fnName), func(t *testing.T) {
					c := c
					liveRestoreEnabled := liveRestoreEnabled
					stopDaemon := stopDaemon

					t.Parallel()

					d := daemon.New(t, "", "dockerd", daemon.Config{})
					client, err := d.NewClient()
					if err != nil {
						t.Fatal(err)
					}

					args := []string{"--iptables=false"}
					if liveRestoreEnabled {
						args = append(args, "--live-restore")
					}

					d.StartWithBusybox(t, args...)
					defer d.Stop(t)
					ctx := context.Background()

					resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, "")
					if err != nil {
						t.Fatal(err)
					}
					defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})

					if err := client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{}); err != nil {
						t.Fatal(err)
					}

					stopDaemon(t, d)
					d.Start(t, args...)

					expected := c.xRunning
					if liveRestoreEnabled {
						expected = c.xRunningLiveRestore
					}

					var running bool
					for i := 0; i < 30; i++ {
						inspect, err := client.ContainerInspect(ctx, resp.ID)
						if err != nil {
							t.Fatal(err)
						}

						running = inspect.State.Running
						if running == expected {
							break
						}
						time.Sleep(2 * time.Second)

					}

					if running != expected {
						t.Fatalf("got unexpected running state, expected %v, got: %v", expected, running)
					}
					// TODO(cpuguy83): test pause states... this seems to be rather undefined currently
				})
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 search

import (
	"testing"
	"github.com/ctdk/goiardi/node"
	"github.com/ctdk/goiardi/role"
	"github.com/ctdk/goiardi/environment"
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/data_bag"
	"fmt"
)

// Most search testing can be handled fine with chef-pedant, but that's no
// reason to not have some go tests for it too.
var node1 *node.Node
var node2 *node.Node
var node3 *node.Node
var node4 *node.Node
var role1 *role.Role
var role2 *role.Role
var role3 *role.Role
var role4 *role.Role
var env1 *environment.ChefEnvironment
var env2 *environment.ChefEnvironment
var env3 *environment.ChefEnvironment
var env4 *environment.ChefEnvironment
var client1 *actor.Actor
var client2 *actor.Actor
var client3 *actor.Actor
var client4 *actor.Actor
var dbag1 *data_bag.DataBag
var dbag2 *data_bag.DataBag
var dbag3 *data_bag.DataBag
var dbag4 *data_bag.DataBag

func makeSearchItems() int{
	/* Gotta populate the search index */
	nodes := make([]*node.Node, 4)
	roles := make([]*role.Role, 4)
	envs := make([]*environment.ChefEnvironment, 4)
	clients := make([]*actor.Actor, 4)
	dbags := make([]*data_bag.DataBag, 4)

	for i := 0; i < 4; i++ {
		nodes[i] = node.New(
	}

	/* Make this function return something so the compiler's happy building
	 * the tests. */
	return 1
}

var v = makeSearchItems()

func TestFoo(t *testing.T){
	return
}
<commit_msg>Fill in go search tests to compliment the chef-pedant ones<commit_after>/*
 * Copyright (c) 2013-2014, Jeremy Bingham (<jbingham@gmail.com>)
 *
 * 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 search

import (
	"testing"
	"github.com/ctdk/goiardi/node"
	"github.com/ctdk/goiardi/role"
	"github.com/ctdk/goiardi/environment"
	"github.com/ctdk/goiardi/actor"
	"github.com/ctdk/goiardi/data_bag"
	"fmt"
)

// Most search testing can be handled fine with chef-pedant, but that's no
// reason to not have some go tests for it too.

var node1 *node.Node
var node2 *node.Node
var node3 *node.Node
var node4 *node.Node
var role1 *role.Role
var role2 *role.Role
var role3 *role.Role
var role4 *role.Role
var env1 *environment.ChefEnvironment
var env2 *environment.ChefEnvironment
var env3 *environment.ChefEnvironment
var env4 *environment.ChefEnvironment
var client1 *actor.Actor
var client2 *actor.Actor
var client3 *actor.Actor
var client4 *actor.Actor
var dbag1 *data_bag.DataBag
var dbag2 *data_bag.DataBag
var dbag3 *data_bag.DataBag
var dbag4 *data_bag.DataBag

func makeSearchItems() int{
	/* Gotta populate the search index */
	nodes := make([]*node.Node, 4)
	roles := make([]*role.Role, 4)
	envs := make([]*environment.ChefEnvironment, 4)
	clients := make([]*actor.Actor, 4)
	dbags := make([]*data_bag.DataBag, 4)

	for i := 0; i < 4; i++ {
		nodes[i], _ = node.New(fmt.Sprintf("node%d",i))
		nodes[i].Save()
		roles[i], _ = role.New(fmt.Sprintf("role%d",i))
		roles[i].Save()
		envs[i], _ = environment.New(fmt.Sprintf("env%d",i))
		envs[i].Save()
		clients[i], _ = actor.New(fmt.Sprintf("client%d",i), "client")
		clients[i].Save()
		dbags[i], _ = data_bag.New(fmt.Sprintf("data_bag%d",i))
		dbags[i].Save()
		dbi := make(map[string]interface{})
		dbi["id"] = fmt.Sprintf("dbi%d", i)
		dbi["foo"] = fmt.Sprintf("dbag_item_%d", i)
		dbags[i].NewDBItem(dbi)
	}
	node1 = nodes[0]
	node2 = nodes[1]
	node3 = nodes[2]
	node4 = nodes[3]
	role1 = roles[0]
	role2 = roles[1]
	role3 = roles[2]
	role4 = roles[3]
	env1 = envs[0]
	env2 = envs[1]
	env3 = envs[2]
	env4 = envs[3]
	client1 = clients[0]
	client2 = clients[1]
	client3 = clients[2]
	client4 = clients[3]
	dbag1 = dbags[0]
	dbag2 = dbags[1]
	dbag3 = dbags[2]
	dbag4 = dbags[3]

	/* Make this function return something so the compiler's happy building
	 * the tests. */
	return 1
}

var v = makeSearchItems()

func TestFoo(t *testing.T){
	return
}

/* Only basic search tests are here. The stronger tests are handled in
 * chef-pedant, but these tests are meant to check basic search functionality.
 */

func TestSearchNode(t *testing.T){
	n, _ := Search("node", "name:node1")
	if n[0].(*node.Node).Name != "node1" {
		t.Errorf("nothing returned from search")
	}
}

func TestSearchNodeAll(t *testing.T){
	n, _ := Search("node", "*:*")
	if len(n) != 4 {
		t.Errorf("Incorrect number of items returned, expected 4, got %d", len(n))
	}
}

func TestSearchRole(t *testing.T){
	r, _ := Search("role", "name:role1")
	if r[0].(*role.Role).Name != "role1" {
		t.Errorf("nothing returned from search")
	}
}

func TestSearchRoleAll(t *testing.T){
	n, _ := Search("role", "*:*")
	if len(n) != 4 {
		t.Errorf("Incorrect number of items returned, expected 4, got %d", len(n))
	}
}

func TestSearchEnv(t *testing.T){
	e, _ := Search("environment", "name:env1")
	if e[0].(*environment.ChefEnvironment).Name != "env1" {
		t.Errorf("nothing returned from search")
	}
}

func TestSearchEnvAll(t *testing.T){
	n, _ := Search("environment", "*:*")
	if len(n) != 4 {
		t.Errorf("Incorrect number of items returned, expected 4, got %d", len(n))
	}
}

func TestSearchClient(t *testing.T){
	c, _ := Search("client", "name:client1")
	if c[0].(*actor.Actor).Name != "client1" {
		t.Errorf("nothing returned from search")
	}
}

func TestSearchClientAll(t *testing.T){
	n, _ := Search("client", "*:*")
	if len(n) != 4 {
		t.Errorf("Incorrect number of items returned, expected 4, got %d", len(n))
	}
}

func TestSearchDbag(t *testing.T){
	d, _ := Search("data_bag1", "foo:dbag_item_1")
	if len(d) == 0 {
		t.Errorf("nothing returned from search")
	}
}

func TestSearchDbagAll(t *testing.T){
	d, _ := Search("data_bag1", "*:*")
	if len(d) != 1 {
		t.Errorf("Incorrect number of items returned, expected 1, got %d", len(d))
	}
}
<|endoftext|>