<commit_before>package ast

import (
	"io"

	"github.com/jimmyfrasche/etlite/internal/ast/internal/writer"
	"github.com/jimmyfrasche/etlite/internal/internal/errint"
	"github.com/jimmyfrasche/etlite/internal/token"
)

//go:generate stringer -type=Kind

type Kind int

const (
	Invalid Kind = iota
	Query
	Exec
	CreateTableFrom
	InsertFrom
	Savepoint
	Release
	BeginTransaction
	Commit
)

//A SQL statement or subquery
//(not including outer parentheses or final semicolon).
//
//It is up to a third party to rewrite subqueries to contain only valid sql
type SQL struct {
	Kind       Kind
	Subqueries []*Import
	Name       []token.Value //only set if CREATE TABLE ... FROM IMPORT
	Cols       []token.Value //recorded for INSERT
	Tokens     []token.Value
}

var _ Node = (*SQL)(nil)

func (*SQL) node() {}

//Pos reports the original position in input.
func (s *SQL) Pos() token.Position {
	return s.Tokens[0].Position
}

//Print stringifies to a writer.
func (s *SQL) Print(to io.Writer) error {
	if s.Kind == Invalid {
		return errint.New("Improperly constructed SQL")
	}
	w := writer.New(to)

	//To avoid handling precedence and such we do not handle unary + or - when lexing
	//so here we must not put a space between +, - and a numeric literal
	//to further simplify this we only emit spaces between two literals.
	//This is not very pretty but it ensures everything works,
	//as long as the underlying SQL is valid.

	var (
		lastWasLit  bool
		placeholder int
	)
	for i, tok := range s.Tokens {

		isLit := tok.Kind == token.Literal && !tok.Op()
		if lastWasLit && isLit {
			w.Sp()
		}
		lastWasLit = isLit

		switch tok.Kind {
		case token.Illegal: //shouldn't happen but why not check anyway?
			w.Sticky(tok.Err)
			return nil
		case token.Argument:
			//parser rewrites arguments to sql
			w.Sticky(errint.Newf("unexpected token at %d, %q", i, tok))
			return nil

		case token.Placeholder:
			if placeholder < 0 || placeholder >= len(s.Subqueries) {
				w.Sticky(errint.Newf("invalid subquery index %d", placeholder))
				return nil
			}

			w.Str("(")
			_ = s.Subqueries[placeholder].Print(w)
			w.Str(")")
			placeholder++

		default:
			w.Stringer(tok)
		}
	}

	return w.Err()
}
<commit_msg>removed out-of-date comment<commit_after>package ast

import (
	"io"

	"github.com/jimmyfrasche/etlite/internal/ast/internal/writer"
	"github.com/jimmyfrasche/etlite/internal/internal/errint"
	"github.com/jimmyfrasche/etlite/internal/token"
)

//go:generate stringer -type=Kind

type Kind int

const (
	Invalid Kind = iota
	Query
	Exec
	CreateTableFrom
	InsertFrom
	Savepoint
	Release
	BeginTransaction
	Commit
)

//A SQL statement or subquery
//(not including outer parentheses or final semicolon).
//
//It is up to a third party to rewrite subqueries to contain only valid sql
type SQL struct {
	Kind       Kind
	Subqueries []*Import
	Name       []token.Value
	Cols       []token.Value //recorded for INSERT
	Tokens     []token.Value
}

var _ Node = (*SQL)(nil)

func (*SQL) node() {}

//Pos reports the original position in input.
func (s *SQL) Pos() token.Position {
	return s.Tokens[0].Position
}

//Print stringifies to a writer.
func (s *SQL) Print(to io.Writer) error {
	if s.Kind == Invalid {
		return errint.New("Improperly constructed SQL")
	}
	w := writer.New(to)

	//To avoid handling precedence and such we do not handle unary + or - when lexing
	//so here we must not put a space between +, - and a numeric literal
	//to further simplify this we only emit spaces between two literals.
	//This is not very pretty but it ensures everything works,
	//as long as the underlying SQL is valid.

	var (
		lastWasLit  bool
		placeholder int
	)
	for i, tok := range s.Tokens {

		isLit := tok.Kind == token.Literal && !tok.Op()
		if lastWasLit && isLit {
			w.Sp()
		}
		lastWasLit = isLit

		switch tok.Kind {
		case token.Illegal: //shouldn't happen but why not check anyway?
			w.Sticky(tok.Err)
			return nil
		case token.Argument:
			//parser rewrites arguments to sql
			w.Sticky(errint.Newf("unexpected token at %d, %q", i, tok))
			return nil

		case token.Placeholder:
			if placeholder < 0 || placeholder >= len(s.Subqueries) {
				w.Sticky(errint.Newf("invalid subquery index %d", placeholder))
				return nil
			}

			w.Str("(")
			_ = s.Subqueries[placeholder].Print(w)
			w.Str(")")
			placeholder++

		default:
			w.Stringer(tok)
		}
	}

	return w.Err()
}
<|endoftext|>


<commit_before>package interpreter

import (
	"fmt"
)

// Enum.size(Array) -> Integer
// Size of the array.
func enumSize(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.size expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		return &IntegerType{Value: int64(len(object.Elements))}, nil
	case *StringType:
		return &IntegerType{Value: int64(len(object.Value))}, nil
	default:
		return nil, fmt.Errorf("Enum.size expects an Array or String")
	}
}

// Enum.reverse(Array) -> Array
// Reverse the elements of the array.
func enumReverse(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.reverse expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		result := []DataType{}
		for i := len(object.Elements) - 1; i >= 0; i-- {
			result = append(result, object.Elements[i])
		}
		return &ArrayType{Elements: result}, nil
	case *StringType:
		result := []DataType{}
		for i := len(object.Value) - 1; i >= 0; i-- {
			result = append(result, &StringType{Value: string(object.Value[i])})
		}
		return &ArrayType{Elements: result}, nil
	default:
		return nil, fmt.Errorf("Enum.reverse expects an Array or String")
	}
}

// Enum.first(Array) -> Any
// Get the first element of the array.
func enumFirst(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.first expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		if len(object.Elements) == 0 {
			return nil, fmt.Errorf("Enum.first expects a non-empty array or string")
		}
		return object.Elements[0], nil
	case *StringType:
		if len(object.Value) == 0 {
			return nil, fmt.Errorf("Enum.first expects a non-empty array or string")
		}
		return &StringType{Value: string(object.Value[0])}, nil
	default:
		return nil, fmt.Errorf("Enum.first expects an Array or String")
	}
}

// Enum.last(Array) -> Any
// Get the last element of the array.
func enumLast(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.last expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		if len(object.Elements) == 0 {
			return nil, fmt.Errorf("Enum.last expects a non-empty array or string")
		}
		return object.Elements[len(object.Elements)-1], nil
	case *StringType:
		if len(object.Value) == 0 {
			return nil, fmt.Errorf("Enum.last expects a non-empty array or string")
		}
		return &StringType{Value: string(object.Value[len(object.Value)-1])}, nil
	default:
		return nil, fmt.Errorf("Enum.last expects an Array or String")
	}
}

// Enum.insert(Arramy, element Any) -> Array
// Insert an element at the end of the array.
func enumInsert(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.insert expects exactly 2 arguments")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		elem := append(object.Elements, args[1])
		return &ArrayType{Elements: elem}, nil
	default:
		return nil, fmt.Errorf("Enum.insert expects an Array")
	}
}

// Enum.delete(Array, index Integer) -> Array
// Delete an element from the array.
func enumDelete(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.delete expects exactly 2 arguments")
	}

	if args[1].Type() != INTEGER_TYPE {
		return nil, fmt.Errorf("Enum.delete expects an Integer index")
	}

	idx := args[1].(*IntegerType).Value

	switch object := args[0].(type) {
	case *ArrayType:
		if int(idx) > len(object.Elements)-1 || idx < 0 {
			return nil, fmt.Errorf("Index supplied to Enum.delete doesn't exist in the Array")
		}

		elem := append(object.Elements[:idx], object.Elements[idx+1:]...)
		return &ArrayType{Elements: elem}, nil
	default:
		return nil, fmt.Errorf("Enum.delete expects an Array")
	}
}

