<commit_before>/*
Copyright 2016 The Fission 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 canaryconfigmgr

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	promClient "github.com/prometheus/client_golang/api/prometheus"
	"github.com/prometheus/common/model"
	"go.uber.org/zap"
	"golang.org/x/net/context"
)

type PrometheusApiClient struct {
	logger *zap.Logger
	client promClient.QueryAPI
}

func MakePrometheusClient(logger *zap.Logger, prometheusSvc string) (*PrometheusApiClient, error) {
	promApiConfig := promClient.Config{
		Address: prometheusSvc,
	}

	promApiClient, err := promClient.New(promApiConfig)
	if err != nil {
		return nil, errors.Wrapf(err, "error creating prometheus api client for svc: %s", prometheusSvc)
	}

	apiQueryClient := promClient.NewQueryAPI(promApiClient)

	// By default, the prometheus client library doesn't test server connectivity when creating
	// prometheus client. As a workaround, here we send out a test query string to ensure that
	// prometheus server is running.
	for i := 0; i < 15; i++ {
		_, err = apiQueryClient.Query(context.Background(), "http_requests_total", time.Now())
		if err == nil {
			break
		}
		time.Sleep(time.Second)
	}

	if err != nil {
		return nil, errors.Wrap(err, "error sending test query to prometheus server")
	}

	logger.Info("successfully made prometheus client with service", zap.String("service", prometheusSvc))
	return &PrometheusApiClient{
		logger: logger.Named("prometheus_api_client"),
		client: apiQueryClient,
	}, nil
}

func (promApiClient *PrometheusApiClient) GetFunctionFailurePercentage(path, method, funcName, funcNs string, window string) (float64, error) {
	// first get a total count of requests to this url in a time window
	reqs, err := promApiClient.GetRequestsToFuncInWindow(path, method, funcName, funcNs, window)
	if err != nil {
		return 0, err
	}

	if reqs <= 0 {
		return -1, fmt.Errorf("no requests to this url %v and method %v in the window: %v", path, method, window)
	}

	// next, get a total count of errored out requests to this function in the same window
	failedReqs, err := promApiClient.GetTotalFailedRequestsToFuncInWindow(funcName, funcNs, path, method, window)
	if err != nil {
		return 0, err
	}

	// calculate the failure percentage of the function
	failurePercentForFunc := (failedReqs / reqs) * 100

	return failurePercentForFunc, nil
}

func (promApiClient *PrometheusApiClient) GetRequestsToFuncInWindow(path string, method string, funcName string, funcNs string, window string) (float64, error) {
	queryString := fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"}[%v]", path, method, funcName, funcNs, window)

	reqs, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	queryString = fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"} offset %v", path, method, funcName, funcNs, window)

	reqsInPrevWindow, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	reqsInCurrentWindow := reqs - reqsInPrevWindow
	promApiClient.logger.Info("function requests",
		zap.Float64("requests", reqs),
		zap.Float64("requests_in_previous_window", reqsInPrevWindow),
		zap.Float64("requests_in_current_window", reqsInCurrentWindow),
		zap.String("function", funcName))

	return reqsInCurrentWindow, nil
}

func (promApiClient *PrometheusApiClient) GetTotalFailedRequestsToFuncInWindow(funcName string, funcNs string, path string, method string, window string) (float64, error) {
	queryString := fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"}[%v]", funcName, funcNs, path, method, window)

	failedRequests, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	queryString = fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"} offset %v", funcName, funcNs, path, method, window)

	failedReqsInPrevWindow, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	failedReqsInCurrentWindow := failedRequests - failedReqsInPrevWindow
	promApiClient.logger.Info("function requests",
		zap.Float64("failed_requests", failedRequests),
		zap.Float64("failed_requests_in_previous_window", failedReqsInPrevWindow),
		zap.Float64("failed_requests_in_current_window", failedReqsInCurrentWindow),
		zap.String("function", funcName))

	return failedReqsInCurrentWindow, nil
}

func (promApiClient *PrometheusApiClient) executeQuery(queryString string) (float64, error) {
	val, err := promApiClient.client.Query(context.Background(), queryString, time.Now())
	if err != nil {
		return 0, errors.Wrapf(err, "error querying prometheus")
	}

	switch {
	case val.Type() == model.ValScalar:
		scalarVal := val.(*model.Scalar)
		return float64(scalarVal.Value), nil

	case val.Type() == model.ValVector:
		vectorVal := val.(model.Vector)
		total := float64(0)
		for _, elem := range vectorVal {
			total = total + float64(elem.Value)
		}
		return total, nil

	case val.Type() == model.ValMatrix:
		matrixVal := val.(model.Matrix)
		total := float64(0)
		for _, elem := range matrixVal {
			total += float64(elem.Values[len(elem.Values)-1].Value)
		}
		return total, nil

	default:
		promApiClient.logger.Info("return value type of prometheus query was unrecognized",
			zap.Any("type", val.Type()))
		return 0, nil
	}
}
<commit_msg>Remove prometheus server connectivity test during controller initialization (#1179)<commit_after>/*
Copyright 2016 The Fission 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 canaryconfigmgr

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	promClient "github.com/prometheus/client_golang/api/prometheus"
	"github.com/prometheus/common/model"
	"go.uber.org/zap"
	"golang.org/x/net/context"
)

type PrometheusApiClient struct {
	logger *zap.Logger
	client promClient.QueryAPI
}

func MakePrometheusClient(logger *zap.Logger, prometheusSvc string) (*PrometheusApiClient, error) {
	promApiConfig := promClient.Config{
		Address: prometheusSvc,
	}

	promApiClient, err := promClient.New(promApiConfig)
	if err != nil {
		return nil, errors.Wrapf(err, "error creating prometheus api client for svc: %s", prometheusSvc)
	}

	apiQueryClient := promClient.NewQueryAPI(promApiClient)

	return &PrometheusApiClient{
		logger: logger.Named("prometheus_api_client"),
		client: apiQueryClient,
	}, nil
}

func (promApiClient *PrometheusApiClient) GetFunctionFailurePercentage(path, method, funcName, funcNs string, window string) (float64, error) {
	// first get a total count of requests to this url in a time window
	reqs, err := promApiClient.GetRequestsToFuncInWindow(path, method, funcName, funcNs, window)
	if err != nil {
		return 0, err
	}

	if reqs <= 0 {
		return -1, fmt.Errorf("no requests to this url %v and method %v in the window: %v", path, method, window)
	}

	// next, get a total count of errored out requests to this function in the same window
	failedReqs, err := promApiClient.GetTotalFailedRequestsToFuncInWindow(funcName, funcNs, path, method, window)
	if err != nil {
		return 0, err
	}

	// calculate the failure percentage of the function
	failurePercentForFunc := (failedReqs / reqs) * 100

	return failurePercentForFunc, nil
}

func (promApiClient *PrometheusApiClient) GetRequestsToFuncInWindow(path string, method string, funcName string, funcNs string, window string) (float64, error) {
	queryString := fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"}[%v]", path, method, funcName, funcNs, window)

	reqs, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	queryString = fmt.Sprintf("fission_function_calls_total{path=\"%s\",method=\"%s\",name=\"%s\",namespace=\"%s\"} offset %v", path, method, funcName, funcNs, window)

	reqsInPrevWindow, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	reqsInCurrentWindow := reqs - reqsInPrevWindow
	promApiClient.logger.Info("function requests",
		zap.Float64("requests", reqs),
		zap.Float64("requests_in_previous_window", reqsInPrevWindow),
		zap.Float64("requests_in_current_window", reqsInCurrentWindow),
		zap.String("function", funcName))

	return reqsInCurrentWindow, nil
}

func (promApiClient *PrometheusApiClient) GetTotalFailedRequestsToFuncInWindow(funcName string, funcNs string, path string, method string, window string) (float64, error) {
	queryString := fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"}[%v]", funcName, funcNs, path, method, window)

	failedRequests, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	queryString = fmt.Sprintf("fission_function_errors_total{name=\"%s\",namespace=\"%s\",path=\"%s\", method=\"%s\"} offset %v", funcName, funcNs, path, method, window)

	failedReqsInPrevWindow, err := promApiClient.executeQuery(queryString)
	if err != nil {
		return 0, errors.Wrapf(err, "error executing query: %s", queryString)
	}

	failedReqsInCurrentWindow := failedRequests - failedReqsInPrevWindow
	promApiClient.logger.Info("function requests",
		zap.Float64("failed_requests", failedRequests),
		zap.Float64("failed_requests_in_previous_window", failedReqsInPrevWindow),
		zap.Float64("failed_requests_in_current_window", failedReqsInCurrentWindow),
		zap.String("function", funcName))

	return failedReqsInCurrentWindow, nil
}

func (promApiClient *PrometheusApiClient) executeQuery(queryString string) (float64, error) {
	val, err := promApiClient.client.Query(context.Background(), queryString, time.Now())
	if err != nil {
		return 0, errors.Wrapf(err, "error querying prometheus")
	}

	switch {
	case val.Type() == model.ValScalar:
		scalarVal := val.(*model.Scalar)
		return float64(scalarVal.Value), nil

	case val.Type() == model.ValVector:
		vectorVal := val.(model.Vector)
		total := float64(0)
		for _, elem := range vectorVal {
			total = total + float64(elem.Value)
		}
		return total, nil

	case val.Type() == model.ValMatrix:
		matrixVal := val.(model.Matrix)
		total := float64(0)
		for _, elem := range matrixVal {
			total += float64(elem.Values[len(elem.Values)-1].Value)
		}
		return total, nil

	default:
		promApiClient.logger.Info("return value type of prometheus query was unrecognized",
			zap.Any("type", val.Type()))
		return 0, nil
	}
}
<|endoftext|>


<commit_before>package user

import (
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/validate"
)

func TestProtect(t *testing.T) {

	var err error

	Secret = "secret"

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"role"}).AddRow(1)

	mock.ExpectQuery(`SELECT COALESCE`).WillReturnRows(rows)

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(validate.ValidateParams())
	router.Use(Auth(true))
	router.Use(Protect())

	router.GET("/important", func(c *gin.Context) {
		c.String(200, "OK")
		return
	})

	first := performRequest(router, "GET", "/important")

	assert.Equal(t, first.Code, 401, "HTTP request code should match")

	user := DefaultUser()
	user.SetId(2)
	user.SetAuthenticated()

	user.hash, err = HashPassword("testpassword")
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotNil(t, user.hash, "password should be returned")
	}

	assert.True(t, user.ComparePassword("testpassword"), "Password should validate")

	token, err := user.CreateToken()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, token, "token should be returned")
	}

	second := performJwtHeaderRequest(router, "GET", "/important", token)

}
<commit_msg>add protect middleware test<commit_after>package user

import (
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"testing"

	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/validate"
)

func TestProtect(t *testing.T) {

	var err error

	Secret = "secret"

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	rows := sqlmock.NewRows([]string{"role"}).AddRow(1)

	mock.ExpectQuery(`SELECT COALESCE`).WillReturnRows(rows)

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(validate.ValidateParams())
	router.Use(Auth(true))
	router.Use(Protect())

	router.GET("/important", func(c *gin.Context) {
		c.String(200, "OK")
		return
	})

	first := performRequest(router, "GET", "/important")

	assert.Equal(t, first.Code, 401, "HTTP request code should match")

	user := DefaultUser()
	user.SetId(2)
	user.SetAuthenticated()

	user.hash, err = HashPassword("testpassword")
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotNil(t, user.hash, "password should be returned")
	}

	assert.True(t, user.ComparePassword("testpassword"), "Password should validate")

	token, err := user.CreateToken()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, token, "token should be returned")
	}

	second := performJwtHeaderRequest(router, "GET", "/important", token)

	assert.Equal(t, second.Code, 200, "HTTP request code should match")

}
<|endoftext|>


<commit_before>package challenges_test

import (
	"reflect"
	"testing"
)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

type ListNode struct {
	Val  int
	Next *ListNode
}

// moving the current node value to the next value and pointing next to next, the "GC" will clean up the object
func deleteNode(node *ListNode) {
	if node != nil && node.Next != nil {
		node.Val = node.Next.Val
		node.Next = node.Next.Next
	}
}

func removeNthFromEnd(head *ListNode, n int) *ListNode {

	len := 1
	d := head
	for d != nil && d.Next != nil {
		len++
		d = d.Next
	}

	if n > len {
		return head
	}

	removeThis := head
	moveRight := len - n
	// going from left to right N spaces
	for i := 1; i <= moveRight; i++ {
		removeThis = removeThis.Next
	}

	// 1->2->3->4->5: if n == 2; 5-2 == 3
	if removeThis != nil && removeThis.Next == nil {
		return nil
	}

	//fmt.Printf("Removing node pos[%d] on len[%d]: %v\n", moveRight, len, removeThis)
	deleteNode(removeThis)
	return head

}

func Test_deleteNode(t *testing.T) {
	type args struct {
		node *ListNode
	}

	n := &ListNode{4, &ListNode{5, &ListNode{1, &ListNode{9, nil}}}}

	tests := []struct {
		name string
		args args
	}{
		{"delete", args{n.Next}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			deleteNode(tt.args.node)
		})
	}
}

func Test_removeNthFromEnd(t *testing.T) {
	type args struct {
		head *ListNode
		n    int
	}

	n := &ListNode{1, &ListNode{2, &ListNode{3, &ListNode{4, &ListNode{5, nil}}}}}

	n2 := &ListNode{1, nil}

	tests := []struct {
		name string
		args args
		want *ListNode
	}{
		// TODO: Add test cases.
		{"remove", args{head: n, n: 2}, n},
		{"remove", args{head: n2, n: 1}, nil},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := removeNthFromEnd(tt.args.head, tt.args.n); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("removeNthFromEnd() = %v, want %v", got, tt.want)
			}
		})
	}
}
<commit_msg>fixed remove from the end.<commit_after>package challenges_test

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/davecgh/go-spew/spew"
)

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

type ListNode struct {
	Val  int
	Next *ListNode
}

// moving the current node value to the next value and pointing next to next, the "GC" will clean up the object
func deleteNode(node *ListNode) {
	if node != nil && node.Next != nil {
		node.Val = node.Next.Val
		node.Next = node.Next.Next
	}
}

func removeNthFromEnd(head *ListNode, n int) *ListNode {

	len := 1
	d := head
	for d != nil && d.Next != nil {
		len++
		d = d.Next
	}

	if n > len {
		return head
	}

	removeThis := head
	moveRight := len - n
	fmt.Printf("Len: %d Moving Right: %d\n", len, moveRight)
	// going from left to right N spaces
	for i := 1; i <= moveRight; i++ {
		removeThis = removeThis.Next
	}
	// deleteting the end (need to back up one)
	if removeThis != nil && removeThis.Next == nil && removeThis != head {
		removeThis = head
		moveRight := len - n - 1
		for i := 1; i <= moveRight; i++ {
			removeThis = removeThis.Next
		}
		removeThis.Next = nil
		return head
	}

	// 1->2->3->4->5: if n == 2; 5-2 == 3
	if removeThis != nil && removeThis.Next == nil && removeThis == head {
		return nil
	}

	//fmt.Printf("Removing node pos[%d] on len[%d]: %v\n", moveRight, len, removeThis)
	deleteNode(removeThis)
	return head

}

func Test_removeNthFromEnd(t *testing.T) {
	type args struct {
		head *ListNode
		n    int
	}

	n1 := &ListNode{1, &ListNode{2, &ListNode{3, &ListNode{4, &ListNode{5, nil}}}}}
	n2 := &ListNode{1, nil}
	n3 := &ListNode{1, &ListNode{2, nil}}
	n4 := &ListNode{1, &ListNode{2, &ListNode{3, nil}}}

	tests := []struct {
		name string
		args args
		want *ListNode
	}{
		{"remove", args{head: n1, n: 2}, n1},
		{"remove", args{head: n2, n: 1}, nil},
		{"remove", args{head: n3, n: 1}, n3},
		{"remove", args{head: n4, n: 1}, n4},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := removeNthFromEnd(tt.args.head, tt.args.n); !reflect.DeepEqual(got, tt.want) {
				t.Errorf("removeNthFromEnd() = %v, want %v", got, tt.want)
			} else {
				t.Log(spew.Sprintf("OK: %v\n", tt.want))
			}
		})
	}
}

func Test_deleteNode(t *testing.T) {
	type args struct {
		node *ListNode
	}

	n := &ListNode{4, &ListNode{5, &ListNode{1, &ListNode{9, nil}}}}

	tests := []struct {
		name string
		args args
	}{
		{"delete", args{n.Next}},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			deleteNode(tt.args.node)
		})
	}
}
<|endoftext|>


<commit_before>package peco

import (
	"testing"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

func TestActionNames(t *testing.T) {
	// These names MUST exist
	names := []string{
		"peco.ForwardChar",
		"peco.BackwardChar",
		"peco.ForwardWord",
		"peco.BackwardWord",
		"peco.BeginningOfLine",
		"peco.EndOfLine",
		"peco.EndOfFile",
		"peco.DeleteForwardChar",
		"peco.DeleteBackwardChar",
		"peco.DeleteForwardWord",
		"peco.DeleteBackwardWord",
		"peco.KillEndOfLine",
		"peco.DeleteAll",
		"peco.SelectPreviousPage",
		"peco.SelectNextPage",
		"peco.SelectPrevious",
		"peco.SelectNext",
		"peco.ToggleSelection",
		"peco.ToggleSelectionAndSelectNext",
		"peco.RotateMatcher",
		"peco.Finish",
		"peco.Cancel",
	}
	for _, name := range names {
		if _, ok := nameToActions[name]; !ok {
			t.Errorf("Action %s should exist, but it does not", name)
		}
	}
}

func expectCaretPos(t *testing.T, c interface {
	CaretPos() int
}, expect int) bool {
	if c.CaretPos() != expect {
		t.Errorf("Expected caret position %d, got %d", expect, c.CaretPos())
		return false
	}
	return true
}

func expectQueryString(t *testing.T, c interface {
	QueryString() string
}, expect string) bool {
	if c.QueryString() != expect {
		t.Errorf("Expected '%s', got '%s'", expect, c.QueryString())
		return false
	}
	return true
}

func TestDoDeleteForwardChar(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, 5)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "ello World!")
	expectCaretPos(t, ctx, 0)
}

func TestDoDeleteForwardWord(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, 5)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " World!")
	expectCaretPos(t, ctx, 0)

	ctx.SetCaretPos(1)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " ")
}

func TestDoDeleteBackwardChar(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World!")
	expectCaretPos(t, ctx, 4)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World")
	expectCaretPos(t, ctx, 0)
}

func TestDoDeleteBackwardWord(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	// In case of an overflow (bug)
	ctx.SetQuery([]rune("foo"))
	ctx.SetCaretPos(5)
	doDeleteBackwardWord(input, termbox.Event{})

	// https://github.com/peco/peco/pull/184#issuecomment-54026739

	// Case 1. " foo<caret>" -> " "
	ctx.SetQuery([]rune(" foo"))
	ctx.SetCaretPos(4)
	doDeleteBackwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " ")
	expectCaretPos(t, ctx, 1)

	// Case 2. "foo bar<caret>" -> "foo "
	ctx.SetQuery([]rune("foo bar"))
	ctx.SetCaretPos(7)
	doDeleteBackwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "foo ")
	expectCaretPos(t, ctx, 4)
}
<commit_msg>Add small test<commit_after>package peco

import (
	"testing"

	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
)

func TestActionFunc(t *testing.T) {
	called := 0
	af := ActionFunc(func(_ *Input, _ termbox.Event) {
		called++
	})
	af.Execute(nil, termbox.Event{})
	if called != 1 {
		t.Errorf("Expected ActionFunc to be called once, but it got called %d times", called)
	}
}

func TestActionNames(t *testing.T) {
	// These names MUST exist
	names := []string{
		"peco.ForwardChar",
		"peco.BackwardChar",
		"peco.ForwardWord",
		"peco.BackwardWord",
		"peco.BeginningOfLine",
		"peco.EndOfLine",
		"peco.EndOfFile",
		"peco.DeleteForwardChar",
		"peco.DeleteBackwardChar",
		"peco.DeleteForwardWord",
		"peco.DeleteBackwardWord",
		"peco.KillEndOfLine",
		"peco.DeleteAll",
		"peco.SelectPreviousPage",
		"peco.SelectNextPage",
		"peco.SelectPrevious",
		"peco.SelectNext",
		"peco.ToggleSelection",
		"peco.ToggleSelectionAndSelectNext",
		"peco.RotateMatcher",
		"peco.Finish",
		"peco.Cancel",
	}
	for _, name := range names {
		if _, ok := nameToActions[name]; !ok {
			t.Errorf("Action %s should exist, but it does not", name)
		}
	}
}

func expectCaretPos(t *testing.T, c interface {
	CaretPos() int
}, expect int) bool {
	if c.CaretPos() != expect {
		t.Errorf("Expected caret position %d, got %d", expect, c.CaretPos())
		return false
	}
	return true
}

func expectQueryString(t *testing.T, c interface {
	QueryString() string
}, expect string) bool {
	if c.QueryString() != expect {
		t.Errorf("Expected '%s', got '%s'", expect, c.QueryString())
		return false
	}
	return true
}

func TestDoDeleteForwardChar(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, 5)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteForwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "ello World!")
	expectCaretPos(t, ctx, 0)
}

func TestDoDeleteForwardWord(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, 5)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "Hello World!")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " World!")
	expectCaretPos(t, ctx, 0)

	ctx.SetCaretPos(1)
	doDeleteForwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " ")
}

func TestDoDeleteBackwardChar(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	ctx.SetQuery([]rune("Hello, World!"))
	ctx.SetCaretPos(5)
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World!")
	expectCaretPos(t, ctx, 4)

	ctx.SetCaretPos(runewidth.StringWidth(ctx.QueryString()))
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World")
	expectCaretPos(t, ctx, runewidth.StringWidth(ctx.QueryString()))

	ctx.SetCaretPos(0)
	doDeleteBackwardChar(input, termbox.Event{})

	expectQueryString(t, ctx, "Hell, World")
	expectCaretPos(t, ctx, 0)
}

func TestDoDeleteBackwardWord(t *testing.T) {
	ctx := NewCtx(nil)
	input := ctx.NewInput()

	// In case of an overflow (bug)
	ctx.SetQuery([]rune("foo"))
	ctx.SetCaretPos(5)
	doDeleteBackwardWord(input, termbox.Event{})

	// https://github.com/peco/peco/pull/184#issuecomment-54026739

	// Case 1. " foo<caret>" -> " "
	ctx.SetQuery([]rune(" foo"))
	ctx.SetCaretPos(4)
	doDeleteBackwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, " ")
	expectCaretPos(t, ctx, 1)

	// Case 2. "foo bar<caret>" -> "foo "
	ctx.SetQuery([]rune("foo bar"))
	ctx.SetCaretPos(7)
	doDeleteBackwardWord(input, termbox.Event{})

	expectQueryString(t, ctx, "foo ")
	expectCaretPos(t, ctx, 4)
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.

package builtin

import "time"
import "fmt"

import "github.com/prataprc/monster/common"

var _ = fmt.Sprintf("dummy")

// Uuid returns a unique value based on current nanosecond timestamp.
func Uuid(scope common.Scope, args ...interface{}) interface{} {
	uuid := time.Now().UnixNano()
	return uuid
}
<commit_msg>monster: generate cryptographic random number.<commit_after>//  Copyright (c) 2013 Couchbase, Inc.

package builtin

import "fmt"
import "bytes"
import "strconv"
import "io"
import "encoding/binary"
import "math/rand"
import crypt "crypto/rand"

import "github.com/prataprc/monster/common"

var _ = fmt.Sprintf("dummy")

type UUID []byte

func init() {
	seed := newUUID().Uint64()
	rand.Seed(int64(seed))
}

// Uuid returns a unique value based on current nanosecond timestamp.
func Uuid(scope common.Scope, args ...interface{}) interface{} {
	return newUUID().Uint64()
}

func newUUID() UUID {
	uuid := make([]byte, 8)
	if n, err := io.ReadFull(crypt.Reader, uuid); err != nil {
		panic("crypt.Reader errored out")
	} else if n != len(uuid) {
		panic("crypt.Reader failed")
	}
	return UUID(uuid)
}

func (u UUID) Uint64() uint64 {
	return binary.LittleEndian.Uint64(([]byte)(u))
}

func (u UUID) Str() string {
	var buf bytes.Buffer
	for i := 0; i < len(u); i++ {
		if i > 0 {
			buf.WriteString(":")
		}
		buf.WriteString(strconv.FormatUint(uint64(u[i]), 16))
	}
	return buf.String()
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 gce

import (
	"fmt"
	"strconv"
	"strings"

	"k8s.io/contrib/cluster-autoscaler/cloudprovider"
	kube_api "k8s.io/kubernetes/pkg/api"
)

// GceCloudProvider implements CloudProvider interface.
type GceCloudProvider struct {
	gceManager *GceManager
	migs       []*Mig
}

// BuildGceCloudProvider builds CloudProvider implementation for GCE.
func BuildGceCloudProvider(gceManager *GceManager, specs []string) (*GceCloudProvider, error) {
	gce := &GceCloudProvider{
		gceManager: gceManager,
		migs:       make([]*Mig, 0),
	}
	for _, spec := range specs {
		if err := gce.addNodeGroup(spec); err != nil {
			return nil, err
		}
	}
	return gce, nil
}

// addNodeGroup adds node group defined in string spec. Format:
// minNodes:maxNodes:migUrl
func (gce *GceCloudProvider) addNodeGroup(spec string) error {
	mig, err := buildMig(spec, gce.gceManager)
	if err != nil {
		return err
	}
	gce.migs = append(gce.migs, mig)
	gce.gceManager.RegisterMig(mig)
	return nil
}

// Name returns name of the cloud provider.
func (gce *GceCloudProvider) Name() string {
	return "gce"
}

// NodeGroups returns all node groups configured for this cloud provider.
func (gce *GceCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
	result := make([]cloudprovider.NodeGroup, 0, len(gce.migs))
	for _, mig := range gce.migs {
		result = append(result, mig)
	}
	return result
}

// NodeGroupForNode returns the node group for the given node.
func (gce *GceCloudProvider) NodeGroupForNode(node *kube_api.Node) (cloudprovider.NodeGroup, error) {
	ref, err := GceRefFromProviderId(node.Spec.ProviderID)
	if err != nil {
		return nil, err
	}
	mig, err := gce.gceManager.GetMigForInstance(ref)
	return mig, err
}

// GceRef contains s reference to some entity in GCE/GKE world.
type GceRef struct {
	Project string
	Zone    string
	Name    string
}

// GceRefFromProviderId creates InstanceConfig object
// from provider id which must be in format:
// gce://<project-id>/<zone>/<name>
// TODO(piosz): add better check whether the id is correct
func GceRefFromProviderId(id string) (*GceRef, error) {
	splitted := strings.Split(id[6:], "/")
	if len(splitted) != 3 {
		return nil, fmt.Errorf("Wrong id: expected format gce://<project-id>/<zone>/<name>, got %v", id)
	}
	return &GceRef{
		Project: splitted[0],
		Zone:    splitted[1],
		Name:    splitted[2],
	}, nil
}

// Mig implements NodeGroup interfrace.
type Mig struct {
	GceRef

	gceManager *GceManager

	minSize int
	maxSize int
}

// MaxSize returns maximum size of the node group.
func (mig *Mig) MaxSize() int {
	return mig.maxSize
}

// MinSize returns minimum size of the node group.
func (mig *Mig) MinSize() int {
	return mig.minSize
}

// TargetSize returns the current TARGET size of the node group. It is possible that the
// number is different from the number of nodes registered in Kuberentes.
func (mig *Mig) TargetSize() (int, error) {
	size, err := mig.gceManager.GetMigSize(mig)
	return int(size), err
}

// IncreaseSize increases Mig size
func (mig *Mig) IncreaseSize(delta int) error {
	if delta <= 0 {
		return fmt.Errorf("size increase must be positive")
	}
	size, err := mig.gceManager.GetMigSize(mig)
	if err != nil {
		return err
	}
	if int(size)+delta > mig.MaxSize() {
		return fmt.Errorf("size increase too large - desired:%d max:%d", int(size)+delta, mig.MaxSize())
	}
	return mig.gceManager.SetMigSize(mig, size+int64(delta))
}

// Belongs returns true if the given node belongs to the NodeGroup.
func (mig *Mig) Belongs(node *kube_api.Node) (bool, error) {
	ref, err := GceRefFromProviderId(node.Spec.ProviderID)
	if err != nil {
		return false, err
	}
	targetMig, err := mig.gceManager.GetMigForInstance(ref)
	if err != nil {
		return false, err
	}
	if targetMig == nil {
		return false, fmt.Errorf("%s doesn't belong to a known mig", node.Name)
	}
	if targetMig.Id() != mig.Id() {
		return false, nil
	}
	return true, nil
}

// DeleteNodes deletes the nodes from the group.
func (mig *Mig) DeleteNodes(nodes []*kube_api.Node) error {
	size, err := mig.gceManager.GetMigSize(mig)
	if err != nil {
		return err
	}
	if int(size) <= mig.MinSize() {
		return fmt.Errorf("min size reached, nodes will not be deleted")
	}
	refs := make([]*GceRef, 0, len(nodes))
	for _, node := range nodes {

		belongs, err := mig.Belongs(node)
		if err != nil {
			return err
		}
		if belongs {
			return fmt.Errorf("%s belong to a different mig than %s", node.Name, mig.Id())
		}
		gceref, err := GceRefFromProviderId(node.Spec.ProviderID)
		if err != nil {
			return err
		}
		refs = append(refs, gceref)
	}
	return mig.gceManager.DeleteInstances(refs)
}

// Id returns mig url.
func (mig *Mig) Id() string {
	return GenerateMigUrl(mig.Project, mig.Zone, mig.Name)
}

// Debug returns a debug string for the Mig.
func (mig *Mig) Debug() string {
	return fmt.Sprintf("%s (%d:%d)", mig.Id(), mig.MinSize(), mig.MaxSize())
}

func buildMig(value string, gceManager *GceManager) (*Mig, error) {
	tokens := strings.SplitN(value, ":", 3)
	if len(tokens) != 3 {
		return nil, fmt.Errorf("wrong nodes configuration: %s", value)
	}

	mig := Mig{
		gceManager: gceManager,
	}
	if size, err := strconv.Atoi(tokens[0]); err == nil {
		if size <= 0 {
			return nil, fmt.Errorf("min size must be >= 1")
		}
		mig.minSize = size
	} else {
		return nil, fmt.Errorf("failed to set min size: %s, expected integer", tokens[0])
	}

	if size, err := strconv.Atoi(tokens[1]); err == nil {
		if size < mig.minSize {
			return nil, fmt.Errorf("max size must be greater or equal to min size")
		}
		mig.maxSize = size
	} else {
		return nil, fmt.Errorf("failed to set max size: %s, expected integer", tokens[1])
	}

	var err error
	if mig.Project, mig.Zone, mig.Name, err = ParseMigUrl(tokens[2]); err != nil {
		return nil, fmt.Errorf("failed to parse mig url: %s got error: %v", tokens[2], err)
	}
	return &mig, nil
}
<commit_msg>Cluster-autoscaler: fix belongs check in gce cloud provider<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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 gce

import (
	"fmt"
	"strconv"
	"strings"

	"k8s.io/contrib/cluster-autoscaler/cloudprovider"
	kube_api "k8s.io/kubernetes/pkg/api"
)

// GceCloudProvider implements CloudProvider interface.
type GceCloudProvider struct {
	gceManager *GceManager
	migs       []*Mig
}

// BuildGceCloudProvider builds CloudProvider implementation for GCE.
func BuildGceCloudProvider(gceManager *GceManager, specs []string) (*GceCloudProvider, error) {
	gce := &GceCloudProvider{
		gceManager: gceManager,
		migs:       make([]*Mig, 0),
	}
	for _, spec := range specs {
		if err := gce.addNodeGroup(spec); err != nil {
			return nil, err
		}
	}
	return gce, nil
}

// addNodeGroup adds node group defined in string spec. Format:
// minNodes:maxNodes:migUrl
func (gce *GceCloudProvider) addNodeGroup(spec string) error {
	mig, err := buildMig(spec, gce.gceManager)
	if err != nil {
		return err
	}
	gce.migs = append(gce.migs, mig)
	gce.gceManager.RegisterMig(mig)
	return nil
}

// Name returns name of the cloud provider.
func (gce *GceCloudProvider) Name() string {
	return "gce"
}

// NodeGroups returns all node groups configured for this cloud provider.
func (gce *GceCloudProvider) NodeGroups() []cloudprovider.NodeGroup {
	result := make([]cloudprovider.NodeGroup, 0, len(gce.migs))
	for _, mig := range gce.migs {
		result = append(result, mig)
	}
	return result
}

// NodeGroupForNode returns the node group for the given node.
func (gce *GceCloudProvider) NodeGroupForNode(node *kube_api.Node) (cloudprovider.NodeGroup, error) {
	ref, err := GceRefFromProviderId(node.Spec.ProviderID)
	if err != nil {
		return nil, err
	}
	mig, err := gce.gceManager.GetMigForInstance(ref)
	return mig, err
}

// GceRef contains s reference to some entity in GCE/GKE world.
type GceRef struct {
	Project string
	Zone    string
	Name    string
}

// GceRefFromProviderId creates InstanceConfig object
// from provider id which must be in format:
// gce://<project-id>/<zone>/<name>
// TODO(piosz): add better check whether the id is correct
func GceRefFromProviderId(id string) (*GceRef, error) {
	splitted := strings.Split(id[6:], "/")
	if len(splitted) != 3 {
		return nil, fmt.Errorf("Wrong id: expected format gce://<project-id>/<zone>/<name>, got %v", id)
	}
	return &GceRef{
		Project: splitted[0],
		Zone:    splitted[1],
		Name:    splitted[2],
	}, nil
}

// Mig implements NodeGroup interfrace.
type Mig struct {
	GceRef

	gceManager *GceManager

	minSize int
	maxSize int
}

// MaxSize returns maximum size of the node group.
func (mig *Mig) MaxSize() int {
	return mig.maxSize
}

// MinSize returns minimum size of the node group.
func (mig *Mig) MinSize() int {
	return mig.minSize
}

// TargetSize returns the current TARGET size of the node group. It is possible that the
// number is different from the number of nodes registered in Kuberentes.
func (mig *Mig) TargetSize() (int, error) {
	size, err := mig.gceManager.GetMigSize(mig)
	return int(size), err
}

// IncreaseSize increases Mig size
func (mig *Mig) IncreaseSize(delta int) error {
	if delta <= 0 {
		return fmt.Errorf("size increase must be positive")
	}
	size, err := mig.gceManager.GetMigSize(mig)
	if err != nil {
		return err
	}
	if int(size)+delta > mig.MaxSize() {
		return fmt.Errorf("size increase too large - desired:%d max:%d", int(size)+delta, mig.MaxSize())
	}
	return mig.gceManager.SetMigSize(mig, size+int64(delta))
}

// Belongs returns true if the given node belongs to the NodeGroup.
func (mig *Mig) Belongs(node *kube_api.Node) (bool, error) {
	ref, err := GceRefFromProviderId(node.Spec.ProviderID)
	if err != nil {
		return false, err
	}
	targetMig, err := mig.gceManager.GetMigForInstance(ref)
	if err != nil {
		return false, err
	}
	if targetMig == nil {
		return false, fmt.Errorf("%s doesn't belong to a known mig", node.Name)
	}
	if targetMig.Id() != mig.Id() {
		return false, nil
	}
	return true, nil
}

// DeleteNodes deletes the nodes from the group.
func (mig *Mig) DeleteNodes(nodes []*kube_api.Node) error {
	size, err := mig.gceManager.GetMigSize(mig)
	if err != nil {
		return err
	}
	if int(size) <= mig.MinSize() {
		return fmt.Errorf("min size reached, nodes will not be deleted")
	}
	refs := make([]*GceRef, 0, len(nodes))
	for _, node := range nodes {

		belongs, err := mig.Belongs(node)
		if err != nil {
			return err
		}
		if !belongs {
			return fmt.Errorf("%s belong to a different mig than %s", node.Name, mig.Id())
		}
		gceref, err := GceRefFromProviderId(node.Spec.ProviderID)
		if err != nil {
			return err
		}
		refs = append(refs, gceref)
	}
	return mig.gceManager.DeleteInstances(refs)
}

// Id returns mig url.
func (mig *Mig) Id() string {
	return GenerateMigUrl(mig.Project, mig.Zone, mig.Name)
}

// Debug returns a debug string for the Mig.
func (mig *Mig) Debug() string {
	return fmt.Sprintf("%s (%d:%d)", mig.Id(), mig.MinSize(), mig.MaxSize())
}

func buildMig(value string, gceManager *GceManager) (*Mig, error) {
	tokens := strings.SplitN(value, ":", 3)
	if len(tokens) != 3 {
		return nil, fmt.Errorf("wrong nodes configuration: %s", value)
	}

	mig := Mig{
		gceManager: gceManager,
	}
	if size, err := strconv.Atoi(tokens[0]); err == nil {
		if size <= 0 {
			return nil, fmt.Errorf("min size must be >= 1")
		}
		mig.minSize = size
	} else {
		return nil, fmt.Errorf("failed to set min size: %s, expected integer", tokens[0])
	}

	if size, err := strconv.Atoi(tokens[1]); err == nil {
		if size < mig.minSize {
			return nil, fmt.Errorf("max size must be greater or equal to min size")
		}
		mig.maxSize = size
	} else {
		return nil, fmt.Errorf("failed to set max size: %s, expected integer", tokens[1])
	}

	var err error
	if mig.Project, mig.Zone, mig.Name, err = ParseMigUrl(tokens[2]); err != nil {
		return nil, fmt.Errorf("failed to parse mig url: %s got error: %v", tokens[2], err)
	}
	return &mig, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 WALLIX

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 commands

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/config"
	"github.com/wallix/awless/console"
	"github.com/wallix/awless/graph"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync"
)

var (
	listAllSiblingsFlag          bool
	noAliasFlag                  bool
	showPropertiesValuesOnlyFlag []string
)

func init() {
	RootCmd.AddCommand(showCmd)
	showCmd.Flags().BoolVar(&listAllSiblingsFlag, "siblings", false, "List all the resource's siblings")
	showCmd.Flags().BoolVar(&noAliasFlag, "no-alias", false, "Disable the resolution of ID to alias")
	showCmd.Flags().StringSliceVar(&showPropertiesValuesOnlyFlag, "values-for", []string{}, "Output values only for given properties keys")
}

var showCmd = &cobra.Command{
	Use:   "show REFERENCE",
	Short: "Show a resource and its interrelations given a REFERENCE: id or name",
	Example: `  awless show i-8d43b21b            # show an instance via its ref
  awless show AIDAJ3Z24GOKHTZO4OIX6 # show a user via its ref
  awless show jsmith                # show a user via its ref,
  awless show @jsmith               # forcing search by name`,
	PersistentPreRun:  applyHooks(initLoggerHook, initAwlessEnvHook, initCloudServicesHook, initSyncerHook, firstInstallDoneHook),
	PersistentPostRun: applyHooks(verifyNewVersionHook, onVersionUpgrade),

	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return errors.New("REFERENCE required. See examples.")
		}

		ref := args[0]
		notFound := fmt.Sprintf("resource with reference '%s' not found", deprefix(ref))

		var resource *graph.Resource
		var gph *graph.Graph

		resource, gph = findResourceInLocalGraphs(ref)

		if resource == nil && localGlobalFlag {
			logger.Info(notFound)
			return nil
		} else if resource == nil {
			runFullSync()

			if resource, gph = findResourceInLocalGraphs(ref); resource == nil {
				logger.Info(notFound)
				return nil
			}
		}

		if !localGlobalFlag && config.GetAutosync() {
			srv, err := cloud.GetServiceForType(resource.Type())
			exitOn(err)
			logger.Verbosef("syncing service for %s type", resource.Type())
			if _, err = sync.DefaultSyncer.Sync(srv); err != nil {
				logger.Verbose(err)
			}
			resource, gph = findResourceInLocalGraphs(ref)
		}

		if resource != nil {
			if len(showPropertiesValuesOnlyFlag) > 0 {
				showResourceValuesOnlyFor(resource, showPropertiesValuesOnlyFlag)
				return nil
			}
			showResource(resource, gph)
		}

		return nil
	},
}

func showResourceValuesOnlyFor(resource *graph.Resource, propKeys []string) {
	var normalized []string
	for _, p := range propKeys {
		normalized = append(normalized, strings.ToLower(strings.Replace(p, " ", "", -1)))
	}

	valuesForKeys := map[string]string{}
	isIncluded := func(s string) (bool, string) {
		for _, n := range normalized {
			if n == strings.ToLower(s) {
				return true, n
			}
		}
		return false, ""
	}
	for k, v := range resource.Properties {
		if ok, p := isIncluded(k); ok {
			valuesForKeys[p] = fmt.Sprint(v)
		}
	}

	var values []string
	for _, n := range normalized {
		if v, ok := valuesForKeys[n]; ok {
			values = append(values, v)
		}
	}

	fmt.Println(strings.Join(values, ","))
}

func showResource(resource *graph.Resource, gph *graph.Graph) {
	displayer, err := console.BuildOptions(
		console.WithHeaders(console.DefaultsColumnDefinitions[resource.Type()]),
		console.WithFormat(listingFormat),
		console.WithMaxWidth(console.GetTerminalWidth()),
	).SetSource(resource).Build()
	exitOn(err)

	exitOn(displayer.Print(os.Stdout))

	var parents []*graph.Resource
	err = gph.Accept(&graph.ParentsVisitor{From: resource, Each: graph.VisitorCollectFunc(&parents)})
	exitOn(err)

	var parentsW bytes.Buffer
	var count int
	for i := len(parents) - 1; i >= 0; i-- {
		if count == 0 {
			fmt.Fprintf(&parentsW, "%s\n", printResourceRef(parents[i]))
		} else {
			fmt.Fprintf(&parentsW, "%s↳ %s\n", strings.Repeat("\t", count), printResourceRef(parents[i]))
		}
		count++
	}

	var childrenW bytes.Buffer
	var hasChildren bool
	printWithTabs := func(r *graph.Resource, distance int) error {
		var tabs bytes.Buffer
		tabs.WriteString(strings.Repeat("\t", count))
		for i := 0; i < distance; i++ {
			tabs.WriteByte('\t')
		}

		display := r.String()
		if r.Same(resource) {
			display = renderGreenFn(printResourceRef(resource))
		} else {
			hasChildren = true
		}
		fmt.Fprintf(&childrenW, "%s↳ %s\n", tabs.String(), display)
		return nil
	}
	err = gph.Accept(&graph.ChildrenVisitor{From: resource, Each: printWithTabs, IncludeFrom: true})
	exitOn(err)

	if len(parents) > 0 || hasChildren {
		fmt.Println(renderCyanBoldFn("\n# Relations:"))
		fmt.Printf(parentsW.String())
		fmt.Printf(childrenW.String())
	}

	appliedOn, err := gph.ListResourcesAppliedOn(resource)
	exitOn(err)
	printResourceList(renderCyanBoldFn("Applied on"), appliedOn)

	dependingOn, err := gph.ListResourcesDependingOn(resource)
	exitOn(err)
	printResourceList(renderCyanBoldFn("Depending on"), dependingOn)

	var siblings []*graph.Resource
	err = gph.Accept(&graph.SiblingsVisitor{From: resource, Each: graph.VisitorCollectFunc(&siblings)})
	exitOn(err)
	printResourceList(renderCyanBoldFn("Siblings"), siblings, "display all with flag --siblings")
}

func runFullSync() {
	if !config.GetAutosync() {
		logger.Info("autosync disabled")
		return
	}

	logger.Infof("cannot find resource in existing data synced locally")
	logger.Infof("running sync for current region '%s'", config.GetAWSRegion())

	var services []cloud.Service
	for _, srv := range cloud.ServiceRegistry {
		services = append(services, srv)
	}

	if _, err := sync.DefaultSyncer.Sync(services...); err != nil {
		logger.Verbose(err)
	}
}

func findResourceInLocalGraphs(ref string) (*graph.Resource, *graph.Graph) {
	g, resources := resolveResourceFromRef(ref)
	switch len(resources) {
	case 0:
		return nil, nil
	case 1:
		return resources[0], g
	default:
		logger.Infof("%d resources found with name '%s'. Show a specific resource with:", len(resources), deprefix(ref))
		for _, res := range resources {
			var buf bytes.Buffer
			buf.WriteString(fmt.Sprintf("\t`awless show %s` to show the %s", res.Id(), res.Type()))
			if state, ok := res.Properties["State"].(string); ok {
				buf.WriteString(fmt.Sprintf(" (state: '%s')", state))
			}
			logger.Infof(buf.String())
		}

		os.Exit(0)
	}

	return nil, nil
}

func resolveResourceFromRef(ref string) (*graph.Graph, []*graph.Resource) {
	g, err := sync.LoadAllLocalGraphs()
	exitOn(err)

	name := deprefix(ref)
	byName := &graph.ByProperty{Key: "Name", Value: name}

	if strings.HasPrefix(ref, "@") {
		logger.Verbosef("prefixed with @: forcing research by name '%s'", name)
		rs, err := g.ResolveResources(byName)
		exitOn(err)
		return g, rs
	} else {
		rs, err := g.ResolveResources(&graph.ById{Id: name})
		exitOn(err)

		if len(rs) > 0 {
			return g, rs
		} else {
			rs, err := g.ResolveResources(
				byName,
				&graph.ByProperty{Key: "Arn", Value: name},
			)
			exitOn(err)

			return g, rs
		}
	}
}

func deprefix(s string) string {
	return strings.TrimPrefix(s, "@")
}

func printResourceList(title string, list []*graph.Resource, shortenListMsg ...string) {
	sort.Sort(byTypeAndString{list})
	all := graph.Resources(list).Map(func(r *graph.Resource) string { return printResourceRef(r) })
	count := len(all)
	max := 3
	if count > 0 {
		if !listAllSiblingsFlag && len(shortenListMsg) > 0 && count > max {
			fmt.Printf("\n%s: %s, ... (%s)\n", title, strings.Join(all[0:max], ", "), shortenListMsg[0])
		} else {
			fmt.Printf("\n%s: %s\n", title, strings.Join(all, ", "))
		}
	}
}

func printResourceRef(r *graph.Resource) string {
	if noAliasFlag {
		return r.Format("%i[%t]")
	}
	return r.Format("%n[%t]")
}

type byTypeAndString struct {
	res []*graph.Resource
}

func (b byTypeAndString) Len() int { return len(b.res) }
func (b byTypeAndString) Swap(i, j int) {
	b.res[i], b.res[j] = b.res[j], b.res[i]
}
func (b byTypeAndString) Less(i, j int) bool {
	if b.res[i].Type() != b.res[j].Type() {
		return b.res[i].Type() < b.res[j].Type()
	}
	return b.res[i].String() <= b.res[j].String()
}
<commit_msg>Fix display of children with --no-alias flag<commit_after>/*
Copyright 2017 WALLIX

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 commands

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/spf13/cobra"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/config"
	"github.com/wallix/awless/console"
	"github.com/wallix/awless/graph"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync"
)

var (
	listAllSiblingsFlag          bool
	noAliasFlag                  bool
	showPropertiesValuesOnlyFlag []string
)

func init() {
	RootCmd.AddCommand(showCmd)
	showCmd.Flags().BoolVar(&listAllSiblingsFlag, "siblings", false, "List all the resource's siblings")
	showCmd.Flags().BoolVar(&noAliasFlag, "no-alias", false, "Disable the resolution of ID to alias")
	showCmd.Flags().StringSliceVar(&showPropertiesValuesOnlyFlag, "values-for", []string{}, "Output values only for given properties keys")
}

var showCmd = &cobra.Command{
	Use:   "show REFERENCE",
	Short: "Show a resource and its interrelations given a REFERENCE: id or name",
	Example: `  awless show i-8d43b21b            # show an instance via its ref
  awless show AIDAJ3Z24GOKHTZO4OIX6 # show a user via its ref
  awless show jsmith                # show a user via its ref,
  awless show @jsmith               # forcing search by name`,
	PersistentPreRun:  applyHooks(initLoggerHook, initAwlessEnvHook, initCloudServicesHook, initSyncerHook, firstInstallDoneHook),
	PersistentPostRun: applyHooks(verifyNewVersionHook, onVersionUpgrade),

	RunE: func(cmd *cobra.Command, args []string) error {
		if len(args) < 1 {
			return errors.New("REFERENCE required. See examples.")
		}

		ref := args[0]
		notFound := fmt.Sprintf("resource with reference '%s' not found", deprefix(ref))

		var resource *graph.Resource
		var gph *graph.Graph

		resource, gph = findResourceInLocalGraphs(ref)

		if resource == nil && localGlobalFlag {
			logger.Info(notFound)
			return nil
		} else if resource == nil {
			runFullSync()

			if resource, gph = findResourceInLocalGraphs(ref); resource == nil {
				logger.Info(notFound)
				return nil
			}
		}

		if !localGlobalFlag && config.GetAutosync() {
			srv, err := cloud.GetServiceForType(resource.Type())
			exitOn(err)
			logger.Verbosef("syncing service for %s type", resource.Type())
			if _, err = sync.DefaultSyncer.Sync(srv); err != nil {
				logger.Verbose(err)
			}
			resource, gph = findResourceInLocalGraphs(ref)
		}

		if resource != nil {
			if len(showPropertiesValuesOnlyFlag) > 0 {
				showResourceValuesOnlyFor(resource, showPropertiesValuesOnlyFlag)
				return nil
			}
			showResource(resource, gph)
		}

		return nil
	},
}

func showResourceValuesOnlyFor(resource *graph.Resource, propKeys []string) {
	var normalized []string
	for _, p := range propKeys {
		normalized = append(normalized, strings.ToLower(strings.Replace(p, " ", "", -1)))
	}

	valuesForKeys := map[string]string{}
	isIncluded := func(s string) (bool, string) {
		for _, n := range normalized {
			if n == strings.ToLower(s) {
				return true, n
			}
		}
		return false, ""
	}
	for k, v := range resource.Properties {
		if ok, p := isIncluded(k); ok {
			valuesForKeys[p] = fmt.Sprint(v)
		}
	}

	var values []string
	for _, n := range normalized {
		if v, ok := valuesForKeys[n]; ok {
			values = append(values, v)
		}
	}

	fmt.Println(strings.Join(values, ","))
}

func showResource(resource *graph.Resource, gph *graph.Graph) {
	displayer, err := console.BuildOptions(
		console.WithHeaders(console.DefaultsColumnDefinitions[resource.Type()]),
		console.WithFormat(listingFormat),
		console.WithMaxWidth(console.GetTerminalWidth()),
	).SetSource(resource).Build()
	exitOn(err)

	exitOn(displayer.Print(os.Stdout))

	var parents []*graph.Resource
	err = gph.Accept(&graph.ParentsVisitor{From: resource, Each: graph.VisitorCollectFunc(&parents)})
	exitOn(err)

	var parentsW bytes.Buffer
	var count int
	for i := len(parents) - 1; i >= 0; i-- {
		if count == 0 {
			fmt.Fprintf(&parentsW, "%s\n", printResourceRef(parents[i]))
		} else {
			fmt.Fprintf(&parentsW, "%s↳ %s\n", strings.Repeat("\t", count), printResourceRef(parents[i]))
		}
		count++
	}

	var childrenW bytes.Buffer
	var hasChildren bool
	printWithTabs := func(r *graph.Resource, distance int) error {
		var tabs bytes.Buffer
		tabs.WriteString(strings.Repeat("\t", count))
		for i := 0; i < distance; i++ {
			tabs.WriteByte('\t')
		}

		display := printResourceRef(r)
		if r.Same(resource) {
			display = renderGreenFn(printResourceRef(resource))
		} else {
			hasChildren = true
		}
		fmt.Fprintf(&childrenW, "%s↳ %s\n", tabs.String(), display)
		return nil
	}
	err = gph.Accept(&graph.ChildrenVisitor{From: resource, Each: printWithTabs, IncludeFrom: true})
	exitOn(err)

	if len(parents) > 0 || hasChildren {
		fmt.Println(renderCyanBoldFn("\n# Relations:"))
		fmt.Printf(parentsW.String())
		fmt.Printf(childrenW.String())
	}

	appliedOn, err := gph.ListResourcesAppliedOn(resource)
	exitOn(err)
	printResourceList(renderCyanBoldFn("Applied on"), appliedOn)

	dependingOn, err := gph.ListResourcesDependingOn(resource)
	exitOn(err)
	printResourceList(renderCyanBoldFn("Depending on"), dependingOn)

	var siblings []*graph.Resource
	err = gph.Accept(&graph.SiblingsVisitor{From: resource, Each: graph.VisitorCollectFunc(&siblings)})
	exitOn(err)
	printResourceList(renderCyanBoldFn("Siblings"), siblings, "display all with flag --siblings")
}

func runFullSync() {
	if !config.GetAutosync() {
		logger.Info("autosync disabled")
		return
	}

	logger.Infof("cannot find resource in existing data synced locally")
	logger.Infof("running sync for current region '%s'", config.GetAWSRegion())

	var services []cloud.Service
	for _, srv := range cloud.ServiceRegistry {
		services = append(services, srv)
	}

	if _, err := sync.DefaultSyncer.Sync(services...); err != nil {
		logger.Verbose(err)
	}
}

func findResourceInLocalGraphs(ref string) (*graph.Resource, *graph.Graph) {
	g, resources := resolveResourceFromRef(ref)
	switch len(resources) {
	case 0:
		return nil, nil
	case 1:
		return resources[0], g
	default:
		logger.Infof("%d resources found with name '%s'. Show a specific resource with:", len(resources), deprefix(ref))
		for _, res := range resources {
			var buf bytes.Buffer
			buf.WriteString(fmt.Sprintf("\t`awless show %s` to show the %s", res.Id(), res.Type()))
			if state, ok := res.Properties["State"].(string); ok {
				buf.WriteString(fmt.Sprintf(" (state: '%s')", state))
			}
			logger.Infof(buf.String())
		}

		os.Exit(0)
	}

	return nil, nil
}

func resolveResourceFromRef(ref string) (*graph.Graph, []*graph.Resource) {
	g, err := sync.LoadAllLocalGraphs()
	exitOn(err)

	name := deprefix(ref)
	byName := &graph.ByProperty{Key: "Name", Value: name}

	if strings.HasPrefix(ref, "@") {
		logger.Verbosef("prefixed with @: forcing research by name '%s'", name)
		rs, err := g.ResolveResources(byName)
		exitOn(err)
		return g, rs
	} else {
		rs, err := g.ResolveResources(&graph.ById{Id: name})
		exitOn(err)

		if len(rs) > 0 {
			return g, rs
		} else {
			rs, err := g.ResolveResources(
				byName,
				&graph.ByProperty{Key: "Arn", Value: name},
			)
			exitOn(err)

			return g, rs
		}
	}
}

func deprefix(s string) string {
	return strings.TrimPrefix(s, "@")
}

func printResourceList(title string, list []*graph.Resource, shortenListMsg ...string) {
	sort.Sort(byTypeAndString{list})
	all := graph.Resources(list).Map(func(r *graph.Resource) string { return printResourceRef(r) })
	count := len(all)
	max := 3
	if count > 0 {
		if !listAllSiblingsFlag && len(shortenListMsg) > 0 && count > max {
			fmt.Printf("\n%s: %s, ... (%s)\n", title, strings.Join(all[0:max], ", "), shortenListMsg[0])
		} else {
			fmt.Printf("\n%s: %s\n", title, strings.Join(all, ", "))
		}
	}
}

func printResourceRef(r *graph.Resource) string {
	if noAliasFlag {
		return r.Format("%i[%t]")
	}
	return r.Format("%n[%t]")
}

type byTypeAndString struct {
	res []*graph.Resource
}

func (b byTypeAndString) Len() int { return len(b.res) }
func (b byTypeAndString) Swap(i, j int) {
	b.res[i], b.res[j] = b.res[j], b.res[i]
}
func (b byTypeAndString) Less(i, j int) bool {
	if b.res[i].Type() != b.res[j].Type() {
		return b.res[i].Type() < b.res[j].Type()
	}
	return b.res[i].String() <= b.res[j].String()
}
<|endoftext|>


<commit_before>package txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
)

const (
	basezone        = "_redirect"
	defaultSub      = "www"
	defaultProtocol = "https"
)

type record struct {
	Version string
	To      string
	Code    int
	Type    string
	Vcs     string
}

// Config contains the middleware's configuration
type Config struct {
	Enable   []string
	Redirect string
}

func (r *record) Parse(str string) error {
	s := strings.Split(str, ";")
	for _, l := range s {
		switch {
		case strings.HasPrefix(l, "v="):
			l = strings.TrimPrefix(l, "v=")
			r.Version = l
			if r.Version != "txtv0" {
				return fmt.Errorf("unhandled version '%s'", r.Version)
			}
			log.Print("WARN: txtv0 is not suitable for production")

		case strings.HasPrefix(l, "to="):
			l = strings.TrimPrefix(l, "to=")
			r.To = l

		case strings.HasPrefix(l, "code="):
			l = strings.TrimPrefix(l, "code=")
			i, err := strconv.Atoi(l)
			if err != nil {
				return fmt.Errorf("could not parse status code: %s", err)
			}
			r.Code = i

		case strings.HasPrefix(l, "type="):
			l = strings.TrimPrefix(l, "type=")
			r.Type = l

		case strings.HasPrefix(l, "vcs="):
			l = strings.TrimPrefix(l, "vcs=")
			r.Vcs = l

		default:
			if r.To != "" {
				return fmt.Errorf("multiple values without keys")
			}
			r.To = l
		}
	}

	if r.Code == 0 {
		r.Code = 301
	}

	if r.Vcs == "" {
		r.Vcs = "git"
	}

	if r.Type == "" {
		r.Type = "host"
	}

	return nil
}

func getBaseTarget(rec record) (string, int) {
	return rec.To, rec.Code
}

func getRecord(host, path string) (record, error) {
	zone := strings.Join([]string{basezone, host}, ".")
	s, err := net.LookupTXT(zone)
	if err != nil {
		return record{}, fmt.Errorf("could not get TXT record: %s", err)
	}

	rec := record{}
	if err = rec.Parse(s[0]); err != nil {
		return rec, fmt.Errorf("could not parse record: %s", err)
	}

	if rec.To == "" {
		s := []string{defaultProtocol, "://", defaultSub, ".", host}
		rec.To = strings.Join(s, "")
	}

	return rec, nil
}

func contains(array []string, word string) bool {
	for _, w := range array {
		if w == word {
			return true
		}
	}
	return false
}

// Redirect the request depending on the redirect record found
func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
	host := r.Host
	path := r.URL.Path

	rec, err := getRecord(host, path)
	if err != nil {
		if strings.HasSuffix(err.Error(), "no such host") {
			s := []string{defaultProtocol, "://", defaultSub, ".", host}
			http.Redirect(w, r, strings.Join(s, ""), 301)
			return nil
		}
		return err
	}

	if !contains(c.Enable, rec.Type) {
		return fmt.Errorf("option disabled")
	}

	if rec.Type == "host" {
		to, code := getBaseTarget(rec)
		http.Redirect(w, r, to, code)
		return nil
	}

	if rec.Type == "gometa" {
		return gometa(w, rec, host, path)
	}

	return fmt.Errorf("record type %s unsupported", rec.Type)
}
<commit_msg>Make 404 the default behavior when www is disabled<commit_after>package txtdirect

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
)

const (
	basezone        = "_redirect"
	defaultSub      = "www"
	defaultProtocol = "https"
)

type record struct {
	Version string
	To      string
	Code    int
	Type    string
	Vcs     string
}

// Config contains the middleware's configuration
type Config struct {
	Enable   []string
	Redirect string
}

func (r *record) Parse(str string) error {
	s := strings.Split(str, ";")
	for _, l := range s {
		switch {
		case strings.HasPrefix(l, "v="):
			l = strings.TrimPrefix(l, "v=")
			r.Version = l
			if r.Version != "txtv0" {
				return fmt.Errorf("unhandled version '%s'", r.Version)
			}
			log.Print("WARN: txtv0 is not suitable for production")

		case strings.HasPrefix(l, "to="):
			l = strings.TrimPrefix(l, "to=")
			r.To = l

		case strings.HasPrefix(l, "code="):
			l = strings.TrimPrefix(l, "code=")
			i, err := strconv.Atoi(l)
			if err != nil {
				return fmt.Errorf("could not parse status code: %s", err)
			}
			r.Code = i

		case strings.HasPrefix(l, "type="):
			l = strings.TrimPrefix(l, "type=")
			r.Type = l

		case strings.HasPrefix(l, "vcs="):
			l = strings.TrimPrefix(l, "vcs=")
			r.Vcs = l

		default:
			if r.To != "" {
				return fmt.Errorf("multiple values without keys")
			}
			r.To = l
		}
	}

	if r.Code == 0 {
		r.Code = 301
	}

	if r.Vcs == "" {
		r.Vcs = "git"
	}

	if r.Type == "" {
		r.Type = "host"
	}

	return nil
}

func getBaseTarget(rec record) (string, int) {
	return rec.To, rec.Code
}

func getRecord(host, path string) (record, error) {
	zone := strings.Join([]string{basezone, host}, ".")
	s, err := net.LookupTXT(zone)
	if err != nil {
		return record{}, fmt.Errorf("could not get TXT record: %s", err)
	}

	rec := record{}
	if err = rec.Parse(s[0]); err != nil {
		return rec, fmt.Errorf("could not parse record: %s", err)
	}

	if rec.To == "" {
		s := []string{defaultProtocol, "://", defaultSub, ".", host}
		rec.To = strings.Join(s, "")
	}

	return rec, nil
}

func contains(array []string, word string) bool {
	for _, w := range array {
		if w == word {
			return true
		}
	}
	return false
}

// Redirect the request depending on the redirect record found
func Redirect(w http.ResponseWriter, r *http.Request, c Config) error {
	host := r.Host
	path := r.URL.Path

	rec, err := getRecord(host, path)
	if err != nil {
		if strings.HasSuffix(err.Error(), "no such host") {
			if contains(c.Enable, "www") {
				s := []string{defaultProtocol, "://", defaultSub, ".", host}
				http.Redirect(w, r, strings.Join(s, ""), 301)
				return nil
			}
			http.NotFound(w, r)
			return nil
		}
		return err
	}

	if !contains(c.Enable, rec.Type) {
		return fmt.Errorf("option disabled")
	}

	if rec.Type == "host" {
		to, code := getBaseTarget(rec)
		http.Redirect(w, r, to, code)
		return nil
	}

	if rec.Type == "gometa" {
		return gometa(w, rec, host, path)
	}

	return fmt.Errorf("record type %s unsupported", rec.Type)
}
<|endoftext|>


<commit_before>package ais

import (
	"errors"
	"strconv"
	"strings"
)

// Packet represents one line of AIS data
type Packet struct {
	Talker     string
	PacketType string
	FragCount  int
	FragNo     int
	SeqId      string
	Channel    string
	Payload    string
	FillBits   int
}

var (
	ErrEmptyPacket         = errors.New("empty packet")
	ErrInvalidPacketPrefix = errors.New("invalid prefix")
	ErrMissingChecksum     = errors.New("missing checksum")
	ErrIncorrectChecksum   = errors.New("incorrect checksum")
	ErrInvalidPacket       = errors.New("invalid packet")
)

// ParsePacket parses one line of AIS data
func ParsePacket(rawPacket string) (*Packet, error) {
	l := len(rawPacket)
	if l == 0 {
		return nil, ErrEmptyPacket
	}

	if rawPacket[0] != '!' {
		return nil, ErrInvalidPacketPrefix
	}

	checksum, err := readChecksum(rawPacket)
	if err != nil {
		return nil, err
	}

	innerMessage := rawPacket[1 : l-3]
	calculatedChecksum := calculateChecksum(innerMessage)
	if checksum != calculatedChecksum {
		return nil, ErrIncorrectChecksum
	}

	parts := strings.Split(innerMessage, ",")

	fragCount, err := toInt(parts[1])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	fragNo, err := toInt(parts[2])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	fillBits, err := toInt(parts[6])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	return &Packet{
		Talker:     parts[0][0:2],
		PacketType: parts[0][2:],
		FragCount:  fragCount,
		FragNo:     fragNo,
		SeqId:      parts[3],
		Channel:    parts[4],
		Payload:    parts[5],
		FillBits:   fillBits,
	}, nil
}

func readChecksum(rawPacket string) (byte, error) {
	l := len(rawPacket)
	if rawPacket[l-3] != '*' {
		return 0, ErrMissingChecksum
	}
	checksumN := rawPacket[l-2:]
	checksum, err := strconv.ParseUint(checksumN, 16, 8)
	if err != nil {
		panic(err)
	}
	return byte(checksum), nil
}

func calculateChecksum(s string) uint8 {
	var checksum int32
	for _, r := range s {
		checksum ^= r
	}
	return uint8(checksum)
}

func toInt(s string) (int, error) {
	return strconv.Atoi(s)
}
<commit_msg>Remove panic<commit_after>package ais

import (
	"errors"
	"strconv"
	"strings"
)

// Packet represents one line of AIS data
type Packet struct {
	Talker     string
	PacketType string
	FragCount  int
	FragNo     int
	SeqId      string
	Channel    string
	Payload    string
	FillBits   int
}

var (
	ErrEmptyPacket         = errors.New("empty packet")
	ErrInvalidPacketPrefix = errors.New("invalid prefix")
	ErrMissingChecksum     = errors.New("missing checksum")
	ErrIncorrectChecksum   = errors.New("incorrect checksum")
	ErrInvalidPacket       = errors.New("invalid packet")
)

// ParsePacket parses one line of AIS data
func ParsePacket(rawPacket string) (*Packet, error) {
	l := len(rawPacket)
	if l == 0 {
		return nil, ErrEmptyPacket
	}

	if rawPacket[0] != '!' {
		return nil, ErrInvalidPacketPrefix
	}

	checksum, err := readChecksum(rawPacket)
	if err != nil {
		return nil, err
	}

	innerMessage := rawPacket[1 : l-3]
	calculatedChecksum := calculateChecksum(innerMessage)
	if checksum != calculatedChecksum {
		return nil, ErrIncorrectChecksum
	}

	parts := strings.Split(innerMessage, ",")

	fragCount, err := toInt(parts[1])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	fragNo, err := toInt(parts[2])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	fillBits, err := toInt(parts[6])
	if err != nil {
		return nil, ErrInvalidPacket
	}
	return &Packet{
		Talker:     parts[0][0:2],
		PacketType: parts[0][2:],
		FragCount:  fragCount,
		FragNo:     fragNo,
		SeqId:      parts[3],
		Channel:    parts[4],
		Payload:    parts[5],
		FillBits:   fillBits,
	}, nil
}

func readChecksum(rawPacket string) (byte, error) {
	l := len(rawPacket)
	if rawPacket[l-3] != '*' {
		return 0, ErrMissingChecksum
	}
	checksumN := rawPacket[l-2:]
	checksum, err := strconv.ParseUint(checksumN, 16, 8)
	if err != nil {
		return 0, err
	}
	return byte(checksum), nil
}

func calculateChecksum(s string) uint8 {
	var checksum int32
	for _, r := range s {
		checksum ^= r
	}
	return uint8(checksum)
}

func toInt(s string) (int, error) {
	return strconv.Atoi(s)
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package subnets_test

import (
	"errors"

	gc "gopkg.in/check.v1"

	"github.com/juju/juju/api/base"
	apitesting "github.com/juju/juju/api/base/testing"
	"github.com/juju/juju/api/subnets"
	"github.com/juju/juju/apiserver/params"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/names"
)

// SubnetsSuite tests the client side subnets API
type SubnetsSuite struct {
	coretesting.BaseSuite

	called    int
	apiCaller base.APICaller
	api       *subnets.API
}

var _ = gc.Suite(&SubnetsSuite{})

func (s *SubnetsSuite) init(c *gc.C, args *apitesting.CheckArgs, err error) {
	s.called = 0
	s.apiCaller = apitesting.CheckingAPICaller(c, args, &s.called, err)
	s.api = subnets.NewAPI(s.apiCaller)
	c.Check(s.api, gc.NotNil)
	c.Check(s.called, gc.Equals, 0)
}

// TestNewAPISuccess checks that a new subnets API is created when passed a non-nil caller
func (s *SubnetsSuite) TestNewAPISuccess(c *gc.C) {
	var called int
	apiCaller := apitesting.CheckingAPICaller(c, nil, &called, nil)
	api := subnets.NewAPI(apiCaller)
	c.Check(api, gc.NotNil)
	c.Check(called, gc.Equals, 0)
}

// TestNewAPIWithNilCaller checks that a new subnets API is not created when passed a nil caller
func (s *SubnetsSuite) TestNewAPIWithNilCaller(c *gc.C) {
	panicFunc := func() { subnets.NewAPI(nil) }
	c.Assert(panicFunc, gc.PanicMatches, "caller is nil")
}

func makeAddSubnetsArgs(cidr, providerId, space string, zones []string) apitesting.CheckArgs {
	spaceTag := names.NewSpaceTag(space).String()
	subnetTag := names.NewSubnetTag(cidr).String()

	expectArgs := params.AddSubnetsParams{
		Subnets: []params.AddSubnetParams{
			{
				SpaceTag:         spaceTag,
				SubnetTag:        subnetTag,
				SubnetProviderId: providerId,
				Zones:            zones,
			}}}

	expectResults := params.ErrorResults{}

	args := apitesting.CheckArgs{
		Facade:  "Subnets",
		Method:  "AddSubnets",
		Args:    expectArgs,
		Results: expectResults,
	}

	return args
}

func makeCreateSubnetsArgs(cidr, space string, zones []string, isPublic bool) apitesting.CheckArgs {
	spaceTag := names.NewSpaceTag(space).String()
	subnetTag := names.NewSubnetTag(cidr).String()

	expectArgs := params.CreateSubnetsParams{
		Subnets: []params.CreateSubnetParams{
			{
				SpaceTag:  spaceTag,
				SubnetTag: subnetTag,
				Zones:     zones,
				IsPublic:  isPublic,
			}}}

	expectResults := params.ErrorResults{}

	args := apitesting.CheckArgs{
		Facade:  "Subnets",
		Method:  "CreateSubnets",
		Args:    expectArgs,
		Results: expectResults,
	}

	return args
}

func (s *SpacesSuite) TestAddSubnet(c *gc.C) {
	cidr := "1.1.1.0/24"
	providerId := "foo"
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeAddSubnetsArgs(cidr, providerId, space, zones)
	s.init(c, &args, nil)
	results, err := s.api.AddSubnet(cidr, providerId, space, zones)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.IsNil)
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SpacesSuite) TestAddSubnetFails(c *gc.C) {
	cidr := "1.1.1.0/24"
	providerId := "foo"
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeAddSubnetsArgs(cidr, providerId, space, zones)
	s.init(c, &args, errors.New("bang"))
	results, err := s.api.AddSubnet(cidr, providerId, space, zones)
	c.Check(s.called, gc.Equals, 1)
	c.Assert(err, gc.ErrorMatches, "bang")
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SpacesSuite) TestCreateSubnet(c *gc.C) {
	cidr := "1.1.1.0/24"
	space := "bar"
	zones := []string{"foo", "bar"}
	isPublic := true
	args := makeCreateSubnetsArgs(cidr, space, zones, isPublic)
	s.init(c, &args, nil)
	results, err := s.api.CreateSubnet(cidr, space, zones, isPublic)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.IsNil)
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SpacesSuite) TestCreateSubnetFails(c *gc.C) {
	cidr := "1.1.1.0/24"
	isPublic := true
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeCreateSubnetsArgs(cidr, space, zones, isPublic)
	s.init(c, &args, errors.New("bang"))
	results, err := s.api.CreateSubnet(cidr, space, zones, isPublic)
	c.Check(s.called, gc.Equals, 1)
	c.Assert(err, gc.ErrorMatches, "bang")
	c.Assert(results, gc.DeepEquals, args.Results)
}
<commit_msg>Test ListSubnets<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package subnets_test

import (
	"errors"

	gc "gopkg.in/check.v1"

	"github.com/juju/juju/api/base"
	apitesting "github.com/juju/juju/api/base/testing"
	"github.com/juju/juju/api/subnets"
	"github.com/juju/juju/apiserver/params"
	coretesting "github.com/juju/juju/testing"
	"github.com/juju/names"
)

// SubnetsSuite tests the client side subnets API
type SubnetsSuite struct {
	coretesting.BaseSuite

	called    int
	apiCaller base.APICaller
	api       *subnets.API
}

var _ = gc.Suite(&SubnetsSuite{})

func (s *SubnetsSuite) init(c *gc.C, args *apitesting.CheckArgs, err error) {
	s.called = 0
	s.apiCaller = apitesting.CheckingAPICaller(c, args, &s.called, err)
	s.api = subnets.NewAPI(s.apiCaller)
	c.Check(s.api, gc.NotNil)
	c.Check(s.called, gc.Equals, 0)
}

// TestNewAPISuccess checks that a new subnets API is created when passed a non-nil caller
func (s *SubnetsSuite) TestNewAPISuccess(c *gc.C) {
	var called int
	apiCaller := apitesting.CheckingAPICaller(c, nil, &called, nil)
	api := subnets.NewAPI(apiCaller)
	c.Check(api, gc.NotNil)
	c.Check(called, gc.Equals, 0)
}

// TestNewAPIWithNilCaller checks that a new subnets API is not created when passed a nil caller
func (s *SubnetsSuite) TestNewAPIWithNilCaller(c *gc.C) {
	panicFunc := func() { subnets.NewAPI(nil) }
	c.Assert(panicFunc, gc.PanicMatches, "caller is nil")
}

func makeAddSubnetsArgs(cidr, providerId, space string, zones []string) apitesting.CheckArgs {
	spaceTag := names.NewSpaceTag(space).String()
	subnetTag := names.NewSubnetTag(cidr).String()

	expectArgs := params.AddSubnetsParams{
		Subnets: []params.AddSubnetParams{
			{
				SpaceTag:         spaceTag,
				SubnetTag:        subnetTag,
				SubnetProviderId: providerId,
				Zones:            zones,
			}}}

	expectResults := params.ErrorResults{}

	args := apitesting.CheckArgs{
		Facade:  "Subnets",
		Method:  "AddSubnets",
		Args:    expectArgs,
		Results: expectResults,
	}

	return args
}

func makeCreateSubnetsArgs(cidr, space string, zones []string, isPublic bool) apitesting.CheckArgs {
	spaceTag := names.NewSpaceTag(space).String()
	subnetTag := names.NewSubnetTag(cidr).String()

	expectArgs := params.CreateSubnetsParams{
		Subnets: []params.CreateSubnetParams{
			{
				SpaceTag:  spaceTag,
				SubnetTag: subnetTag,
				Zones:     zones,
				IsPublic:  isPublic,
			}}}

	expectResults := params.ErrorResults{}

	args := apitesting.CheckArgs{
		Facade:  "Subnets",
		Method:  "CreateSubnets",
		Args:    expectArgs,
		Results: expectResults,
	}

	return args
}

func makeListSubnetsArgs(space names.SpaceTag, zone string) apitesting.CheckArgs {
	expectResults := params.ListSubnetsResults{}
	expectArgs := params.ListSubnetsParams{
		Filters: []params.ListSubnetsFilterParamsParams{
			{
				SpaceTag: space,
				Zone:     zone,
			}}}
	args := apitesting.CheckArgs{
		Facade:  "Subnets",
		Method:  "ListSubnets",
		Results: expectResults,
		Args:    expectArgs,
	}
	return args
}

func (s *SubnetsSuite) TestAddSubnet(c *gc.C) {
	cidr := "1.1.1.0/24"
	providerId := "foo"
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeAddSubnetsArgs(cidr, providerId, space, zones)
	s.init(c, &args, nil)
	results, err := s.api.AddSubnet(cidr, providerId, space, zones)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.IsNil)
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SubnetsSuite) TestAddSubnetFails(c *gc.C) {
	cidr := "1.1.1.0/24"
	providerId := "foo"
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeAddSubnetsArgs(cidr, providerId, space, zones)
	s.init(c, &args, errors.New("bang"))
	results, err := s.api.AddSubnet(cidr, providerId, space, zones)
	c.Check(s.called, gc.Equals, 1)
	c.Assert(err, gc.ErrorMatches, "bang")
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SubnetsSuite) TestCreateSubnet(c *gc.C) {
	cidr := "1.1.1.0/24"
	space := "bar"
	zones := []string{"foo", "bar"}
	isPublic := true
	args := makeCreateSubnetsArgs(cidr, space, zones, isPublic)
	s.init(c, &args, nil)
	results, err := s.api.CreateSubnet(cidr, space, zones, isPublic)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.IsNil)
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SubnetsSuite) TestCreateSubnetFails(c *gc.C) {
	cidr := "1.1.1.0/24"
	isPublic := true
	space := "bar"
	zones := []string{"foo", "bar"}
	args := makeCreateSubnetsArgs(cidr, space, zones, isPublic)
	s.init(c, &args, errors.New("bang"))
	results, err := s.api.CreateSubnet(cidr, space, zones, isPublic)
	c.Check(s.called, gc.Equals, 1)
	c.Assert(err, gc.ErrorMatches, "bang")
	c.Assert(results, gc.DeepEquals, args.Results)
}

func (s *SubnetsSuite) TestListSubnets(c *gc.C) {
	space := names.SpaceTag("foo")
	zone := "bar"
	args := makeListSubnetsArgs(space, zone)
	s.init(c, &args, nil)
	results, err := s.api.ListSubnets(space, zone)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.IsNil)
	c.Assert(results, gc.DeepEquals, expectResults)
}

func (s *SubnetsSuite) TestListSubnetsFails(c *gc.C) {
	space := names.SpaceTag("foo")
	zone := "bar"
	args := makeListSubnetsArgs(space, zone)
	s.init(c, &args, errors.New("bang"))
	results, err := s.api.ListSubnets(space, zone)
	c.Assert(s.called, gc.Equals, 1)
	c.Assert(err, gc.ErrorMatches, "bang")
	c.Assert(results, gc.DeepEquals, args.Results)
}
<|endoftext|>


<commit_before>// 7 february 2014

package ui

import (
	"fmt"
	"os"
)

var (
	_messageBox = user32.NewProc("MessageBoxW")
)

func _msgBox(parent *Window, primarytext string, secondarytext string, uType uint32) (result chan int) {
	// http://msdn.microsoft.com/en-us/library/windows/desktop/aa511267.aspx says "Use task dialogs whenever appropriate to achieve a consistent look and layout. Task dialogs require Windows Vista® or later, so they aren't suitable for earlier versions of Windows. If you must use a message box, separate the main instruction from the supplemental instruction with two line breaks."
	text := primarytext
	if secondarytext != "" {
		text += "\n\n" + secondarytext
	}
	ptext := toUTF16(text)
	ptitle := toUTF16(os.Args[0])
	parenthwnd := _HWND(_NULL)
	if parent != dialogWindow {
		parenthwnd = parent.sysData.hwnd
		uType |= _MB_APPLMODAL // only for this window
	} else {
		uType |= _MB_TASKMODAL // make modal to every window in the program (they're all windows of the uitask, which is a single thread)
	}
	retchan := make(chan int)
	go func() {
		ret := make(chan uiret)
		defer close(ret)
		uitask <- &uimsg{
			call: _messageBox,
			p: []uintptr{
				uintptr(parenthwnd),
				utf16ToArg(ptext),
				utf16ToArg(ptitle),
				uintptr(uType),
			},
			ret: ret,
		}
		r := <-ret
		if r.ret == 0 { // failure
			panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", r.err, uType, os.Args[0], text))
		}
		retchan <- int(r.ret)
	}()
	return retchan
}

func (w *Window) msgBox(primarytext string, secondarytext string) (done chan struct{}) {
	done = make(chan struct{})
	go func() {
		<-_msgBox(w, primarytext, secondarytext, _MB_OK)
		done <- struct{}{}
	}()
	return done
}

func (w *Window) msgBoxError(primarytext string, secondarytext string) (done chan struct{}) {
	done = make(chan struct{})
	go func() {
		<-_msgBox(w, primarytext, secondarytext, _MB_OK|_MB_ICONERROR)
		done <- struct{}{}
	}()
	return done
}
<commit_msg>Disabled MsgBox() on Windows for the time being; I'm going to restructure uitask to avoid needing to deal with channels and it's the only thing using uimsg now.<commit_after>// 7 february 2014

package ui

import (
	"fmt"
	"os"
)

var (
	_messageBox = user32.NewProc("MessageBoxW")
)

func _msgBox(parent *Window, primarytext string, secondarytext string, uType uint32) (result chan int) {
	// http://msdn.microsoft.com/en-us/library/windows/desktop/aa511267.aspx says "Use task dialogs whenever appropriate to achieve a consistent look and layout. Task dialogs require Windows Vista® or later, so they aren't suitable for earlier versions of Windows. If you must use a message box, separate the main instruction from the supplemental instruction with two line breaks."
	text := primarytext
	if secondarytext != "" {
		text += "\n\n" + secondarytext
	}
	ptext := toUTF16(text)
	ptitle := toUTF16(os.Args[0])
	parenthwnd := _HWND(_NULL)
	if parent != dialogWindow {
		parenthwnd = parent.sysData.hwnd
		uType |= _MB_APPLMODAL // only for this window
	} else {
		uType |= _MB_TASKMODAL // make modal to every window in the program (they're all windows of the uitask, which is a single thread)
	}
	retchan := make(chan int)
	go func() {
		ret := make(chan uiret)
		defer close(ret)
/* TODO
		uitask <- &uimsg{
			call: _messageBox,
			p: []uintptr{
				uintptr(parenthwnd),
				utf16ToArg(ptext),
				utf16ToArg(ptitle),
				uintptr(uType),
			},
			ret: ret,
		}
*/
		r := <-ret
		if r.ret == 0 { // failure
			panic(fmt.Sprintf("error displaying message box to user: %v\nstyle: 0x%08X\ntitle: %q\ntext:\n%s", r.err, uType, os.Args[0], text))
		}
		retchan <- int(r.ret)
	}()
	return retchan
}

