<commit_before>package elasticorm_test

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/fvosberg/elasticorm"

	"gopkg.in/olivere/elastic.v5"
)

func TestDatastoreEnsureIndexExists(t *testing.T) {
	type User struct {
		Name        string `json:"name"`
		DateOfBirth string `json:"date" elasticorm:"type=date"`
	}
	client := elasticClient(t)
	deleteAllIndices(t, client)

	ds, err := elasticorm.NewDatastore(
		client,
		elasticorm.ForStruct(&User{}),
	)
	ok(t, err)
	err = ds.EnsureIndexExists()
	ok(t, err)

	indexExists(t, client, `users`)
	actMapping, err := client.GetMapping().Do(context.Background())
	ok(t, err)
	actMappingJSON, err := json.Marshal(actMapping)
	ok(t, err)
	equals(
		t,
		`{"users":{"mappings":{"user":{"properties":{"date":{"type":"date"},"name":{"type":"text"}}}}}}`,
		string(actMappingJSON),
	)
}

func TestDatastoreCreateAUser(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
	}
	elasticClient, ds := initDatastore(t, &User{})

	user := &User{
		// TODO test error on setted ID
		FirstName: `Foobar`,
		LastName:  `Barfoo`,
	}
	err := ds.Create(user)
	ok(t, err)

	if user.ID == `` {
		t.Error(`The ID of the user should be set after persisting`)
		t.FailNow()
	}
	_, err = elasticClient.Refresh().Do(context.Background())
	ok(t, err)
	gotUser := &User{}
	err = ds.Find(user.ID, gotUser)
	ok(t, err)
	equals(t, *user, *gotUser)
}

func TestDatastoreUpdateAUser(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
	}
	_, ds := initDatastore(t, &User{})

	u := &User{
		FirstName: `Pre Firstname`,
		LastName:  `Lastname`,
	}
	err := ds.Create(u)
	ok(t, err)
	u.FirstName = `Post Firstname`
	err = ds.Update(u)
	ok(t, err)

	if u.ID == `` {
		t.Error(`The ID of the user should not be empty`)
		t.FailNow()
	}
	gotUser := User{}
	err = ds.Find(u.ID, &gotUser)
	ok(t, err)
	equals(t, `Post Firstname`, gotUser.FirstName)
}

func TestDatastoreFindOneBy(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name" elasticorm:"sortable"`
		Email     string `json:"email" elasticorm:"type=keyword"`
	}
	tests := []struct {
		title         string
		users         []User
		searchField   string
		searchValue   string
		shouldFind    User
		expectedError error
		SortBy        string
		Ordering      string
	}{
		{
			title: `Find a user by email`,
			users: []User{
				User{FirstName: `Wrong user`, Email: `wrong1@bar.com`},
				User{FirstName: `The first name`, Email: `foo@bar.com`},
				User{FirstName: `Wrong user`, Email: `wrong2@bar.com`},
			},
			searchField: `Email`,
			searchValue: `foo@bar.com`,
			shouldFind:  User{FirstName: `The first name`, Email: `foo@bar.com`},
		},
		{
			title:         `Don't find a user by wrong email`,
			users:         []User{User{FirstName: `The first name`, Email: `foo@bar.com`}},
			searchField:   `Email`,
			searchValue:   `bar@foo.com`,
			shouldFind:    User{},
			expectedError: elasticorm.ErrNotFound,
		},
		{
			title:         `Search for a field which doesn't exist`,
			users:         []User{User{FirstName: `The first name`, Email: `foo@bar.com`}},
			searchField:   `email`,
			searchValue:   `foo@bar.com`,
			shouldFind:    User{},
			expectedError: errors.New(`Mapping configuration has no mapping for struct field`),
		},
		{
			title: `Search with sort - asc`,
			users: []User{
				User{FirstName: `ABC`, Email: `match@bar.com`},
				User{FirstName: `DEF`, Email: `not@bar.com`},
				User{FirstName: `GHI`, Email: `match@bar.com`},
			},
			searchField: `Email`,
			searchValue: `match@bar.com`,
			shouldFind:  User{FirstName: `ABC`, Email: `match@bar.com`},
			SortBy:      `FirstName`,
			Ordering:    `asc`,
		},
		{
			title: `Search with sort - desc`,
			users: []User{
				User{FirstName: `ABC`, Email: `match@bar.com`},
				User{FirstName: `DEF`, Email: `not@bar.com`},
				User{FirstName: `GHI`, Email: `match@bar.com`},
			},
			searchField: `Email`,
			searchValue: `match@bar.com`,
			shouldFind:  User{FirstName: `GHI`, Email: `match@bar.com`},
			SortBy:      `FirstName`,
			Ordering:    `desc`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.title, func(t *testing.T) {
			elasticClient, ds := initDatastore(t, &User{})
			for _, user := range tt.users {
				err := ds.Create(&user)
				ok(t, err)
				elasticClient.Refresh().Do(context.Background())
			}

			found := User{}
			opts := []elasticorm.QueryOptFunc{}
			if tt.SortBy != `` || tt.Ordering != `` {
				opts = append(opts, ds.SetSorting(tt.SortBy, tt.Ordering))
			}
			err := ds.FindOneBy(tt.searchField, tt.searchValue, &found, opts...)

			if tt.expectedError != nil {
				equals(t, tt.expectedError.Error(), err.Error())
			} else {
				ok(t, err)
			}
			tt.shouldFind.ID = found.ID
			equals(t, tt.shouldFind, found)
		})
	}
}

func TestFindByGeoBoundingBox(t *testing.T) {
	// TODO support deeper nested location structs like User.Home.Location
	// TODO check search on non geopoint
	type Location struct {
		Lat float64 `json:"lat"`
		Lon float64 `json:"lon"`
	}
	type User struct {
		ID       string    `json:"id" elasticorm:"id"`
		Name     string    `json:"name"`
		Location *Location `json:"loc" elasticorm:"type=geo_point"`
	}

	_, ds := initDatastore(t, &User{})
	err := ds.Create(&User{Name: "Juister", Location: &Location{Lat: 53.679598, Lon: 6.994391}})
	ok(t, err)
	err = ds.Create(&User{Name: "Swimmer", Location: &Location{Lat: 53.693986, Lon: 6.992063}})
	ok(t, err)
	ds.Refresh()
	bottomLeft := Location{
		Lat: 53.672103,
		Lon: 6.962326,
	}
	topRight := Location{
		Lat: 53.685006,
		Lon: 7.017360,
	}

	found := []User{}
	err = ds.FindByGeoBoundingBox(
		`Location`,
		elasticorm.NewBoundingBox(topRight.Lat, topRight.Lon, bottomLeft.Lat, bottomLeft.Lon),
		&found,
	)
	ok(t, err)

	equals(t, 1, len(found))
	equals(t, "Juister", found[0].Name)
}