// Enum.map(Array, fn Function) -> Array
// Map a function to every element of the array.
func enumMap(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.map expects exactly 2 arguments")
	}

	if args[1].Type() != FUNCTION_TYPE {
		return nil, fmt.Errorf("Enum.map expects an Array")
	}

	object := []DataType{}

	switch obj := args[0].(type) {
	case *ArrayType:
		object = obj.Elements
	case *StringType:
		for _, v := range obj.Value {
			object = append(object, &StringType{Value: string(v)})
		}
	default:
		return nil, fmt.Errorf("Enum.map expects an Array or String")
	}

	function := args[1].(*FunctionType)

	if len(function.Parameters) != 1 {
		return nil, fmt.Errorf("Enum.map expects a function with exactly 1 parameter")
	}

	runner := New()
	result := []DataType{}
	for _, v := range object {
		function.Scope.Write(function.Parameters[0].Value, v)
		result = append(result, runner.Interpret(function.Body, function.Scope))
	}

	return &ArrayType{Elements: result}, nil
}<commit_msg>Check in Enum.map if result isn't nil<commit_after>package interpreter

import (
	"fmt"
)

// Enum.size(Array) -> Integer
// Size of the array.
func enumSize(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.size expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		return &IntegerType{Value: int64(len(object.Elements))}, nil
	case *StringType:
		return &IntegerType{Value: int64(len(object.Value))}, nil
	default:
		return nil, fmt.Errorf("Enum.size expects an Array or String")
	}
}

// Enum.reverse(Array) -> Array
// Reverse the elements of the array.
func enumReverse(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.reverse expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		result := []DataType{}
		for i := len(object.Elements) - 1; i >= 0; i-- {
			result = append(result, object.Elements[i])
		}
		return &ArrayType{Elements: result}, nil
	case *StringType:
		result := []DataType{}
		for i := len(object.Value) - 1; i >= 0; i-- {
			result = append(result, &StringType{Value: string(object.Value[i])})
		}
		return &ArrayType{Elements: result}, nil
	default:
		return nil, fmt.Errorf("Enum.reverse expects an Array or String")
	}
}

// Enum.first(Array) -> Any
// Get the first element of the array.
func enumFirst(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.first expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		if len(object.Elements) == 0 {
			return nil, fmt.Errorf("Enum.first expects a non-empty array or string")
		}
		return object.Elements[0], nil
	case *StringType:
		if len(object.Value) == 0 {
			return nil, fmt.Errorf("Enum.first expects a non-empty array or string")
		}
		return &StringType{Value: string(object.Value[0])}, nil
	default:
		return nil, fmt.Errorf("Enum.first expects an Array or String")
	}
}

// Enum.last(Array) -> Any
// Get the last element of the array.
func enumLast(args ...DataType) (DataType, error) {
	if len(args) != 1 {
		return nil, fmt.Errorf("Enum.last expects exactly 1 argument")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		if len(object.Elements) == 0 {
			return nil, fmt.Errorf("Enum.last expects a non-empty array or string")
		}
		return object.Elements[len(object.Elements)-1], nil
	case *StringType:
		if len(object.Value) == 0 {
			return nil, fmt.Errorf("Enum.last expects a non-empty array or string")
		}
		return &StringType{Value: string(object.Value[len(object.Value)-1])}, nil
	default:
		return nil, fmt.Errorf("Enum.last expects an Array or String")
	}
}

// Enum.insert(Arramy, element Any) -> Array
// Insert an element at the end of the array.
func enumInsert(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.insert expects exactly 2 arguments")
	}

	switch object := args[0].(type) {
	case *ArrayType:
		elem := append(object.Elements, args[1])
		return &ArrayType{Elements: elem}, nil
	default:
		return nil, fmt.Errorf("Enum.insert expects an Array")
	}
}

// Enum.delete(Array, index Integer) -> Array
// Delete an element from the array.
func enumDelete(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.delete expects exactly 2 arguments")
	}

	if args[1].Type() != INTEGER_TYPE {
		return nil, fmt.Errorf("Enum.delete expects an Integer index")
	}

	idx := args[1].(*IntegerType).Value

	switch object := args[0].(type) {
	case *ArrayType:
		if int(idx) > len(object.Elements)-1 || idx < 0 {
			return nil, fmt.Errorf("Index supplied to Enum.delete doesn't exist in the Array")
		}

		elem := append(object.Elements[:idx], object.Elements[idx+1:]...)
		return &ArrayType{Elements: elem}, nil
	default:
		return nil, fmt.Errorf("Enum.delete expects an Array")
	}
}

// Enum.map(Array, fn Function) -> Array
// Map a function to every element of the array.
func enumMap(args ...DataType) (DataType, error) {
	if len(args) != 2 {
		return nil, fmt.Errorf("Enum.map expects exactly 2 arguments")
	}

	if args[1].Type() != FUNCTION_TYPE {
		return nil, fmt.Errorf("Enum.map expects an Array")
	}

	object := []DataType{}

	switch obj := args[0].(type) {
	case *ArrayType:
		object = obj.Elements
	case *StringType:
		for _, v := range obj.Value {
			object = append(object, &StringType{Value: string(v)})
		}
	default:
		return nil, fmt.Errorf("Enum.map expects an Array or String")
	}

	function := args[1].(*FunctionType)

	if len(function.Parameters) != 1 {
		return nil, fmt.Errorf("Enum.map expects a function with exactly 1 parameter")
	}

	runner := New()
	array := []DataType{}
	for _, v := range object {
		function.Scope.Write(function.Parameters[0].Value, v)
		result := runner.Interpret(function.Body, function.Scope)

		if result != nil {
			array = append(array, result)
		}
	}

	return &ArrayType{Elements: array}, nil
}<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	start := time.Now()
	if tidb.IsQuery(txnLine) {
		rows, err := tx.Query(txnLine)
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		// report elapsed time and rows in set
		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}

		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: rows affected and last insert id
		res, err := tx.Exec(txnLine)
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0:
			fmt.Printf("Query OK, 0 row affected")
		case 1:
			fmt.Printf("Query OK, 1 row affected")
		default:
			fmt.Printf("Query OK, %v rows affected", cnt)
		}
	}
	fmt.Printf(" (%.2f sec)\n", time.Since(start).Seconds())
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<commit_msg>move timing as close as possible to query execution instruction<commit_after>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	if tidb.IsQuery(txnLine) {
		start := time.Now()
		rows, err := tx.Query(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: last insert id
		start := time.Now()
		res, err := tx.Exec(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0:
			fmt.Printf("Query OK, 0 row affected")
		case 1:
			fmt.Printf("Query OK, 1 row affected")
		default:
			fmt.Printf("Query OK, %v rows affected", cnt)
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
	}
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<|endoftext|>


<commit_before>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"path"
	"runtime"
	"testing"
)

func TestInterpretor(t *testing.T) {
	Describe(t, "インタープリターのテスト", func() {
		data := []byte{'A', ' ', 'B', '\t', '\r', '\n'}
		Context("インスタンス生成", func() {
			It("インスタンスが生成できること", func() {
				actual := NewInterpreter(data)
				Expect(actual).To(Exist)
				Expect(actual.origin).To(Equal, data)
			})
		})
		Context("不要な文字を排除する関数", func() {
			It("不要なデータ以外排除されていること", func() {
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n'})
			})
			It("不要なデータ以外排除されていること（改行を増やす）", func() {
				data = append(data, '\n')
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n', '\n'})
			})
		})
		Context("ソースファイルをコマンドリストに変換する関数", func() {
			It("スタックに１をプッシュするコマンドが作成されること", func() {
				data = []byte{'P', 'u', 's', 'h', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommandWithParam("stack", "push", 1))
			})
			It("スタックをコピーするコマンドが作成されること", func() {
				data = []byte{'C', 'o', 'p', 'y', ' ', '\n', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "copy"))
			})
			It("スタックを入れ替えるコマンドが作成されること", func() {
				data = []byte{'S', 'w', 'a', 'p', ' ', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "swap"))
			})
			It("スタックを削除するコマンドが作成されること", func() {
				data = []byte{'R', 'e', 'm', 'o', 'v', 'e', ' ', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "remove"))
			})
			It("定義されていない命令が指定されたときにundefinedの命令が作成されること", func() {
				data = []byte{'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ラベルを定義するコマンドが作成されること", func() {
				data = []byte{'L', 'a', 'b', 'l', '\n', ' ', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("label", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'C', 'a', 'l', 'l', '\n', ' ', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("call", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'G', 'o', 't', 'o', '\n', ' ', '\n', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("goto", "1001"))
			})
			It("スタックの値が０のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'=', '=', '0', 'G', 'o', 't', 'o', '\n', '\t', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack==0 then goto", "1001"))
			})
			It("スタックの値が０未満のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'<', '0', 'G', 'o', 't', 'o', '\n', '\t', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack<0 then goto", "1001"))
			})
			It("呼び出し元に戻るコマンドが作成されること", func() {
				data = []byte{'R', 'e', 't', 'u', 'r', 'n', '\n', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("return"))
			})
			It("プログラムを終了するコマンドが作成されること", func() {
				data = []byte{'E', 'x', 'i', 't', '\n', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("exit"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\n', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("足し算する命令が作成されること", func() {
				data = []byte{'a', 'd', 'd', '\t', ' ', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("add"))
			})
			It("引き算する命令が作成されること", func() {
				data = []byte{'s', 'u', 'b', '\t', ' ', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("sub"))
			})
			It("掛け算する命令が作成されること", func() {
				data = []byte{'m', 'u', 'l', '\t', ' ', ' ', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mul"))
			})
			It("割り算する命令が作成されること", func() {
				data = []byte{'d', 'i', 'v', '\t', ' ', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("div"))
			})
			It("余りを求める命令が作成されること", func() {
				data = []byte{'m', 'o', 'd', '\t', ' ', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mod"))
			})
		})
	})
}

