<commit_before>package main

import (
	"unicode"
	"unicode/utf8"
	term "github.com/nsf/termbox-go"
)

var (
	taboffset = 4
	pageoffset =8
)

//type place int
//
//var (
//	NONE place = iota
//	BOC
//	EOC
//	EOL
//)

type cursor struct {
	line int
	boff int // byte offset.
	voff int // visual offset. It may be different with cursor offset. For that, use cursor.offset().
	t text
	// stick place - will implement later
}

func newCursor(t text) *cursor {
	return &cursor{0, 0, 0, t}
}

func setTermboxCursor(c *cursor, v *viewer, l *layout) {
	viewbound := l.mainViewerBound()
	viewx, viewy := viewbound.Min.X, viewbound.Min.Y
	cy, cx := c.positionInViewer(v)
	term.SetCursor(viewx+cx, viewy+cy)
}

// cursor offset cannot go further than line's maximum visual length.
func (c *cursor) offset() (coff int) {
	maxlen := c.lineVisualLength()
	if c.voff >  maxlen {
		return maxlen
	}

	// Cursor should not in the middle of multi-length(visual) character.
	// So we should recalculate cursor offset.
	remain := c.lineData()
	lastcoff := 0
	for {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		lastcoff = coff
		coff += runeVisualLength(r)
		if coff==c.voff {
			return coff
		} else if coff > c.voff {
			return lastcoff
		}
	}
	return
}

func (c *cursor) position() (int, int) {
	return c.line, c.offset()
}

func (c *cursor) positionInViewer(v *viewer) (int, int) {
	return c.line-v.min.Y, c.offset()-v.min.X
}

// text on the line
func (c *cursor) lineData() line {
	return c.t[c.line]
}

func (c *cursor) lineDataUntilCursor() line {
	return c.lineData()[:c.boff]
}

func (c *cursor) lineDataFromCursor() line {
	return c.lineData()[c.boff:]
}

func (c *cursor) exceededLineLimit() bool {
	return c.boff > len(c.lineData())
}

func (c *cursor) runeAfter() (rune, int) {
	return utf8.DecodeRune(c.lineData()[c.boff:])
}

func (c *cursor) runeBefore() (rune, int) {
	return utf8.DecodeLastRune(c.lineData()[:c.boff])
}

// should refine after
// may be use dictionary??
func runeVisualLength(r rune) int {
	if r=='\t' {
		return taboffset
	}
	return 1
}

func (c *cursor) lineVisualLength() int {
	return c.voffFromBoff(len(c.lineData()))
}

// Set boff and voff from current cursor position.
func (c *cursor) resetInternalOffsets() {
	c.boff = c.boffFromCoff(c.offset())
	c.voff = c.voffFromBoff(c.boff)
}

func (c *cursor) boffFromCoff(coff int) (boff int) {
	remain := c.lineData()
	for coff>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		boff += rlen
		coff -= runeVisualLength(r)
	}
	return
}

func (c *cursor) voffFromBoff(boff int) (voff int){
	remain := c.lineData()[:boff]
	for len(remain) > 0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		voff += runeVisualLength(r)
	}
	return
}

func (c *cursor) setOffsets(boff int) {
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) atBol() bool{
	return c.boff == 0
}

func (c *cursor) atEol() bool{
	return c.boff == len(c.lineData())
}

func (c *cursor) onFirstline() bool{
	return c.line == 0
}

func (c *cursor) onLastline() bool {
	return c.line == len(c.t)-1
}

func (c *cursor) atBof() bool {
	return c.onFirstline() && c.atBol()
}

func (c *cursor) atEof() bool {
	return c.onLastline() && c.atEol()
}

func (c *cursor) moveLeft() {
	c.resetInternalOffsets()
	if c.atBof() {
		return
	} else if c.atBol() {
		c.line -= 1
		c.boff = len(c.lineData())
		c.voff = c.voffFromBoff(c.boff)
		return
	}
	r, rlen := c.runeBefore()
	c.boff -= rlen
	c.voff -= runeVisualLength(r)
}

func (c *cursor) moveRight() {
	c.resetInternalOffsets()
	if c.atEof() {
		return
	} else if c.atEol() || c.exceededLineLimit(){
		c.line += 1
		c.setOffsets(0)
		return
	}
	r, rlen := c.runeAfter()
	c.boff += rlen
	c.voff += runeVisualLength(r)
}

// With move up and down, we will lazily evaluate internal offsets.
func (c *cursor) moveUp() {
	if c.onFirstline() {
		return
	}
	c.line--

}

func (c *cursor) moveDown() {
	if c.onLastline() {
		return
	}
	c.line++
}

func (c *cursor) moveBow() {
	c.resetInternalOffsets()
	if c.atBof() {
		return
	}
	// First we should pass every space character.
	for {
		r, _ := c.runeBefore()
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
			break
		}
		c.moveLeft()
	}
	// Then we will find first space charactor and stop.
	for {
		r, _ := c.runeBefore()
		if !(unicode.IsLetter(r) || unicode.IsDigit(r)) {
			return
		}
		c.moveLeft()
	}
}

// See moveEow for the algorithm.
func (c *cursor) moveEow() {
	c.resetInternalOffsets()
	if c.atEof() {
		return
	}
	for {
		r, _ := c.runeAfter()
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
			break
		}
		c.moveRight()
	}
	for {
		r, _ := c.runeAfter()
		if !(unicode.IsLetter(r) || unicode.IsDigit(r)) {
			return
		}
		c.moveRight()
	}
}

func (c *cursor) moveBol() {
	// if already bol, move cursor to prev line
	if c.boff == 0 && !c.onFirstline() {
		c.line--
		return
	}

	// if  prev data is all spaces, move cursor to beginning of line
	remain := c.lineDataUntilCursor()
	allspace := true
	for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			allspace = false
			break
		}
	}
	if allspace {
		c.boff = 0
		c.voff = 0
		return
	}

	// or, move cursor to first character of text on line.
	remain = c.lineData()
	boff := 0
        for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			break
		}
		boff += rlen
	}
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) moveEol() {
	// if already eol, move to next line
	if c.boff == len(c.lineData()) && !c.onLastline() {
		c.line++
	}

	// if  prev data is not all spaces move cursor to eol.
	remain := c.lineData()[:c.boff+1] // we should use runelength instead of 1
	allspace := true
	for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			allspace = false
			break
		}
	}
	if !allspace {
		c.boff = len(c.lineData())
		c.voff = c.voffFromBoff(c.boff)
		return
	}

	// or, move it to first chararacter of text on line.
	remain = c.lineData()
	boff := 0
	for len(remain)>0 { // will make this a function
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			break
		}
		boff +=rlen
	}
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) pageUp() {
	for i:=0; i < pageoffset; i++ {
		if c.onFirstline() {
			break
		}
		c.line--
	}
}

func (c *cursor) pageDown() {
	for i:=0; i < pageoffset; i++ {
		if c.onLastline() {
			break
		}
		c.line++
	}
}
<commit_msg>moveEow, moveBow hung. If no letter or digit left.<commit_after>package main

import (
	"unicode"
	"unicode/utf8"
	term "github.com/nsf/termbox-go"
)

var (
	taboffset = 4
	pageoffset =8
)

//type place int
//
//var (
//	NONE place = iota
//	BOC
//	EOC
//	EOL
//)

type cursor struct {
	line int
	boff int // byte offset.
	voff int // visual offset. It may be different with cursor offset. For that, use cursor.offset().
	t text
	// stick place - will implement later
}

func newCursor(t text) *cursor {
	return &cursor{0, 0, 0, t}
}

func setTermboxCursor(c *cursor, v *viewer, l *layout) {
	viewbound := l.mainViewerBound()
	viewx, viewy := viewbound.Min.X, viewbound.Min.Y
	cy, cx := c.positionInViewer(v)
	term.SetCursor(viewx+cx, viewy+cy)
}

// cursor offset cannot go further than line's maximum visual length.
func (c *cursor) offset() (coff int) {
	maxlen := c.lineVisualLength()
	if c.voff >  maxlen {
		return maxlen
	}

	// Cursor should not in the middle of multi-length(visual) character.
	// So we should recalculate cursor offset.
	remain := c.lineData()
	lastcoff := 0
	for {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		lastcoff = coff
		coff += runeVisualLength(r)
		if coff==c.voff {
			return coff
		} else if coff > c.voff {
			return lastcoff
		}
	}
	return
}

func (c *cursor) position() (int, int) {
	return c.line, c.offset()
}

func (c *cursor) positionInViewer(v *viewer) (int, int) {
	return c.line-v.min.Y, c.offset()-v.min.X
}

// text on the line
func (c *cursor) lineData() line {
	return c.t[c.line]
}

func (c *cursor) lineDataUntilCursor() line {
	return c.lineData()[:c.boff]
}

func (c *cursor) lineDataFromCursor() line {
	return c.lineData()[c.boff:]
}

func (c *cursor) exceededLineLimit() bool {
	return c.boff > len(c.lineData())
}

func (c *cursor) runeAfter() (rune, int) {
	return utf8.DecodeRune(c.lineData()[c.boff:])
}

func (c *cursor) runeBefore() (rune, int) {
	return utf8.DecodeLastRune(c.lineData()[:c.boff])
}

// should refine after
// may be use dictionary??
func runeVisualLength(r rune) int {
	if r=='\t' {
		return taboffset
	}
	return 1
}

func (c *cursor) lineVisualLength() int {
	return c.voffFromBoff(len(c.lineData()))
}

// Set boff and voff from current cursor position.
func (c *cursor) resetInternalOffsets() {
	c.boff = c.boffFromCoff(c.offset())
	c.voff = c.voffFromBoff(c.boff)
}

func (c *cursor) boffFromCoff(coff int) (boff int) {
	remain := c.lineData()
	for coff>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		boff += rlen
		coff -= runeVisualLength(r)
	}
	return
}

func (c *cursor) voffFromBoff(boff int) (voff int){
	remain := c.lineData()[:boff]
	for len(remain) > 0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		voff += runeVisualLength(r)
	}
	return
}

func (c *cursor) setOffsets(boff int) {
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) atBol() bool{
	return c.boff == 0
}

func (c *cursor) atEol() bool{
	return c.boff == len(c.lineData())
}

func (c *cursor) onFirstline() bool{
	return c.line == 0
}

func (c *cursor) onLastline() bool {
	return c.line == len(c.t)-1
}

func (c *cursor) atBof() bool {
	return c.onFirstline() && c.atBol()
}

func (c *cursor) atEof() bool {
	return c.onLastline() && c.atEol()
}

func (c *cursor) moveLeft() {
	c.resetInternalOffsets()
	if c.atBof() {
		return
	} else if c.atBol() {
		c.line -= 1
		c.boff = len(c.lineData())
		c.voff = c.voffFromBoff(c.boff)
		return
	}
	r, rlen := c.runeBefore()
	c.boff -= rlen
	c.voff -= runeVisualLength(r)
}

func (c *cursor) moveRight() {
	c.resetInternalOffsets()
	if c.atEof() {
		return
	} else if c.atEol() || c.exceededLineLimit(){
		c.line += 1
		c.setOffsets(0)
		return
	}
	r, rlen := c.runeAfter()
	c.boff += rlen
	c.voff += runeVisualLength(r)
}