func TestFindByGeoDistance(t *testing.T) {
	type Location struct {
		Lat float64 `json:"lat"`
		Lon float64 `json:"lon"`
	}
	type Isle struct {
		ID       string    `json:"id" elasticorm:"id"`
		Name     string    `json:"name"`
		Location *Location `json:"loc" elasticorm:"type=geo_point"`
	}

	_, ds := initDatastore(t, &Isle{})
	err := ds.Create(&Isle{Name: "Memmert", Location: &Location{Lat: 53.640652, Lon: 6.887995}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Juist", Location: &Location{Lat: 53.681747, Lon: 7.008158}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Borkum", Location: &Location{Lat: 53.640652, Lon: 6.887995}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Langeoog", Location: &Location{Lat: 53.743725, Lon: 7.481725}})
	ok(t, err)
	ds.Refresh()

	found := []Isle{}
	err = ds.FindByGeoDistance(
		`Location`,
		53.666499,
		7.050261,
		`11.1km`,
		&found,
	)
	ok(t, err)

	equals(t, 3, len(found))
	equals(t, "Juist", found[0].Name)
	equals(t, "Memmert", found[1].Name)
}

func TestFindAll(t *testing.T) {
	assertions := []struct {
		Offset        int
		Limit         int
		Order         string
		ExpectedNames []string
	}{
		{
			Offset: 0,
			Limit:  10,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 0`,
				`Unknown No. 1`,
				`Unknown No. 2`,
				`Unknown No. 3`,
				`Unknown No. 4`,
				`Unknown No. 5`,
				`Unknown No. 6`,
				`Unknown No. 7`,
				`Unknown No. 8`,
				`Unknown No. 9`,
			},
		},
		{
			Offset: 0,
			Limit:  3,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 0`,
				`Unknown No. 1`,
				`Unknown No. 2`,
			},
		},
		{
			Offset: 3,
			Limit:  3,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 3`,
				`Unknown No. 4`,
				`Unknown No. 5`,
			},
		},
		{
			Offset: 3,
			Limit:  3,
			Order:  `desc`,
			ExpectedNames: []string{
				`Unknown No. 6`,
				`Unknown No. 5`,
				`Unknown No. 4`,
			},
		},
	}

	type User struct {
		ID   string `json:"id" elasticorm:"id"`
		Name string `json:"name" elasticorm:"type=text,sortable"` // TODO error on not sorted | test with keyword
	}

	_, ds := initDatastore(t, &User{})
	err := ds.CleanUp()
	ok(t, err)
	for i := 0; i < 10; i++ {
		err := ds.Create(&User{
			Name: fmt.Sprintf("Unknown No. %d", i),
		})
		ok(t, err)
		// refresh after each creation to get the desired sorting
		ds.Refresh()
	}

	for _, a := range assertions {
		found := []User{}
		err = ds.FindAll(a.Offset, a.Limit, &found, ds.SetSorting(`Name`, a.Order))
		ok(t, err)

		equals(t, len(found), len(a.ExpectedNames))
		for i, name := range a.ExpectedNames {
			equals(t, name, found[i].Name)
		}
	}
}

func initDatastore(t *testing.T, i interface{}) (*elastic.Client, *elasticorm.Datastore) {
	client := elasticClient(t)
	deleteAllIndices(t, client)
	ds, err := elasticorm.NewDatastore(
		client,
		elasticorm.ForStruct(i),
	)
	ok(t, err)
	err = ds.EnsureIndexExists()
	ok(t, err)
	return client, ds
}

func elasticClient(t *testing.T) *elastic.Client {
	client, err := elastic.NewClient(
		elastic.SetURL(elasticSearchURL),
		elastic.SetTraceLog(fileLogger(`elastic-trace.log`)),
	)
	if err != nil {
		t.Logf(
			"Using %s as elasticsearch URL - please provide a running elasticsearch instance under this URL, or configure it with the env variable EDS_ES_URL. Be carefull, all data will be erased.",
			elasticSearchURL,
		)
		t.Error(`Could not start elasticsearch` + err.Error())
		t.FailNow()
	}
	return client
}

func fileLogger(name string) *log.Logger {
	f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		panic(err)
	}
	logger := log.New(f, ``, log.LstdFlags)
	return logger
}

func deleteAllIndices(t *testing.T, c *elastic.Client) {
	_, err := c.DeleteIndex(`_all`).Do(context.Background())
	ok(t, err)
	_, err = c.Refresh().Do(context.Background())
	ok(t, err)
}

func indexExists(t *testing.T, c *elastic.Client, indexName string) {
	_, err := c.Refresh().Do(context.Background())
	ok(t, err)
	exists, err := c.IndexExists(indexName).Do(context.Background())
	ok(t, err)
	assert(t, exists, `The index `+indexName+` should exist`)
}
<commit_msg>[BUGFIX] wrong coordinates of test fixtures<commit_after>package elasticorm_test

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/fvosberg/elasticorm"

	"gopkg.in/olivere/elastic.v5"
)

func TestDatastoreEnsureIndexExists(t *testing.T) {
	type User struct {
		Name        string `json:"name"`
		DateOfBirth string `json:"date" elasticorm:"type=date"`
	}
	client := elasticClient(t)
	deleteAllIndices(t, client)

	ds, err := elasticorm.NewDatastore(
		client,
		elasticorm.ForStruct(&User{}),
	)
	ok(t, err)
	err = ds.EnsureIndexExists()
	ok(t, err)

	indexExists(t, client, `users`)
	actMapping, err := client.GetMapping().Do(context.Background())
	ok(t, err)
	actMappingJSON, err := json.Marshal(actMapping)
	ok(t, err)
	equals(
		t,
		`{"users":{"mappings":{"user":{"properties":{"date":{"type":"date"},"name":{"type":"text"}}}}}}`,
		string(actMappingJSON),
	)
}

func TestDatastoreCreateAUser(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
	}
	elasticClient, ds := initDatastore(t, &User{})

	user := &User{
		// TODO test error on setted ID
		FirstName: `Foobar`,
		LastName:  `Barfoo`,
	}
	err := ds.Create(user)
	ok(t, err)

	if user.ID == `` {
		t.Error(`The ID of the user should be set after persisting`)
		t.FailNow()
	}
	_, err = elasticClient.Refresh().Do(context.Background())
	ok(t, err)
	gotUser := &User{}
	err = ds.Find(user.ID, gotUser)
	ok(t, err)
	equals(t, *user, *gotUser)
}

func TestDatastoreUpdateAUser(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name"`
		LastName  string `json:"last_name"`
	}
	_, ds := initDatastore(t, &User{})

	u := &User{
		FirstName: `Pre Firstname`,
		LastName:  `Lastname`,
	}
	err := ds.Create(u)
	ok(t, err)
	u.FirstName = `Post Firstname`
	err = ds.Update(u)
	ok(t, err)

	if u.ID == `` {
		t.Error(`The ID of the user should not be empty`)
		t.FailNow()
	}
	gotUser := User{}
	err = ds.Find(u.ID, &gotUser)
	ok(t, err)
	equals(t, `Post Firstname`, gotUser.FirstName)
}

func TestDatastoreFindOneBy(t *testing.T) {
	type User struct {
		ID        string `json:"id" elasticorm:"id"`
		FirstName string `json:"first_name" elasticorm:"sortable"`
		Email     string `json:"email" elasticorm:"type=keyword"`
	}
	tests := []struct {
		title         string
		users         []User
		searchField   string
		searchValue   string
		shouldFind    User
		expectedError error
		SortBy        string
		Ordering      string
	}{
		{
			title: `Find a user by email`,
			users: []User{
				User{FirstName: `Wrong user`, Email: `wrong1@bar.com`},
				User{FirstName: `The first name`, Email: `foo@bar.com`},
				User{FirstName: `Wrong user`, Email: `wrong2@bar.com`},
			},
			searchField: `Email`,
			searchValue: `foo@bar.com`,
			shouldFind:  User{FirstName: `The first name`, Email: `foo@bar.com`},
		},
		{
			title:         `Don't find a user by wrong email`,
			users:         []User{User{FirstName: `The first name`, Email: `foo@bar.com`}},
			searchField:   `Email`,
			searchValue:   `bar@foo.com`,
			shouldFind:    User{},
			expectedError: elasticorm.ErrNotFound,
		},
		{
			title:         `Search for a field which doesn't exist`,
			users:         []User{User{FirstName: `The first name`, Email: `foo@bar.com`}},
			searchField:   `email`,
			searchValue:   `foo@bar.com`,
			shouldFind:    User{},
			expectedError: errors.New(`Mapping configuration has no mapping for struct field`),
		},
		{
			title: `Search with sort - asc`,
			users: []User{
				User{FirstName: `ABC`, Email: `match@bar.com`},
				User{FirstName: `DEF`, Email: `not@bar.com`},
				User{FirstName: `GHI`, Email: `match@bar.com`},
			},
			searchField: `Email`,
			searchValue: `match@bar.com`,
			shouldFind:  User{FirstName: `ABC`, Email: `match@bar.com`},
			SortBy:      `FirstName`,
			Ordering:    `asc`,
		},
		{
			title: `Search with sort - desc`,
			users: []User{
				User{FirstName: `ABC`, Email: `match@bar.com`},
				User{FirstName: `DEF`, Email: `not@bar.com`},
				User{FirstName: `GHI`, Email: `match@bar.com`},
			},
			searchField: `Email`,
			searchValue: `match@bar.com`,
			shouldFind:  User{FirstName: `GHI`, Email: `match@bar.com`},
			SortBy:      `FirstName`,
			Ordering:    `desc`,
		},
	}

	for _, tt := range tests {
		t.Run(tt.title, func(t *testing.T) {
			elasticClient, ds := initDatastore(t, &User{})
			for _, user := range tt.users {
				err := ds.Create(&user)
				ok(t, err)
				elasticClient.Refresh().Do(context.Background())
			}

			found := User{}
			opts := []elasticorm.QueryOptFunc{}
			if tt.SortBy != `` || tt.Ordering != `` {
				opts = append(opts, ds.SetSorting(tt.SortBy, tt.Ordering))
			}
			err := ds.FindOneBy(tt.searchField, tt.searchValue, &found, opts...)

			if tt.expectedError != nil {
				equals(t, tt.expectedError.Error(), err.Error())
			} else {
				ok(t, err)
			}
			tt.shouldFind.ID = found.ID
			equals(t, tt.shouldFind, found)
		})
	}
}

func TestFindByGeoBoundingBox(t *testing.T) {
	// TODO support deeper nested location structs like User.Home.Location
	// TODO check search on non geopoint
	type Location struct {
		Lat float64 `json:"lat"`
		Lon float64 `json:"lon"`
	}
	type User struct {
		ID       string    `json:"id" elasticorm:"id"`
		Name     string    `json:"name"`
		Location *Location `json:"loc" elasticorm:"type=geo_point"`
	}

	_, ds := initDatastore(t, &User{})
	err := ds.Create(&User{Name: "Juister", Location: &Location{Lat: 53.679598, Lon: 6.994391}})
	ok(t, err)
	err = ds.Create(&User{Name: "Swimmer", Location: &Location{Lat: 53.693986, Lon: 6.992063}})
	ok(t, err)
	ds.Refresh()
	bottomLeft := Location{
		Lat: 53.672103,
		Lon: 6.962326,
	}
	topRight := Location{
		Lat: 53.685006,
		Lon: 7.017360,
	}

	found := []User{}
	err = ds.FindByGeoBoundingBox(
		`Location`,
		elasticorm.NewBoundingBox(topRight.Lat, topRight.Lon, bottomLeft.Lat, bottomLeft.Lon),
		&found,
	)
	ok(t, err)

	equals(t, 1, len(found))
	equals(t, "Juister", found[0].Name)
}

func TestFindByGeoDistance(t *testing.T) {
	type Location struct {
		Lat float64 `json:"lat"`
		Lon float64 `json:"lon"`
	}
	type Isle struct {
		ID       string    `json:"id" elasticorm:"id"`
		Name     string    `json:"name"`
		Location *Location `json:"loc" elasticorm:"type=geo_point"`
	}

	_, ds := initDatastore(t, &Isle{})
	err := ds.Create(&Isle{Name: "Memmert", Location: &Location{Lat: 53.640652, Lon: 6.887995}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Juist", Location: &Location{Lat: 53.681747, Lon: 7.008158}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Borkum", Location: &Location{Lat: 53.600230, Lon: 6.711053}})
	ok(t, err)
	err = ds.Create(&Isle{Name: "Langeoog", Location: &Location{Lat: 53.743725, Lon: 7.481725}})
	ok(t, err)
	ds.Refresh()

	found := []Isle{}
	err = ds.FindByGeoDistance(
		`Location`,
		53.666499,
		7.050261,
		`11.1km`,
		&found,
	)
	ok(t, err)

	equals(t, 2, len(found))
	equals(t, "Juist", found[0].Name)
	equals(t, "Memmert", found[1].Name)
}

func TestFindAll(t *testing.T) {
	assertions := []struct {
		Offset        int
		Limit         int
		Order         string
		ExpectedNames []string
	}{
		{
			Offset: 0,
			Limit:  10,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 0`,
				`Unknown No. 1`,
				`Unknown No. 2`,
				`Unknown No. 3`,
				`Unknown No. 4`,
				`Unknown No. 5`,
				`Unknown No. 6`,
				`Unknown No. 7`,
				`Unknown No. 8`,
				`Unknown No. 9`,
			},
		},
		{
			Offset: 0,
			Limit:  3,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 0`,
				`Unknown No. 1`,
				`Unknown No. 2`,
			},
		},
		{
			Offset: 3,
			Limit:  3,
			Order:  `asc`,
			ExpectedNames: []string{
				`Unknown No. 3`,
				`Unknown No. 4`,
				`Unknown No. 5`,
			},
		},
		{
			Offset: 3,
			Limit:  3,
			Order:  `desc`,
			ExpectedNames: []string{
				`Unknown No. 6`,
				`Unknown No. 5`,
				`Unknown No. 4`,
			},
		},
	}

	type User struct {
		ID   string `json:"id" elasticorm:"id"`
		Name string `json:"name" elasticorm:"type=text,sortable"` // TODO error on not sorted | test with keyword
	}

	_, ds := initDatastore(t, &User{})
	err := ds.CleanUp()
	ok(t, err)
	for i := 0; i < 10; i++ {
		err := ds.Create(&User{
			Name: fmt.Sprintf("Unknown No. %d", i),
		})
		ok(t, err)
		// refresh after each creation to get the desired sorting
		ds.Refresh()
	}

	for _, a := range assertions {
		found := []User{}
		err = ds.FindAll(a.Offset, a.Limit, &found, ds.SetSorting(`Name`, a.Order))
		ok(t, err)

		equals(t, len(found), len(a.ExpectedNames))
		for i, name := range a.ExpectedNames {
			equals(t, name, found[i].Name)
		}
	}
}

func initDatastore(t *testing.T, i interface{}) (*elastic.Client, *elasticorm.Datastore) {
	client := elasticClient(t)
	deleteAllIndices(t, client)
	ds, err := elasticorm.NewDatastore(
		client,
		elasticorm.ForStruct(i),
	)
	ok(t, err)
	err = ds.EnsureIndexExists()
	ok(t, err)
	return client, ds
}

func elasticClient(t *testing.T) *elastic.Client {
	client, err := elastic.NewClient(
		elastic.SetURL(elasticSearchURL),
		elastic.SetTraceLog(fileLogger(`elastic-trace.log`)),
	)
	if err != nil {
		t.Logf(
			"Using %s as elasticsearch URL - please provide a running elasticsearch instance under this URL, or configure it with the env variable EDS_ES_URL. Be carefull, all data will be erased.",
			elasticSearchURL,
		)
		t.Error(`Could not start elasticsearch` + err.Error())
		t.FailNow()
	}
	return client
}

func fileLogger(name string) *log.Logger {
	f, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		panic(err)
	}
	logger := log.New(f, ``, log.LstdFlags)
	return logger
}

func deleteAllIndices(t *testing.T, c *elastic.Client) {
	_, err := c.DeleteIndex(`_all`).Do(context.Background())
	ok(t, err)
	_, err = c.Refresh().Do(context.Background())
	ok(t, err)
}

func indexExists(t *testing.T, c *elastic.Client, indexName string) {
	_, err := c.Refresh().Do(context.Background())
	ok(t, err)
	exists, err := c.IndexExists(indexName).Do(context.Background())
	ok(t, err)
	assert(t, exists, `The index `+indexName+` should exist`)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/go-ini/ini"
)

func main() {

	args := os.Args[1:]
	text2analize := ""
	attribts := new(attributes)
	setupfile := "setup.ini"

	//Carregar setup através do .ini
	cfg, err := ini.Load(setupfile)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	err = cfg.Section("attributes").MapTo(attribts)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	/*Caso existam argumentos de entrada,
	se comporta apenas como aplicação de console,
	caso contrário se comporta como serviço de api web*/
	if len(args) != 0 {
		for i := 0; i < len(args); i++ {
			if args[i] == "-m" {
				attribts.Method = args[i+1]
				i = i + 1
			} else {
				text2analize += args[i] + " "
			}

		}
		log.Println(execNlpnetCommand(attribts, text2analize))

	} else {
		http.HandleFunc("/parser", func(w http.ResponseWriter, r *http.Request) {

			/* Valida as entradas e carrega a estrutura */
			if method := r.FormValue("method"); method != "" {
				attribts.Method = method
			}
			if txt := r.FormValue("txt"); txt != "" {
				text2analize = txt
			}

			/* Retorna a mensagem analisada */
			io.WriteString(w, execNlpnetCommand(attribts, text2analize))

		})
		fmt.Printf("nlpnet2go running at: %s\n", attribts.Port)
		http.ListenAndServe(":"+attribts.Port, nil)

	}

}