func current_dir() string {
	_, fpath, _, _ := runtime.Caller(0)
	return path.Dir(fpath)
}
<commit_msg>解析できないパターンがきたときにエラーが発生することを確認<commit_after>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"path"
	"runtime"
	"testing"
)

func TestInterpretor(t *testing.T) {
	Describe(t, "インタープリターのテスト", func() {
		data := []byte{'A', ' ', 'B', '\t', '\r', '\n'}
		Context("インスタンス生成", func() {
			It("インスタンスが生成できること", func() {
				actual := NewInterpreter(data)
				Expect(actual).To(Exist)
				Expect(actual.origin).To(Equal, data)
			})
		})
		Context("不要な文字を排除する関数", func() {
			It("不要なデータ以外排除されていること", func() {
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n'})
			})
			It("不要なデータ以外排除されていること（改行を増やす）", func() {
				data = append(data, '\n')
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n', '\n'})
			})
		})
		Context("ソースファイルをコマンドリストに変換する関数", func() {
			It("スタックに１をプッシュするコマンドが作成されること", func() {
				data = []byte{'P', 'u', 's', 'h', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommandWithParam("stack", "push", 1))
			})
			It("スタックをコピーするコマンドが作成されること", func() {
				data = []byte{'C', 'o', 'p', 'y', ' ', '\n', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "copy"))
			})
			It("スタックを入れ替えるコマンドが作成されること", func() {
				data = []byte{'S', 'w', 'a', 'p', ' ', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "swap"))
			})
			It("スタックを削除するコマンドが作成されること", func() {
				data = []byte{'R', 'e', 'm', 'o', 'v', 'e', ' ', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "remove"))
			})
			It("定義されていない命令が指定されたときにundefinedの命令が作成されること", func() {
				data = []byte{'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ラベルを定義するコマンドが作成されること", func() {
				data = []byte{'L', 'a', 'b', 'l', '\n', ' ', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("label", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'C', 'a', 'l', 'l', '\n', ' ', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("call", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'G', 'o', 't', 'o', '\n', ' ', '\n', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("goto", "1001"))
			})
			It("スタックの値が０のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'=', '=', '0', 'G', 'o', 't', 'o', '\n', '\t', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack==0 then goto", "1001"))
			})
			It("スタックの値が０未満のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'<', '0', 'G', 'o', 't', 'o', '\n', '\t', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack<0 then goto", "1001"))
			})
			It("呼び出し元に戻るコマンドが作成されること", func() {
				data = []byte{'R', 'e', 't', 'u', 'r', 'n', '\n', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("return"))
			})
			It("プログラムを終了するコマンドが作成されること", func() {
				data = []byte{'E', 'x', 'i', 't', '\n', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("exit"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\n', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("足し算する命令が作成されること", func() {
				data = []byte{'a', 'd', 'd', '\t', ' ', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("add"))
			})
			It("引き算する命令が作成されること", func() {
				data = []byte{'s', 'u', 'b', '\t', ' ', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("sub"))
			})
			It("掛け算する命令が作成されること", func() {
				data = []byte{'m', 'u', 'l', '\t', ' ', ' ', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mul"))
			})
			It("割り算する命令が作成されること", func() {
				data = []byte{'d', 'i', 'v', '\t', ' ', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("div"))
			})
			It("余りを求める命令が作成されること", func() {
				data = []byte{'m', 'o', 'd', '\t', ' ', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mod"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
		})
	})
}

func current_dir() string {
	_, fpath, _, _ := runtime.Caller(0)
	return path.Dir(fpath)
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"compress/flate"
	crand "crypto/rand"
	"fmt"
	"io"
	"math/rand"
	"net/url"
	"time"
)

const _letters string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func init() {
	rand.Seed(time.Now().UnixNano())
}

// NewUUID generates and returns url friendly uuid
// Source: http://play.golang.org/p/4FkNSiUDMg
// @returns string
// @returns error
func NewUUID() (string, error) {
	uuid := make([]byte, 16)
	n, err := io.ReadFull(crand.Reader, uuid)
	if n != len(uuid) || err != nil {
		return "", err
	}
	// variant bits; see section 4.1.1
	uuid[8] = uuid[8]&^0xc0 | 0x80
	// version 4 (pseudo-random); see section 4.1.3
	uuid[6] = uuid[6]&^0xf0 | 0x40
	// return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]), nil
	return fmt.Sprintf("%x%x%x%x%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}

// NewUUID2 generates and returns a uuid
// @returns string
// @returns error
func NewUUID2() (string, error) {
	b := make([]byte, 16)
	n, err := io.ReadFull(crand.Reader, b)
	if n != len(b) || err != nil {
		return "", err
	}
	// variant bits; see section 4.1.1
	b[8] = b[8]&^0xc0 | 0x80
	// version 4 (pseudo-random); see section 4.1.3
	b[6] = b[6]&^0xf0 | 0x40
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]), nil
}

// NewAPIKey generates and returns an apikey of desired length
// @param int length of apikey
// @returns string
func NewAPIKey(n int) string {
	s := ""
	for i := 1; i <= n; i++ {
		s += string(_letters[rand.Intn(len(_letters))])
	}
	return s
}

// stringInSlice loops through a []string and returns a bool if string is found
// @param a {string} string to find
// @param list {[]string} array of strings to search
// @returns bool
func StringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

// sliceIndex loops through a []string and returns the index of a string
// Description:
//		Loops through array of strings
//		Checks each string in array for match
//		If string match occurs returns index
// @param value {string} string to find
// @param slice {[]string} array of strings to search
// @returns int
func SliceIndex(value string, slice []string) int {
	for p, v := range slice {
		if v == value {
			return p
		}
	}
	return -1
}

// Compression
// Source: https://github.com/schollz/gofind/blob/master/utils.go#L146-L169
//         https://github.com/schollz/gofind/blob/master/fingerprint.go#L43-L54
// Description:
//		Compress and Decompress bytes
func CompressByte(src []byte) []byte {
	compressedData := new(bytes.Buffer)
	Compress(src, compressedData, 9)
	return compressedData.Bytes()
}

func DecompressByte(src []byte) []byte {
	compressedData := bytes.NewBuffer(src)
	deCompressedData := new(bytes.Buffer)
	Decompress(compressedData, deCompressedData)
	return deCompressedData.Bytes()
}

func Compress(src []byte, dest io.Writer, level int) {
	compressor, _ := flate.NewWriter(dest, level)
	compressor.Write(src)
	compressor.Close()
}

func Decompress(src io.Reader, dest io.Writer) {
	decompressor := flate.NewReader(src)
	io.Copy(dest, decompressor)
	decompressor.Close()
}

// isUrl
// https://www.socketloop.com/tutorials/golang-how-to-validate-url-the-right-way
func IsUrl(str string) bool {
	fmt.Println(str)
	var validURL bool
	_, err := url.Parse(str)
	if err != nil {
		fmt.Println(err)
		validURL = false
	} else {
		validURL = true
	}
	return validURL
}
<commit_msg>fixed utils<commit_after><|endoftext|>


<commit_before>package utils

import (
	"errors"
	"fmt"
	"math"
	"sort"
	"strconv"
	"strings"

	"github.com/vmware/govmomi/vim25/types"
)

// Type generic type
type Type int

// Min : get the minimum of values
func Min(n ...int64) int64 {
	var min int64 = -1
	for _, i := range n {
		if i >= 0 {
			if min == -1 {
				min = i
			} else {
				if i < min {
					min = i
				}
			}
		}
	}
	return min
}

// Max : get the maximum of the values
func Max(n ...int64) int64 {
	var max int64 = -1
	for _, i := range n {
		if i >= 0 {
			if max == -1 {
				max = i
			} else {
				if i > max {
					max = i
				}
			}
		}
	}
	return max
}

// Sum : Sum the values
func Sum(n ...int64) int64 {
	var total int64
	for _, i := range n {
		if i > 0 {
			total += i
		}
	}
	return total
}

// Average : average the values
func Average(n ...int64) int64 {
	var total int64
	var count int64
	for _, i := range n {
		if i >= 0 {
			count++
			total += i
		}
	}
	favg := float64(total) / float64(count)
	return int64(math.Floor(favg + .5))
}

// MapObjRefs fills in object references into a map to another object reference
func MapObjRefs(property string, sourceVal *types.AnyType, dest map[string]*[]types.ManagedObjectReference, index string) error {
	mors, ok := (*sourceVal).(types.ArrayOfManagedObjectReference)
	if ok {
		if len(mors.ManagedObjectReference) > 0 {
			dest[index] = &mors.ManagedObjectReference
			return nil
		}
		return errors.New("Property " + property + " of " + index + " didn't contain any object references")
	}
	return errors.New("Property " + property + " of " + index + " was not a ManagedObjectReferences, it was " + fmt.Sprintf("%T", sourceVal))
}

// MapObjRef fills in object reference into a map to another object reference
func MapObjRef(property string, sourceVal *types.AnyType, dest map[string]*string, index string) error {
	mor, ok := (*sourceVal).(types.ManagedObjectReference)
	if ok {
		dest[index] = &mor.Value
		return nil
	}
	return errors.New("Property " + property + " of " + index + " was not a ManagedObjectReference, it was " + fmt.Sprintf("%T", sourceVal))
}

// MapObjInt32 fills in an int32 into a map to another object reference
func MapObjInt32(property string, sourceVal *types.AnyType, dest map[string]*int32, index string) error {
	val, ok := (*sourceVal).(int32)
	if ok {
		dest[index] = &val
		return nil
	}
	return errors.New("Property " + property + " of " + index + " was not an int32, it was " + fmt.Sprintf("%T", sourceVal))
}

// StringMaptoString converts a string map to csv or get the first value
func StringMaptoString(value []string, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return value[0]
	}
	return strings.Join(value, separator)
}