// With move up and down, we will lazily evaluate internal offsets.
func (c *cursor) moveUp() {
	if c.onFirstline() {
		return
	}
	c.line--

}

func (c *cursor) moveDown() {
	if c.onLastline() {
		return
	}
	c.line++
}

func (c *cursor) moveBow() {
	c.resetInternalOffsets()
	if c.atBof() {
		return
	}
	// First we should pass every space character.
	for {
		r, _ := c.runeBefore()
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
			break
		}
		c.moveLeft()
		if c.atBof() {
			return
		}
	}
	// Then we will find first space charactor and stop.
	for {
		r, _ := c.runeBefore()
		if !(unicode.IsLetter(r) || unicode.IsDigit(r)) {
			return
		}
		c.moveLeft()
		if c.atBof() {
			return
		}
	}
}

// See moveEow for the algorithm.
func (c *cursor) moveEow() {
	c.resetInternalOffsets()
	if c.atEof() {
		return
	}
	for {
		r, _ := c.runeAfter()
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
			break
		}
		c.moveRight()
		if c.atEof() {
			return
		}
	}
	for {
		r, _ := c.runeAfter()
		if !(unicode.IsLetter(r) || unicode.IsDigit(r)) {
			return
		}
		c.moveRight()
		if c.atEof() {
			return
		}
	}
}

func (c *cursor) moveBol() {
	// if already bol, move cursor to prev line
	if c.boff == 0 && !c.onFirstline() {
		c.line--
		return
	}

	// if  prev data is all spaces, move cursor to beginning of line
	remain := c.lineDataUntilCursor()
	allspace := true
	for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			allspace = false
			break
		}
	}
	if allspace {
		c.boff = 0
		c.voff = 0
		return
	}

	// or, move cursor to first character of text on line.
	remain = c.lineData()
	boff := 0
        for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			break
		}
		boff += rlen
	}
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) moveEol() {
	// if already eol, move to next line
	if c.boff == len(c.lineData()) && !c.onLastline() {
		c.line++
	}

	// if  prev data is not all spaces move cursor to eol.
	remain := c.lineData()[:c.boff+1] // we should use runelength instead of 1
	allspace := true
	for len(remain)>0 {
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			allspace = false
			break
		}
	}
	if !allspace {
		c.boff = len(c.lineData())
		c.voff = c.voffFromBoff(c.boff)
		return
	}

	// or, move it to first chararacter of text on line.
	remain = c.lineData()
	boff := 0
	for len(remain)>0 { // will make this a function
		r, rlen := utf8.DecodeRune(remain)
		remain = remain[rlen:]
		if !unicode.IsSpace(r) {
			break
		}
		boff +=rlen
	}
	c.boff = boff
	c.voff = c.voffFromBoff(boff)
}

func (c *cursor) pageUp() {
	for i:=0; i < pageoffset; i++ {
		if c.onFirstline() {
			break
		}
		c.line--
	}
}

func (c *cursor) pageDown() {
	for i:=0; i < pageoffset; i++ {
		if c.onLastline() {
			break
		}
		c.line++
	}
}
<|endoftext|>


<commit_before>package http

import (
	"io/ioutil"

	"net/http"
	"net/url"
	"reflect"
	"testing"

	"github.com/hashicorp/vault/vault"
)

func TestSysHealth_get(t *testing.T) {
	core := vault.TestCore(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	resp, err := http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	var actual map[string]interface{}
	expected := map[string]interface{}{
		"initialized": false,
		"sealed":      true,
		"standby":     true,
	}
	testResponseStatus(t, resp, 501)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	keys, _ := vault.TestCoreInit(t, core)
	resp, err = http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"initialized": true,
		"sealed":      true,
		"standby":     true,
	}
	testResponseStatus(t, resp, 503)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	for _, key := range keys {
		if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil {
			t.Fatalf("unseal err: %s", err)
		}
	}
	resp, err = http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"initialized": true,
		"sealed":      false,
		"standby":     false,
	}
	testResponseStatus(t, resp, 200)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

}

func TestSysHealth_customcodes(t *testing.T) {
	core := vault.TestCore(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	queryurl, err := url.Parse(addr + "/v1/sys/health?uninitcode=581&sealedcode=523&activecode=202")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	resp, err := http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	var actual map[string]interface{}
	expected := map[string]interface{}{
		"initialized": false,
		"sealed":      true,
		"standby":     true,
	}
	testResponseStatus(t, resp, 581)
	testResponseBody(t, resp, &actual)

	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	keys, _ := vault.TestCoreInit(t, core)
	resp, err = http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"initialized": true,
		"sealed":      true,
		"standby":     true,
	}
	testResponseStatus(t, resp, 523)
	testResponseBody(t, resp, &actual)

	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	for _, key := range keys {
		if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil {
			t.Fatalf("unseal err: %s", err)
		}
	}
	resp, err = http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"initialized": true,
		"sealed":      false,
		"standby":     false,
	}
	testResponseStatus(t, resp, 202)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}
}

func TestSysHealth_head(t *testing.T) {
	core, _, _ := vault.TestCoreUnsealed(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	testData := []struct {
		uri  string
		code int
	}{
		{"", 200},
		{"?activecode=503", 503},
		{"?activecode=notacode", 400},
	}

	for _, tt := range testData {
		queryurl, err := url.Parse(addr + "/v1/sys/health" + tt.uri)
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}
		resp, err := http.Head(queryurl.String())
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}

		if resp.StatusCode != tt.code {
			t.Fatalf("HEAD %v expected code %d, got %d.", queryurl, tt.code, resp.StatusCode)
		}

		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}
		if len(data) > 0 {
			t.Fatalf("HEAD %v expected no body, received \"%v\".", queryurl, data)
		}
	}
}
<commit_msg>Fix sys/health tests (#3762)<commit_after>package http

import (
	"io/ioutil"

	"net/http"
	"net/url"
	"reflect"
	"testing"

	"github.com/hashicorp/vault/vault"
)

func TestSysHealth_get(t *testing.T) {
	core := vault.TestCore(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	resp, err := http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	var actual map[string]interface{}
	expected := map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              false,
		"sealed":                   true,
		"standby":                  true,
	}
	testResponseStatus(t, resp, 501)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	keys, _ := vault.TestCoreInit(t, core)
	resp, err = http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              true,
		"sealed":                   true,
		"standby":                  true,
	}
	testResponseStatus(t, resp, 503)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	for _, key := range keys {
		if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil {
			t.Fatalf("unseal err: %s", err)
		}
	}
	resp, err = http.Get(addr + "/v1/sys/health")
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              true,
		"sealed":                   false,
		"standby":                  false,
	}
	testResponseStatus(t, resp, 200)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

}

func TestSysHealth_customcodes(t *testing.T) {
	core := vault.TestCore(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	queryurl, err := url.Parse(addr + "/v1/sys/health?uninitcode=581&sealedcode=523&activecode=202")
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	resp, err := http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	var actual map[string]interface{}
	expected := map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              false,
		"sealed":                   true,
		"standby":                  true,
	}
	testResponseStatus(t, resp, 581)
	testResponseBody(t, resp, &actual)

	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	keys, _ := vault.TestCoreInit(t, core)
	resp, err = http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              true,
		"sealed":                   true,
		"standby":                  true,
	}
	testResponseStatus(t, resp, 523)
	testResponseBody(t, resp, &actual)

	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}

	for _, key := range keys {
		if _, err := vault.TestCoreUnseal(core, vault.TestKeyCopy(key)); err != nil {
			t.Fatalf("unseal err: %s", err)
		}
	}
	resp, err = http.Get(queryurl.String())
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	actual = map[string]interface{}{}
	expected = map[string]interface{}{
		"replication_dr_secondary": false,
		"initialized":              true,
		"sealed":                   false,
		"standby":                  false,
	}
	testResponseStatus(t, resp, 202)
	testResponseBody(t, resp, &actual)
	expected["server_time_utc"] = actual["server_time_utc"]
	expected["version"] = actual["version"]
	if actual["cluster_name"] == nil {
		delete(expected, "cluster_name")
	} else {
		expected["cluster_name"] = actual["cluster_name"]
	}
	if actual["cluster_id"] == nil {
		delete(expected, "cluster_id")
	} else {
		expected["cluster_id"] = actual["cluster_id"]
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Fatalf("bad: expected:%#v\nactual:%#v", expected, actual)
	}
}

func TestSysHealth_head(t *testing.T) {
	core, _, _ := vault.TestCoreUnsealed(t)
	ln, addr := TestServer(t, core)
	defer ln.Close()

	testData := []struct {
		uri  string
		code int
	}{
		{"", 200},
		{"?activecode=503", 503},
		{"?activecode=notacode", 400},
	}

	for _, tt := range testData {
		queryurl, err := url.Parse(addr + "/v1/sys/health" + tt.uri)
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}
		resp, err := http.Head(queryurl.String())
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}

		if resp.StatusCode != tt.code {
			t.Fatalf("HEAD %v expected code %d, got %d.", queryurl, tt.code, resp.StatusCode)
		}

		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatalf("err on %v: %s", queryurl, err)
		}
		if len(data) > 0 {
			t.Fatalf("HEAD %v expected no body, received \"%v\".", queryurl, data)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package reporter

import (
	"github.com/getgauge/gauge/execution/event"
	"github.com/getgauge/gauge/execution/result"
	"github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/gauge"
	. "gopkg.in/check.v1"
)

func (s *MySuite) TestSubscribeSpecEnd(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.SpecEnd, nil, nil))
	c.Assert(dw.output, Equals, "\n")
}

func (s *MySuite) TestSubscribeSpecStart(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	spec := &gauge.Specification{Heading: &gauge.Heading{Value: "My Spec Heading"}}

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.SpecStart, spec, nil))
	c.Assert(dw.output, Equals, "# My Spec Heading\n")
}

func (s *MySuite) TestSubscribeScenarioStart(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	sce := &gauge.Scenario{Heading: &gauge.Heading{Value: "My Scenario Heading"}}

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.ScenarioStart, sce, nil))
	c.Assert(dw.output, Equals, "  ## My Scenario Heading\n")
}

func (s *MySuite) TestSubscribeScenarioEnd(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	sceHeading := "My scenario heading"
	sceRes := result.NewScenarioResult(&gauge_messages.ProtoScenario{ScenarioHeading: &sceHeading})

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.ScenarioEnd, nil, sceRes))
	c.Assert(dw.output, Equals, "")
}
<commit_msg>Fixing go fmt warning<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package reporter

import (
	"github.com/getgauge/gauge/execution/event"
	"github.com/getgauge/gauge/execution/result"
	"github.com/getgauge/gauge/gauge"
	"github.com/getgauge/gauge/gauge_messages"
	. "gopkg.in/check.v1"
)

func (s *MySuite) TestSubscribeSpecEnd(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.SpecEnd, nil, nil))
	c.Assert(dw.output, Equals, "\n")
}

func (s *MySuite) TestSubscribeSpecStart(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	spec := &gauge.Specification{Heading: &gauge.Heading{Value: "My Spec Heading"}}

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.SpecStart, spec, nil))
	c.Assert(dw.output, Equals, "# My Spec Heading\n")
}