func (w *Window) msgBox(primarytext string, secondarytext string) (done chan struct{}) {
	done = make(chan struct{})
	go func() {
		<-_msgBox(w, primarytext, secondarytext, _MB_OK)
		done <- struct{}{}
	}()
	return done
}

func (w *Window) msgBoxError(primarytext string, secondarytext string) (done chan struct{}) {
	done = make(chan struct{})
	go func() {
		<-_msgBox(w, primarytext, secondarytext, _MB_OK|_MB_ICONERROR)
		done <- struct{}{}
	}()
	return done
}
<|endoftext|>


<commit_before>package system

import (
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

///////////////////////////////////////////////////////////////////////////////
// Integration: ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

type Shell struct {
	coverage       bool
	gobin          string
	reportsPath    string
	defaultTimeout string
}

func NewShell(gobin, reportsPath string, coverage bool, defaultTimeout string) *Shell {
	return &Shell{
		coverage:       coverage,
		gobin:          gobin,
		reportsPath:    reportsPath,
		defaultTimeout: defaultTimeout,
	}
}

func (self *Shell) GoTest(directory, packageName string, arguments []string) (output string, err error) {
	reportFilename := strings.Replace(packageName, "/", "-", -1)
	reportPath := filepath.Join(self.reportsPath, reportFilename)
	reportData := reportPath + ".txt"
	reportHTML := reportPath + ".html"

	goconvey := findGoConvey(directory, self.gobin, packageName).Execute()
	compilation := compile(directory, self.gobin).Execute()
	withCoverage := runWithCoverage(compilation, goconvey, self.coverage, reportData, directory, self.gobin, self.defaultTimeout, arguments).Execute()
	final := runWithoutCoverage(compilation, withCoverage, goconvey, directory, self.gobin, self.defaultTimeout, arguments).Execute()
	go generateReports(final, self.coverage, directory, self.gobin, reportData, reportHTML).Execute()

	return final.Output, final.Error
}

///////////////////////////////////////////////////////////////////////////////
// Functional Core:////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

func findGoConvey(directory, gobin, packageName string) Command {
	return NewCommand(directory, gobin, "list", "-f", "'{{.TestImports}}'", packageName)
}

func compile(directory, gobin string) Command {
	return NewCommand(directory, gobin, "test", "-i")
}

func runWithCoverage(compile, goconvey Command, coverage bool, reportPath, directory, gobin, defaultTimeout string, customArguments []string) Command {
	if compile.Error != nil {
		return compile
	}

	if !coverage {
		return compile
	}

	arguments := []string{"test", "-v", "-coverprofile=" + reportPath}

	customArgsText := strings.Join(customArguments, "\t")
	if !strings.Contains(customArgsText, "-covermode=") {
		arguments = append(arguments, "-covermode=set")
	}

	if !strings.Contains(customArgsText, "-timeout=") {
		arguments = append(arguments, "-timeout="+defaultTimeout)
	}

	if strings.Contains(goconvey.Output, goconveyDSLImport) {
		arguments = append(arguments, "-json")
	}

	arguments = append(arguments, customArguments...)

	return NewCommand(directory, gobin, arguments...)
}

func runWithoutCoverage(compile, withCoverage, goconvey Command, directory, gobin, defaultTimeout string, customArguments []string) Command {
	if compile.Error != nil {
		return compile
	}

	if coverageStatementRE.MatchString(withCoverage.Output) {
		return withCoverage
	}

	log.Printf("Coverage output: %v", withCoverage.Output)

	log.Print("Run without coverage")

	arguments := []string{"test", "-v"}
	customArgsText := strings.Join(customArguments, "\t")
	if !strings.Contains(customArgsText, "-timeout=") {
		arguments = append(arguments, "-timeout="+defaultTimeout)
	}

	if strings.Contains(goconvey.Output, goconveyDSLImport) {
		arguments = append(arguments, "-json")
	}
	arguments = append(arguments, customArguments...)
	return NewCommand(directory, gobin, arguments...)
}

func generateReports(previous Command, coverage bool, directory, gobin, reportData, reportHTML string) Command {
	if previous.Error != nil {
		return previous
	}

	if !coverage {
		return previous
	}

	return NewCommand(directory, gobin, "tool", "cover", "-html="+reportData, "-o", reportHTML)
}

///////////////////////////////////////////////////////////////////////////////
// Imperative Shell: //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

type Command struct {
	directory  string
	executable string
	arguments  []string

	Output string
	Error  error
}

func NewCommand(directory, executable string, arguments ...string) Command {
	return Command{
		directory:  directory,
		executable: executable,
		arguments:  arguments,
	}
}

func (this Command) Execute() Command {
	if len(this.executable) == 0 {
		return this
	}

	if len(this.Output) > 0 || this.Error != nil {
		return this
	}

	command := exec.Command(this.executable, this.arguments...)
	command.Dir = this.directory
	var rawOutput []byte
	rawOutput, this.Error = command.CombinedOutput()
	this.Output = string(rawOutput)
	return this
}

///////////////////////////////////////////////////////////////////////////////

const goconveyDSLImport = "github.com/smartystreets/goconvey/convey " // note the trailing space: we don't want to target packages nested in the /convey package.
var coverageStatementRE = regexp.MustCompile(`(?m)^coverage: \d+\.\d% of statements(.*)$|^panic: test timed out after `)
<commit_msg>Added error checks along with hints about source of error<commit_after>package system

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

///////////////////////////////////////////////////////////////////////////////
// Integration: ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

type Shell struct {
	coverage       bool
	gobin          string
	reportsPath    string
	defaultTimeout string
}

func NewShell(gobin, reportsPath string, coverage bool, defaultTimeout string) *Shell {
	return &Shell{
		coverage:       coverage,
		gobin:          gobin,
		reportsPath:    reportsPath,
		defaultTimeout: defaultTimeout,
	}
}

func (self *Shell) GoTest(directory, packageName string, arguments []string) (output string, err error) {
	reportFilename := strings.Replace(packageName, "/", "-", -1)
	reportPath := filepath.Join(self.reportsPath, reportFilename)
	reportData := reportPath + ".txt"
	reportHTML := reportPath + ".html"

	goconvey := findGoConvey(directory, self.gobin, packageName).Execute()
	if goconvey.Error != nil {
		return fmt.Sprintf("Is your source in $GOPATH or using symbolic links?\n%s",
			goconvey.Output), goconvey.Error
	}
	compilation := compile(directory, self.gobin).Execute()
	withCoverage := runWithCoverage(compilation, goconvey, self.coverage, reportData, directory, self.gobin, self.defaultTimeout, arguments).Execute()
	if withCoverage.Error != nil {
		return withCoverage.Output, withCoverage.Error
	}
	final := runWithoutCoverage(compilation, withCoverage, goconvey, directory, self.gobin, self.defaultTimeout, arguments).Execute()
	go generateReports(final, self.coverage, directory, self.gobin, reportData, reportHTML).Execute()

	return final.Output, final.Error
}

///////////////////////////////////////////////////////////////////////////////
// Functional Core:////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

func findGoConvey(directory, gobin, packageName string) Command {
	return NewCommand(directory, gobin, "list", "-f", "'{{.TestImports}}'", packageName)
}

func compile(directory, gobin string) Command {
	return NewCommand(directory, gobin, "test", "-i")
}

func runWithCoverage(compile, goconvey Command, coverage bool, reportPath, directory, gobin, defaultTimeout string, customArguments []string) Command {
	if compile.Error != nil {
		return compile
	}

	if !coverage {
		return compile
	}

	arguments := []string{"test", "-v", "-coverprofile=" + reportPath}

	customArgsText := strings.Join(customArguments, "\t")
	if !strings.Contains(customArgsText, "-covermode=") {
		arguments = append(arguments, "-covermode=set")
	}

	if !strings.Contains(customArgsText, "-timeout=") {
		arguments = append(arguments, "-timeout="+defaultTimeout)
	}

	if strings.Contains(goconvey.Output, goconveyDSLImport) {
		arguments = append(arguments, "-json")
	}

	arguments = append(arguments, customArguments...)

	return NewCommand(directory, gobin, arguments...)
}

func runWithoutCoverage(compile, withCoverage, goconvey Command, directory, gobin, defaultTimeout string, customArguments []string) Command {
	if compile.Error != nil {
		return compile
	}

	if coverageStatementRE.MatchString(withCoverage.Output) {
		return withCoverage
	}

	log.Printf("Coverage output: %v", withCoverage.Output)

	log.Print("Run without coverage")

	arguments := []string{"test", "-v"}
	customArgsText := strings.Join(customArguments, "\t")
	if !strings.Contains(customArgsText, "-timeout=") {
		arguments = append(arguments, "-timeout="+defaultTimeout)
	}

	if strings.Contains(goconvey.Output, goconveyDSLImport) {
		arguments = append(arguments, "-json")
	}
	arguments = append(arguments, customArguments...)
	return NewCommand(directory, gobin, arguments...)
}

func generateReports(previous Command, coverage bool, directory, gobin, reportData, reportHTML string) Command {
	if previous.Error != nil {
		return previous
	}

	if !coverage {
		return previous
	}

	return NewCommand(directory, gobin, "tool", "cover", "-html="+reportData, "-o", reportHTML)
}

///////////////////////////////////////////////////////////////////////////////
// Imperative Shell: //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

type Command struct {
	directory  string
	executable string
	arguments  []string

	Output string
	Error  error
}

func NewCommand(directory, executable string, arguments ...string) Command {
	return Command{
		directory:  directory,
		executable: executable,
		arguments:  arguments,
	}
}

func (this Command) Execute() Command {
	if len(this.executable) == 0 {
		return this
	}

	if len(this.Output) > 0 || this.Error != nil {
		return this
	}

	command := exec.Command(this.executable, this.arguments...)
	command.Dir = this.directory
	var rawOutput []byte
	rawOutput, this.Error = command.CombinedOutput()
	this.Output = string(rawOutput)
	return this
}

///////////////////////////////////////////////////////////////////////////////

const goconveyDSLImport = "github.com/smartystreets/goconvey/convey " // note the trailing space: we don't want to target packages nested in the /convey package.
var coverageStatementRE = regexp.MustCompile(`(?m)^coverage: \d+\.\d% of statements(.*)$|^panic: test timed out after `)
<|endoftext|>


<commit_before><commit_msg>helper: Escape test name in TF_LOG_PATH_MASK<commit_after><|endoftext|>