// IntMaptoString converts a int map to csv or get the first value
func IntMaptoString(value []int, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.Itoa(value[0])
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.Itoa(i))
	}
	return strings.Join(strval, separator)
}

// Int32MaptoString converts a int32 map to csv or get the first value
func Int32MaptoString(value []int32, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.FormatInt(int64(value[0]), 10)
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.FormatInt(int64(i), 10))
	}
	return strings.Join(strval, separator)
}

// Int64MaptoString converts a int64 map to csv or get the first value
func Int64MaptoString(value []int64, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.FormatInt(value[0], 10)
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.FormatInt(i, 10))
	}
	return strings.Join(strval, separator)
}

// ValToString : try to convert interface to string. Separated by separator if slice
func ValToString(value interface{}, separator string, noarray bool) string {
	switch v := value.(type) {
	case string:
		return v
	case []string:
		return StringMaptoString(v, separator, noarray)
	case int:
		return strconv.Itoa(v)
	case []int:
		return IntMaptoString(v, separator, noarray)
	case int32:
		return strconv.FormatInt(int64(v), 10)
	case []int32:
		return Int32MaptoString(v, separator, noarray)
	case int64:
		return strconv.FormatInt(v, 10)
	case []int64:
		return Int64MaptoString(v, separator, noarray)
	default:
		return ""
	}
}

// Join map[int]string into a string
func Join(values map[int]string, separator string) string {
	var keys []int
	for k := range values {
		keys = append(keys, k)
	}
	sort.Ints(keys)
	// create a map with the key parts in order
	var tmp []string
	for _, k := range keys {
		tmp = append(tmp, values[k])
	}
	return strings.Join(tmp, separator)
}

// MustAtoi converts a string to integer and return 0 i case of error
func MustAtoi(value string) int {
	i, err := strconv.Atoi(value)
	if err != nil {
		i = 0
	}
	return i
}

// FindHostAndCluster Find cluster for managed entity
func FindHostAndCluster(entity *string,
	vmToHost map[string]*string,
	morToParent map[string]*string,
	morToName map[string]*string) (*string, *string, error) {
	// get host
	var host *string
	var hostname *string
	var cluster *string
	if strings.HasPrefix(*entity, "vm-") {
		if vmhost, ok := vmToHost[*entity]; ok {
			host = vmhost
			if vmhostname, ok := morToName[*host]; ok {
				hostname = vmhostname
			}
		}
	} else if strings.HasPrefix(*entity, "host-") {
		host = entity
	}
	// check if a host was found
	if host == nil {
		return nil, nil, errors.New("No host found for " + *entity)
	}
	if parmor, ok := morToParent[*host]; ok {
		if strings.HasPrefix(*parmor, "cluster-") {
			cluster = morToName[*parmor]
		} else if !strings.HasPrefix(*parmor, "domain-") {
			// ComputeRessource parent denotes a standalong host
			// Any other is weird
			return hostname, nil, errors.New("No suitable parent for host " + *host + " to determine cluster")
		}
	}
	return hostname, cluster, nil
}

// ConvertToKV converts a map[string]string to a csv with k=v pairs
func ConvertToKV(values map[string]string) string {
	var tmp []string
	for key, val := range values {
		if len(val) == 0 {
			continue
		}
		tmp = append(tmp, fmt.Sprintf("%s=%s", key, val))
	}
	return strings.Join(tmp, ",")
}

// Reverse reverses the values of an array
func Reverse(array []string) {
	for i := len(array)/2 - 1; i >= 0; i-- {
		opp := len(array) - 1 - i
		array[i], array[opp] = array[opp], array[i]
	}
}

// CleanStringMap removes unkonw keys from a map of string
func CleanStringMap(m map[string]*string, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				break
			}
			found = false
		}
		if !found {
			delete(m, mor)
		}
	}
}

// CleanMorefsMap removes unkonw keys from a map of manged object references
func CleanMorefsMap(m map[string]*[]types.ManagedObjectReference, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				break
			}
			found = false
		}
		if !found {
			delete(m, mor)
		}
	}
}

// CleanInt32Map removes unkonw keys from a map of int32
func CleanInt32Map(m map[string]*int32, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				break
			}
			found = false
		}
		if !found {
			delete(m, mor)
		}
	}
}

// CleanTagsMap removes unkonw keys from a map of tag
func CleanTagsMap(m map[string]*[]types.Tag, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				break
			}
			found = false
		}
		if !found {
			delete(m, mor)
		}
	}
}

// CleanDiskInfosMap removes unkonw keys from a map of tag
func CleanDiskInfosMap(m map[string]*[]types.GuestDiskInfo, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				break
			}
			found = false
		}
		if !found {
			delete(m, mor)
		}
	}
}
<commit_msg>correct cleanup<commit_after>package utils

import (
	"errors"
	"fmt"
	"log"
	"math"
	"sort"
	"strconv"
	"strings"

	"github.com/vmware/govmomi/vim25/types"
)

var stdlog, errlog *log.Logger

// Min : get the minimum of values
func Min(n ...int64) int64 {
	var min int64 = -1
	for _, i := range n {
		if i >= 0 {
			if min == -1 {
				min = i
			} else {
				if i < min {
					min = i
				}
			}
		}
	}
	return min
}

// Max : get the maximum of the values
func Max(n ...int64) int64 {
	var max int64 = -1
	for _, i := range n {
		if i >= 0 {
			if max == -1 {
				max = i
			} else {
				if i > max {
					max = i
				}
			}
		}
	}
	return max
}