func execNlpnetCommand(attribts *attributes, text2analize string) string {

	cmdArgs := []string{attribts.Nlpnet2gopy, "-t", text2analize, "-m", attribts.Method}
	cmd := exec.Command(attribts.CmdName, cmdArgs...)

	cmdReader, err := cmd.Output()
	if err != nil {
		fmt.Printf("Error: [%s]", err.Error())
		os.Exit(1)
	}

	/* Conversão para JSON */
	var result string
	if attribts.Method == "pos" {
		//fmt.Printf("%s\n", string(cmdReader))
		/*
			Os replaces abaixo são para tratar o retorno do nlpnet.
			Exemplo: [[(u'o', u'ART'), (u'rato', u'N'), (u'roeu', u'V'), (u'a', u'ART'), (u'roupa', u'N'), (u'do', u'PREP+ART'), (u'rei', u'N'), (u'de', u'PREP'), (u'roma', u'N'), (u'com', u'PREP'), (u'queijo', u'N')]]
		*/
		replacer := strings.NewReplacer("[", "", "]", "", "(u'", "", " u'", "", "'", "", "),", ");")
		replacerInsider := strings.NewReplacer("(", "", ")", "")
		result = replacer.Replace(string(cmdReader))
		retornos := strings.Split(result, ";")
		result = ""
		ret := Retorno{}
		arrRetornoItems := []RetornoItem{}
		for _, item := range retornos {
			item = replacerInsider.Replace(item)
			chaveValores := strings.Split(item, ",")
			tipo := strings.TrimSpace(chaveValores[1])
			valor := strings.TrimSpace(chaveValores[0])
			if tipo == "N" || tipo == "NPROP" {
				if valor == "queijo" {
					tipo = "ALIMENTO"
				}
			}
			retItem := RetornoItem{Chave: tipo, Valor: valor}
			arrRetornoItems = append(arrRetornoItems, retItem)
			fmt.Printf("Tipo: [%s] Valor: [%s]\n", tipo, valor)
		}
		ret.RetornoItems = arrRetornoItems
		jsonret, err := json.Marshal(ret)
		if err != nil {
			return "Erro na geracao do JSON. Erro: " + err.Error()
		}
		return string(jsonret)
	} else {
		return string(cmdReader)
	}
	return ""

}

type attributes struct {
	Method      string `ini:"method"`
	Port        string `ini:"port"`
	CmdName     string `ini:"cmdName"`
	Nlpnet2gopy string `ini:"nlpnet2gopy"`
	Setdatadir  string `ini:"setdatadir"`
}

type Retorno struct {
	RetornoItems []RetornoItem `json:"items"`
}
type RetornoItem struct {
	Chave string `json:"chave"`
	Valor string `json:"valor"`
}
<commit_msg>remove unnecessary return<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"

	"github.com/go-ini/ini"
)

func main() {

	args := os.Args[1:]
	text2analize := ""
	attribts := new(attributes)
	setupfile := "setup.ini"

	//Carregar setup através do .ini
	cfg, err := ini.Load(setupfile)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	err = cfg.Section("attributes").MapTo(attribts)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		os.Exit(1)
	}

	/*Caso existam argumentos de entrada,
	se comporta apenas como aplicação de console,
	caso contrário se comporta como serviço de api web*/
	if len(args) != 0 {
		for i := 0; i < len(args); i++ {
			if args[i] == "-m" {
				attribts.Method = args[i+1]
				i = i + 1
			} else {
				text2analize += args[i] + " "
			}

		}
		log.Println(execNlpnetCommand(attribts, text2analize))

	} else {
		http.HandleFunc("/parser", func(w http.ResponseWriter, r *http.Request) {

			/* Valida as entradas e carrega a estrutura */
			if method := r.FormValue("method"); method != "" {
				attribts.Method = method
			}
			if txt := r.FormValue("txt"); txt != "" {
				text2analize = txt
			}

			/* Retorna a mensagem analisada */
			io.WriteString(w, execNlpnetCommand(attribts, text2analize))

		})
		fmt.Printf("nlpnet2go running at: %s\n", attribts.Port)
		http.ListenAndServe(":"+attribts.Port, nil)

	}

}

func execNlpnetCommand(attribts *attributes, text2analize string) string {

	cmdArgs := []string{attribts.Nlpnet2gopy, "-t", text2analize, "-m", attribts.Method}
	cmd := exec.Command(attribts.CmdName, cmdArgs...)

	cmdReader, err := cmd.Output()
	if err != nil {
		fmt.Printf("Error: [%s]", err.Error())
		os.Exit(1)
	}

	/* Conversão para JSON */
	var result string
	if attribts.Method == "pos" {
		//fmt.Printf("%s\n", string(cmdReader))
		/*
			Os replaces abaixo são para tratar o retorno do nlpnet.
			Exemplo: [[(u'o', u'ART'), (u'rato', u'N'), (u'roeu', u'V'), (u'a', u'ART'), (u'roupa', u'N'), (u'do', u'PREP+ART'), (u'rei', u'N'), (u'de', u'PREP'), (u'roma', u'N'), (u'com', u'PREP'), (u'queijo', u'N')]]
		*/
		replacer := strings.NewReplacer("[", "", "]", "", "(u'", "", " u'", "", "'", "", "),", ");")
		replacerInsider := strings.NewReplacer("(", "", ")", "")
		result = replacer.Replace(string(cmdReader))
		retornos := strings.Split(result, ";")
		result = ""
		ret := Retorno{}
		arrRetornoItems := []RetornoItem{}
		for _, item := range retornos {
			item = replacerInsider.Replace(item)
			chaveValores := strings.Split(item, ",")
			tipo := strings.TrimSpace(chaveValores[1])
			valor := strings.TrimSpace(chaveValores[0])
			if tipo == "N" || tipo == "NPROP" {
				if valor == "queijo" {
					tipo = "ALIMENTO"
				}
			}
			retItem := RetornoItem{Chave: tipo, Valor: valor}
			arrRetornoItems = append(arrRetornoItems, retItem)
			fmt.Printf("Tipo: [%s] Valor: [%s]\n", tipo, valor)
		}
		ret.RetornoItems = arrRetornoItems
		jsonret, err := json.Marshal(ret)
		if err != nil {
			return "Erro na geracao do JSON. Erro: " + err.Error()
		}
		return string(jsonret)
	} else {
		return string(cmdReader)
	}

}

type attributes struct {
	Method      string `ini:"method"`
	Port        string `ini:"port"`
	CmdName     string `ini:"cmdName"`
	Nlpnet2gopy string `ini:"nlpnet2gopy"`
	Setdatadir  string `ini:"setdatadir"`
}

type Retorno struct {
	RetornoItems []RetornoItem `json:"items"`
}
type RetornoItem struct {
	Chave string `json:"chave"`
	Valor string `json:"valor"`
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/autoscaling"
)

func resource_aws_autoscaling_group_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	var err error
	autoScalingGroupOpts := autoscaling.CreateAutoScalingGroup{}

	if rs.Attributes["min_size"] != "" {
		autoScalingGroupOpts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"])
		autoScalingGroupOpts.SetMinSize = true
	}

	if rs.Attributes["max_size"] != "" {
		autoScalingGroupOpts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"])
		autoScalingGroupOpts.SetMaxSize = true
	}

	if rs.Attributes["default_cooldown"] != "" {
		autoScalingGroupOpts.DefaultCooldown, err = strconv.Atoi(rs.Attributes["default_cooldown"])
		autoScalingGroupOpts.SetDefaultCooldown = true
	}

	if rs.Attributes["desired_capacity"] != "" {
		autoScalingGroupOpts.DesiredCapacity, err = strconv.Atoi(rs.Attributes["desired_capacity"])
		autoScalingGroupOpts.SetDesiredCapacity = true
	}

	if rs.Attributes["health_check_grace_period"] != "" {
		autoScalingGroupOpts.HealthCheckGracePeriod, err = strconv.Atoi(rs.Attributes["health_check_grace_period"])
		autoScalingGroupOpts.SetHealthCheckGracePeriod = true
	}

	if err != nil {
		return nil, fmt.Errorf("Error parsing configuration: %s", err)
	}

	if _, ok := rs.Attributes["availability_zones.#"]; ok {
		autoScalingGroupOpts.AvailZone = expandStringList(flatmap.Expand(
			rs.Attributes, "availability_zones").([]interface{}))
	}

	if _, ok := rs.Attributes["load_balancers.#"]; ok {
		autoScalingGroupOpts.LoadBalancerNames = expandStringList(flatmap.Expand(
			rs.Attributes, "load_balancers").([]interface{}))
	}

	if _, ok := rs.Attributes["vpc_identifier.#"]; ok {
		autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(flatmap.Expand(
			rs.Attributes, "vpc_identifier").([]interface{}))
	}

	autoScalingGroupOpts.Name = rs.Attributes["name"]
	autoScalingGroupOpts.HealthCheckType = rs.Attributes["health_check_type"]
	autoScalingGroupOpts.LaunchConfigurationName = rs.Attributes["launch_configuration"]

	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
	_, err = autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
	if err != nil {
		return nil, fmt.Errorf("Error creating AutoScaling Group: %s", err)
	}

	rs.ID = rs.Attributes["name"]
	rs.Dependencies = []terraform.ResourceDependency{
		terraform.ResourceDependency{ID: rs.Attributes["launch_configuration"]},
	}

	log.Printf("[INFO] AutoScaling Group ID: %s", rs.ID)

	g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn)
	if err != nil {
		return rs, err
	}

	return resource_aws_autoscaling_group_update_state(rs, g)
}

func resource_aws_autoscaling_group_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn
	rs := s.MergeDiff(d)

	opts := autoscaling.UpdateAutoScalingGroup{
		Name: rs.ID,
	}

	var err error

	if _, ok := d.Attributes["min_size"]; ok {
		opts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"])
		opts.SetMinSize = true
	}

	if _, ok := d.Attributes["max_size"]; ok {
		opts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"])
		opts.SetMaxSize = true
	}

	if err != nil {
		return s, fmt.Errorf("Error parsing configuration: %s", err)
	}

	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)

	_, err = autoscalingconn.UpdateAutoScalingGroup(&opts)

	if err != nil {
		return rs, fmt.Errorf("Error updating AutoScaling group: %s", err)
	}

	g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn)

	if err != nil {
		return rs, err
	}

	return resource_aws_autoscaling_group_update_state(rs, g)
}

func resource_aws_autoscaling_group_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	log.Printf("[DEBUG] AutoScaling Group destroy: %v", s.ID)

	deleteopts := autoscaling.DeleteAutoScalingGroup{Name: s.ID}

	// You can force an autoscaling group to delete
	// even if it's in the process of scaling a resource.
	// Normally, you would set the min-size and max-size to 0,0
	// and then delete the group. This bypasses that and leaves
	// resources potentially dangling.
	if s.Attributes["force_delete"] != "" {
		deleteopts.ForceDelete = true
	}

	_, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts)

	if err != nil {
		autoscalingerr, ok := err.(*autoscaling.Error)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			return nil
		}
		return err
	}

	return nil
}

func resource_aws_autoscaling_group_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	g, err := resource_aws_autoscaling_group_retrieve(s.ID, autoscalingconn)

	if err != nil {
		return s, err
	}

	return resource_aws_autoscaling_group_update_state(s, g)
}

func resource_aws_autoscaling_group_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {

	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"availability_zone":         diff.AttrTypeCreate,
			"default_cooldown":          diff.AttrTypeCreate,
			"desired_capacity":          diff.AttrTypeCreate,
			"force_delete":              diff.AttrTypeCreate,
			"health_check_grace_period": diff.AttrTypeCreate,
			"health_check_type":         diff.AttrTypeCreate,
			"launch_configuration":      diff.AttrTypeCreate,
			"load_balancers":            diff.AttrTypeCreate,
			"name":                      diff.AttrTypeCreate,
			"vpc_zone_identifier":       diff.AttrTypeCreate,

			"max_size": diff.AttrTypeUpdate,
			"min_size": diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"health_check_grace_period",
			"health_check_type",
			"default_cooldown",
			"vpc_zone_identifier",
			"desired_capacity",
			"force_delete",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_autoscaling_group_update_state(
	s *terraform.ResourceState,
	g *autoscaling.AutoScalingGroup) (*terraform.ResourceState, error) {

	s.Attributes["min_size"] = strconv.Itoa(g.MinSize)
	s.Attributes["max_size"] = strconv.Itoa(g.MaxSize)
	s.Attributes["default_cooldown"] = strconv.Itoa(g.DefaultCooldown)
	s.Attributes["name"] = g.Name
	s.Attributes["desired_capacity"] = strconv.Itoa(g.DesiredCapacity)
	s.Attributes["health_check_grace_period"] = strconv.Itoa(g.HealthCheckGracePeriod)
	s.Attributes["health_check_type"] = g.HealthCheckType
	s.Attributes["launch_configuration"] = g.LaunchConfigurationName
	s.Attributes["vpc_zone_identifier"] = g.VPCZoneIdentifier

	// Flatten our group values
	toFlatten := make(map[string]interface{})

	// Special case the return of amazons load balancers names in the XML having
	// a blank entry
	if len(g.LoadBalancerNames) > 0 && g.LoadBalancerNames[0].LoadBalancerName != "" {
		toFlatten["load_balancers"] = flattenLoadBalancers(g.LoadBalancerNames)
	}

	toFlatten["availability_zones"] = flattenAvailabilityZones(g.AvailabilityZones)

	for k, v := range flatmap.Flatten(toFlatten) {
		s.Attributes[k] = v
	}

	return s, nil
}

// Returns a single group by its ID
func resource_aws_autoscaling_group_retrieve(id string, autoscalingconn *autoscaling.AutoScaling) (*autoscaling.AutoScalingGroup, error) {
	describeOpts := autoscaling.DescribeAutoScalingGroups{
		Names: []string{id},
	}

	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)

	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)

	if err != nil {
		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
	}

	// Verify AWS returned our sg
	if len(describeGroups.AutoScalingGroups) != 1 ||
		describeGroups.AutoScalingGroups[0].Name != id {
		if err != nil {
			return nil, fmt.Errorf("Unable to find AutoScaling group: %#v", describeGroups.AutoScalingGroups)
		}
	}

	g := describeGroups.AutoScalingGroups[0]

	return &g, nil
}