func (s *MySuite) TestSubscribeScenarioStart(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	sce := &gauge.Scenario{Heading: &gauge.Heading{Value: "My Scenario Heading"}}

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.ScenarioStart, sce, nil))
	c.Assert(dw.output, Equals, "  ## My Scenario Heading\n")
}

func (s *MySuite) TestSubscribeScenarioEnd(c *C) {
	dw, sc := setupSimpleConsole()
	currentReporter = sc
	SimpleConsoleOutput = true
	event.InitRegistry()
	sceHeading := "My scenario heading"
	sceRes := result.NewScenarioResult(&gauge_messages.ProtoScenario{ScenarioHeading: &sceHeading})

	ListenExecutionEvents()

	event.Notify(event.NewExecutionEvent(event.ScenarioEnd, nil, sceRes))
	c.Assert(dw.output, Equals, "")
}
<|endoftext|>


<commit_before>package epaxos

import (
	"sort"

	"github.com/google/btree"

	pb "github.com/nvanbenschoten/epaxos/epaxos/epaxospb"
)

type instanceState int

//go:generate stringer -type=instanceState
const (
	none instanceState = iota
	preAccepted
	accepted
	committed
	executed
)

type instance struct {
	p     *epaxos
	r     pb.ReplicaID
	i     pb.InstanceNum
	cmd   pb.Command
	seq   pb.SeqNum
	deps  map[pb.Dependency]struct{}
	state instanceState

	// command-leader state
	preAcceptReplies int
	differentReplies bool
	slowPathTimer    tickingTimer
	acceptReplies    int
}

// TODO restructure state machine

const slowPathTimout = 2

func (p *epaxos) newInstance(r pb.ReplicaID, i pb.InstanceNum) *instance {
	inst := &instance{p: p, r: r, i: i}
	inst.slowPathTimer = makeTickingTimer(slowPathTimout, func() {
		inst.transitionToAccept()
	})
	return inst
}

//
// BTree Functions
//

// Len implements the btree.Item interface.
func (inst *instance) Less(than btree.Item) bool {
	return inst.i < than.(*instance).i
}

// instanceKey creates a key to index into the commands btree.
func instanceKey(i pb.InstanceNum) btree.Item {
	return &instance{i: i}
}

//
// State-Transitions
//

func (inst *instance) transitionToPreAccept() {
	inst.assertState(none)
	inst.state = preAccepted
	inst.broadcastPreAccept()
}

func (inst *instance) transitionToAccept() {
	inst.assertState(preAccepted)
	inst.state = accepted
	inst.broadcastAccept()
}

func (inst *instance) transitionToCommit() {
	inst.assertState(preAccepted, accepted)
	inst.state = committed
	inst.broadcastCommit()
	inst.prepareToExecute()
}

func (inst *instance) assertState(valid ...instanceState) {
	cur := inst.state
	for _, v := range valid {
		if v == cur {
			return
		}
	}
	inst.p.logger.Panicf("unexpected state %v; expected %v", cur, valid)
}

// broadcastPreAccept broadcasts a PreAccept message to all other nodes.
func (inst *instance) broadcastPreAccept() {
	inst.broadcast(&pb.PreAccept{InstanceState: inst.instanceState()})
}

// broadcastAccept broadcasts an Accept message to all other nodes.
func (inst *instance) broadcastAccept() {
	inst.broadcast(&pb.Accept{InstanceState: inst.instanceStateWithoutCommand()})
}

// broadcastCommit broadcasts a Commit message to all other nodes.
func (inst *instance) broadcastCommit() {
	inst.broadcast(&pb.Commit{InstanceState: inst.instanceState()})
}

//
// Message Handlers
//

func (inst *instance) onPreAccept(pa *pb.PreAccept) {
	// Only handle if this is a new instance, and set the state to preAccepted.
	if inst.state != none {
		inst.p.logger.Debugf("ignoring PreAccept message while in state %v: %v", inst.state, pa)
		return
	}
	inst.state = preAccepted

	// Determine the local sequence number and deps for this command.
	maxLocalSeq, localDeps := inst.p.seqAndDepsForCommand(*pa.Command)

	// Record the command for the instance.
	inst.cmd = *pa.Command

	// The updated sequence number is set to the maximum of the local maximum
	// sequence number and the the PreAccept's sequence number
	inst.seq = pb.MaxSeqNum(pa.SeqNum, maxLocalSeq+1)

	// Determine the union of the local dependencies and the PreAccept's dependencies.
	depsUnion := localDeps
	for _, dep := range pa.Deps {
		depsUnion[dep] = struct{}{}
	}
	inst.deps = depsUnion

	// If the sequence number and the deps turn out to be the same as those in
	// the PreAccept message, reply with a simple PreAcceptOK message.
	if inst.seq == pa.SeqNum && len(inst.deps) == len(pa.Deps) {
		inst.reply(&pb.PreAcceptOK{})
		return
	}

	// Reply to PreAccept message with updated information.
	inst.reply(&pb.PreAcceptReply{
		UpdatedSeqNum: inst.seq,
		UpdatedDeps:   depSliceFromMap(depsUnion),
	})
}

// fastPathAvailable returns whether the fast path is still available, given
// (possibly zero) more PreAcceptReply messages.
func (inst *instance) fastPathAvailable() bool {
	return !inst.differentReplies
}

func (inst *instance) onPreAcceptOK(paOK *pb.PreAcceptOK) {
	if inst.state != preAccepted {
		inst.p.logger.Debugf("ignoring PreAcceptOK message while in state %v: %v", inst.state, paOK)
		return
	}

	inst.preAcceptReplies++
	inst.onEitherPreAcceptReply()
}

func (inst *instance) onPreAcceptReply(paReply *pb.PreAcceptReply) {
	if inst.state != preAccepted {
		inst.p.logger.Debugf("ignoring PreAcceptReply message while in state %v: %v", inst.state, paReply)
		return
	}

	// Update the instance state based on the PreAcceptReply.
	changed := inst.updateInstanceState(paReply.UpdatedSeqNum, paReply.UpdatedDeps)

	// Update whether we've ever seen any new information in PreAcceptReply messages.
	inst.differentReplies = inst.differentReplies || changed

	inst.preAcceptReplies++
	inst.onEitherPreAcceptReply()
}

func (inst *instance) onEitherPreAcceptReply() {
	replies := inst.preAcceptReplies + 1 // +1 for leader
	takeFastPath := !inst.differentReplies && inst.p.fastQuorum(replies)
	takeSlowPath := inst.p.quorum(replies)
	switch {
	case takeFastPath:
		inst.p.unregisterTimer(&inst.slowPathTimer)
		inst.transitionToCommit()
	case takeSlowPath:
		// We have enough replies to take the slow path, however we don't want to
		// take it immediately in-case it's possible to take the fast path instead.
		if !inst.fastPathAvailable() {
			// Since the fast path will never be available, take the slow path.
			inst.p.unregisterTimer(&inst.slowPathTimer)
			inst.transitionToAccept()
		} else if !inst.slowPathTimer.isSet() {
			// Delay for a few ticks before taking slow path to allow for the fast
			// path quorum to be achieved.
			inst.p.registerOneTimeTimer(&inst.slowPathTimer)
		} else {
			// Timer already set. This reply will help us get to the fast path.
		}
	}
}

func (inst *instance) onAccept(a *pb.Accept) {
	if inst.state != preAccepted {
		inst.p.logger.Debugf("ignoring Accept message while in state %v: %v", inst.state, a)
		return
	}

	inst.state = accepted
	inst.updateInstanceState(a.SeqNum, a.Deps)
	inst.reply(&pb.AcceptOK{})
}

func (inst *instance) onAcceptOK(aOK *pb.AcceptOK) {
	if inst.state != accepted {
		inst.p.logger.Debugf("ignoring AcceptOK message while in state %v: %v", inst.state, aOK)
		return
	}

	inst.acceptReplies++
	if inst.p.quorum(inst.acceptReplies + 1 /* +1 for leader */) {
		inst.transitionToCommit()
	}
}

func (inst *instance) onCommit(c *pb.Commit) {
	if inst.state != preAccepted && inst.state != accepted {
		inst.p.logger.Debugf("ignoring Commit message while in state %v: %v", inst.state, c)
		return
	}

	inst.state = committed
	inst.cmd = *c.Command
	inst.updateInstanceState(c.SeqNum, c.Deps)
	inst.prepareToExecute()
}

//
// Utility Functions
//

func (inst *instance) instanceStateWithoutCommand() pb.InstanceState {
	return pb.InstanceState{
		SeqNum: inst.seq,
		Deps:   inst.depSlice(),
	}
}

func (inst *instance) instanceState() pb.InstanceState {
	is := inst.instanceStateWithoutCommand()
	is.Command = &inst.cmd
	return is
}

// updateInstanceState updates the instance with the new sequence number and the
// new dependencies. It returns whether the instance was changed.
func (inst *instance) updateInstanceState(newSeq pb.SeqNum, newDeps []pb.Dependency) bool {
	// Check whether this PreAccept reply is identical to our preAccept or if
	// the remote peer returned extra information that we weren't aware of. An
	// identical fast path quorum allows us to skip the Paxos-Accept phase.
	sameSeq := inst.seq == newSeq
	if !sameSeq {
		// newSeq will always be larger if it is updated, so this
		// is identical to:
		//   inst.seq = pb.MaxSeqNum(inst.seq, newSeq)
		inst.seq = newSeq
	}

	// Length check == equality check, because depsUnion was a union of remote
	// deps and local deps.
	sameDeps := len(newDeps) == len(inst.deps)
	if !sameDeps {
		// Merge remote deps into local deps.
		for _, dep := range newDeps {
			inst.deps[dep] = struct{}{}
		}
	}

	changed := !(sameSeq && sameDeps)
	return changed
}

// depSlice returns the instance's dependencies as a slice instead of a map.
func (inst *instance) depSlice() []pb.Dependency {
	return depSliceFromMap(inst.deps)
}

func depSliceFromMap(depsMap map[pb.Dependency]struct{}) []pb.Dependency {
	deps := make([]pb.Dependency, 0, len(depsMap))
	for dep := range depsMap {
		deps = append(deps, dep)
	}
	// Sort so that the order is deterministic.
	sort.Sort(pb.Dependencies(deps))
	return deps
}

func (inst *instance) prepareToExecute() {
	inst.p.prepareToExecute(inst)
}
<commit_msg>Improve instance state checking<commit_after>package epaxos

import (
	"sort"

	"github.com/google/btree"

	pb "github.com/nvanbenschoten/epaxos/epaxos/epaxospb"
)

type instanceState int

//go:generate stringer -type=instanceState
const (
	none instanceState = iota
	preAccepted
	accepted
	committed
	executed
)

type instance struct {
	p     *epaxos
	r     pb.ReplicaID
	i     pb.InstanceNum
	cmd   pb.Command
	seq   pb.SeqNum
	deps  map[pb.Dependency]struct{}
	state instanceState

	// command-leader state
	preAcceptReplies int
	differentReplies bool
	slowPathTimer    tickingTimer
	acceptReplies    int
}

// TODO restructure state machine

const slowPathTimout = 2

func (p *epaxos) newInstance(r pb.ReplicaID, i pb.InstanceNum) *instance {
	inst := &instance{p: p, r: r, i: i}
	inst.slowPathTimer = makeTickingTimer(slowPathTimout, func() {
		inst.transitionToAccept()
	})
	return inst
}