// Sum : Sum the values
func Sum(n ...int64) int64 {
	var total int64
	for _, i := range n {
		if i > 0 {
			total += i
		}
	}
	return total
}

// Average : average the values
func Average(n ...int64) int64 {
	var total int64
	var count int64
	for _, i := range n {
		if i >= 0 {
			count++
			total += i
		}
	}
	favg := float64(total) / float64(count)
	return int64(math.Floor(favg + .5))
}

// MapObjRefs fills in object references into a map to another object reference
func MapObjRefs(property string, sourceVal *types.AnyType, dest map[string]*[]types.ManagedObjectReference, index string) error {
	mors, ok := (*sourceVal).(types.ArrayOfManagedObjectReference)
	if ok {
		if len(mors.ManagedObjectReference) > 0 {
			dest[index] = &mors.ManagedObjectReference
			return nil
		}
		return errors.New("Property " + property + " of " + index + " didn't contain any object references")
	}
	return errors.New("Property " + property + " of " + index + " was not a ManagedObjectReferences, it was " + fmt.Sprintf("%T", sourceVal))
}

// MapObjRef fills in object reference into a map to another object reference
func MapObjRef(property string, sourceVal *types.AnyType, dest map[string]*string, index string) error {
	mor, ok := (*sourceVal).(types.ManagedObjectReference)
	if ok {
		dest[index] = &mor.Value
		return nil
	}
	return errors.New("Property " + property + " of " + index + " was not a ManagedObjectReference, it was " + fmt.Sprintf("%T", sourceVal))
}

// MapObjInt32 fills in an int32 into a map to another object reference
func MapObjInt32(property string, sourceVal *types.AnyType, dest map[string]*int32, index string) error {
	val, ok := (*sourceVal).(int32)
	if ok {
		dest[index] = &val
		return nil
	}
	return errors.New("Property " + property + " of " + index + " was not an int32, it was " + fmt.Sprintf("%T", sourceVal))
}

// StringMaptoString converts a string map to csv or get the first value
func StringMaptoString(value []string, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return value[0]
	}
	return strings.Join(value, separator)
}

// IntMaptoString converts a int map to csv or get the first value
func IntMaptoString(value []int, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.Itoa(value[0])
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.Itoa(i))
	}
	return strings.Join(strval, separator)
}

// Int32MaptoString converts a int32 map to csv or get the first value
func Int32MaptoString(value []int32, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.FormatInt(int64(value[0]), 10)
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.FormatInt(int64(i), 10))
	}
	return strings.Join(strval, separator)
}

// Int64MaptoString converts a int64 map to csv or get the first value
func Int64MaptoString(value []int64, separator string, noarray bool) string {
	if len(value) == 0 {
		return ""
	}
	if noarray {
		return strconv.FormatInt(value[0], 10)
	}
	var strval []string
	for _, i := range value {
		strval = append(strval, strconv.FormatInt(i, 10))
	}
	return strings.Join(strval, separator)
}

// ValToString : try to convert interface to string. Separated by separator if slice
func ValToString(value interface{}, separator string, noarray bool) string {
	switch v := value.(type) {
	case string:
		return v
	case []string:
		return StringMaptoString(v, separator, noarray)
	case int:
		return strconv.Itoa(v)
	case []int:
		return IntMaptoString(v, separator, noarray)
	case int32:
		return strconv.FormatInt(int64(v), 10)
	case []int32:
		return Int32MaptoString(v, separator, noarray)
	case int64:
		return strconv.FormatInt(v, 10)
	case []int64:
		return Int64MaptoString(v, separator, noarray)
	default:
		return ""
	}
}

// Join map[int]string into a string
func Join(values map[int]string, separator string) string {
	var keys []int
	for k := range values {
		keys = append(keys, k)
	}
	sort.Ints(keys)
	// create a map with the key parts in order
	var tmp []string
	for _, k := range keys {
		tmp = append(tmp, values[k])
	}
	return strings.Join(tmp, separator)
}

// MustAtoi converts a string to integer and return 0 i case of error
func MustAtoi(value string) int {
	i, err := strconv.Atoi(value)
	if err != nil {
		i = 0
	}
	return i
}

// FindHostAndCluster Find cluster for managed entity
func FindHostAndCluster(entity *string,
	vmToHost map[string]*string,
	morToParent map[string]*string,
	morToName map[string]*string) (*string, *string, error) {
	// get host
	var host *string
	var hostname *string
	var cluster *string
	if strings.HasPrefix(*entity, "vm-") {
		if vmhost, ok := vmToHost[*entity]; ok {
			host = vmhost
			if vmhostname, ok := morToName[*host]; ok {
				hostname = vmhostname
			}
		}
	} else if strings.HasPrefix(*entity, "host-") {
		host = entity
	}
	// check if a host was found
	if host == nil {
		return nil, nil, errors.New("No host found for " + *entity)
	}
	if parmor, ok := morToParent[*host]; ok {
		if strings.HasPrefix(*parmor, "cluster-") {
			cluster = morToName[*parmor]
		} else if !strings.HasPrefix(*parmor, "domain-") {
			// ComputeRessource parent denotes a standalong host
			// Any other is weird
			return hostname, nil, errors.New("No suitable parent for host " + *host + " to determine cluster")
		}
	}
	return hostname, cluster, nil
}

// ConvertToKV converts a map[string]string to a csv with k=v pairs
func ConvertToKV(values map[string]string) string {
	var tmp []string
	for key, val := range values {
		if len(val) == 0 {
			continue
		}
		tmp = append(tmp, fmt.Sprintf("%s=%s", key, val))
	}
	return strings.Join(tmp, ",")
}

// Reverse reverses the values of an array
func Reverse(array []string) {
	for i := len(array)/2 - 1; i >= 0; i-- {
		opp := len(array) - 1 - i
		array[i], array[opp] = array[opp], array[i]
	}
}

// CleanStringMap removes unkonw keys from a map of string
func CleanStringMap(m map[string]*string, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				found = true
				break
			}
		}
		if !found {
			stdlog.Println("removing mor from string map: " + mor)
			delete(m, mor)
		}
	}
}

// CleanMorefsMap removes unkonw keys from a map of manged object references
func CleanMorefsMap(m map[string]*[]types.ManagedObjectReference, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				found = true
				break
			}
		}
		if !found {
			stdlog.Println("removing mor from moref map: " + mor)
			delete(m, mor)
		}
	}
}

// CleanInt32Map removes unkonw keys from a map of int32
func CleanInt32Map(m map[string]*int32, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				found = true
				break
			}
		}
		if !found {
			stdlog.Println("removing mor from int map: " + mor)
			delete(m, mor)
		}
	}
}

// CleanTagsMap removes unkonw keys from a map of tag
func CleanTagsMap(m map[string]*[]types.Tag, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				found = true
				break
			}
		}
		if !found {
			stdlog.Println("removing mor from tags map: " + mor)
			delete(m, mor)
		}
	}
}

// CleanDiskInfosMap removes unkonw keys from a map of tag
func CleanDiskInfosMap(m map[string]*[]types.GuestDiskInfo, refs []string) {
	for mor := range m {
		found := false
		for _, refmor := range refs {
			if refmor == mor {
				found = true
				break
			}
		}
		if !found {
			stdlog.Println("removing mor from disk info map: " + mor)
			delete(m, mor)
		}
	}
}
<|endoftext|>


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

package utils

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"text/template"

	beeLogger "github.com/beego/bee/logger"
	"github.com/beego/bee/logger/colors"
)

// Go is a basic promise implementation: it wraps calls a function in a goroutine
// and returns a channel which will later return the function's return value.
func Go(f func() error) chan error {
	ch := make(chan error)
	go func() {
		ch <- f()
	}()
	return ch
}

// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// GetGOPATHs returns all paths in GOPATH variable.
func GetGOPATHs() []string {
	gopath := os.Getenv("GOPATH")
	var paths []string
	if runtime.GOOS == "windows" {
		gopath = strings.Replace(gopath, "\\", "/", -1)
		paths = strings.Split(gopath, ";")
	} else {
		paths = strings.Split(gopath, ":")
	}
	return paths
}