func resource_aws_autoscaling_group_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"name",
			"max_size",
			"min_size",
			"availability_zones.*",
			"launch_configuration",
		},
		Optional: []string{
			"health_check_grace_period",
			"health_check_type",
			"desired_capacity",
			"force_delete",
		},
	}
}
<commit_msg>Allow 'load_balancers.*' to pass resource_aws_autoscaling_group_validation<commit_after>package aws

import (
	"fmt"
	"log"
	"strconv"

	"github.com/hashicorp/terraform/flatmap"
	"github.com/hashicorp/terraform/helper/config"
	"github.com/hashicorp/terraform/helper/diff"
	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/goamz/autoscaling"
)

func resource_aws_autoscaling_group_create(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	// Merge the diff into the state so that we have all the attributes
	// properly.
	rs := s.MergeDiff(d)

	var err error
	autoScalingGroupOpts := autoscaling.CreateAutoScalingGroup{}

	if rs.Attributes["min_size"] != "" {
		autoScalingGroupOpts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"])
		autoScalingGroupOpts.SetMinSize = true
	}

	if rs.Attributes["max_size"] != "" {
		autoScalingGroupOpts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"])
		autoScalingGroupOpts.SetMaxSize = true
	}

	if rs.Attributes["default_cooldown"] != "" {
		autoScalingGroupOpts.DefaultCooldown, err = strconv.Atoi(rs.Attributes["default_cooldown"])
		autoScalingGroupOpts.SetDefaultCooldown = true
	}

	if rs.Attributes["desired_capacity"] != "" {
		autoScalingGroupOpts.DesiredCapacity, err = strconv.Atoi(rs.Attributes["desired_capacity"])
		autoScalingGroupOpts.SetDesiredCapacity = true
	}

	if rs.Attributes["health_check_grace_period"] != "" {
		autoScalingGroupOpts.HealthCheckGracePeriod, err = strconv.Atoi(rs.Attributes["health_check_grace_period"])
		autoScalingGroupOpts.SetHealthCheckGracePeriod = true
	}

	if err != nil {
		return nil, fmt.Errorf("Error parsing configuration: %s", err)
	}

	if _, ok := rs.Attributes["availability_zones.#"]; ok {
		autoScalingGroupOpts.AvailZone = expandStringList(flatmap.Expand(
			rs.Attributes, "availability_zones").([]interface{}))
	}

	if _, ok := rs.Attributes["load_balancers.#"]; ok {
		autoScalingGroupOpts.LoadBalancerNames = expandStringList(flatmap.Expand(
			rs.Attributes, "load_balancers").([]interface{}))
	}

	if _, ok := rs.Attributes["vpc_identifier.#"]; ok {
		autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(flatmap.Expand(
			rs.Attributes, "vpc_identifier").([]interface{}))
	}

	autoScalingGroupOpts.Name = rs.Attributes["name"]
	autoScalingGroupOpts.HealthCheckType = rs.Attributes["health_check_type"]
	autoScalingGroupOpts.LaunchConfigurationName = rs.Attributes["launch_configuration"]

	log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts)
	_, err = autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts)
	if err != nil {
		return nil, fmt.Errorf("Error creating AutoScaling Group: %s", err)
	}

	rs.ID = rs.Attributes["name"]
	rs.Dependencies = []terraform.ResourceDependency{
		terraform.ResourceDependency{ID: rs.Attributes["launch_configuration"]},
	}

	log.Printf("[INFO] AutoScaling Group ID: %s", rs.ID)

	g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn)
	if err != nil {
		return rs, err
	}

	return resource_aws_autoscaling_group_update_state(rs, g)
}

func resource_aws_autoscaling_group_update(
	s *terraform.ResourceState,
	d *terraform.ResourceDiff,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn
	rs := s.MergeDiff(d)

	opts := autoscaling.UpdateAutoScalingGroup{
		Name: rs.ID,
	}

	var err error

	if _, ok := d.Attributes["min_size"]; ok {
		opts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"])
		opts.SetMinSize = true
	}

	if _, ok := d.Attributes["max_size"]; ok {
		opts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"])
		opts.SetMaxSize = true
	}

	if err != nil {
		return s, fmt.Errorf("Error parsing configuration: %s", err)
	}

	log.Printf("[DEBUG] AutoScaling Group update configuration: %#v", opts)

	_, err = autoscalingconn.UpdateAutoScalingGroup(&opts)

	if err != nil {
		return rs, fmt.Errorf("Error updating AutoScaling group: %s", err)
	}

	g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn)

	if err != nil {
		return rs, err
	}

	return resource_aws_autoscaling_group_update_state(rs, g)
}

func resource_aws_autoscaling_group_destroy(
	s *terraform.ResourceState,
	meta interface{}) error {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	log.Printf("[DEBUG] AutoScaling Group destroy: %v", s.ID)

	deleteopts := autoscaling.DeleteAutoScalingGroup{Name: s.ID}

	// You can force an autoscaling group to delete
	// even if it's in the process of scaling a resource.
	// Normally, you would set the min-size and max-size to 0,0
	// and then delete the group. This bypasses that and leaves
	// resources potentially dangling.
	if s.Attributes["force_delete"] != "" {
		deleteopts.ForceDelete = true
	}

	_, err := autoscalingconn.DeleteAutoScalingGroup(&deleteopts)

	if err != nil {
		autoscalingerr, ok := err.(*autoscaling.Error)
		if ok && autoscalingerr.Code == "InvalidGroup.NotFound" {
			return nil
		}
		return err
	}

	return nil
}

func resource_aws_autoscaling_group_refresh(
	s *terraform.ResourceState,
	meta interface{}) (*terraform.ResourceState, error) {
	p := meta.(*ResourceProvider)
	autoscalingconn := p.autoscalingconn

	g, err := resource_aws_autoscaling_group_retrieve(s.ID, autoscalingconn)

	if err != nil {
		return s, err
	}

	return resource_aws_autoscaling_group_update_state(s, g)
}

func resource_aws_autoscaling_group_diff(
	s *terraform.ResourceState,
	c *terraform.ResourceConfig,
	meta interface{}) (*terraform.ResourceDiff, error) {

	b := &diff.ResourceBuilder{
		Attrs: map[string]diff.AttrType{
			"availability_zone":         diff.AttrTypeCreate,
			"default_cooldown":          diff.AttrTypeCreate,
			"desired_capacity":          diff.AttrTypeCreate,
			"force_delete":              diff.AttrTypeCreate,
			"health_check_grace_period": diff.AttrTypeCreate,
			"health_check_type":         diff.AttrTypeCreate,
			"launch_configuration":      diff.AttrTypeCreate,
			"load_balancers":            diff.AttrTypeCreate,
			"name":                      diff.AttrTypeCreate,
			"vpc_zone_identifier":       diff.AttrTypeCreate,

			"max_size": diff.AttrTypeUpdate,
			"min_size": diff.AttrTypeUpdate,
		},

		ComputedAttrs: []string{
			"health_check_grace_period",
			"health_check_type",
			"default_cooldown",
			"vpc_zone_identifier",
			"desired_capacity",
			"force_delete",
		},
	}

	return b.Diff(s, c)
}

func resource_aws_autoscaling_group_update_state(
	s *terraform.ResourceState,
	g *autoscaling.AutoScalingGroup) (*terraform.ResourceState, error) {

	s.Attributes["min_size"] = strconv.Itoa(g.MinSize)
	s.Attributes["max_size"] = strconv.Itoa(g.MaxSize)
	s.Attributes["default_cooldown"] = strconv.Itoa(g.DefaultCooldown)
	s.Attributes["name"] = g.Name
	s.Attributes["desired_capacity"] = strconv.Itoa(g.DesiredCapacity)
	s.Attributes["health_check_grace_period"] = strconv.Itoa(g.HealthCheckGracePeriod)
	s.Attributes["health_check_type"] = g.HealthCheckType
	s.Attributes["launch_configuration"] = g.LaunchConfigurationName
	s.Attributes["vpc_zone_identifier"] = g.VPCZoneIdentifier

	// Flatten our group values
	toFlatten := make(map[string]interface{})

	// Special case the return of amazons load balancers names in the XML having
	// a blank entry
	if len(g.LoadBalancerNames) > 0 && g.LoadBalancerNames[0].LoadBalancerName != "" {
		toFlatten["load_balancers"] = flattenLoadBalancers(g.LoadBalancerNames)
	}

	toFlatten["availability_zones"] = flattenAvailabilityZones(g.AvailabilityZones)

	for k, v := range flatmap.Flatten(toFlatten) {
		s.Attributes[k] = v
	}

	return s, nil
}

// Returns a single group by its ID
func resource_aws_autoscaling_group_retrieve(id string, autoscalingconn *autoscaling.AutoScaling) (*autoscaling.AutoScalingGroup, error) {
	describeOpts := autoscaling.DescribeAutoScalingGroups{
		Names: []string{id},
	}

	log.Printf("[DEBUG] AutoScaling Group describe configuration: %#v", describeOpts)

	describeGroups, err := autoscalingconn.DescribeAutoScalingGroups(&describeOpts)

	if err != nil {
		return nil, fmt.Errorf("Error retrieving AutoScaling groups: %s", err)
	}

	// Verify AWS returned our sg
	if len(describeGroups.AutoScalingGroups) != 1 ||
		describeGroups.AutoScalingGroups[0].Name != id {
		if err != nil {
			return nil, fmt.Errorf("Unable to find AutoScaling group: %#v", describeGroups.AutoScalingGroups)
		}
	}

	g := describeGroups.AutoScalingGroups[0]

	return &g, nil
}

func resource_aws_autoscaling_group_validation() *config.Validator {
	return &config.Validator{
		Required: []string{
			"name",
			"max_size",
			"min_size",
			"availability_zones.*",
			"launch_configuration",
		},
		Optional: []string{
			"health_check_grace_period",
			"health_check_type",
			"desired_capacity",
			"force_delete",
			"load_balancers.*",
		},
	}
}
<|endoftext|>


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

// Package base provides some helpers to make constructing bar modules easier.
package base

import (
	"os/exec"
	"sync"

	"github.com/soumya92/barista/bar"
	"github.com/soumya92/barista/base/scheduler"
	"github.com/soumya92/barista/outputs"
)

// Base is a simple module that satisfies the bar.Module interface, while adding
// some useful functions to make building modules on top somewhat simpler.
type Base struct {
	sync.Mutex
	channel        chan bar.Output
	clickHandler   func(bar.Event)
	updateFunc     func()
	paused         bool
	updateOnResume bool
	outputOnResume bar.Output
	lastError      error
	scheduler      scheduler.Scheduler
}

// Module implements bar's Module, Clickable, and Pausable,
// and adds a method to trigger updates on demand.
type Module interface {
	bar.Module
	bar.Clickable
	bar.Pausable
	Update()
}

// WithClickHandler extends Module to add support for a generic click handler
// that only receives the bar.Event. Most custom modules should extend Module
// with their own OnClick method that provides module-specific information.
type WithClickHandler interface {
	Module
	OnClick(func(bar.Event)) Module
}