//
// BTree Functions
//

// Len implements the btree.Item interface.
func (inst *instance) Less(than btree.Item) bool {
	return inst.i < than.(*instance).i
}

// instanceKey creates a key to index into the commands btree.
func instanceKey(i pb.InstanceNum) btree.Item {
	return &instance{i: i}
}

//
// State-Transitions
//

func (inst *instance) transitionToPreAccept() {
	inst.assertState(none)
	inst.state = preAccepted
	inst.broadcastPreAccept()
}

func (inst *instance) transitionToAccept() {
	inst.assertState(preAccepted)
	inst.state = accepted
	inst.broadcastAccept()
}

func (inst *instance) transitionToCommit() {
	inst.assertState(preAccepted, accepted)
	inst.state = committed
	inst.broadcastCommit()
	inst.prepareToExecute()
}

func (inst *instance) isStates(states ...instanceState) bool {
	cur := inst.state
	for _, s := range states {
		if s == cur {
			return true
		}
	}
	return false
}

func (inst *instance) assertState(valid ...instanceState) {
	if !inst.isStates(valid...) {
		inst.p.logger.Panicf("unexpected state %v; expected %v", inst.state, valid)
	}
}

// broadcastPreAccept broadcasts a PreAccept message to all other nodes.
func (inst *instance) broadcastPreAccept() {
	inst.broadcast(&pb.PreAccept{InstanceState: inst.instanceState()})
}

// broadcastAccept broadcasts an Accept message to all other nodes.
func (inst *instance) broadcastAccept() {
	inst.broadcast(&pb.Accept{InstanceState: inst.instanceStateWithoutCommand()})
}

// broadcastCommit broadcasts a Commit message to all other nodes.
func (inst *instance) broadcastCommit() {
	inst.broadcast(&pb.Commit{InstanceState: inst.instanceState()})
}

//
// Message Handlers
//

func (inst *instance) onPreAccept(pa *pb.PreAccept) {
	// Only handle if this is a new instance, and set the state to preAccepted.
	if !inst.isStates(none) {
		inst.p.logger.Debugf("ignoring PreAccept message while in state %v: %v", inst.state, pa)
		return
	}
	inst.state = preAccepted

	// Determine the local sequence number and deps for this command.
	maxLocalSeq, localDeps := inst.p.seqAndDepsForCommand(*pa.Command)

	// Record the command for the instance.
	inst.cmd = *pa.Command

	// The updated sequence number is set to the maximum of the local maximum
	// sequence number and the the PreAccept's sequence number
	inst.seq = pb.MaxSeqNum(pa.SeqNum, maxLocalSeq+1)

	// Determine the union of the local dependencies and the PreAccept's dependencies.
	depsUnion := localDeps
	for _, dep := range pa.Deps {
		depsUnion[dep] = struct{}{}
	}
	inst.deps = depsUnion

	// If the sequence number and the deps turn out to be the same as those in
	// the PreAccept message, reply with a simple PreAcceptOK message.
	if inst.seq == pa.SeqNum && len(inst.deps) == len(pa.Deps) {
		inst.reply(&pb.PreAcceptOK{})
		return
	}

	// Reply to PreAccept message with updated information.
	inst.reply(&pb.PreAcceptReply{
		UpdatedSeqNum: inst.seq,
		UpdatedDeps:   depSliceFromMap(depsUnion),
	})
}

// fastPathAvailable returns whether the fast path is still available, given
// (possibly zero) more PreAcceptReply messages.
func (inst *instance) fastPathAvailable() bool {
	return !inst.differentReplies
}

func (inst *instance) onPreAcceptOK(paOK *pb.PreAcceptOK) {
	if !inst.isStates(preAccepted) {
		inst.p.logger.Debugf("ignoring PreAcceptOK message while in state %v: %v", inst.state, paOK)
		return
	}

	inst.preAcceptReplies++
	inst.onEitherPreAcceptReply()
}

func (inst *instance) onPreAcceptReply(paReply *pb.PreAcceptReply) {
	if !inst.isStates(preAccepted) {
		inst.p.logger.Debugf("ignoring PreAcceptReply message while in state %v: %v", inst.state, paReply)
		return
	}

	// Update the instance state based on the PreAcceptReply.
	changed := inst.updateInstanceState(paReply.UpdatedSeqNum, paReply.UpdatedDeps)

	// Update whether we've ever seen any new information in PreAcceptReply messages.
	inst.differentReplies = inst.differentReplies || changed

	inst.preAcceptReplies++
	inst.onEitherPreAcceptReply()
}

func (inst *instance) onEitherPreAcceptReply() {
	replies := inst.preAcceptReplies + 1 // +1 for leader
	takeFastPath := !inst.differentReplies && inst.p.fastQuorum(replies)
	takeSlowPath := inst.p.quorum(replies)
	switch {
	case takeFastPath:
		inst.p.unregisterTimer(&inst.slowPathTimer)
		inst.transitionToCommit()
	case takeSlowPath:
		// We have enough replies to take the slow path, however we don't want to
		// take it immediately in-case it's possible to take the fast path instead.
		if !inst.fastPathAvailable() {
			// Since the fast path will never be available, take the slow path.
			inst.p.unregisterTimer(&inst.slowPathTimer)
			inst.transitionToAccept()
		} else if !inst.slowPathTimer.isSet() {
			// Delay for a few ticks before taking slow path to allow for the fast
			// path quorum to be achieved.
			inst.p.registerOneTimeTimer(&inst.slowPathTimer)
		} else {
			// Timer already set. This reply will help us get to the fast path.
		}
	}
}

func (inst *instance) onAccept(a *pb.Accept) {
	if !inst.isStates(none, preAccepted) {
		inst.p.logger.Debugf("ignoring Accept message while in state %v: %v", inst.state, a)
		return
	}

	inst.state = accepted
	inst.updateInstanceState(a.SeqNum, a.Deps)
	inst.reply(&pb.AcceptOK{})
}

func (inst *instance) onAcceptOK(aOK *pb.AcceptOK) {
	if !inst.isStates(accepted) {
		inst.p.logger.Debugf("ignoring AcceptOK message while in state %v: %v", inst.state, aOK)
		return
	}

	inst.acceptReplies++
	if inst.p.quorum(inst.acceptReplies + 1 /* +1 for leader */) {
		inst.transitionToCommit()
	}
}

func (inst *instance) onCommit(c *pb.Commit) {
	if !inst.isStates(none, preAccepted, accepted) {
		inst.p.logger.Debugf("ignoring Commit message while in state %v: %v", inst.state, c)
		return
	}

	inst.state = committed
	inst.cmd = *c.Command
	inst.updateInstanceState(c.SeqNum, c.Deps)
	inst.prepareToExecute()
}

//
// Utility Functions
//

func (inst *instance) instanceStateWithoutCommand() pb.InstanceState {
	return pb.InstanceState{
		SeqNum: inst.seq,
		Deps:   inst.depSlice(),
	}
}

func (inst *instance) instanceState() pb.InstanceState {
	is := inst.instanceStateWithoutCommand()
	is.Command = &inst.cmd
	return is
}

// updateInstanceState updates the instance with the new sequence number and the
// new dependencies. It returns whether the instance was changed.
func (inst *instance) updateInstanceState(newSeq pb.SeqNum, newDeps []pb.Dependency) bool {
	// Check whether this PreAccept reply is identical to our preAccept or if
	// the remote peer returned extra information that we weren't aware of. An
	// identical fast path quorum allows us to skip the Paxos-Accept phase.
	sameSeq := inst.seq == newSeq
	if !sameSeq {
		// newSeq will always be larger if it is updated, so this
		// is identical to:
		//   inst.seq = pb.MaxSeqNum(inst.seq, newSeq)
		inst.seq = newSeq
	}

	// Length check == equality check, because depsUnion was a union of remote
	// deps and local deps.
	sameDeps := len(newDeps) == len(inst.deps)
	if !sameDeps {
		// Merge remote deps into local deps.
		for _, dep := range newDeps {
			inst.deps[dep] = struct{}{}
		}
	}

	changed := !(sameSeq && sameDeps)
	return changed
}

// depSlice returns the instance's dependencies as a slice instead of a map.
func (inst *instance) depSlice() []pb.Dependency {
	return depSliceFromMap(inst.deps)
}

func depSliceFromMap(depsMap map[pb.Dependency]struct{}) []pb.Dependency {
	deps := make([]pb.Dependency, 0, len(depsMap))
	for dep := range depsMap {
		deps = append(deps, dep)
	}
	// Sort so that the order is deterministic.
	sort.Sort(pb.Dependencies(deps))
	return deps
}

func (inst *instance) prepareToExecute() {
	inst.p.prepareToExecute(inst)
}
<|endoftext|>


<commit_before>package vals

import (
	"errors"
	"reflect"
)

// Indexer wraps the Index method.
type Indexer interface {
	// Index retrieves the value corresponding to the specified key in the
	// container. It returns the value (if any), and whether it actually exists.
	Index(k interface{}) (v interface{}, ok bool)
}

// ErrIndexer wraps the Index method.
type ErrIndexer interface {
	// Index retrieves one value from the receiver at the specified index.
	Index(k interface{}) (interface{}, error)
}

var errNotIndexable = errors.New("not indexable")

type noSuchKeyError struct {
	key interface{}
}

// NoSuchKey returns an error indicating that a key is not found in a map-like
// value.
func NoSuchKey(k interface{}) error {
	return noSuchKeyError{k}
}

func (err noSuchKeyError) Error() string {
	return "no such key: " + Repr(err.key, NoPretty)
}

// Index indexes a value with the given key. It is implemented for the builtin
// type string, the List type, StructMap types, and types satisfying the
// ErrIndexer or Indexer interface (the Map type satisfies Indexer). For other
// types, it returns a nil value and a non-nil error.
func Index(a, k interface{}) (interface{}, error) {
	switch a := a.(type) {
	case string:
		return indexString(a, k)
	case List:
		return indexList(a, k)
	case StructMap:
		fieldName, ok := k.(string)
		if !ok {
			return nil, NoSuchKey(k)
		}
		return indexStructMap(a, fieldName)
	case ErrIndexer:
		return a.Index(k)
	case Indexer:
		v, ok := a.Index(k)
		if !ok {
			return nil, NoSuchKey(k)
		}
		return v, nil
	default:
		return nil, errNotIndexable
	}
}

func indexStructMap(a StructMap, k string) (interface{}, error) {
	info := getStructMapInfo(reflect.TypeOf(a))
	for i, fieldName := range info.fieldNames {
		if k == fieldName {
			return reflect.ValueOf(a).Field(i).Interface(), nil
		}
	}
	return nil, NoSuchKey(k)
}
<commit_msg>eval/vals: Make Index of StructMaps use FromGo.<commit_after>package vals

import (
	"errors"
	"reflect"
)

// Indexer wraps the Index method.
type Indexer interface {
	// Index retrieves the value corresponding to the specified key in the
	// container. It returns the value (if any), and whether it actually exists.
	Index(k interface{}) (v interface{}, ok bool)
}

// ErrIndexer wraps the Index method.
type ErrIndexer interface {
	// Index retrieves one value from the receiver at the specified index.
	Index(k interface{}) (interface{}, error)
}