// IsBeegoProject checks whether the current path is a Beego application or not
func IsBeegoProject(thePath string) bool {
	mainFiles := []string{}
	hasBeegoRegex := regexp.MustCompile(`(?s)package main.*?import.*?\(.*?github.com/astaxie/beego".*?\).*func main()`)
	c := make(chan error)
	// Walk the application path tree to look for main files.
	// Main files must satisfy the 'hasBeegoRegex' regular expression.
	go func() {
		filepath.Walk(thePath, func(fpath string, f os.FileInfo, err error) error {
			if err != nil {
				return nil
			}
			// Skip sub-directories
			if !f.IsDir() {
				var data []byte
				data, err = ioutil.ReadFile(fpath)
				if err != nil {
					c <- err
					return nil
				}

				if len(hasBeegoRegex.Find(data)) > 0 {
					mainFiles = append(mainFiles, fpath)
				}
			}
			return nil
		})
		close(c)
	}()

	if err := <-c; err != nil {
		beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
	}

	if len(mainFiles) > 0 {
		return true
	}
	return false
}

// SearchGOPATHs searchs the user GOPATH(s) for the specified application name.
// It returns a boolean, the application's GOPATH and its full path.
func SearchGOPATHs(app string) (bool, string, string) {
	gps := GetGOPATHs()
	if len(gps) == 0 {
		beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
	}

	// Lookup the application inside the user workspace(s)
	for _, gopath := range gps {
		var currentPath string

		if !strings.Contains(app, "src") {
			gopathsrc := path.Join(gopath, "src")
			currentPath = path.Join(gopathsrc, app)
		} else {
			currentPath = app
		}

		if IsExist(currentPath) {
			return true, gopath, currentPath
		}
	}
	return false, "", ""
}

// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
// confirmations. If the input is not recognized, it will ask again. The function does not return
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
func AskForConfirmation() bool {
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		beeLogger.Log.Fatalf("%s", err)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response) {
		return true
	} else if containsString(nokayResponses, response) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return AskForConfirmation()
	}
}

func containsString(slice []string, element string) bool {
	for _, elem := range slice {
		if elem == element {
			return true
		}
	}
	return false
}

// snake string, XxYy to xx_yy
func SnakeString(s string) string {
	data := make([]byte, 0, len(s)*2)
	j := false
	num := len(s)
	for i := 0; i < num; i++ {
		d := s[i]
		if i > 0 && d >= 'A' && d <= 'Z' && j {
			data = append(data, '_')
		}
		if d != '_' {
			j = true
		}
		data = append(data, d)
	}
	return strings.ToLower(string(data[:]))
}

func CamelString(s string) string {
	data := make([]byte, 0, len(s))
	j := false
	k := false
	num := len(s) - 1
	for i := 0; i <= num; i++ {
		d := s[i]
		if !k && d >= 'A' && d <= 'Z' {
			k = true
		}
		if d >= 'a' && d <= 'z' && (j || !k) {
			d = d - 32
			j = false
			k = true
		}
		if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
			j = true
			continue
		}
		data = append(data, d)
	}
	return string(data[:])
}

// camelCase converts a _ delimited string to camel case
// e.g. very_important_person => VeryImportantPerson
func CamelCase(in string) string {
	tokens := strings.Split(in, "_")
	for i := range tokens {
		tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
	}
	return strings.Join(tokens, "")
}

// formatSourceCode formats source files
func FormatSourceCode(filename string) {
	cmd := exec.Command("gofmt", "-w", filename)
	if err := cmd.Run(); err != nil {
		beeLogger.Log.Warnf("Error while running gofmt: %s", err)
	}
}

// CloseFile attempts to close the passed file
// or panics with the actual error
func CloseFile(f *os.File) {
	err := f.Close()
	MustCheck(err)
}

// MustCheck panics when the error is not nil
func MustCheck(err error) {
	if err != nil {
		panic(err)
	}
}

// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
	f, err := os.Create(filename)
	MustCheck(err)
	defer CloseFile(f)
	_, err = f.WriteString(content)
	MustCheck(err)
}

// __FILE__ returns the file name in which the function was invoked
func FILE() string {
	_, file, _, _ := runtime.Caller(1)
	return file
}

// __LINE__ returns the line number at which the function was invoked
func LINE() int {
	_, _, line, _ := runtime.Caller(1)
	return line
}

// BeeFuncMap returns a FuncMap of functions used in different templates.
func BeeFuncMap() template.FuncMap {
	return template.FuncMap{
		"trim":       strings.TrimSpace,
		"bold":       colors.Bold,
		"headline":   colors.MagentaBold,
		"foldername": colors.RedBold,
		"endline":    EndLine,
		"tmpltostr":  TmplToString,
	}
}

// TmplToString parses a text template and return the result as a string.
func TmplToString(tmpl string, data interface{}) string {
	t := template.New("tmpl").Funcs(BeeFuncMap())
	template.Must(t.Parse(tmpl))

	var doc bytes.Buffer
	err := t.Execute(&doc, data)
	MustCheck(err)

	return doc.String()
}

// EndLine returns the a newline escape character
func EndLine() string {
	return "\n"
}

func Tmpl(text string, data interface{}) {
	output := colors.NewColorWriter(os.Stderr)

	t := template.New("Usage").Funcs(BeeFuncMap())
	template.Must(t.Parse(text))

	err := t.Execute(output, data)
	if err != nil {
		beeLogger.Log.Error(err.Error())
	}
}

func CheckEnv(appname string) (apppath, packpath string, err error) {
	gps := GetGOPATHs()
	if len(gps) == 0 {
		beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
	}
	currpath, _ := os.Getwd()
	currpath = path.Join(currpath, appname)
	for _, gpath := range gps {
		gsrcpath := path.Join(gpath, "src")
		if strings.HasPrefix(currpath, gsrcpath) {
			packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(filepath.Separator), "/", -1)
			return currpath, packpath, nil
		}
	}

	// In case of multiple paths in the GOPATH, by default
	// we use the first path
	gopath := gps[0]

	beeLogger.Log.Warn("You current workdir is not inside $GOPATH/src.")
	beeLogger.Log.Debugf("GOPATH: %s", FILE(), LINE(), gopath)

	gosrcpath := path.Join(gopath, "src")
	apppath = path.Join(gosrcpath, appname)

	if _, e := os.Stat(apppath); !os.IsNotExist(e) {
		err = fmt.Errorf("Cannot create application without removing '%s' first", apppath)
		beeLogger.Log.Errorf("Path '%s' already exists", apppath)
		return
	}
	packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(filepath.Separator)), "/")
	return
}

func PrintErrorAndExit(message, errorTemplate string) {
	Tmpl(fmt.Sprintf(errorTemplate, message), nil)
	os.Exit(2)
}
<commit_msg>Ability to execute commands using Go tool<commit_after>// Copyright 2013 bee authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package utils

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"text/template"
	"unicode"

	beeLogger "github.com/beego/bee/logger"
	"github.com/beego/bee/logger/colors"
)

// Go is a basic promise implementation: it wraps calls a function in a goroutine
// and returns a channel which will later return the function's return value.
func Go(f func() error) chan error {
	ch := make(chan error)
	go func() {
		ch <- f()
	}()
	return ch
}

// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
	_, err := os.Stat(path)
	return err == nil || os.IsExist(err)
}

// GetGOPATHs returns all paths in GOPATH variable.
func GetGOPATHs() []string {
	gopath := os.Getenv("GOPATH")
	var paths []string
	if runtime.GOOS == "windows" {
		gopath = strings.Replace(gopath, "\\", "/", -1)
		paths = strings.Split(gopath, ";")
	} else {
		paths = strings.Split(gopath, ":")
	}
	return paths
}

// IsBeegoProject checks whether the current path is a Beego application or not
func IsBeegoProject(thePath string) bool {
	mainFiles := []string{}
	hasBeegoRegex := regexp.MustCompile(`(?s)package main.*?import.*?\(.*?github.com/astaxie/beego".*?\).*func main()`)
	c := make(chan error)
	// Walk the application path tree to look for main files.
	// Main files must satisfy the 'hasBeegoRegex' regular expression.
	go func() {
		filepath.Walk(thePath, func(fpath string, f os.FileInfo, err error) error {
			if err != nil {
				return nil
			}
			// Skip sub-directories
			if !f.IsDir() {
				var data []byte
				data, err = ioutil.ReadFile(fpath)
				if err != nil {
					c <- err
					return nil
				}

				if len(hasBeegoRegex.Find(data)) > 0 {
					mainFiles = append(mainFiles, fpath)
				}
			}
			return nil
		})
		close(c)
	}()

	if err := <-c; err != nil {
		beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
	}

	if len(mainFiles) > 0 {
		return true
	}
	return false
}