// Stream starts up the worker goroutine, and channels its output to the bar.
func (b *Base) Stream() <-chan bar.Output {
	b.Resume()
	// Constructed when New is called, but is not directly exposed to extending
	// modules. Use Output or Clear to control the bar output.
	return b.channel
}

// Click handles click events from the bar.
// A middle click will always force an update, but if the module
// is currently in an error state, the configured click handler
// will be replaced by one that shows the error message using
// i3-nagbar on left click and updates the module on right click
func (b *Base) Click(e bar.Event) {
	b.Lock()
	err := b.lastError
	b.Unlock()
	if err == nil {
		if e.Button == bar.ButtonMiddle {
			b.Update()
		}
		b.Lock()
		handler := b.clickHandler
		b.Unlock()
		if handler != nil {
			handler(e)
		}
		return
	}
	switch e.Button {
	case bar.ButtonRight, bar.ButtonMiddle:
		b.Lock()
		b.lastError = nil
		b.Unlock()
		b.Clear()
		b.Update()
	case bar.ButtonLeft:
		go exec.Command("i3-nagbar", "-m", err.Error()).Run()
	}
}

// Pause marks the module as paused, which suspends updates
// and outputs to the bar.
func (b *Base) Pause() {
	b.Lock()
	defer b.Unlock()
	b.paused = true
}

// Resume continues normal updating of the module, and performs an
// immediate update if any updates occurred while the module was paused.
func (b *Base) Resume() {
	var doOutput bar.Output
	var doUpdate bool

	b.Lock()
	b.paused = false
	if b.outputOnResume != nil {
		doOutput = b.outputOnResume
		b.outputOnResume = nil
	}
	if b.updateOnResume {
		doUpdate = true
		b.updateOnResume = false
	}
	b.Unlock()

	if doOutput != nil {
		b.Output(doOutput)
	}
	if doUpdate {
		b.Update()
	}
}

// Update marks the module as ready for an update.
// The actual update may not happen immediately, e.g. if the bar is hidden.
func (b *Base) Update() {
	b.Lock()
	defer b.Unlock()
	if b.updateFunc == nil {
		return
	}
	if b.paused {
		b.updateOnResume = true
		return
	}
	go b.updateFunc()
}

// UnlockAndUpdate unlocks the base mutex and marks the module as
// ready for an update. The primary use case for this method is to allow
// defer base.UnlockAndUpdate(), since otherwise implementing modules
// must unlock the mutex before updating, preventing the use of defer.
func (b *Base) UnlockAndUpdate() {
	b.Unlock()
	b.Update()
}

// OnClick sets the click handler.
// This is a minimal default implementation; derived modules should implement an
// alternative OnClick method that exposes module-specific data to the handler function.
// Returns Module to allow bar.Add/bar.Run on the result.
func (b *Base) OnClick(handler func(bar.Event)) Module {
	b.Lock()
	defer b.Unlock()
	b.clickHandler = handler
	return b
}

// New constructs a new base module.
func New() *Base {
	b := &Base{
		channel: make(chan bar.Output, 10),
		// Modules start paused so that any modifications prior to Stream()
		// are not applied before the module has started.
		paused: true,
		// Trigger an initial update when Stream is first called.
		updateOnResume: true,
	}
	b.scheduler = scheduler.Do(b.Update)
	return b
}

// OnUpdate sets the function that will be called when the module needs
// to be update. That function can choose to call Output/Clear/Error to
// update the output, but is not required if no visual update is necessary.
// This method is only called while the bar is visible, to conserve resources
// when possible. For this reason, it is recommended that heavy update work,
// e.g. http requests, should happen here and not in an independent timer.
func (b *Base) OnUpdate(updateFunc func()) {
	b.Lock()
	defer b.Unlock()
	b.updateFunc = updateFunc
}

// Clear hides the module from the bar.
func (b *Base) Clear() {
	b.Output(outputs.Empty())
}

// Output updates the module's output.
func (b *Base) Output(out bar.Output) {
	b.Lock()
	b.lastError = nil
	b.Unlock()
	b.internalOutput(out)
}

// Error shows an error on the bar.
// It shows an urgent "Error" on the bar (or the full text if it fits),
// and when clicked shows the full error using i3-nagbar.
func (b *Base) Error(err error) bool {
	if err == nil {
		return false
	}
	b.Lock()
	b.lastError = err
	b.Unlock()
	b.internalOutput(outputs.Error(err))
	return true
}

// internalOutput updates the module's output,
// while accounting for the module's paused state.
func (b *Base) internalOutput(out bar.Output) {
	b.Lock()
	defer b.Unlock()
	if b.paused {
		b.outputOnResume = out
		return
	}
	b.channel <- out
}

// Schedule returns the scheduler for the module's update function.
// This allows derived modules to change the update frequency, or
// even enable and disable scheduled updates, without needing to
// worry about inadvertently scheduling multiple concurrent updates.
func (b *Base) Schedule() scheduler.Scheduler {
	return b.scheduler
}
<commit_msg>Reduce mutex locking/unlocking in base output<commit_after>// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package base provides some helpers to make constructing bar modules easier.
package base

import (
	"os/exec"
	"sync"

	"github.com/soumya92/barista/bar"
	"github.com/soumya92/barista/base/scheduler"
	"github.com/soumya92/barista/outputs"
)

// Base is a simple module that satisfies the bar.Module interface, while adding
// some useful functions to make building modules on top somewhat simpler.
type Base struct {
	sync.Mutex
	channel        chan bar.Output
	clickHandler   func(bar.Event)
	updateFunc     func()
	paused         bool
	updateOnResume bool
	outputOnResume bar.Output
	lastError      error
	scheduler      scheduler.Scheduler
}

// Module implements bar's Module, Clickable, and Pausable,
// and adds a method to trigger updates on demand.
type Module interface {
	bar.Module
	bar.Clickable
	bar.Pausable
	Update()
}

// WithClickHandler extends Module to add support for a generic click handler
// that only receives the bar.Event. Most custom modules should extend Module
// with their own OnClick method that provides module-specific information.
type WithClickHandler interface {
	Module
	OnClick(func(bar.Event)) Module
}

// Stream starts up the worker goroutine, and channels its output to the bar.
func (b *Base) Stream() <-chan bar.Output {
	b.Resume()
	// Constructed when New is called, but is not directly exposed to extending
	// modules. Use Output or Clear to control the bar output.
	return b.channel
}

// Click handles click events from the bar.
// A middle click will always force an update, but if the module
// is currently in an error state, the configured click handler
// will be replaced by one that shows the error message using
// i3-nagbar on left click and updates the module on right click
func (b *Base) Click(e bar.Event) {
	b.Lock()
	err := b.lastError
	b.Unlock()
	if err == nil {
		if e.Button == bar.ButtonMiddle {
			b.Update()
		}
		b.Lock()
		handler := b.clickHandler
		b.Unlock()
		if handler != nil {
			handler(e)
		}
		return
	}
	switch e.Button {
	case bar.ButtonRight, bar.ButtonMiddle:
		b.Clear()
		b.Update()
	case bar.ButtonLeft:
		go exec.Command("i3-nagbar", "-m", err.Error()).Run()
	}
}

// Pause marks the module as paused, which suspends updates
// and outputs to the bar.
func (b *Base) Pause() {
	b.Lock()
	defer b.Unlock()
	b.paused = true
}

// Resume continues normal updating of the module, and performs an
// immediate update if any updates occurred while the module was paused.
func (b *Base) Resume() {
	var doOutput bar.Output
	var doUpdate bool

	b.Lock()
	b.paused = false
	if b.outputOnResume != nil {
		doOutput = b.outputOnResume
		b.outputOnResume = nil
	}
	if b.updateOnResume {
		doUpdate = true
		b.updateOnResume = false
	}
	b.Unlock()

	if doOutput != nil {
		b.Output(doOutput)
	}
	if doUpdate {
		b.Update()
	}
}

// Update marks the module as ready for an update.
// The actual update may not happen immediately, e.g. if the bar is hidden.
func (b *Base) Update() {
	b.Lock()
	defer b.Unlock()
	if b.updateFunc == nil {
		return
	}
	if b.paused {
		b.updateOnResume = true
		return
	}
	go b.updateFunc()
}

// UnlockAndUpdate unlocks the base mutex and marks the module as
// ready for an update. The primary use case for this method is to allow
// defer base.UnlockAndUpdate(), since otherwise implementing modules
// must unlock the mutex before updating, preventing the use of defer.
func (b *Base) UnlockAndUpdate() {
	b.Unlock()
	b.Update()
}

// OnClick sets the click handler.
// This is a minimal default implementation; derived modules should implement an
// alternative OnClick method that exposes module-specific data to the handler function.
// Returns Module to allow bar.Add/bar.Run on the result.
func (b *Base) OnClick(handler func(bar.Event)) Module {
	b.Lock()
	defer b.Unlock()
	b.clickHandler = handler
	return b
}

// New constructs a new base module.
func New() *Base {
	b := &Base{
		channel: make(chan bar.Output, 10),
		// Modules start paused so that any modifications prior to Stream()
		// are not applied before the module has started.
		paused: true,
		// Trigger an initial update when Stream is first called.
		updateOnResume: true,
	}
	b.scheduler = scheduler.Do(b.Update)
	return b
}

// OnUpdate sets the function that will be called when the module needs
// to be update. That function can choose to call Output/Clear/Error to
// update the output, but is not required if no visual update is necessary.
// This method is only called while the bar is visible, to conserve resources
// when possible. For this reason, it is recommended that heavy update work,
// e.g. http requests, should happen here and not in an independent timer.
func (b *Base) OnUpdate(updateFunc func()) {
	b.Lock()
	defer b.Unlock()
	b.updateFunc = updateFunc
}

// Clear hides the module from the bar.
func (b *Base) Clear() {
	b.Output(outputs.Empty())
}

// Output updates the module's output.
func (b *Base) Output(out bar.Output) {
	b.Lock()
	defer b.Unlock()
	b.lastError = nil
	b.internalOutput(out)
}

// Error shows an error on the bar.
// It shows an urgent "Error" on the bar (or the full text if it fits),
// and when clicked shows the full error using i3-nagbar.
func (b *Base) Error(err error) bool {
	if err == nil {
		return false
	}
	b.Lock()
	defer b.Unlock()
	b.lastError = err
	b.internalOutput(outputs.Error(err))
	return true
}

// internalOutput updates the module's output,
// while accounting for the module's paused state.
func (b *Base) internalOutput(out bar.Output) {
	if b.paused {
		b.outputOnResume = out
		return
	}
	b.channel <- out
}

// Schedule returns the scheduler for the module's update function.
// This allows derived modules to change the update frequency, or
// even enable and disable scheduled updates, without needing to
// worry about inadvertently scheduling multiple concurrent updates.
func (b *Base) Schedule() scheduler.Scheduler {
	return b.scheduler
}
<|endoftext|>


<commit_before>/*
Package consts implements constants for the entire project
*/
package consts

// ConfigurationFileName is the configuration file name of Goyave
const ConfigurationFileName = ".goyave.toml"
<commit_msg>Change .goyave.toml file to .goyave<commit_after>/*
Package consts implements constants for the entire project
*/
package consts

// ConfigurationFileName is the configuration file name of Goyave
const ConfigurationFileName = ".goyave"
<|endoftext|>


<commit_before>package api

import (
	"math/big"

	"gopkg.in/fatih/set.v0"

	"github.com/bytom/blockchain/query"
	"github.com/bytom/consensus/difficulty"
	chainjson "github.com/bytom/encoding/json"
	"github.com/bytom/errors"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
)

// return best block hash
func (a *API) getBestBlockHash() Response {
	blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
	return NewSuccessResponse(blockHash)
}

// return current block count
func (a *API) getBlockCount() Response {
	blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
	return NewSuccessResponse(blockHeight)
}

// BlockTx is the tx struct for getBlock func
type BlockTx struct {
	ID         bc.Hash                  `json:"id"`
	Version    uint64                   `json:"version"`
	Size       uint64                   `json:"size"`
	TimeRange  uint64                   `json:"time_range"`
	Inputs     []*query.AnnotatedInput  `json:"inputs"`
	Outputs    []*query.AnnotatedOutput `json:"outputs"`
	StatusFail bool                     `json:"status_fail"`
	MuxID      bc.Hash                  `json:"mux_id"`
}

// BlockReq is used to handle getBlock req
type BlockReq struct {
	BlockHeight uint64             `json:"block_height"`
	BlockHash   chainjson.HexBytes `json:"block_hash"`
}