var errNotIndexable = errors.New("not indexable")

type noSuchKeyError struct {
	key interface{}
}

// NoSuchKey returns an error indicating that a key is not found in a map-like
// value.
func NoSuchKey(k interface{}) error {
	return noSuchKeyError{k}
}

func (err noSuchKeyError) Error() string {
	return "no such key: " + Repr(err.key, NoPretty)
}

// Index indexes a value with the given key. It is implemented for the builtin
// type string, the List type, StructMap types, and types satisfying the
// ErrIndexer or Indexer interface (the Map type satisfies Indexer). For other
// types, it returns a nil value and a non-nil error.
func Index(a, k interface{}) (interface{}, error) {
	switch a := a.(type) {
	case string:
		return indexString(a, k)
	case List:
		return indexList(a, k)
	case StructMap:
		fieldName, ok := k.(string)
		if !ok {
			return nil, NoSuchKey(k)
		}
		return indexStructMap(a, fieldName)
	case ErrIndexer:
		return a.Index(k)
	case Indexer:
		v, ok := a.Index(k)
		if !ok {
			return nil, NoSuchKey(k)
		}
		return v, nil
	default:
		return nil, errNotIndexable
	}
}

func indexStructMap(a StructMap, k string) (interface{}, error) {
	info := getStructMapInfo(reflect.TypeOf(a))
	for i, fieldName := range info.fieldNames {
		if k == fieldName {
			return FromGo(reflect.ValueOf(a).Field(i).Interface()), nil
		}
	}
	return nil, NoSuchKey(k)
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package filter

import (
	"github.com/getgauge/gauge/parser"
	"math/rand"
	"sort"
	"time"
)

type specsFilter interface {
	filter([]*parser.Specification) []*parser.Specification
}

type tagsFilter struct {
	tagExp string
}

type specsGroupFilter struct {
	group       int
	execStreams int
}

type specRandomizer struct {
	dontRandomize bool
}

func (tagsFilter *tagsFilter) filter(specs []*parser.Specification) []*parser.Specification {
	if tagsFilter.tagExp != "" {
		validateTagExpression(tagsFilter.tagExp)
		specs = filterSpecsByTags(specs, tagsFilter.tagExp)
	}
	return specs
}

func (groupFilter *specsGroupFilter) filter(specs []*parser.Specification) []*parser.Specification {
	if groupFilter.group == -1 {
		return specs
	}

	if groupFilter.group < 1 || groupFilter.group > groupFilter.execStreams {
		return make([]*parser.Specification, 0)
	}
	return DistributeSpecs(specs, groupFilter.execStreams)[groupFilter.group-1].Specs
}

func DistributeSpecs(specifications []*parser.Specification, distributions int) []*SpecCollection {
	specCollections := make([]*SpecCollection, distributions)
	for i := 0; i < len(specifications); i++ {
		mod := i % distributions
		if specCollections[mod] == nil {
			specCollections[mod] = &SpecCollection{Specs: make([]*parser.Specification, 0)}
		}
		specCollections[mod].Specs = append(specCollections[mod].Specs, specifications[i])
	}
	return specCollections
}

type SpecCollection struct {
	Specs []*parser.Specification
}

func (s *SpecCollection) SpecNames() []string {
	specNames := make([]string, 0)
	for _, spec := range s.Specs {
		specNames = append(specNames, spec.FileName)
	}
	return specNames
}

func (randomizer *specRandomizer) filter(specs []*parser.Specification) []*parser.Specification {
	if !randomizer.dontRandomize {
		return shuffleSpecs(specs)
	}
	return specs
}

func shuffleSpecs(allSpecs []*parser.Specification) []*parser.Specification {
	dest := make([]*parser.Specification, len(allSpecs))
	rand.Seed(int64(time.Now().Nanosecond()))
	perm := rand.Perm(len(allSpecs))
	for i, v := range perm {
		dest[v] = allSpecs[i]
	}
	return dest
}

type ByFileName []*parser.Specification

func (s ByFileName) Len() int {
	return len(s)
}

func (s ByFileName) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s ByFileName) Less(i, j int) bool {
	return s[i].FileName < s[j].FileName
}

func sortSpecsList(allSpecs []*parser.Specification) []*parser.Specification {
	sort.Sort(ByFileName(allSpecs))
	return allSpecs
}
<commit_msg>Sorting specs before distributing for group execution<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package filter

import (
	"github.com/getgauge/gauge/parser"
	"math/rand"
	"sort"
	"time"
)

type specsFilter interface {
	filter([]*parser.Specification) []*parser.Specification
}

type tagsFilter struct {
	tagExp string
}

type specsGroupFilter struct {
	group       int
	execStreams int
}

type specRandomizer struct {
	dontRandomize bool
}

func (tagsFilter *tagsFilter) filter(specs []*parser.Specification) []*parser.Specification {
	if tagsFilter.tagExp != "" {
		validateTagExpression(tagsFilter.tagExp)
		specs = filterSpecsByTags(specs, tagsFilter.tagExp)
	}
	return specs
}

func (groupFilter *specsGroupFilter) filter(specs []*parser.Specification) []*parser.Specification {
	if groupFilter.group == -1 {
		return specs
	}

	if groupFilter.group < 1 || groupFilter.group > groupFilter.execStreams {
		return make([]*parser.Specification, 0)
	}
	return DistributeSpecs(sortSpecsList(specs), groupFilter.execStreams)[groupFilter.group-1].Specs
}

func DistributeSpecs(specifications []*parser.Specification, distributions int) []*SpecCollection {
	specCollections := make([]*SpecCollection, distributions)
	for i := 0; i < len(specifications); i++ {
		mod := i % distributions
		if specCollections[mod] == nil {
			specCollections[mod] = &SpecCollection{Specs: make([]*parser.Specification, 0)}
		}
		specCollections[mod].Specs = append(specCollections[mod].Specs, specifications[i])
	}
	return specCollections
}

type SpecCollection struct {
	Specs []*parser.Specification
}

func (s *SpecCollection) SpecNames() []string {
	specNames := make([]string, 0)
	for _, spec := range s.Specs {
		specNames = append(specNames, spec.FileName)
	}
	return specNames
}

func (randomizer *specRandomizer) filter(specs []*parser.Specification) []*parser.Specification {
	if !randomizer.dontRandomize {
		return shuffleSpecs(specs)
	}
	return specs
}

func shuffleSpecs(allSpecs []*parser.Specification) []*parser.Specification {
	dest := make([]*parser.Specification, len(allSpecs))
	rand.Seed(int64(time.Now().Nanosecond()))
	perm := rand.Perm(len(allSpecs))
	for i, v := range perm {
		dest[v] = allSpecs[i]
	}
	return dest
}

type ByFileName []*parser.Specification

func (s ByFileName) Len() int {
	return len(s)
}

func (s ByFileName) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

func (s ByFileName) Less(i, j int) bool {
	return s[i].FileName < s[j].FileName
}

func sortSpecsList(allSpecs []*parser.Specification) []*parser.Specification {
	sort.Sort(ByFileName(allSpecs))
	return allSpecs
}
<|endoftext|>


<commit_before>package devices

import (
	"encoding/json"
	"errors"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"

	log "github.com/cihub/seelog"
)

//type DeviceInterface interface {
//[> TODO: add methods <]
//SetName(string)
//SyncState(interface{})
//}

var regex = regexp.MustCompile(`^([^\s\[][^\s\[]*)?(\[.*?([0-9]+).*?\])?$`)

//Device is the abstraction between devices on the nodes and the device on the server
type Device struct {
	Type     string                 `json:"type"`
	Node     string                 `json:"node,omitempty"`
	Id       string                 `json:"id,omitempty"`
	Name     string                 `json:"name,omitempty"`
	Online   bool                   `json:"online"`
	StateMap map[string]string      `json:"stateMap,omitempty"`
	State    map[string]interface{} `json:"state,omitempty"`
	Tags     []string               `json:"tags"`

	sync.RWMutex
}

// NewDevice returns a new Device
func NewDevice() *Device {
	device := &Device{
		StateMap: make(map[string]string),
	}

	return device
}

//func (d *Device) SetName(name string) {
//d.Name = name
//}

// SyncState syncs the state between the node data and the device
func (d *Device) SyncState(state interface{}) {
	d.Lock()

	var err error
	d.State = make(map[string]interface{})
	for k, v := range d.StateMap {
		if value, err := path(state, v); err == nil {
			if reflect.ValueOf(value).IsNil() { // Dont accept nil values
				delete(d.State, k) // Remove it from the map
				continue
			}
			d.State[k] = value
			continue
		}
		log.Error(err)
	}
	d.StateMap = nil

	d.Unlock()
}

// SetOnline sets the online state of the device
func (d *Device) SetOnline(online bool) {
	d.Lock()
	d.Online = online
	d.Unlock()
}

// Map is a list of all devices. The key should be "<nodeuuid>.<deviceuuid>"
type Map struct {
	devices map[string]*Device
	sync.RWMutex
}

// NewMap returns initialized Map
func NewMap() *Map {
	return &Map{
		devices: make(map[string]*Device),
	}
}

// Add adds a device the the device map.
func (m *Map) Add(dev *Device) {
	m.Lock()
	defer m.Unlock()

	if dev.Node != "" {
		m.devices[dev.Node+"."+dev.Id] = dev
		return
	}
	m.devices[dev.Id] = dev
}

// Deletes a device from the map.
func (m *Map) Delete(id string) {
	m.Lock()
	defer m.Unlock()

	delete(m.devices, id)
}

// Exists return true if device id exists in the map
func (m *Map) Exists(id string) bool {
	m.RLock()
	defer m.RUnlock()

	if _, ok := m.devices[id]; ok {
		return true
	}
	return false
}

// ByID returns device based on id. If device has node set the id will be node.id
func (m *Map) ByID(uuid string) *Device {
	m.RLock()
	defer m.RUnlock()

	if node, ok := m.devices[uuid]; ok {
		return node
	}
	return nil
}

// All returns a list of all devices
func (m *Map) All() map[string]*Device {
	m.RLock()
	defer m.RUnlock()

	return m.devices
}

// Len returns length of map
func (m *Map) Len() int {
	m.RLock()
	defer m.RUnlock()

	return len(m.devices)
}

func (m *Map) MarshalJSON() ([]byte, error) {
	alias := make(map[string]Device)
	m.RLock()

	for k, v := range m.devices {
		if v != nil {
			alias[k] = *v
		}
	}
	defer m.RUnlock()
	return json.Marshal(alias)
}

func (m *Map) UnmarshalJSON(b []byte) error {
	var alias map[string]*Device
	err := json.Unmarshal(b, &alias)
	if err != nil {
		return err
	}

	m.Lock()
	m.devices = alias
	m.Unlock()

	return nil
}