// SearchGOPATHs searchs the user GOPATH(s) for the specified application name.
// It returns a boolean, the application's GOPATH and its full path.
func SearchGOPATHs(app string) (bool, string, string) {
	gps := GetGOPATHs()
	if len(gps) == 0 {
		beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
	}

	// Lookup the application inside the user workspace(s)
	for _, gopath := range gps {
		var currentPath string

		if !strings.Contains(app, "src") {
			gopathsrc := path.Join(gopath, "src")
			currentPath = path.Join(gopathsrc, app)
		} else {
			currentPath = app
		}

		if IsExist(currentPath) {
			return true, gopath, currentPath
		}
	}
	return false, "", ""
}

// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
// confirmations. If the input is not recognized, it will ask again. The function does not return
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
func AskForConfirmation() bool {
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		beeLogger.Log.Fatalf("%s", err)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response) {
		return true
	} else if containsString(nokayResponses, response) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return AskForConfirmation()
	}
}

func containsString(slice []string, element string) bool {
	for _, elem := range slice {
		if elem == element {
			return true
		}
	}
	return false
}

// snake string, XxYy to xx_yy
func SnakeString(s string) string {
	data := make([]byte, 0, len(s)*2)
	j := false
	num := len(s)
	for i := 0; i < num; i++ {
		d := s[i]
		if i > 0 && d >= 'A' && d <= 'Z' && j {
			data = append(data, '_')
		}
		if d != '_' {
			j = true
		}
		data = append(data, d)
	}
	return strings.ToLower(string(data[:]))
}

func CamelString(s string) string {
	data := make([]byte, 0, len(s))
	j := false
	k := false
	num := len(s) - 1
	for i := 0; i <= num; i++ {
		d := s[i]
		if !k && d >= 'A' && d <= 'Z' {
			k = true
		}
		if d >= 'a' && d <= 'z' && (j || !k) {
			d = d - 32
			j = false
			k = true
		}
		if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
			j = true
			continue
		}
		data = append(data, d)
	}
	return string(data[:])
}

// camelCase converts a _ delimited string to camel case
// e.g. very_important_person => VeryImportantPerson
func CamelCase(in string) string {
	tokens := strings.Split(in, "_")
	for i := range tokens {
		tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
	}
	return strings.Join(tokens, "")
}

// formatSourceCode formats source files
func FormatSourceCode(filename string) {
	cmd := exec.Command("gofmt", "-w", filename)
	if err := cmd.Run(); err != nil {
		beeLogger.Log.Warnf("Error while running gofmt: %s", err)
	}
}

// CloseFile attempts to close the passed file
// or panics with the actual error
func CloseFile(f *os.File) {
	err := f.Close()
	MustCheck(err)
}

// MustCheck panics when the error is not nil
func MustCheck(err error) {
	if err != nil {
		panic(err)
	}
}

// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
	f, err := os.Create(filename)
	MustCheck(err)
	defer CloseFile(f)
	_, err = f.WriteString(content)
	MustCheck(err)
}

// __FILE__ returns the file name in which the function was invoked
func FILE() string {
	_, file, _, _ := runtime.Caller(1)
	return file
}

// __LINE__ returns the line number at which the function was invoked
func LINE() int {
	_, _, line, _ := runtime.Caller(1)
	return line
}

// BeeFuncMap returns a FuncMap of functions used in different templates.
func BeeFuncMap() template.FuncMap {
	return template.FuncMap{
		"trim":       strings.TrimSpace,
		"bold":       colors.Bold,
		"headline":   colors.MagentaBold,
		"foldername": colors.RedBold,
		"endline":    EndLine,
		"tmpltostr":  TmplToString,
	}
}

// TmplToString parses a text template and return the result as a string.
func TmplToString(tmpl string, data interface{}) string {
	t := template.New("tmpl").Funcs(BeeFuncMap())
	template.Must(t.Parse(tmpl))

	var doc bytes.Buffer
	err := t.Execute(&doc, data)
	MustCheck(err)

	return doc.String()
}

// EndLine returns the a newline escape character
func EndLine() string {
	return "\n"
}

func Tmpl(text string, data interface{}) {
	output := colors.NewColorWriter(os.Stderr)

	t := template.New("Usage").Funcs(BeeFuncMap())
	template.Must(t.Parse(text))

	err := t.Execute(output, data)
	if err != nil {
		beeLogger.Log.Error(err.Error())
	}
}

func CheckEnv(appname string) (apppath, packpath string, err error) {
	gps := GetGOPATHs()
	if len(gps) == 0 {
		beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
	}
	currpath, _ := os.Getwd()
	currpath = path.Join(currpath, appname)
	for _, gpath := range gps {
		gsrcpath := path.Join(gpath, "src")
		if strings.HasPrefix(currpath, gsrcpath) {
			packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(filepath.Separator), "/", -1)
			return currpath, packpath, nil
		}
	}

	// In case of multiple paths in the GOPATH, by default
	// we use the first path
	gopath := gps[0]

	beeLogger.Log.Warn("You current workdir is not inside $GOPATH/src.")
	beeLogger.Log.Debugf("GOPATH: %s", FILE(), LINE(), gopath)

	gosrcpath := path.Join(gopath, "src")
	apppath = path.Join(gosrcpath, appname)

	if _, e := os.Stat(apppath); !os.IsNotExist(e) {
		err = fmt.Errorf("Cannot create application without removing '%s' first", apppath)
		beeLogger.Log.Errorf("Path '%s' already exists", apppath)
		return
	}
	packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(filepath.Separator)), "/")
	return
}

func PrintErrorAndExit(message, errorTemplate string) {
	Tmpl(fmt.Sprintf(errorTemplate, message), nil)
	os.Exit(2)
}

// GoCommand executes the passed command using Go tool
func GoCommand(command string, args ...string) error {
	allargs := []string{command}
	allargs = append(allargs, args...)
	goBuild := exec.Command("go", allargs...)
	goBuild.Stderr = os.Stderr
	return goBuild.Run()
}

// GoBuild runs the "go build" command on the specified package
func GoBuild(debugname, pkg string) error {
	buildFlags := "-ldflags='-linkmode internal'"
	args := []string{"-gcflags", "-N -l", "-o", debugname}
	if buildFlags != "" {
		args = append(args, SplitQuotedFields(buildFlags)...)
	}
	args = append(args, pkg)
	return GoCommand("build", args...)
}

// SplitQuotedFields is like strings.Fields but ignores spaces
// inside areas surrounded by single quotes.
// To specify a single quote use backslash to escape it: '\''
func SplitQuotedFields(in string) []string {
	type stateEnum int
	const (
		inSpace stateEnum = iota
		inField
		inQuote
		inQuoteEscaped
	)
	state := inSpace
	r := []string{}
	var buf bytes.Buffer

	for _, ch := range in {
		switch state {
		case inSpace:
			if ch == '\'' {
				state = inQuote
			} else if !unicode.IsSpace(ch) {
				buf.WriteRune(ch)
				state = inField
			}

		case inField:
			if ch == '\'' {
				state = inQuote
			} else if unicode.IsSpace(ch) {
				r = append(r, buf.String())
				buf.Reset()
			} else {
				buf.WriteRune(ch)
			}

		case inQuote:
			if ch == '\'' {
				state = inField
			} else if ch == '\\' {
				state = inQuoteEscaped
			} else {
				buf.WriteRune(ch)
			}

		case inQuoteEscaped:
			buf.WriteRune(ch)
			state = inQuote
		}
	}

	if buf.Len() != 0 {
		r = append(r, buf.String())
	}

	return r
}
<|endoftext|>


<commit_before>package regex

import (
	"fmt"
	"time"

	"cirello.io/gochatbot/bot"
)

var regexRules = []regexRule{
	{
		`{{ .RobotName }} jump`, `tells the robot to jump`,
		func(bot bot.Self, msg string, matches []string) []string {
			var ret []string
			ret = append(ret, "{{ .User }}, How high?")
			lastJumpTS := bot.MemoryRead("jump", "lastJump")
			ret = append(ret, fmt.Sprint("{{ .User }} (last time I jumped:", lastJumpTS, ")"))
			bot.MemorySave("jump", "lastJump", fmt.Sprint(time.Now()))

			return ret
		},
	},
}
<commit_msg>Add example command in Regex rule which uses its matches<commit_after>package regex

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"cirello.io/gochatbot/bot"
)