// GetBlockResp is the resp for getBlock api
type GetBlockResp struct {
	Hash                   *bc.Hash   `json:"hash"`
	Size                   uint64     `json:"size"`
	Version                uint64     `json:"version"`
	Height                 uint64     `json:"height"`
	PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
	Timestamp              uint64     `json:"timestamp"`
	Nonce                  uint64     `json:"nonce"`
	Bits                   uint64     `json:"bits"`
	Difficulty             string     `json:"difficulty"`
	TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
	TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
	Transactions           []*BlockTx `json:"transactions"`
}

// return block by hash/height
func (a *API) getBlock(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	txStatus, err := a.chain.GetTransactionStatus(&blockHash)
	rawBlock, err := block.MarshalText()
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockResp{
		Hash:                   &blockHash,
		Size:                   uint64(len(rawBlock)),
		Version:                block.Version,
		Height:                 block.Height,
		PreviousBlockHash:      &block.PreviousBlockHash,
		Timestamp:              block.Timestamp,
		Nonce:                  block.Nonce,
		Bits:                   block.Bits,
		Difficulty:             difficulty.CalcWork(block.Bits).String(),
		TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
		TransactionStatusHash:  &block.TransactionStatusHash,
		Transactions:           []*BlockTx{},
	}

	for i, orig := range block.Transactions {
		tx := &BlockTx{
			ID:        orig.ID,
			Version:   orig.Version,
			Size:      orig.SerializedSize,
			TimeRange: orig.TimeRange,
			Inputs:    []*query.AnnotatedInput{},
			Outputs:   []*query.AnnotatedOutput{},
		}
		tx.StatusFail, err = txStatus.GetStatus(i)
		if err != nil {
			return NewSuccessResponse(resp)
		}

		resOutID := orig.ResultIds[0]
		resOut, ok := orig.Entries[*resOutID].(*bc.Output)
		if ok {
			tx.MuxID = *resOut.Source.Ref
		} else {
			resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
			tx.MuxID = *resRetire.Source.Ref
		}

		for i := range orig.Inputs {
			tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
		}
		for i := range orig.Outputs {
			tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
		}
		resp.Transactions = append(resp.Transactions, tx)
	}
	return NewSuccessResponse(resp)
}

// GetRawBlockResp is resp struct for getRawBlock API
type GetRawBlockResp struct {
	RawBlock *types.Block `json:"raw_block"`
}

func (a *API) getRawBlock(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := GetRawBlockResp{RawBlock: block}
	return NewSuccessResponse(resp)
}

// GetBlockHeaderResp is resp struct for getBlockHeader API
type GetBlockHeaderResp struct {
	BlockHeader *types.BlockHeader `json:"block_header"`
	Reward      uint64             `json:"reward"`
}

func (a *API) getBlockHeader(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockHeaderResp{
		BlockHeader: &block.BlockHeader,
		Reward:      block.Transactions[0].Outputs[0].Amount,
	}
	return NewSuccessResponse(resp)
}

func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
	if len(ins.BlockHash) == 32 {
		hash := hexBytesToHash(ins.BlockHash)
		return a.chain.GetBlockByHash(&hash)
	} else {
		return a.chain.GetBlockByHeight(ins.BlockHeight)
	}
}

func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
	b32 := [32]byte{}
	copy(b32[:], hexBytes)
	return bc.NewHash(b32)
}

// GetDifficultyResp is resp struct for getDifficulty API
type GetDifficultyResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	Bits        uint64   `json:"bits"`
	Difficulty  string   `json:"difficulty"`
}

func (a *API) getDifficulty(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	resp := &GetDifficultyResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		Bits:        block.Bits,
		Difficulty:  difficulty.CalcWork(block.Bits).String(),
	}
	return NewSuccessResponse(resp)
}

// getHashRateResp is resp struct for getHashRate API
type getHashRateResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	HashRate    uint64   `json:"hash_rate"`
}

func (a *API) getHashRate(ins BlockReq) Response {
	if len(ins.BlockHash) != 32 && len(ins.BlockHash) != 0 {
		err := errors.New("Block hash format error.")
		return NewErrorResponse(err)
	}
	if ins.BlockHeight == 0 {
		ins.BlockHeight = a.chain.BestBlockHeight()
	}

	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	diffTime := block.Timestamp - preBlock.Timestamp
	hashCount := difficulty.CalcWork(block.Bits)
	hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))

	blockHash := block.Hash()
	resp := &getHashRateResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		HashRate:    hashRate.Uint64(),
	}
	return NewSuccessResponse(resp)
}

// MerkleBlockReq is used to handle getTxOutProof req
type MerkleBlockReq struct {
	TxIDs     []chainjson.HexBytes `json:"tx_ids"`
	BlockHash chainjson.HexBytes   `json:"block_hash"`
}

// GetMerkleBlockResp is resp struct for GetTxOutProof API
type GetMerkleBlockResp struct {
	BlockHeader  types.BlockHeader `json:"block_header"`
	TxHashes     []*bc.Hash        `json:"tx_hashes"`
	StatusHashes []*bc.Hash        `json:"status_hashes"`
	Flags        []uint32          `json:"flags"`
	MatchedTxIDs []*bc.Hash        `json:"matched_tx_ids"`
}

func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
	blockReq := BlockReq{BlockHash: ins.BlockHash}
	block, err := a.getBlockHelper(blockReq)
	if err != nil {
		return NewErrorResponse(err)
	}

	matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
	var matchedTxIDs []*bc.Hash
	for _, tx := range matchedTxs {
		matchedTxIDs = append(matchedTxIDs, &tx.ID)
	}

	hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
	flags := make([]uint32, len(compactFlags))
	for i, flag := range compactFlags {
		flags[i] = uint32(flag)
	}

	blockHash := block.Hash()
	statuses, err := a.chain.GetTransactionStatus(&blockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)

	resp := &GetMerkleBlockResp{
		BlockHeader:  block.BlockHeader,
		TxHashes:     hashes,
		StatusHashes: statusHashes,
		Flags:        flags,
		MatchedTxIDs: matchedTxIDs,
	}
	return NewSuccessResponse(resp)
}

func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
	txIDSet := set.New()
	for _, txID := range filterTxIDs {
		hash := hexBytesToHash(txID)
		txIDSet.Add(hash.String())
	}

	var matchedTxs []*types.Tx
	for _, tx := range txs {
		hashStr := tx.ID.String()
		if txIDSet.Has(hashStr) {
			matchedTxs = append(matchedTxs, tx)
		}
	}
	return matchedTxs
}
<commit_msg>fix bug for calculate hash rate (#1362)<commit_after>package api

import (
	"math/big"

	"gopkg.in/fatih/set.v0"

	"github.com/bytom/blockchain/query"
	"github.com/bytom/consensus/difficulty"
	chainjson "github.com/bytom/encoding/json"
	"github.com/bytom/errors"
	"github.com/bytom/protocol/bc"
	"github.com/bytom/protocol/bc/types"
)

// return best block hash
func (a *API) getBestBlockHash() Response {
	blockHash := map[string]string{"block_hash": a.chain.BestBlockHash().String()}
	return NewSuccessResponse(blockHash)
}

// return current block count
func (a *API) getBlockCount() Response {
	blockHeight := map[string]uint64{"block_count": a.chain.BestBlockHeight()}
	return NewSuccessResponse(blockHeight)
}

// BlockTx is the tx struct for getBlock func
type BlockTx struct {
	ID         bc.Hash                  `json:"id"`
	Version    uint64                   `json:"version"`
	Size       uint64                   `json:"size"`
	TimeRange  uint64                   `json:"time_range"`
	Inputs     []*query.AnnotatedInput  `json:"inputs"`
	Outputs    []*query.AnnotatedOutput `json:"outputs"`
	StatusFail bool                     `json:"status_fail"`
	MuxID      bc.Hash                  `json:"mux_id"`
}

// BlockReq is used to handle getBlock req
type BlockReq struct {
	BlockHeight uint64             `json:"block_height"`
	BlockHash   chainjson.HexBytes `json:"block_hash"`
}

// GetBlockResp is the resp for getBlock api
type GetBlockResp struct {
	Hash                   *bc.Hash   `json:"hash"`
	Size                   uint64     `json:"size"`
	Version                uint64     `json:"version"`
	Height                 uint64     `json:"height"`
	PreviousBlockHash      *bc.Hash   `json:"previous_block_hash"`
	Timestamp              uint64     `json:"timestamp"`
	Nonce                  uint64     `json:"nonce"`
	Bits                   uint64     `json:"bits"`
	Difficulty             string     `json:"difficulty"`
	TransactionsMerkleRoot *bc.Hash   `json:"transaction_merkle_root"`
	TransactionStatusHash  *bc.Hash   `json:"transaction_status_hash"`
	Transactions           []*BlockTx `json:"transactions"`
}

// return block by hash/height
func (a *API) getBlock(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	txStatus, err := a.chain.GetTransactionStatus(&blockHash)
	rawBlock, err := block.MarshalText()
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockResp{
		Hash:                   &blockHash,
		Size:                   uint64(len(rawBlock)),
		Version:                block.Version,
		Height:                 block.Height,
		PreviousBlockHash:      &block.PreviousBlockHash,
		Timestamp:              block.Timestamp,
		Nonce:                  block.Nonce,
		Bits:                   block.Bits,
		Difficulty:             difficulty.CalcWork(block.Bits).String(),
		TransactionsMerkleRoot: &block.TransactionsMerkleRoot,
		TransactionStatusHash:  &block.TransactionStatusHash,
		Transactions:           []*BlockTx{},
	}

	for i, orig := range block.Transactions {
		tx := &BlockTx{
			ID:        orig.ID,
			Version:   orig.Version,
			Size:      orig.SerializedSize,
			TimeRange: orig.TimeRange,
			Inputs:    []*query.AnnotatedInput{},
			Outputs:   []*query.AnnotatedOutput{},
		}
		tx.StatusFail, err = txStatus.GetStatus(i)
		if err != nil {
			return NewSuccessResponse(resp)
		}

		resOutID := orig.ResultIds[0]
		resOut, ok := orig.Entries[*resOutID].(*bc.Output)
		if ok {
			tx.MuxID = *resOut.Source.Ref
		} else {
			resRetire, _ := orig.Entries[*resOutID].(*bc.Retirement)
			tx.MuxID = *resRetire.Source.Ref
		}

		for i := range orig.Inputs {
			tx.Inputs = append(tx.Inputs, a.wallet.BuildAnnotatedInput(orig, uint32(i)))
		}
		for i := range orig.Outputs {
			tx.Outputs = append(tx.Outputs, a.wallet.BuildAnnotatedOutput(orig, i))
		}
		resp.Transactions = append(resp.Transactions, tx)
	}
	return NewSuccessResponse(resp)
}

// GetRawBlockResp is resp struct for getRawBlock API
type GetRawBlockResp struct {
	RawBlock *types.Block `json:"raw_block"`
}

func (a *API) getRawBlock(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := GetRawBlockResp{RawBlock: block}
	return NewSuccessResponse(resp)
}

// GetBlockHeaderResp is resp struct for getBlockHeader API
type GetBlockHeaderResp struct {
	BlockHeader *types.BlockHeader `json:"block_header"`
	Reward      uint64             `json:"reward"`
}

func (a *API) getBlockHeader(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	resp := &GetBlockHeaderResp{
		BlockHeader: &block.BlockHeader,
		Reward:      block.Transactions[0].Outputs[0].Amount,
	}
	return NewSuccessResponse(resp)
}

func (a *API) getBlockHelper(ins BlockReq) (*types.Block, error) {
	if len(ins.BlockHash) == 32 {
		hash := hexBytesToHash(ins.BlockHash)
		return a.chain.GetBlockByHash(&hash)
	} else {
		return a.chain.GetBlockByHeight(ins.BlockHeight)
	}
}

func hexBytesToHash(hexBytes chainjson.HexBytes) bc.Hash {
	b32 := [32]byte{}
	copy(b32[:], hexBytes)
	return bc.NewHash(b32)
}

// GetDifficultyResp is resp struct for getDifficulty API
type GetDifficultyResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	Bits        uint64   `json:"bits"`
	Difficulty  string   `json:"difficulty"`
}

func (a *API) getDifficulty(ins BlockReq) Response {
	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	blockHash := block.Hash()
	resp := &GetDifficultyResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		Bits:        block.Bits,
		Difficulty:  difficulty.CalcWork(block.Bits).String(),
	}
	return NewSuccessResponse(resp)
}