func path(state interface{}, jp string) (interface{}, error) {
	if jp == "" {
		return nil, errors.New("invalid path")
	}
	for _, token := range strings.Split(jp, ".") {
		sl := regex.FindAllStringSubmatch(token, -1)
		if len(sl) == 0 {
			return nil, errors.New("invalid path1")
		}
		ss := sl[0]
		if ss[1] != "" {
			switch v1 := state.(type) {
			case map[string]interface{}:
				state = v1[ss[1]]
			}
		}
		if ss[3] != "" {
			ii, err := strconv.Atoi(ss[3])
			is := ss[3]
			if err != nil {
				return nil, errors.New("invalid path2")
			}
			switch v2 := state.(type) {
			case []interface{}:
				state = v2[ii]
			case map[string]interface{}:
				state = v2[is]
			}
		}
	}
	return state, nil
}
<commit_msg>Fixed failing build<commit_after>package devices

import (
	"encoding/json"
	"errors"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"sync"

	log "github.com/cihub/seelog"
)

//type DeviceInterface interface {
//[> TODO: add methods <]
//SetName(string)
//SyncState(interface{})
//}

var regex = regexp.MustCompile(`^([^\s\[][^\s\[]*)?(\[.*?([0-9]+).*?\])?$`)

//Device is the abstraction between devices on the nodes and the device on the server
type Device struct {
	Type     string                 `json:"type"`
	Node     string                 `json:"node,omitempty"`
	Id       string                 `json:"id,omitempty"`
	Name     string                 `json:"name,omitempty"`
	Online   bool                   `json:"online"`
	StateMap map[string]string      `json:"stateMap,omitempty"`
	State    map[string]interface{} `json:"state,omitempty"`
	Tags     []string               `json:"tags"`

	sync.RWMutex
}

// NewDevice returns a new Device
func NewDevice() *Device {
	device := &Device{
		StateMap: make(map[string]string),
	}

	return device
}

//func (d *Device) SetName(name string) {
//d.Name = name
//}

// SyncState syncs the state between the node data and the device
func (d *Device) SyncState(state interface{}) {
	d.Lock()

	var err error
	d.State = make(map[string]interface{})
	for k, v := range d.StateMap {
		if value, err := path(state, v); err == nil {
			if !reflect.ValueOf(value).IsValid() { // Dont accept nil values
				delete(d.State, k) // Remove it from the map
				continue
			}
			d.State[k] = value
			continue
		}
		log.Error(err)
	}
	d.StateMap = nil

	d.Unlock()
}

// SetOnline sets the online state of the device
func (d *Device) SetOnline(online bool) {
	d.Lock()
	d.Online = online
	d.Unlock()
}

// Map is a list of all devices. The key should be "<nodeuuid>.<deviceuuid>"
type Map struct {
	devices map[string]*Device
	sync.RWMutex
}

// NewMap returns initialized Map
func NewMap() *Map {
	return &Map{
		devices: make(map[string]*Device),
	}
}

// Add adds a device the the device map.
func (m *Map) Add(dev *Device) {
	m.Lock()
	defer m.Unlock()

	if dev.Node != "" {
		m.devices[dev.Node+"."+dev.Id] = dev
		return
	}
	m.devices[dev.Id] = dev
}

// Deletes a device from the map.
func (m *Map) Delete(id string) {
	m.Lock()
	defer m.Unlock()

	delete(m.devices, id)
}

// Exists return true if device id exists in the map
func (m *Map) Exists(id string) bool {
	m.RLock()
	defer m.RUnlock()

	if _, ok := m.devices[id]; ok {
		return true
	}
	return false
}

// ByID returns device based on id. If device has node set the id will be node.id
func (m *Map) ByID(uuid string) *Device {
	m.RLock()
	defer m.RUnlock()

	if node, ok := m.devices[uuid]; ok {
		return node
	}
	return nil
}

// All returns a list of all devices
func (m *Map) All() map[string]*Device {
	m.RLock()
	defer m.RUnlock()

	return m.devices
}

// Len returns length of map
func (m *Map) Len() int {
	m.RLock()
	defer m.RUnlock()

	return len(m.devices)
}

func (m *Map) MarshalJSON() ([]byte, error) {
	alias := make(map[string]Device)
	m.RLock()

	for k, v := range m.devices {
		if v != nil {
			alias[k] = *v
		}
	}
	defer m.RUnlock()
	return json.Marshal(alias)
}

func (m *Map) UnmarshalJSON(b []byte) error {
	var alias map[string]*Device
	err := json.Unmarshal(b, &alias)
	if err != nil {
		return err
	}

	m.Lock()
	m.devices = alias
	m.Unlock()

	return nil
}

func path(state interface{}, jp string) (interface{}, error) {
	if jp == "" {
		return nil, errors.New("invalid path")
	}
	for _, token := range strings.Split(jp, ".") {
		sl := regex.FindAllStringSubmatch(token, -1)
		if len(sl) == 0 {
			return nil, errors.New("invalid path1")
		}
		ss := sl[0]
		if ss[1] != "" {
			switch v1 := state.(type) {
			case map[string]interface{}:
				state = v1[ss[1]]
			}
		}
		if ss[3] != "" {
			ii, err := strconv.Atoi(ss[3])
			is := ss[3]
			if err != nil {
				return nil, errors.New("invalid path2")
			}
			switch v2 := state.(type) {
			case []interface{}:
				state = v2[ii]
			case map[string]interface{}:
				state = v2[is]
			}
		}
	}
	return state, nil
}
<|endoftext|>


<commit_before>package protocol

type Data struct {
	Partition int32
	RecordSet []byte
}

type TopicData struct {
	Topic string
	Data  []*Data
}

type ProduceRequest struct {
	// unsupported: Acks int16
	Timeout   int32
	TopicData []*TopicData
}

func (r *ProduceRequest) Encode(e PacketEncoder) error {
	e.PutInt32(r.Timeout)
	e.PutArrayLength(len(r.TopicData))
	for _, td := range r.TopicData {
		e.PutString(td.Topic)
		e.PutArrayLength(len(td.Data))
		for _, d := range td.Data {
			e.PutInt32(d.Partition)
			e.PutBytes(d.RecordSet)
		}
	}
	return nil
}