var regexRules = []regexRule{
	{
		`{{ .RobotName }} jump`, `tells the robot to jump`,
		func(bot bot.Self, msg string, matches []string) []string {
			var ret []string
			ret = append(ret, "{{ .User }}, How high?")
			lastJumpTS := bot.MemoryRead("jump", "lastJump")
			ret = append(ret, fmt.Sprint("{{ .User }} (last time I jumped:", lastJumpTS, ")"))
			bot.MemorySave("jump", "lastJump", fmt.Sprint(time.Now()))

			return ret
		},
	},
	{
		`{{ .RobotName }} godoc (.*)`, `search godoc.org and return the first result`,
		func(bot bot.Self, msg string, matches []string) []string {
			if len(matches) < 2 {
				return []string{}
			}

			resp, err := http.Get(fmt.Sprintf("http://api.godoc.org/search?q=%s", url.QueryEscape(matches[1])))
			if err != nil {
				return []string{err.Error()}
			}
			defer resp.Body.Close()

			var data struct {
				Results []struct {
					Path     string `json:"path"`
					Synopsis string `json:"synopsis"`
				} `json:"results"`
			}

			if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
				return []string{err.Error()}
			}

			if len(data.Results) == 0 {
				return []string{"package not found"}
			}

			return []string{fmt.Sprintf("%s %s/%s", data.Results[0].Synopsis, "http://godoc.org", data.Results[0].Path)}

		},
	},
}
<|endoftext|>


<commit_before>package quicksort

func Sort(a []int) {
	if len(a) < 2 {
		return
	}
	p := partition(a)
	Sort(a[:p])
	Sort(a[p+1:])
}

func partition(a []int) int {
	p := medianPivot(a)
	last := len(a) - 1
	swap(a, p, last)

	firstHigh := 0
	for i := 0; i < last; i++ {
		v := a[i]
		if v < a[last] {
			swap(a, i, firstHigh)
			firstHigh++
		}
	}
	swap(a, last, firstHigh)

	return firstHigh
}

func swap(a []int, i, j int) {
	a[i], a[j] = a[j], a[i]
}

func medianPivot(a []int) int {
	mid := len(a) / 2
	end := len(a) - 1

	switch {
	case between(a[0], a[mid], a[end]):
		return 0
	case between(a[mid], a[0], a[end]):
		return mid
	default:
		return end
	}
}

func between(a, x, y int) bool {
	return x <= a && a <= y || y <= a && a <= x
}

/* randomPivot is an alternative to medianPivot, but mediaPivot is recommended.
func randomPivot(a []int) int {
	return rand.Intn(len(a))
}
*/
<commit_msg>[quicksort/go] More idiomatic loop<commit_after>package quicksort

func Sort(a []int) {
	if len(a) < 2 {
		return
	}
	p := partition(a)
	Sort(a[:p])
	Sort(a[p+1:])
}

func partition(a []int) int {
	p := medianPivot(a)
	pv := a[p]

	last := len(a) - 1
	swap(a, p, last)

	firstHigh := 0
	for i, v := range a {
		if v < pv {
			swap(a, i, firstHigh)
			firstHigh++
		}
	}
	swap(a, last, firstHigh)

	return firstHigh
}

func swap(a []int, i, j int) {
	a[i], a[j] = a[j], a[i]
}

func medianPivot(a []int) int {
	mid := len(a) / 2
	end := len(a) - 1

	switch {
	case between(a[0], a[mid], a[end]):
		return 0
	case between(a[mid], a[0], a[end]):
		return mid
	default:
		return end
	}
}

func between(a, x, y int) bool {
	return x <= a && a <= y || y <= a && a <= x
}

/* randomPivot is an alternative to medianPivot, but mediaPivot is recommended.
func randomPivot(a []int) int {
	return rand.Intn(len(a))
}
*/
<|endoftext|>


<commit_before>package filter

import (
	"github.com/fitstar/falcore"
	"math"
	"net/http"
	"testing"
	"time"
	// "fmt"
)

func TestUpstreamThrottle(t *testing.T) {
	// Start a test server
	sleepPipe := falcore.NewPipeline()
	sleepPipe.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response {
		time.Sleep(time.Second)
		return falcore.StringResponse(req.HttpRequest, 200, nil, "OK")
	}))
	sleepSrv := falcore.NewServer(0, sleepPipe)
	go func() {
		sleepSrv.ListenAndServe()
	}()
	<-sleepSrv.AcceptReady

	// Build Upstream
	up := NewUpstream(NewUpstreamTransport("localhost", sleepSrv.Port(), 0, nil))
	// pipe := falcore.NewPipeline()
	// pipe.Upstream.PushBack(up)

	resCh := make(chan *http.Response, 10)
	var i int64 = 1
	for ; i < 12; i++ {
		start := time.Now()
		up.SetMaxConcurrent(i)

		for j := 0; j < 10; j++ {
			go func() {
				req, _ := http.NewRequest("GET", "http://localhost/", nil)
				_, res := falcore.TestWithRequest(req, up, nil)
				resCh <- res
				// fmt.Println("OK")
			}()
		}
		for j := 0; j < 10; j++ {
			res := <-resCh
			if res.StatusCode != 200 {
				t.Fatalf("Error: %v", res)
			}
		}

		duration := time.Since(start)
		seconds := float64(duration) / float64(time.Second)
		goal := math.Ceil(10.0 / float64(i))
		// fmt.Println(i, "Time:", seconds, "Goal:", goal)
		if seconds < goal {
			t.Errorf("%v: Too short: %v < %v", i, seconds, goal)
		}
	}

}
<commit_msg>cleaned up upstream_throttle_test to use channels instead of sleep.  much faster<commit_after>package filter

import (
	"fmt"
	"github.com/fitstar/falcore"
	"net/http"
	// "strconv"
	"testing"
)

const REQ_COUNT = 100

func TestUpstreamThrottle(t *testing.T) {
	// Build a thing for
	var started = make(chan chan bool, REQ_COUNT+1)

	// Start a test server
	sleepPipe := falcore.NewPipeline()
	sleepPipe.Upstream.PushBack(falcore.NewRequestFilter(func(req *falcore.Request) *http.Response {
		// get chan
		// j, _ := strconv.Atoi(req.HttpRequest.URL.Query().Get("j"))
		// fmt.Println(req.HttpRequest.URL, j)
		c := make(chan bool)
		started <- c
		// wait on chan
		<-c
		// fmt.Println("DONE")
		return falcore.StringResponse(req.HttpRequest, 200, nil, "OK")
	}))
	sleepSrv := falcore.NewServer(0, sleepPipe)
	defer sleepSrv.StopAccepting()
	go func() {
		sleepSrv.ListenAndServe()
	}()
	<-sleepSrv.AcceptReady

	// Build Upstream
	up := NewUpstream(NewUpstreamTransport("localhost", sleepSrv.Port(), 0, nil))
	// pipe := falcore.NewPipeline()
	// pipe.Upstream.PushBack(up)

	resCh := make(chan *http.Response, REQ_COUNT)
	var i int64 = 1
	for ; i < 12; i++ {
		// fmt.Println("Testing with limit", i)

		up.SetMaxConcurrent(i)

		for j := 0; j < REQ_COUNT; j++ {
			var jj = j
			go func() {
				// fmt.Println("STARTING")
				req, _ := http.NewRequest("GET", fmt.Sprintf("http://localhost/foo?j=%v", jj), nil)
				_, res := falcore.TestWithRequest(req, up, nil)
				res.Body.Close()
				resCh <- res
				// fmt.Println("OK")
			}()
		}
		for j := 0; j < REQ_COUNT; j++ {
			// make sure we haven't gone over the limit
			// fmt.Println(i, len(started))
			if r := int64(len(started)); r > i {
				t.Errorf("%v: Over the limit: %v", i, r)
			}

			// send a finish signal
			(<-started) <- true

			// collect the result
			res := <-resCh
			if res.StatusCode != 200 {
				t.Fatalf("Error: %v", res)
			}
		}
	}

}
<|endoftext|>