// getHashRateResp is resp struct for getHashRate API
type getHashRateResp struct {
	BlockHash   *bc.Hash `json:"hash"`
	BlockHeight uint64   `json:"height"`
	HashRate    uint64   `json:"hash_rate"`
}

func (a *API) getHashRate(ins BlockReq) Response {
	if len(ins.BlockHash) != 32 && len(ins.BlockHash) != 0 {
		err := errors.New("Block hash format error.")
		return NewErrorResponse(err)
	}
	if ins.BlockHeight == 0 {
		ins.BlockHeight = a.chain.BestBlockHeight()
	}

	block, err := a.getBlockHelper(ins)
	if err != nil {
		return NewErrorResponse(err)
	}

	preBlock, err := a.chain.GetBlockByHash(&block.PreviousBlockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	diffTime := block.Timestamp - preBlock.Timestamp
	if preBlock.Timestamp >= block.Timestamp {
		diffTime = 1
	}
	hashCount := difficulty.CalcWork(block.Bits)
	hashRate := new(big.Int).Div(hashCount, big.NewInt(int64(diffTime)))

	blockHash := block.Hash()
	resp := &getHashRateResp{
		BlockHash:   &blockHash,
		BlockHeight: block.Height,
		HashRate:    hashRate.Uint64(),
	}
	return NewSuccessResponse(resp)
}

// MerkleBlockReq is used to handle getTxOutProof req
type MerkleBlockReq struct {
	TxIDs     []chainjson.HexBytes `json:"tx_ids"`
	BlockHash chainjson.HexBytes   `json:"block_hash"`
}

// GetMerkleBlockResp is resp struct for GetTxOutProof API
type GetMerkleBlockResp struct {
	BlockHeader  types.BlockHeader `json:"block_header"`
	TxHashes     []*bc.Hash        `json:"tx_hashes"`
	StatusHashes []*bc.Hash        `json:"status_hashes"`
	Flags        []uint32          `json:"flags"`
	MatchedTxIDs []*bc.Hash        `json:"matched_tx_ids"`
}

func (a *API) getMerkleProof(ins MerkleBlockReq) Response {
	blockReq := BlockReq{BlockHash: ins.BlockHash}
	block, err := a.getBlockHelper(blockReq)
	if err != nil {
		return NewErrorResponse(err)
	}

	matchedTxs := getMatchedTx(block.Transactions, ins.TxIDs)
	var matchedTxIDs []*bc.Hash
	for _, tx := range matchedTxs {
		matchedTxIDs = append(matchedTxIDs, &tx.ID)
	}

	hashes, compactFlags := types.GetTxMerkleTreeProof(block.Transactions, matchedTxs)
	flags := make([]uint32, len(compactFlags))
	for i, flag := range compactFlags {
		flags[i] = uint32(flag)
	}

	blockHash := block.Hash()
	statuses, err := a.chain.GetTransactionStatus(&blockHash)
	if err != nil {
		return NewErrorResponse(err)
	}

	statusHashes := types.GetStatusMerkleTreeProof(statuses.VerifyStatus, compactFlags)

	resp := &GetMerkleBlockResp{
		BlockHeader:  block.BlockHeader,
		TxHashes:     hashes,
		StatusHashes: statusHashes,
		Flags:        flags,
		MatchedTxIDs: matchedTxIDs,
	}
	return NewSuccessResponse(resp)
}

func getMatchedTx(txs []*types.Tx, filterTxIDs []chainjson.HexBytes) []*types.Tx {
	txIDSet := set.New()
	for _, txID := range filterTxIDs {
		hash := hexBytesToHash(txID)
		txIDSet.Add(hash.String())
	}

	var matchedTxs []*types.Tx
	for _, tx := range txs {
		hashStr := tx.ID.String()
		if txIDSet.Has(hashStr) {
			matchedTxs = append(matchedTxs, tx)
		}
	}
	return matchedTxs
}
<|endoftext|>


<commit_before>package beanstalk

import "sync"

// ConsumerPool maintains a pool of beanstalk consumers.
type ConsumerPool struct {
	// C offers up newly reserved beanstalk jobs.
	C         <-chan *Job
	c         chan *Job
	consumers []*Consumer
	stopOnce  sync.Once
	mu        sync.Mutex
}

// NewConsumerPool creates a pool of beanstalk consumers.
func NewConsumerPool(urls []string, tubes []string, options *Options) (*ConsumerPool, error) {
	jobC := make(chan *Job)
	pool := &ConsumerPool{C: jobC, c: jobC}

	// Create a consumer for each URL.
	for _, url := range urls {
		consumer, err := NewConsumer(url, tubes, jobC, options)
		if err != nil {
			return nil, err
		}

		pool.consumers = append(pool.consumers, consumer)
	}

	// Start all the consumers.
	for _, consumer := range pool.consumers {
		consumer.Start()
	}

	return pool, nil
}

// Stop shuts down all the consumers in the pool.
func (pool *ConsumerPool) Stop() {
	pool.stopOnce.Do(func() {
		pool.mu.Lock()
		defer pool.mu.Unlock()

		for i, consumer := range pool.consumers {
			consumer.Stop()
			pool.consumers[i] = nil
		}

		pool.consumers = []*Consumer{}
		close(pool.c)
	})
}

// Play tells all the consumers to start reservering jobs.
func (pool *ConsumerPool) Play() {
	pool.mu.Lock()
	defer pool.mu.Unlock()

	for _, consumer := range pool.consumers {
		consumer.Play()
	}
}

// Pause tells all the consumer to stop reservering jobs.
func (pool *ConsumerPool) Pause() {
	pool.mu.Lock()
	defer pool.mu.Unlock()

	for _, consumer := range pool.consumers {
		consumer.Pause()
	}
}
<commit_msg>Don't close the channel, as the Stop() calls to the consumers is async and can cause a write to a close channel to happen<commit_after>package beanstalk

import "sync"

// ConsumerPool maintains a pool of beanstalk consumers.
type ConsumerPool struct {
	// C offers up newly reserved beanstalk jobs.
	C         <-chan *Job
	c         chan *Job
	consumers []*Consumer
	stopOnce  sync.Once
	mu        sync.Mutex
}

// NewConsumerPool creates a pool of beanstalk consumers.
func NewConsumerPool(urls []string, tubes []string, options *Options) (*ConsumerPool, error) {
	jobC := make(chan *Job)
	pool := &ConsumerPool{C: jobC, c: jobC}

	// Create a consumer for each URL.
	for _, url := range urls {
		consumer, err := NewConsumer(url, tubes, jobC, options)
		if err != nil {
			return nil, err
		}

		pool.consumers = append(pool.consumers, consumer)
	}

	// Start all the consumers.
	for _, consumer := range pool.consumers {
		consumer.Start()
	}

	return pool, nil
}

// Stop shuts down all the consumers in the pool.
func (pool *ConsumerPool) Stop() {
	pool.stopOnce.Do(func() {
		pool.mu.Lock()
		defer pool.mu.Unlock()

		for i, consumer := range pool.consumers {
			consumer.Stop()
			pool.consumers[i] = nil
		}

		pool.consumers = []*Consumer{}
	})
}

// Play tells all the consumers to start reservering jobs.
func (pool *ConsumerPool) Play() {
	pool.mu.Lock()
	defer pool.mu.Unlock()

	for _, consumer := range pool.consumers {
		consumer.Play()
	}
}

// Pause tells all the consumer to stop reservering jobs.
func (pool *ConsumerPool) Pause() {
	pool.mu.Lock()
	defer pool.mu.Unlock()

	for _, consumer := range pool.consumers {
		consumer.Pause()
	}
}
<|endoftext|>


<commit_before>package command

import (
	"context"
	"strings"
	"sync"

	"github.com/igungor/ilber/bot"
	"github.com/igungor/telegram"
)

// A Command is an implementation of a bot command.
type Command struct {
	// Name of the command without the leading slash.
	Name string

	// Short description of the command
	ShortLine string

	// Hidden enables commands to be hidden from the /help output, such as
	// Telegram's built-in commands and easter eggs.
	Hidden bool

	// Run runs the command.
	Run func(context.Context, *bot.Bot, *telegram.Message)
}

var (
	// mu guards commands-map access
	mu       sync.Mutex
	commands = make(map[string]*Command)
)

func register(cmd *Command) {
	mu.Lock()
	defer mu.Unlock()

	if cmd.Name == "" {
		panic("cannot register command with an empty name")
	}
	if cmd.Run == nil {
		panic("cannot register command with an empty Run function value")
	}
	if _, ok := commands[cmd.Name]; ok {
		panic("plugin already registered: " + cmd.Name)
	}

	commands[cmd.Name] = cmd
}

// Lookup looks-up name from registered commands and returns
// corresponding Command if any.
func Lookup(cmdname string) *Command {
	mu.Lock()
	defer mu.Unlock()

	cmdname = strings.TrimSuffix(cmdname, "@ilberbot")
	cmd, ok := commands[cmdname]
	if !ok {
		return nil
	}
	return cmd
}
<commit_msg>main: fix typo<commit_after>package command

import (
	"context"
	"strings"
	"sync"

	"github.com/igungor/ilber/bot"
	"github.com/igungor/telegram"
)

// A Command is an implementation of a bot command.
type Command struct {
	// Name of the command without the leading slash.
	Name string

	// Short description of the command
	ShortLine string

	// Hidden enables commands to be hidden from the /help output, such as
	// Telegram's built-in commands and easter eggs.
	Hidden bool

	// Run runs the command.
	Run func(context.Context, *bot.Bot, *telegram.Message)
}

var (
	// mu guards commands-map access
	mu       sync.Mutex
	commands = make(map[string]*Command)
)

func register(cmd *Command) {
	mu.Lock()
	defer mu.Unlock()

	if cmd.Name == "" {
		panic("cannot register command with an empty name")
	}
	if cmd.Run == nil {
		panic("cannot register command with an empty Run function value")
	}
	if _, ok := commands[cmd.Name]; ok {
		panic("command already registered: " + cmd.Name)
	}

	commands[cmd.Name] = cmd
}

// Lookup looks-up name from registered commands and returns
// corresponding Command if any.
func Lookup(cmdname string) *Command {
	mu.Lock()
	defer mu.Unlock()

	cmdname = strings.TrimSuffix(cmdname, "@ilberbot")
	cmd, ok := commands[cmdname]
	if !ok {
		return nil
	}
	return cmd
}
<|endoftext|>


<commit_before>// Package command implements functions for responding to user
// input and dispatching to appropriate backend commands.
package command

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"

	"github.com/derekparker/delve/proctl"
)

type cmdfunc func(proc *proctl.DebuggedProcess, args ...string) error

type command struct {
	aliases []string
	helpMsg string
	cmdFn   cmdfunc
}

// Returns true if the command string matches one of the aliases for this command
func (c command) match(cmdstr string) bool {
	for _, v := range c.aliases {
		if v == cmdstr {
			return true
		}
	}
	return false
}

type Commands struct {
	cmds    []command
	lastCmd cmdfunc
}

// Returns a Commands struct with default commands defined.
func DebugCommands() *Commands {
	c := &Commands{}

	c.cmds = []command{
		command{aliases: []string{"help"}, cmdFn: c.help, helpMsg: "Prints the help message."},
		command{aliases: []string{"break", "b"}, cmdFn: breakpoint, helpMsg: "Set break point at the entry point of a function, or at a specific file/line. Example: break foo.go:13"},
		command{aliases: []string{"continue", "c"}, cmdFn: cont, helpMsg: "Run until breakpoint or program termination."},
		command{aliases: []string{"step", "si"}, cmdFn: step, helpMsg: "Single step through program."},
		command{aliases: []string{"next", "n"}, cmdFn: next, helpMsg: "Step over to next source line."},
		command{aliases: []string{"threads"}, cmdFn: threads, helpMsg: "Print out info for every traced thread."},
		command{aliases: []string{"thread", "t"}, cmdFn: thread, helpMsg: "Switch to the specified thread."},
		command{aliases: []string{"clear"}, cmdFn: clear, helpMsg: "Deletes breakpoint."},
		command{aliases: []string{"goroutines"}, cmdFn: goroutines, helpMsg: "Print out info for every goroutine."},
		command{aliases: []string{"breakpoints", "bp"}, cmdFn: breakpoints, helpMsg: "Print out info for active breakpoints."},
		command{aliases: []string{"print", "p"}, cmdFn: printVar, helpMsg: "Evaluate a variable."},
		command{aliases: []string{"info"}, cmdFn: info, helpMsg: "Provides info about args, funcs, locals, sources, or vars."},
		command{aliases: []string{"exit"}, cmdFn: nullCommand, helpMsg: "Exit the debugger."},
	}

	return c
}