func (r *ProduceRequest) Decode(d PacketDecoder) error {
	var err error
	r.Timeout, err = d.Int32()
	if err != nil {
		return err
	}
	tdlen, err := d.ArrayLength()
	r.TopicData = make([]*TopicData, tdlen)
	for i := range r.TopicData {
		td := new(TopicData)
		r.TopicData[i] = td
		td.Topic, err = d.String()
		if err != nil {
			return err
		}
		dlen, err := d.ArrayLength()
		if err != nil {
			return err
		}
		td.Data = make([]*Data, dlen)
		for j := range td.Data {
			data := new(Data)
			td.Data[j] = data
			data.Partition, err = d.Int32()
			if err != nil {
				return err
			}
			data.RecordSet, err = d.Bytes()
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (r *ProduceRequest) Key() int16 {
	return 0
}

func (r *ProduceRequest) Version() int16 {
	return 2
}
<commit_msg>produce: support acks<commit_after>package protocol

type Data struct {
	Partition int32
	RecordSet []byte
}

type TopicData struct {
	Topic string
	Data  []*Data
}

type ProduceRequest struct {
	Acks      int16
	Timeout   int32
	TopicData []*TopicData
}

func (r *ProduceRequest) Encode(e PacketEncoder) error {
	e.PutInt32(r.Timeout)
	e.PutArrayLength(len(r.TopicData))
	for _, td := range r.TopicData {
		e.PutString(td.Topic)
		e.PutArrayLength(len(td.Data))
		for _, d := range td.Data {
			e.PutInt32(d.Partition)
			e.PutBytes(d.RecordSet)
		}
	}
	return nil
}

func (r *ProduceRequest) Decode(d PacketDecoder) error {
	var err error
	r.Acks, err = d.Int16()
	if err != nil {
		return err
	}
	r.Timeout, err = d.Int32()
	if err != nil {
		return err
	}
	tdlen, err := d.ArrayLength()
	r.TopicData = make([]*TopicData, tdlen)
	for i := range r.TopicData {
		td := new(TopicData)
		r.TopicData[i] = td
		td.Topic, err = d.String()
		if err != nil {
			return err
		}
		dlen, err := d.ArrayLength()
		if err != nil {
			return err
		}
		td.Data = make([]*Data, dlen)
		for j := range td.Data {
			data := new(Data)
			td.Data[j] = data
			data.Partition, err = d.Int32()
			if err != nil {
				return err
			}
			data.RecordSet, err = d.Bytes()
			if err != nil {
				return err
			}
		}
	}
	return nil
}

func (r *ProduceRequest) Key() int16 {
	return 0
}

func (r *ProduceRequest) Version() int16 {
	return 2
}
<|endoftext|>


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

// Package baidubce define a set of core data structure, and implements a set of core functions.
package baidubce

import (
	"fmt"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"baidubce/util"
)

const (
	// ExpirationPeriodInSeconds 1800s is the default expiration period.
	ExpirationPeriodInSeconds = 1800
)

// Region map of baidubce
var Region = map[string]string{
	"bj": "bj.bcebos.com",
	"gz": "gz.bcebos.com",
}

// Credentials struct for baidubce.
type Credentials struct {
	AccessKeyID     string
	SecretAccessKey string
}

// NewCredentials returns an instance of type `Credentials`.
func NewCredentials(AccessKeyID, secretAccessKey string) *Credentials {
	return &Credentials{AccessKeyID, secretAccessKey}
}

// DefaultCredentials provided a default `Credentials` instance.
var DefaultCredentials = Credentials{
	os.Getenv("BAIDU_BCE_AK"),
	os.Getenv("BAIDU_BCE_SK"),
}

// Config contains options for baidubce api.
type Config struct {
	Credentials
	Endpoint   string
	APIVersion string
}

// DefaultConfig provided a default `Config` instance.
var DefaultConfig = Config{DefaultCredentials, "", "v1"}

// SignOption contains options for signature of baidubce api.
type SignOption struct {
	Timestamp                 string
	ExpirationPeriodInSeconds int
	Headers                   map[string]string
	HeadersToSign             []string
	headersToSignSpecified    bool
}

// NewSignOption is the instance factory for `SignOption`.
func NewSignOption(timestamp string, expirationPeriodInSeconds int,
	headers map[string]string, headersToSign []string) *SignOption {

	return &SignOption{timestamp, expirationPeriodInSeconds,
		headers, headersToSign, len(headersToSign) > 0}
}

func CheckSignOption(option *SignOption) *SignOption {
	if option == nil {
		return &SignOption{}
	}

	return option
}

func (option *SignOption) AddHeadersToSign(headers ...string) {
	if option.HeadersToSign == nil {
		option.HeadersToSign = []string{}
	}

	for _, header := range headers {
		option.HeadersToSign = append(option.HeadersToSign, header)
	}
}

func (option *SignOption) AddHeader(key, value string) {
	if option.Headers == nil {
		option.Headers = make(map[string]string)
	}

	option.Headers[key] = value
}

func (option *SignOption) init() {
	if option.Timestamp == "" {
		option.Timestamp = util.TimeToUTCString(time.Now())
	}

	if option.ExpirationPeriodInSeconds <= 0 {
		option.ExpirationPeriodInSeconds = ExpirationPeriodInSeconds
	}

	if option.Headers == nil {
		option.Headers = make(map[string]string, 3)
	} else {
		util.MapKeyToLower(option.Headers)
	}

	option.headersToSignSpecified = len(option.HeadersToSign) > 0
	util.SliceToLower(option.HeadersToSign)

	if !util.Contains(option.HeadersToSign, "host", true) {
		option.HeadersToSign = append(option.HeadersToSign, "host")
	}

	if util.Contains(option.HeadersToSign, "date", true) {
		if !util.MapContains(option.Headers, generateHeaderValidCompareFunc("date")) {
			option.Headers["date"] = time.Now().Format(time.RFC1123)
		} else {
			option.Headers["date"] = util.TimeStringToRFC1123(util.GetMapValue(option.Headers, "date", true))
		}
	} else if util.Contains(option.HeadersToSign, "x-bce-date", true) {
		if !util.MapContains(option.Headers, generateHeaderValidCompareFunc("x-bce-date")) {
			option.Headers["x-bce-date"] = option.Timestamp
		}
	} else {
		option.HeadersToSign = append(option.HeadersToSign, "x-bce-date")
		option.Headers["x-bce-date"] = option.Timestamp
	}
}

func (option *SignOption) signedHeadersToString() string {
	var result string
	length := len(option.HeadersToSign)
	if option.headersToSignSpecified && length > 0 {
		headers := make([]string, 0, length)
		headers = append(headers, option.HeadersToSign...)
		sort.Strings(headers)
		result = strings.Join(headers, ";")
	}

	return result
}

// GenerateAuthorization returns authorization code of baidubce api.
func GenerateAuthorization(credentials Credentials, req Request, option *SignOption) string {
	if option == nil {
		option = &SignOption{}
	}
	option.init()

	authorization := "bce-auth-v1/" + credentials.AccessKeyID
	authorization += "/" + option.Timestamp
	authorization += "/" + strconv.Itoa(option.ExpirationPeriodInSeconds)
	signature := sign(credentials, req, option)
	authorization += "/" + option.signedHeadersToString() + "/" + signature

	req.addHeader("Authorization", authorization)

	return authorization
}

// Client is the base client struct for all products of baidubce.
type Client struct {
	Config
}

func (c *Client) GetUriPath(uriPath string) string {
	if c.APIVersion != "" {
		return fmt.Sprintf("/%s/%s", c.APIVersion, uriPath)
	}

	return fmt.Sprintf("/%s", uriPath)
}

// SendRequest sends a http request to the endpoint of baidubce api.
func (c *Client) SendRequest(req *Request, option *SignOption) (*Response, *Error) {
	GenerateAuthorization(c.Credentials, *req, option)
	httpClient := http.Client{}
	res, err := httpClient.Do(req.raw())

	defer func() {
		if res != nil {
			res.Body.Close()
		}
	}()

	if err != nil {
		return nil, NewError(err)
	}

	bceResponse := NewResponse(res)

	if res.StatusCode >= 400 {
		return bceResponse, NewErrorFromJSON(bceResponse.Body)
	}

	return bceResponse, nil
}

func generateHeaderValidCompareFunc(headerKey string) func(string, string) bool {
	return func(key, value string) bool {
		return strings.ToLower(key) == strings.ToLower(headerKey) && value != ""
	}
}

// sign returns signed signature.
func sign(credentials Credentials, req Request, option *SignOption) string {
	signingKey := getSigningKey(credentials, option)
	req.prepareHeaders(option)
	canonicalRequest := req.canonical(option)
	signature := util.HmacSha256Hex(signingKey, canonicalRequest)

	return signature
}

func getSigningKey(credentials Credentials, option *SignOption) string {
	var authStringPrefix = fmt.Sprintf("bce-auth-v1/%s", credentials.AccessKeyID)
	authStringPrefix += "/" + option.Timestamp
	authStringPrefix += "/" + strconv.Itoa(option.ExpirationPeriodInSeconds)

	return util.HmacSha256Hex(credentials.SecretAccessKey, authStringPrefix)
}
<commit_msg>format uri path<commit_after>/**
 * Copyright (c) 2015 Guoyao Wu, All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @file core.go
 * @author guoyao
 */

// Package baidubce define a set of core data structure, and implements a set of core functions.
package baidubce

import (
	"fmt"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"baidubce/util"
)

const (
	// ExpirationPeriodInSeconds 1800s is the default expiration period.
	ExpirationPeriodInSeconds = 1800
)

// Region map of baidubce
var Region = map[string]string{
	"bj": "bj.bcebos.com",
	"gz": "gz.bcebos.com",
}

// Credentials struct for baidubce.
type Credentials struct {
	AccessKeyID     string
	SecretAccessKey string
}

// NewCredentials returns an instance of type `Credentials`.
func NewCredentials(AccessKeyID, secretAccessKey string) *Credentials {
	return &Credentials{AccessKeyID, secretAccessKey}
}

// DefaultCredentials provided a default `Credentials` instance.
var DefaultCredentials = Credentials{
	os.Getenv("BAIDU_BCE_AK"),
	os.Getenv("BAIDU_BCE_SK"),
}

// Config contains options for baidubce api.
type Config struct {
	Credentials
	Endpoint   string
	APIVersion string
}

// DefaultConfig provided a default `Config` instance.
var DefaultConfig = Config{DefaultCredentials, "", "v1"}

// SignOption contains options for signature of baidubce api.
type SignOption struct {
	Timestamp                 string
	ExpirationPeriodInSeconds int
	Headers                   map[string]string
	HeadersToSign             []string
	headersToSignSpecified    bool
}

// NewSignOption is the instance factory for `SignOption`.
func NewSignOption(timestamp string, expirationPeriodInSeconds int,
	headers map[string]string, headersToSign []string) *SignOption {

	return &SignOption{timestamp, expirationPeriodInSeconds,
		headers, headersToSign, len(headersToSign) > 0}
}

func CheckSignOption(option *SignOption) *SignOption {
	if option == nil {
		return &SignOption{}
	}

	return option
}

func (option *SignOption) AddHeadersToSign(headers ...string) {
	if option.HeadersToSign == nil {
		option.HeadersToSign = []string{}
	}

	option.HeadersToSign = append(option.HeadersToSign, headers...)
}

func (option *SignOption) AddHeader(key, value string) {
	if option.Headers == nil {
		option.Headers = make(map[string]string)
	}

	option.Headers[key] = value
}

func (option *SignOption) init() {
	if option.Timestamp == "" {
		option.Timestamp = util.TimeToUTCString(time.Now())
	}

	if option.ExpirationPeriodInSeconds <= 0 {
		option.ExpirationPeriodInSeconds = ExpirationPeriodInSeconds
	}

	if option.Headers == nil {
		option.Headers = make(map[string]string, 3)
	} else {
		util.MapKeyToLower(option.Headers)
	}

	option.headersToSignSpecified = len(option.HeadersToSign) > 0
	util.SliceToLower(option.HeadersToSign)

	if !util.Contains(option.HeadersToSign, "host", true) {
		option.HeadersToSign = append(option.HeadersToSign, "host")
	}

	if util.Contains(option.HeadersToSign, "date", true) {
		if !util.MapContains(option.Headers, generateHeaderValidCompareFunc("date")) {
			option.Headers["date"] = time.Now().Format(time.RFC1123)
		} else {
			option.Headers["date"] = util.TimeStringToRFC1123(util.GetMapValue(option.Headers, "date", true))
		}
	} else if util.Contains(option.HeadersToSign, "x-bce-date", true) {
		if !util.MapContains(option.Headers, generateHeaderValidCompareFunc("x-bce-date")) {
			option.Headers["x-bce-date"] = option.Timestamp
		}
	} else {
		option.HeadersToSign = append(option.HeadersToSign, "x-bce-date")
		option.Headers["x-bce-date"] = option.Timestamp
	}
}

func (option *SignOption) signedHeadersToString() string {
	var result string
	length := len(option.HeadersToSign)
	if option.headersToSignSpecified && length > 0 {
		headers := make([]string, 0, length)
		headers = append(headers, option.HeadersToSign...)
		sort.Strings(headers)
		result = strings.Join(headers, ";")
	}

	return result
}

// GenerateAuthorization returns authorization code of baidubce api.
func GenerateAuthorization(credentials Credentials, req Request, option *SignOption) string {
	if option == nil {
		option = &SignOption{}
	}
	option.init()

	authorization := "bce-auth-v1/" + credentials.AccessKeyID
	authorization += "/" + option.Timestamp
	authorization += "/" + strconv.Itoa(option.ExpirationPeriodInSeconds)
	signature := sign(credentials, req, option)
	authorization += "/" + option.signedHeadersToString() + "/" + signature

	req.addHeader("Authorization", authorization)

	return authorization
}

// Client is the base client struct for all products of baidubce.
type Client struct {
	Config
}

func (c *Client) GetUriPath(uriPath string) string {
	if strings.Index(uriPath, "/") == 0 {
		uriPath = uriPath[1:]
	}

	if c.APIVersion != "" {
		return fmt.Sprintf("/%s/%s", c.APIVersion, uriPath)
	}

	return fmt.Sprintf("/%s", uriPath)
}

// SendRequest sends a http request to the endpoint of baidubce api.
func (c *Client) SendRequest(req *Request, option *SignOption) (*Response, *Error) {
	GenerateAuthorization(c.Credentials, *req, option)
	httpClient := http.Client{}
	res, err := httpClient.Do(req.raw())

	defer func() {
		if res != nil {
			res.Body.Close()
		}
	}()

	if err != nil {
		return nil, NewError(err)
	}

	bceResponse := NewResponse(res)

	if res.StatusCode >= 400 {
		return bceResponse, NewErrorFromJSON(bceResponse.Body)
	}

	return bceResponse, nil
}

func generateHeaderValidCompareFunc(headerKey string) func(string, string) bool {
	return func(key, value string) bool {
		return strings.ToLower(key) == strings.ToLower(headerKey) && value != ""
	}
}

// sign returns signed signature.
func sign(credentials Credentials, req Request, option *SignOption) string {
	signingKey := getSigningKey(credentials, option)
	req.prepareHeaders(option)
	canonicalRequest := req.canonical(option)
	signature := util.HmacSha256Hex(signingKey, canonicalRequest)

	return signature
}

func getSigningKey(credentials Credentials, option *SignOption) string {
	var authStringPrefix = fmt.Sprintf("bce-auth-v1/%s", credentials.AccessKeyID)
	authStringPrefix += "/" + option.Timestamp
	authStringPrefix += "/" + strconv.Itoa(option.ExpirationPeriodInSeconds)

	return util.HmacSha256Hex(credentials.SecretAccessKey, authStringPrefix)
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
)

func usage() {
	xprintf(`usage: go tool dist [command]
Commands are:

banner         print installation banner
bootstrap      rebuild everything
clean          deletes all built files
env [-p]       print environment (-p: include $PATH)
install [dir]  install individual directory
list [-json]   list all supported platforms
test [-h]      run Go test(s)
version        print Go version

All commands take -v flags to emit extra information.
`)
	xexit(2)
}

// commands records the available commands.
var commands = map[string]func(){
	"banner":    cmdbanner,
	"bootstrap": cmdbootstrap,
	"clean":     cmdclean,
	"env":       cmdenv,
	"install":   cmdinstall,
	"list":      cmdlist,
	"test":      cmdtest,
	"version":   cmdversion,
}

// main takes care of OS-specific startup and dispatches to xmain.
func main() {
	os.Setenv("TERM", "dumb") // disable escape codes in clang errors

	// provide -check-armv6k first, before checking for $GOROOT so that
	// it is possible to run this check without having $GOROOT available.
	if len(os.Args) > 1 && os.Args[1] == "-check-armv6k" {
		useARMv6K() // might fail with SIGILL
		println("ARMv6K supported.")
		os.Exit(0)
	}

	gohostos = runtime.GOOS
	switch gohostos {
	case "aix":
		// uname -m doesn't work under AIX
		gohostarch = "ppc64"
	case "darwin":
		// macOS 10.9 and later require clang
		defaultclang = true
	case "freebsd":
		// Since FreeBSD 10 gcc is no longer part of the base system.
		defaultclang = true
	case "openbsd":
		// OpenBSD ships with GCC 4.2, which is now quite old.
		defaultclang = true
	case "plan9":
		gohostarch = os.Getenv("objtype")
		if gohostarch == "" {
			fatalf("$objtype is unset")
		}
	case "solaris", "illumos":
		// Solaris and illumos systems have multi-arch userlands, and
		// "uname -m" reports the machine hardware name; e.g.,
		// "i86pc" on both 32- and 64-bit x86 systems.  Check for the
		// native (widest) instruction set on the running kernel:
		out := run("", CheckExit, "isainfo", "-n")
		if strings.Contains(out, "amd64") {
			gohostarch = "amd64"
		}
		if strings.Contains(out, "i386") {
			gohostarch = "386"
		}
	case "windows":
		exe = ".exe"
	}

	sysinit()

	if gohostarch == "" {
		// Default Unix system.
		out := run("", CheckExit, "uname", "-m")
		outAll := run("", CheckExit, "uname", "-a")
		switch {
		case strings.Contains(outAll, "RELEASE_ARM64"):
			// MacOS prints
			// Darwin p1.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:01 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T6000 x86_64
			// on ARM64 laptops when there is an x86 parent in the
			// process tree. Look for the RELEASE_ARM64 to avoid being
			// confused into building an x86 toolchain.
			gohostarch = "arm64"
		case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
			gohostarch = "amd64"
		case strings.Contains(out, "86"):
			gohostarch = "386"
			if gohostos == "darwin" {
				// Even on 64-bit platform, some versions of macOS uname -m prints i386.
				// We don't support any of the OS X versions that run on 32-bit-only hardware anymore.
				gohostarch = "amd64"
			}
		case strings.Contains(out, "aarch64"), strings.Contains(out, "arm64"):
			gohostarch = "arm64"
		case strings.Contains(out, "arm"):
			gohostarch = "arm"
			if gohostos == "netbsd" && strings.Contains(run("", CheckExit, "uname", "-p"), "aarch64") {
				gohostarch = "arm64"
			}
		case strings.Contains(out, "ppc64le"):
			gohostarch = "ppc64le"
		case strings.Contains(out, "ppc64"):
			gohostarch = "ppc64"
		case strings.Contains(out, "mips64"):
			gohostarch = "mips64"
			if elfIsLittleEndian(os.Args[0]) {
				gohostarch = "mips64le"
			}
		case strings.Contains(out, "mips"):
			gohostarch = "mips"
			if elfIsLittleEndian(os.Args[0]) {
				gohostarch = "mipsle"
			}
		case strings.Contains(out, "loongarch64"):
			gohostarch = "loong64"
		case strings.Contains(out, "riscv64"):
			gohostarch = "riscv64"
		case strings.Contains(out, "s390x"):
			gohostarch = "s390x"
		case gohostos == "darwin", gohostos == "ios":
			if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") {
				gohostarch = "arm64"
			}
		case gohostos == "freebsd":
			if strings.Contains(run("", CheckExit, "uname", "-p"), "riscv64") {
				gohostarch = "riscv64"
			}
		case gohostos == "openbsd":
			if strings.Contains(run("", CheckExit, "uname", "-p"), "mips64") {
				gohostarch = "mips64"
			}
		default:
			fatalf("unknown architecture: %s", out)
		}
	}

	if gohostarch == "arm" || gohostarch == "mips64" || gohostarch == "mips64le" {
		maxbg = min(maxbg, runtime.NumCPU())
	}
	bginit()

	if len(os.Args) > 1 && os.Args[1] == "-check-goarm" {
		useVFPv1() // might fail with SIGILL
		println("VFPv1 OK.")
		useVFPv3() // might fail with SIGILL
		println("VFPv3 OK.")
		os.Exit(0)
	}

	xinit()
	xmain()
	xexit(0)
}

// The OS-specific main calls into the portable code here.
func xmain() {
	if len(os.Args) < 2 {
		usage()
	}
	cmd := os.Args[1]
	os.Args = os.Args[1:] // for flag parsing during cmd
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: go tool dist %s [options]\n", cmd)
		flag.PrintDefaults()
		os.Exit(2)
	}
	if f, ok := commands[cmd]; ok {
		f()
	} else {
		xprintf("unknown command %s\n", cmd)
		usage()
	}
}
<commit_msg>cmd/dist: add serial/small build option for GOMAXPROCS=1<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"strings"
)

func usage() {
	xprintf(`usage: go tool dist [command]
Commands are:

banner         print installation banner
bootstrap      rebuild everything
clean          deletes all built files
env [-p]       print environment (-p: include $PATH)
install [dir]  install individual directory
list [-json]   list all supported platforms
test [-h]      run Go test(s)
version        print Go version

All commands take -v flags to emit extra information.
`)
	xexit(2)
}

// commands records the available commands.
var commands = map[string]func(){
	"banner":    cmdbanner,
	"bootstrap": cmdbootstrap,
	"clean":     cmdclean,
	"env":       cmdenv,
	"install":   cmdinstall,
	"list":      cmdlist,
	"test":      cmdtest,
	"version":   cmdversion,
}

// main takes care of OS-specific startup and dispatches to xmain.
func main() {
	os.Setenv("TERM", "dumb") // disable escape codes in clang errors

	// provide -check-armv6k first, before checking for $GOROOT so that
	// it is possible to run this check without having $GOROOT available.
	if len(os.Args) > 1 && os.Args[1] == "-check-armv6k" {
		useARMv6K() // might fail with SIGILL
		println("ARMv6K supported.")
		os.Exit(0)
	}

	gohostos = runtime.GOOS
	switch gohostos {
	case "aix":
		// uname -m doesn't work under AIX
		gohostarch = "ppc64"
	case "darwin":
		// macOS 10.9 and later require clang
		defaultclang = true
	case "freebsd":
		// Since FreeBSD 10 gcc is no longer part of the base system.
		defaultclang = true
	case "openbsd":
		// OpenBSD ships with GCC 4.2, which is now quite old.
		defaultclang = true
	case "plan9":
		gohostarch = os.Getenv("objtype")
		if gohostarch == "" {
			fatalf("$objtype is unset")
		}
	case "solaris", "illumos":
		// Solaris and illumos systems have multi-arch userlands, and
		// "uname -m" reports the machine hardware name; e.g.,
		// "i86pc" on both 32- and 64-bit x86 systems.  Check for the
		// native (widest) instruction set on the running kernel:
		out := run("", CheckExit, "isainfo", "-n")
		if strings.Contains(out, "amd64") {
			gohostarch = "amd64"
		}
		if strings.Contains(out, "i386") {
			gohostarch = "386"
		}
	case "windows":
		exe = ".exe"
	}

	sysinit()

	if gohostarch == "" {
		// Default Unix system.
		out := run("", CheckExit, "uname", "-m")
		outAll := run("", CheckExit, "uname", "-a")
		switch {
		case strings.Contains(outAll, "RELEASE_ARM64"):
			// MacOS prints
			// Darwin p1.local 21.1.0 Darwin Kernel Version 21.1.0: Wed Oct 13 17:33:01 PDT 2021; root:xnu-8019.41.5~1/RELEASE_ARM64_T6000 x86_64
			// on ARM64 laptops when there is an x86 parent in the
			// process tree. Look for the RELEASE_ARM64 to avoid being
			// confused into building an x86 toolchain.
			gohostarch = "arm64"
		case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
			gohostarch = "amd64"
		case strings.Contains(out, "86"):
			gohostarch = "386"
			if gohostos == "darwin" {
				// Even on 64-bit platform, some versions of macOS uname -m prints i386.
				// We don't support any of the OS X versions that run on 32-bit-only hardware anymore.
				gohostarch = "amd64"
			}
		case strings.Contains(out, "aarch64"), strings.Contains(out, "arm64"):
			gohostarch = "arm64"
		case strings.Contains(out, "arm"):
			gohostarch = "arm"
			if gohostos == "netbsd" && strings.Contains(run("", CheckExit, "uname", "-p"), "aarch64") {
				gohostarch = "arm64"
			}
		case strings.Contains(out, "ppc64le"):
			gohostarch = "ppc64le"
		case strings.Contains(out, "ppc64"):
			gohostarch = "ppc64"
		case strings.Contains(out, "mips64"):
			gohostarch = "mips64"
			if elfIsLittleEndian(os.Args[0]) {
				gohostarch = "mips64le"
			}
		case strings.Contains(out, "mips"):
			gohostarch = "mips"
			if elfIsLittleEndian(os.Args[0]) {
				gohostarch = "mipsle"
			}
		case strings.Contains(out, "loongarch64"):
			gohostarch = "loong64"
		case strings.Contains(out, "riscv64"):
			gohostarch = "riscv64"
		case strings.Contains(out, "s390x"):
			gohostarch = "s390x"
		case gohostos == "darwin", gohostos == "ios":
			if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") {
				gohostarch = "arm64"
			}
		case gohostos == "freebsd":
			if strings.Contains(run("", CheckExit, "uname", "-p"), "riscv64") {
				gohostarch = "riscv64"
			}
		case gohostos == "openbsd":
			if strings.Contains(run("", CheckExit, "uname", "-p"), "mips64") {
				gohostarch = "mips64"
			}
		default:
			fatalf("unknown architecture: %s", out)
		}
	}

	if gohostarch == "arm" || gohostarch == "mips64" || gohostarch == "mips64le" {
		maxbg = min(maxbg, runtime.NumCPU())
	}
	// For deterministic make.bash debugging and for smallest-possible footprint,
	// pay attention to GOMAXPROCS=1.  This was a bad idea for 1.4 bootstrap, but
	// the bootstrap version is now 1.17+ and thus this is fine.
	if runtime.GOMAXPROCS(0) == 1 {
		maxbg = 1
	}
	bginit()

	if len(os.Args) > 1 && os.Args[1] == "-check-goarm" {
		useVFPv1() // might fail with SIGILL
		println("VFPv1 OK.")
		useVFPv3() // might fail with SIGILL
		println("VFPv3 OK.")
		os.Exit(0)
	}

	xinit()
	xmain()
	xexit(0)
}

// The OS-specific main calls into the portable code here.
func xmain() {
	if len(os.Args) < 2 {
		usage()
	}
	cmd := os.Args[1]
	os.Args = os.Args[1:] // for flag parsing during cmd
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "usage: go tool dist %s [options]\n", cmd)
		flag.PrintDefaults()
		os.Exit(2)
	}
	if f, ok := commands[cmd]; ok {
		f()
	} else {
		xprintf("unknown command %s\n", cmd)
		usage()
	}
}
<|endoftext|>