// Register custom commands. Expects cf to be a func of type cmdfunc,
// returning only an error.
func (c *Commands) Register(cmdstr string, cf cmdfunc, helpMsg string) {
	for _, v := range c.cmds {
		if v.match(cmdstr) {
			v.cmdFn = cf
			return
		}
	}

	c.cmds = append(c.cmds, command{aliases: []string{cmdstr}, cmdFn: cf, helpMsg: helpMsg})
}

// Find will look up the command function for the given command input.
// If it cannot find the command it will defualt to noCmdAvailable().
// If the command is an empty string it will replay the last command.
func (c *Commands) Find(cmdstr string) cmdfunc {
	// If <enter> use last command, if there was one.
	if cmdstr == "" {
		if c.lastCmd != nil {
			return c.lastCmd
		}
		return nullCommand
	}

	for _, v := range c.cmds {
		if v.match(cmdstr) {
			c.lastCmd = v.cmdFn
			return v.cmdFn
		}
	}

	return noCmdAvailable
}

func CommandFunc(fn func() error) cmdfunc {
	return func(p *proctl.DebuggedProcess, args ...string) error {
		return fn()
	}
}

func noCmdAvailable(p *proctl.DebuggedProcess, args ...string) error {
	return fmt.Errorf("command not available")
}

func nullCommand(p *proctl.DebuggedProcess, args ...string) error {
	return nil
}

func (c *Commands) help(p *proctl.DebuggedProcess, args ...string) error {
	fmt.Println("The following commands are available:")
	for _, cmd := range c.cmds {
		fmt.Printf("\t%s - %s\n", strings.Join(cmd.aliases, "|"), cmd.helpMsg)
	}
	return nil
}

func threads(p *proctl.DebuggedProcess, args ...string) error {
	for _, th := range p.Threads {
		prefix := "  "
		if th == p.CurrentThread {
			prefix = "* "
		}
		loc, err := th.Location()
		if err != nil {
			return err
		}
		if loc.Fn != nil {
			fmt.Printf("%sThread %d at %#v %s:%d %s\n", prefix, th.Id, loc.PC, loc.File, loc.Line, loc.Fn.Name)
		} else {
			fmt.Printf("%sThread %d at %#v\n", prefix, th.Id, loc.PC)
		}
	}
	return nil
}

func thread(p *proctl.DebuggedProcess, args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("you must specify a thread")
	}
	oldTid := p.CurrentThread.Id
	tid, err := strconv.Atoi(args[0])
	if err != nil {
		return err
	}

	err = p.SwitchThread(tid)
	if err != nil {
		return err
	}

	fmt.Printf("Switched from %d to %d\n", oldTid, tid)
	return nil
}

func goroutines(p *proctl.DebuggedProcess, args ...string) error {
	var fname string
	gs, err := p.GoroutinesInfo()
	if err != nil {
		return err
	}

	fmt.Printf("[%d goroutines]\n", len(gs))
	for _, g := range gs {
		if g.Func != nil {
			fname = g.Func.Name
		}
		fmt.Printf("Goroutine %d - %s:%d %s\n", g.Id, g.File, g.Line, fname)
	}

	return nil
}

func cont(p *proctl.DebuggedProcess, args ...string) error {
	err := p.Continue()
	if err != nil {
		return err
	}

	return printcontext(p)
}

func step(p *proctl.DebuggedProcess, args ...string) error {
	err := p.Step()
	if err != nil {
		return err
	}

	return printcontext(p)
}

func next(p *proctl.DebuggedProcess, args ...string) error {
	err := p.Next()
	if err != nil {
		return err
	}

	return printcontext(p)
}

func clear(p *proctl.DebuggedProcess, args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("not enough arguments")
	}

	bp, err := p.ClearByLocation(args[0])
	if err != nil {
		return err
	}

	fmt.Printf("Breakpoint %d cleared at %#v for %s %s:%d\n", bp.ID, bp.Addr, bp.FunctionName, bp.File, bp.Line)

	return nil
}

type ById []*proctl.BreakPoint

func (a ById) Len() int           { return len(a) }
func (a ById) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ById) Less(i, j int) bool { return a[i].ID < a[j].ID }

func breakpoints(p *proctl.DebuggedProcess, args ...string) error {
	bps := make([]*proctl.BreakPoint, 0, len(p.BreakPoints)+4)

	for _, bp := range p.HWBreakPoints {
		if bp == nil {
			continue
		}
		bps = append(bps, bp)
	}

	for _, bp := range p.BreakPoints {
		if bp.Temp {
			continue
		}
		bps = append(bps, bp)
	}

	sort.Sort(ById(bps))
	for _, bp := range bps {
		fmt.Println(bp)
	}

	return nil
}

func breakpoint(p *proctl.DebuggedProcess, args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("not enough arguments")
	}

	bp, err := p.BreakByLocation(args[0])
	if err != nil {
		return err
	}

	fmt.Printf("Breakpoint %d set at %#v for %s %s:%d\n", bp.ID, bp.Addr, bp.FunctionName, bp.File, bp.Line)

	return nil
}

func printVar(p *proctl.DebuggedProcess, args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("not enough arguments")
	}

	val, err := p.EvalSymbol(args[0])
	if err != nil {
		return err
	}

	fmt.Println(val.Value)
	return nil
}

func filterVariables(vars []*proctl.Variable, filter *regexp.Regexp) []string {
	data := make([]string, 0, len(vars))
	for _, v := range vars {
		if v == nil {
			continue
		}
		if filter == nil || filter.Match([]byte(v.Name)) {
			data = append(data, fmt.Sprintf("%s = %s", v.Name, v.Value))
		}
	}
	return data
}

func info(p *proctl.DebuggedProcess, args ...string) error {
	if len(args) == 0 {
		return fmt.Errorf("not enough arguments. expected info type [regex].")
	}

	// Allow for optional regex
	var filter *regexp.Regexp
	if len(args) >= 2 {
		var err error
		if filter, err = regexp.Compile(args[1]); err != nil {
			return fmt.Errorf("invalid filter argument: %s", err.Error())
		}
	}

	var data []string

	switch args[0] {
	case "sources":
		data = make([]string, 0, len(p.Sources()))
		for f := range p.Sources() {
			if filter == nil || filter.Match([]byte(f)) {
				data = append(data, f)
			}
		}

	case "funcs":
		data = make([]string, 0, len(p.Funcs()))
		for _, f := range p.Funcs() {
			if f.Sym != nil && (filter == nil || filter.Match([]byte(f.Name))) {
				data = append(data, f.Name)
			}
		}

	case "args":
		vars, err := p.CurrentThread.FunctionArguments()
		if err != nil {
			return nil
		}
		data = filterVariables(vars, filter)

	case "locals":
		vars, err := p.CurrentThread.LocalVariables()
		if err != nil {
			return nil
		}
		data = filterVariables(vars, filter)

	case "vars":
		vars, err := p.CurrentThread.PackageVariables()
		if err != nil {
			return nil
		}
		data = filterVariables(vars, filter)

	default:
		return fmt.Errorf("unsupported info type, must be args, funcs, locals, sources, or vars")
	}

	// sort and output data
	sort.Sort(sort.StringSlice(data))

	for _, d := range data {
		fmt.Println(d)
	}

	return nil
}

func printcontext(p *proctl.DebuggedProcess) error {
	var context []string

	regs, err := p.Registers()
	if err != nil {
		return err
	}

	f, l, fn := p.PCToLine(regs.PC())

	if fn != nil {
		fmt.Printf("current loc: %s %s:%d\n", fn.Name, f, l)
		file, err := os.Open(f)
		if err != nil {
			return err
		}
		defer file.Close()

		buf := bufio.NewReader(file)
		for i := 1; i < l-5; i++ {
			_, err := buf.ReadString('\n')
			if err != nil && err != io.EOF {
				return err
			}
		}

		for i := l - 5; i <= l+5; i++ {
			line, err := buf.ReadString('\n')
			if err != nil {
				if err != io.EOF {
					return err
				}

				if err == io.EOF {
					break
				}
			}

			arrow := "  "
			if i == l {
				arrow = "=>"
			}

			context = append(context, fmt.Sprintf("\033[34m%s %d\033[0m: %s", arrow, i, line))
		}
	} else {
		fmt.Printf("Stopped at: 0x%x\n", regs.PC())
		context = append(context, "\033[34m=>\033[0m    no source available")
	}

	fmt.Println(strings.Join(context, ""))

	return nil
}
<commit_msg>Remove unused file<commit_after><|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"
)

// CompileCommand is the command that is responsible for "compiling" the
// Appfile into a set of data that is used by the other commands for
// execution.
type CompileCommand struct {
	Meta
}

func (c *CompileCommand) Run(args []string) int {
	fs := c.FlagSet("compile", FlagSetAppfile|FlagSetOutputDir)
	if err := fs.Parse(args); err != nil {
		return 1
	}

	// Load the appfile
	app, err := c.Appfile()
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Get a core
	core, err := c.Core(app)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error loading core: %s", err))
		return 1
	}

	// Get the active infrastructure just for UI reasons
	infra := app.ActiveInfrastructure()

	// Before the compilation, output to the user what is going on
	ui := c.OttoUi()
	ui.Header("Compiling...")
	ui.Message(fmt.Sprintf("Application:    %s", app.Application.Name))
	ui.Message(fmt.Sprintf("Project:        %s", app.Project.Name))
	ui.Message(fmt.Sprintf(
		"Infrastructure: %s (%s)",
		infra.Type,
		infra.Flavor))

	// Compile!
	if err := core.Compile(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error compiling: %s", err))
		return 1
	}

	// Success!
	ui.Header("Compilation success!")
	ui.Message(fmt.Sprintf(
		"This means that Otto is now ready to start a development environment,\n" +
			"deploy this application, build the supporting infastructure, and\n" +
			"more. See the help for more information.\n\n" +
			"Supporting files to enable Otto to manage your application from\n" +
			"development to deployment have been placed in the output directory.\n " +
			"These files can be manually inspected to determine what Otto will do."))

	return 0
}

func (c *CompileCommand) Synopsis() string {
	return "Prepares your project for being run."
}

func (c *CompileCommand) Help() string {
	helpText := `
Usage: otto [options] [path]

  Compiles the Appfile into the set of supporting files used for
  development, deploy, etc. If path is not specified, the current directory
  is assumed.

`

	return strings.TrimSpace(helpText)
}
<commit_msg>command/compile: style tweak<commit_after>package command

import (
	"fmt"
	"strings"
)

// CompileCommand is the command that is responsible for "compiling" the
// Appfile into a set of data that is used by the other commands for
// execution.
type CompileCommand struct {
	Meta
}

func (c *CompileCommand) Run(args []string) int {
	fs := c.FlagSet("compile", FlagSetAppfile|FlagSetOutputDir)
	if err := fs.Parse(args); err != nil {
		return 1
	}

	// Load the appfile
	app, err := c.Appfile()
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	// Get a core
	core, err := c.Core(app)
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error loading core: %s", err))
		return 1
	}

	// Get the active infrastructure just for UI reasons
	infra := app.ActiveInfrastructure()

	// Before the compilation, output to the user what is going on
	ui := c.OttoUi()
	ui.Header("Compiling...")
	ui.Message(fmt.Sprintf("Application:    %s", app.Application.Name))
	ui.Message(fmt.Sprintf("Project:        %s", app.Project.Name))
	ui.Message(fmt.Sprintf(
		"Infrastructure: %s (%s)",
		infra.Type,
		infra.Flavor))

	// Compile!
	if err := core.Compile(); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error compiling: %s", err))
		return 1
	}

	// Success!
	ui.Header("Compilation success!")
	ui.Message(fmt.Sprintf(
		"This means that Otto is now ready to start a development environment,\n" +
			"deploy this application, build the supporting infastructure, and\n" +
			"more. See the help for more information.\n\n" +
			"Supporting files to enable Otto to manage your application from\n" +
			"development to deployment have been placed in the output directory.\n" +
			"These files can be manually inspected to determine what Otto will do."))

	return 0
}

func (c *CompileCommand) Synopsis() string {
	return "Prepares your project for being run."
}

func (c *CompileCommand) Help() string {
	helpText := `
Usage: otto [options] [path]

  Compiles the Appfile into the set of supporting files used for
  development, deploy, etc. If path is not specified, the current directory
  is assumed.

`

	return strings.TrimSpace(helpText)
}
<|endoftext|>