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

package main

import (
	"fmt"
	"time"
)

type tester struct {
	failures         []failure
	cluster          *cluster
	limit            int
	consistencyCheck bool

	status          Status
	currentRevision int64
}

// compactQPS is rough number of compact requests per second.
// Previous tests showed etcd can compact about 60,000 entries per second.
const compactQPS = 50000

func (tt *tester) runLoop() {
	tt.status.Since = time.Now()
	tt.status.RoundLimit = tt.limit
	tt.status.cluster = tt.cluster
	for _, f := range tt.failures {
		tt.status.Failures = append(tt.status.Failures, f.Desc())
	}

	var prevCompactRev int64
	for round := 0; round < tt.limit || tt.limit == -1; round++ {
		tt.status.setRound(round)
		roundTotalCounter.Inc()

		if ok, err := tt.doRound(round); !ok {
			if err != nil || tt.cleanup() != nil {
				return
			}
			continue
		}
		// -1 so that logPrefix doesn't print out 'case'
		tt.status.setCase(-1)

		revToCompact := max(0, tt.currentRevision-10000)
		compactN := revToCompact - prevCompactRev
		timeout := 10 * time.Second
		if prevCompactRev != 0 && compactN > 0 {
			timeout += time.Duration(compactN/compactQPS) * time.Second
		}
		prevCompactRev = revToCompact

		plog.Printf("%s compacting %d entries (timeout %v)", tt.logPrefix(), compactN, timeout)
		if err := tt.compact(revToCompact, timeout); err != nil {
			plog.Warningf("%s functional-tester compact got error (%v)", tt.logPrefix(), err)
			if err := tt.cleanup(); err != nil {
				return
			}
		}
		if round > 0 && round%500 == 0 { // every 500 rounds
			if err := tt.defrag(); err != nil {
				plog.Warningf("%s functional-tester returning with error (%v)", tt.logPrefix(), err)
				return
			}
		}
	}

	plog.Printf("%s functional-tester is finished", tt.logPrefix())
}

func (tt *tester) doRound(round int) (bool, error) {
	for j, f := range tt.failures {
		caseTotalCounter.WithLabelValues(f.Desc()).Inc()
		tt.status.setCase(j)

		if err := tt.cluster.WaitHealth(); err != nil {
			plog.Printf("%s wait full health error: %v", tt.logPrefix(), err)
			return false, nil
		}

		plog.Printf("%s injecting failure %q", tt.logPrefix(), f.Desc())
		if err := f.Inject(tt.cluster, round); err != nil {
			plog.Printf("%s injection error: %v", tt.logPrefix(), err)
			return false, nil
		}
		plog.Printf("%s injected failure", tt.logPrefix())

		plog.Printf("%s recovering failure %q", tt.logPrefix(), f.Desc())
		if err := f.Recover(tt.cluster, round); err != nil {
			plog.Printf("%s recovery error: %v", tt.logPrefix(), err)
			return false, nil
		}
		plog.Printf("%s recovered failure", tt.logPrefix())

		if tt.cluster.v2Only {
			plog.Printf("%s succeed!", tt.logPrefix())
			continue
		}

		if !tt.consistencyCheck {
			if err := tt.updateRevision(); err != nil {
				plog.Warningf("%s functional-tester returning with tt.updateRevision error (%v)", tt.logPrefix(), err)
				return false, err
			}
			continue
		}

		failed, err := tt.checkConsistency()
		if err != nil {
			plog.Warningf("%s functional-tester returning with tt.checkConsistency error (%v)", tt.logPrefix(), err)
			return false, err
		}
		if failed {
			return false, nil
		}
		plog.Printf("%s succeed!", tt.logPrefix())
	}
	return true, nil
}

func (tt *tester) updateRevision() error {
	revs, _, err := tt.cluster.getRevisionHash()
	for _, rev := range revs {
		tt.currentRevision = rev
		break // just need get one of the current revisions
	}
	return err
}

func (tt *tester) checkConsistency() (failed bool, err error) {
	tt.cancelStressers()
	defer func() {
		serr := tt.startStressers()
		if err == nil {
			err = serr
		}
	}()

	plog.Printf("%s updating current revisions...", tt.logPrefix())
	var (
		revs   map[string]int64
		hashes map[string]int64
		ok     bool
	)
	for i := 0; i < 7; i++ {
		time.Sleep(time.Second)

		revs, hashes, err = tt.cluster.getRevisionHash()
		if err != nil {
			plog.Printf("%s #%d failed to get current revisions (%v)", tt.logPrefix(), i, err)
			continue
		}
		if tt.currentRevision, ok = getSameValue(revs); ok {
			break
		}

		plog.Printf("%s #%d inconsistent current revisions %+v", tt.logPrefix(), i, revs)
	}
	plog.Printf("%s updated current revisions with %d", tt.logPrefix(), tt.currentRevision)

	if !ok || err != nil {
		plog.Printf("%s checking current revisions failed [revisions: %v]", tt.logPrefix(), revs)
		failed = true
		return
	}
	plog.Printf("%s all members are consistent with current revisions [revisions: %v]", tt.logPrefix(), revs)

	plog.Printf("%s checking current storage hashes...", tt.logPrefix())
	if _, ok = getSameValue(hashes); !ok {
		plog.Printf("%s checking current storage hashes failed [hashes: %v]", tt.logPrefix(), hashes)
		failed = true
		return
	}
	plog.Printf("%s all members are consistent with storage hashes", tt.logPrefix())
	return
}

func (tt *tester) compact(rev int64, timeout time.Duration) (err error) {
	tt.cancelStressers()
	defer func() {
		serr := tt.startStressers()
		if err == nil {
			err = serr
		}
	}()

	plog.Printf("%s compacting storage (current revision %d, compact revision %d)", tt.logPrefix(), tt.currentRevision, rev)
	if err = tt.cluster.compactKV(rev, timeout); err != nil {
		return err
	}
	plog.Printf("%s compacted storage (compact revision %d)", tt.logPrefix(), rev)

	plog.Printf("%s checking compaction (compact revision %d)", tt.logPrefix(), rev)
	if err = tt.cluster.checkCompact(rev); err != nil {
		plog.Warningf("%s checkCompact error (%v)", tt.logPrefix(), err)
		return err
	}

	plog.Printf("%s confirmed compaction (compact revision %d)", tt.logPrefix(), rev)
	return nil
}

func (tt *tester) defrag() error {
	plog.Printf("%s defragmenting...", tt.logPrefix())
	if err := tt.cluster.defrag(); err != nil {
		plog.Warningf("%s defrag error (%v)", tt.logPrefix(), err)
		if cerr := tt.cleanup(); cerr != nil {
			return fmt.Errorf("%s, %s", err, cerr)
		}
		return err
	}

	plog.Printf("%s defragmented...", tt.logPrefix())
	return nil
}

func (tt *tester) logPrefix() string {
	var (
		rd     = tt.status.getRound()
		cs     = tt.status.getCase()
		prefix = fmt.Sprintf("[round#%d case#%d]", rd, cs)
	)
	if cs == -1 {
		prefix = fmt.Sprintf("[round#%d]", rd)
	}
	return prefix
}

func (tt *tester) cleanup() error {
	roundFailedTotalCounter.Inc()
	desc := "compact/defrag"
	if tt.status.Case != -1 {
		desc = tt.failures[tt.status.Case].Desc()
	}
	caseFailedTotalCounter.WithLabelValues(desc).Inc()

	plog.Printf("%s cleaning up...", tt.logPrefix())
	if err := tt.cluster.Cleanup(); err != nil {
		plog.Warningf("%s cleanup error: %v", tt.logPrefix(), err)
		return err
	}

	if err := tt.cluster.Reset(); err != nil {
		plog.Warningf("%s cleanup Bootstrap error: %v", tt.logPrefix(), err)
		return err
	}

	return nil
}

func (tt *tester) cancelStressers() {
	plog.Printf("%s canceling the stressers...", tt.logPrefix())
	for _, s := range tt.cluster.Stressers {
		s.Cancel()
	}
	plog.Printf("%s canceled stressers", tt.logPrefix())
}

func (tt *tester) startStressers() error {
	plog.Printf("%s starting the stressers...", tt.logPrefix())
	for _, s := range tt.cluster.Stressers {
		if err := s.Stress(); err != nil {
			return err
		}
	}
	plog.Printf("%s started stressers", tt.logPrefix())
	return nil
}
<commit_msg>etcd-tester: fix compact rev counting<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"time"
)

type tester struct {
	failures         []failure
	cluster          *cluster
	limit            int
	consistencyCheck bool

	status          Status
	currentRevision int64
}

// compactQPS is rough number of compact requests per second.
// Previous tests showed etcd can compact about 60,000 entries per second.
const compactQPS = 50000

func (tt *tester) runLoop() {
	tt.status.Since = time.Now()
	tt.status.RoundLimit = tt.limit
	tt.status.cluster = tt.cluster
	for _, f := range tt.failures {
		tt.status.Failures = append(tt.status.Failures, f.Desc())
	}

	var prevCompactRev int64
	for round := 0; round < tt.limit || tt.limit == -1; round++ {
		tt.status.setRound(round)
		roundTotalCounter.Inc()

		if ok, err := tt.doRound(round); !ok {
			if err != nil || tt.cleanup() != nil {
				return
			}
			prevCompactRev = 0 // reset after clean up
			continue
		}
		// -1 so that logPrefix doesn't print out 'case'
		tt.status.setCase(-1)

		revToCompact := max(0, tt.currentRevision-10000)
		compactN := revToCompact - prevCompactRev
		timeout := 10 * time.Second
		if compactN > 0 {
			timeout += time.Duration(compactN/compactQPS) * time.Second
		}
		prevCompactRev = revToCompact

		plog.Printf("%s compacting %d entries (timeout %v)", tt.logPrefix(), compactN, timeout)
		if err := tt.compact(revToCompact, timeout); err != nil {
			plog.Warningf("%s functional-tester compact got error (%v)", tt.logPrefix(), err)
			if err := tt.cleanup(); err != nil {
				return
			}
			prevCompactRev = 0 // reset after clean up
		}
		if round > 0 && round%500 == 0 { // every 500 rounds
			if err := tt.defrag(); err != nil {
				plog.Warningf("%s functional-tester returning with error (%v)", tt.logPrefix(), err)
				return
			}
		}
	}

	plog.Printf("%s functional-tester is finished", tt.logPrefix())
}

func (tt *tester) doRound(round int) (bool, error) {
	for j, f := range tt.failures {
		caseTotalCounter.WithLabelValues(f.Desc()).Inc()
		tt.status.setCase(j)

		if err := tt.cluster.WaitHealth(); err != nil {
			plog.Printf("%s wait full health error: %v", tt.logPrefix(), err)
			return false, nil
		}

		plog.Printf("%s injecting failure %q", tt.logPrefix(), f.Desc())
		if err := f.Inject(tt.cluster, round); err != nil {
			plog.Printf("%s injection error: %v", tt.logPrefix(), err)
			return false, nil
		}
		plog.Printf("%s injected failure", tt.logPrefix())

		plog.Printf("%s recovering failure %q", tt.logPrefix(), f.Desc())
		if err := f.Recover(tt.cluster, round); err != nil {
			plog.Printf("%s recovery error: %v", tt.logPrefix(), err)
			return false, nil
		}
		plog.Printf("%s recovered failure", tt.logPrefix())

		if tt.cluster.v2Only {
			plog.Printf("%s succeed!", tt.logPrefix())
			continue
		}

		if !tt.consistencyCheck {
			if err := tt.updateRevision(); err != nil {
				plog.Warningf("%s functional-tester returning with tt.updateRevision error (%v)", tt.logPrefix(), err)
				return false, err
			}
			continue
		}

		failed, err := tt.checkConsistency()
		if err != nil {
			plog.Warningf("%s functional-tester returning with tt.checkConsistency error (%v)", tt.logPrefix(), err)
			return false, err
		}
		if failed {
			return false, nil
		}
		plog.Printf("%s succeed!", tt.logPrefix())
	}
	return true, nil
}

func (tt *tester) updateRevision() error {
	revs, _, err := tt.cluster.getRevisionHash()
	for _, rev := range revs {
		tt.currentRevision = rev
		break // just need get one of the current revisions
	}
	return err
}

func (tt *tester) checkConsistency() (failed bool, err error) {
	tt.cancelStressers()
	defer func() {
		serr := tt.startStressers()
		if err == nil {
			err = serr
		}
	}()

	plog.Printf("%s updating current revisions...", tt.logPrefix())
	var (
		revs   map[string]int64
		hashes map[string]int64
		ok     bool
	)
	for i := 0; i < 7; i++ {
		time.Sleep(time.Second)

		revs, hashes, err = tt.cluster.getRevisionHash()
		if err != nil {
			plog.Printf("%s #%d failed to get current revisions (%v)", tt.logPrefix(), i, err)
			continue
		}
		if tt.currentRevision, ok = getSameValue(revs); ok {
			break
		}

		plog.Printf("%s #%d inconsistent current revisions %+v", tt.logPrefix(), i, revs)
	}
	plog.Printf("%s updated current revisions with %d", tt.logPrefix(), tt.currentRevision)

	if !ok || err != nil {
		plog.Printf("%s checking current revisions failed [revisions: %v]", tt.logPrefix(), revs)
		failed = true
		return
	}
	plog.Printf("%s all members are consistent with current revisions [revisions: %v]", tt.logPrefix(), revs)

	plog.Printf("%s checking current storage hashes...", tt.logPrefix())
	if _, ok = getSameValue(hashes); !ok {
		plog.Printf("%s checking current storage hashes failed [hashes: %v]", tt.logPrefix(), hashes)
		failed = true
		return
	}
	plog.Printf("%s all members are consistent with storage hashes", tt.logPrefix())
	return
}

func (tt *tester) compact(rev int64, timeout time.Duration) (err error) {
	tt.cancelStressers()
	defer func() {
		serr := tt.startStressers()
		if err == nil {
			err = serr
		}
	}()

	plog.Printf("%s compacting storage (current revision %d, compact revision %d)", tt.logPrefix(), tt.currentRevision, rev)
	if err = tt.cluster.compactKV(rev, timeout); err != nil {
		return err
	}
	plog.Printf("%s compacted storage (compact revision %d)", tt.logPrefix(), rev)

	plog.Printf("%s checking compaction (compact revision %d)", tt.logPrefix(), rev)
	if err = tt.cluster.checkCompact(rev); err != nil {
		plog.Warningf("%s checkCompact error (%v)", tt.logPrefix(), err)
		return err
	}

	plog.Printf("%s confirmed compaction (compact revision %d)", tt.logPrefix(), rev)
	return nil
}

func (tt *tester) defrag() error {
	plog.Printf("%s defragmenting...", tt.logPrefix())
	if err := tt.cluster.defrag(); err != nil {
		plog.Warningf("%s defrag error (%v)", tt.logPrefix(), err)
		if cerr := tt.cleanup(); cerr != nil {
			return fmt.Errorf("%s, %s", err, cerr)
		}
		return err
	}

	plog.Printf("%s defragmented...", tt.logPrefix())
	return nil
}

func (tt *tester) logPrefix() string {
	var (
		rd     = tt.status.getRound()
		cs     = tt.status.getCase()
		prefix = fmt.Sprintf("[round#%d case#%d]", rd, cs)
	)
	if cs == -1 {
		prefix = fmt.Sprintf("[round#%d]", rd)
	}
	return prefix
}

func (tt *tester) cleanup() error {
	roundFailedTotalCounter.Inc()
	desc := "compact/defrag"
	if tt.status.Case != -1 {
		desc = tt.failures[tt.status.Case].Desc()
	}
	caseFailedTotalCounter.WithLabelValues(desc).Inc()

	plog.Printf("%s cleaning up...", tt.logPrefix())
	if err := tt.cluster.Cleanup(); err != nil {
		plog.Warningf("%s cleanup error: %v", tt.logPrefix(), err)
		return err
	}

	if err := tt.cluster.Reset(); err != nil {
		plog.Warningf("%s cleanup Bootstrap error: %v", tt.logPrefix(), err)
		return err
	}

	return nil
}

func (tt *tester) cancelStressers() {
	plog.Printf("%s canceling the stressers...", tt.logPrefix())
	for _, s := range tt.cluster.Stressers {
		s.Cancel()
	}
	plog.Printf("%s canceled stressers", tt.logPrefix())
}

func (tt *tester) startStressers() error {
	plog.Printf("%s starting the stressers...", tt.logPrefix())
	for _, s := range tt.cluster.Stressers {
		if err := s.Stress(); err != nil {
			return err
		}
	}
	plog.Printf("%s started stressers", tt.logPrefix())
	return nil
}
<|endoftext|>


<commit_before>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"fmt"
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "{→,←,↓,↑} to move cells, {0-9} to enter number, {m}ark mode, other {c}ommand"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "  {1-9} to toggle marks, {ENTER} to commit, {ESC} to cancel"
const STATUS_COMMAND = "COMMAND: {h}int, {q}uit, {n}ew puzzle, {ESC} cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

//A debug override; if true will print a color palette to the screen, wait for
//a keypress, and then quit. Useful for seeing what different colors are
//available to use.
const DRAW_PALETTE = false

func main() {

	//TODO: should be possible to run it and pass in a puzzle to use.

	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	termbox.SetOutputMode(termbox.Output256)

	model := newModel()

	width, _ := termbox.Size()
	model.outputWidth = width

	if DRAW_PALETTE {
		drawColorPalette()
		//Wait until something happens, generally a key is pressed.
		termbox.PollEvent()
		return
	}

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			model.state.handleInput(model, evt)
		}
		draw(model)
		if model.exitNow {
			break mainloop
		}
		model.EndOfEventLoop()
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func drawColorPalette() {
	clearScreen()
	x := 0
	y := 0

	for i := 0x00; i <= 0xFF; i++ {
		numToPrint := "  " + fmt.Sprintf("%02X", i) + "  "
		for _, ch := range numToPrint {
			termbox.SetCell(x, y, ch, termbox.ColorBlack, termbox.Attribute(i))
			x++
		}
		//Fit 8 print outs on a line before creating a new one
		if i%8 == 0 {
			x = 0
			y++
		}
	}

	termbox.Flush()
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = 0x12
			} else if ch == lockedRune {
				defaultColor = 0x35
			} else if runeIsNum(ch) {
				defaultColor = termbox.ColorWhite | termbox.AttrBold
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = 0xf0
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '{' {
			underlined = true
			continue
		} else if ch == '}' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	underlined = false

	splitMessage := strings.Split(model.consoleMessage, "\n")

	for _, line := range splitMessage {
		y++
		x = 0
		for _, ch := range line {
			if ch == '{' {
				underlined = true
				continue
			} else if ch == '}' {
				underlined = false
				continue
			}
			fg := termbox.ColorWhite
			if underlined {
				fg = fg | termbox.AttrBold
			}
			termbox.SetCell(x, y, ch, fg, termbox.ColorBlack)
			x++
		}
	}

	termbox.Flush()
}
<commit_msg>Added a divider above and below statusLine, and made console print out more dimly<commit_after>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"fmt"
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "{→,←,↓,↑} to move cells, {0-9} to enter number, {m}ark mode, other {c}ommand"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "  {1-9} to toggle marks, {ENTER} to commit, {ESC} to cancel"
const STATUS_COMMAND = "COMMAND: {h}int, {q}uit, {n}ew puzzle, {ESC} cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

//A debug override; if true will print a color palette to the screen, wait for
//a keypress, and then quit. Useful for seeing what different colors are
//available to use.
const DRAW_PALETTE = false

func main() {

	//TODO: should be possible to run it and pass in a puzzle to use.

	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	termbox.SetOutputMode(termbox.Output256)

	model := newModel()

	width, _ := termbox.Size()
	model.outputWidth = width

	if DRAW_PALETTE {
		drawColorPalette()
		//Wait until something happens, generally a key is pressed.
		termbox.PollEvent()
		return
	}

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			model.state.handleInput(model, evt)
		}
		draw(model)
		if model.exitNow {
			break mainloop
		}
		model.EndOfEventLoop()
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func drawColorPalette() {
	clearScreen()
	x := 0
	y := 0

	for i := 0x00; i <= 0xFF; i++ {
		numToPrint := "  " + fmt.Sprintf("%02X", i) + "  "
		for _, ch := range numToPrint {
			termbox.SetCell(x, y, ch, termbox.ColorBlack, termbox.Attribute(i))
			x++
		}
		//Fit 8 print outs on a line before creating a new one
		if i%8 == 0 {
			x = 0
			y++
		}
	}

	termbox.Flush()
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	width, _ := termbox.Size()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = 0x12
			} else if ch == lockedRune {
				defaultColor = 0x35
			} else if runeIsNum(ch) {
				defaultColor = termbox.ColorWhite | termbox.AttrBold
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = 0xf0
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//Divider
	y++
	for x = 0; x < width; x++ {
		termbox.SetCell(x, y, '-', 0xf0, termbox.ColorBlack)
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '{' {
			underlined = true
			continue
		} else if ch == '}' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	//Divider
	y++
	for x = 0; x < width; x++ {
		termbox.SetCell(x, y, '-', 0xf0, termbox.ColorBlack)
	}

	underlined = false

	splitMessage := strings.Split(model.consoleMessage, "\n")

	for _, line := range splitMessage {
		y++
		x = 0
		for _, ch := range line {
			if ch == '{' {
				underlined = true
				continue
			} else if ch == '}' {
				underlined = false
				continue
			}
			fg := termbox.Attribute(0xf0)
			if underlined {
				fg = fg | termbox.AttrBold
			}
			termbox.SetCell(x, y, ch, fg, termbox.ColorBlack)
			x++
		}
	}

	termbox.Flush()
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/mohae/benchutil"
)

const (
	Flat = "FlatBuffers"
	JSON = "JSON"
)

// flags
var (
	output         string
	format         string
	section        bool
	sectionHeaders bool
	nameSections   bool
)

func init() {
	flag.StringVar(&output, "output", "stdout", "output destination")
	flag.StringVar(&output, "o", "stdout", "output destination (short)")
	flag.StringVar(&format, "format", "txt", "format of output")
	flag.StringVar(&format, "f", "txt", "format of output")
	flag.BoolVar(&nameSections, "namesections", false, "use group as section name: some restrictions apply")
	flag.BoolVar(&nameSections, "n", false, "use group as section name: some restrictions apply")
	flag.BoolVar(&section, "sections", false, "don't separate groups of tests into sections")
	flag.BoolVar(&section, "s", false, "don't separate groups of tests into sections")
	flag.BoolVar(&sectionHeaders, "sectionheader", false, "if there are sections, add a section header row")
	flag.BoolVar(&sectionHeaders, "h", false, "if there are sections, add a section header row")
}

func main() {
	flag.Parse()
	done := make(chan struct{})
	go benchutil.Dot(done)

	// set the output
	var w io.Writer
	var err error
	switch output {
	case "stdout":
		w = os.Stdout
	default:
		w, err = os.OpenFile(output, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		defer w.(*os.File).Close()
	}
	// get the benchmark for the desired format
	// process the output
	var bench benchutil.Benchmarker
	switch format {
	case "csv":
		bench = benchutil.NewCSVBench(w)
	case "md":
		bench = benchutil.NewMDBench(w)
		bench.(*benchutil.MDBench).GroupAsSectionName = nameSections
	default:
		bench = benchutil.NewStringBench(w)
	}
	bench.SectionPerGroup(section)
	bench.SectionHeaders(sectionHeaders)
	// CPU
	runCPUBenchmarks(bench)

	// Disk
	runDiskBenchmarks(bench)

	// Memory
	runMemBenchmarks(bench)

	// Network
	runNetBenchmarks(bench)

	// Platform
	runPlatformBenchmarks(bench)

	// Sysinfo
	runSysinfoBenchmarks(bench)

	fmt.Println("\ngenerating output...\n")
	err = bench.Out()
	if err != nil {
		fmt.Printf("error generating output: %s\n", err)
	}
}
<commit_msg>add flag for including system info in the output<commit_after>// Copyright 2016 Joel Scoble and The JoeFriday authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io"
	"os"

	"github.com/mohae/benchutil"
)

const (
	Flat = "FlatBuffers"
	JSON = "JSON"
)

// flags
var (
	output         string
	format         string
	section        bool
	sectionHeaders bool
	nameSections   bool
	systemInfo     bool
)

func init() {
	flag.StringVar(&output, "output", "stdout", "output destination")
	flag.StringVar(&output, "o", "stdout", "output destination (short)")
	flag.StringVar(&format, "format", "txt", "format of output")
	flag.StringVar(&format, "f", "txt", "format of output")
	flag.BoolVar(&nameSections, "namesections", false, "use group as section name: some restrictions apply")
	flag.BoolVar(&nameSections, "n", false, "use group as section name: some restrictions apply")
	flag.BoolVar(&section, "sections", false, "don't separate groups of tests into sections")
	flag.BoolVar(&section, "s", false, "don't separate groups of tests into sections")
	flag.BoolVar(&sectionHeaders, "sectionheader", false, "if there are sections, add a section header row")
	flag.BoolVar(&sectionHeaders, "h", false, "if there are sections, add a section header row")
	flag.BoolVar(&systemInfo, "sysinfo", false, "add the system information to the outpu")
	flag.BoolVar(&systemInfo, "i", false, "add the system information to the outpu")
}

func main() {
	flag.Parse()
	done := make(chan struct{})
	go benchutil.Dot(done)

	// set the output
	var w io.Writer
	var err error
	switch output {
	case "stdout":
		w = os.Stdout
	default:
		w, err = os.OpenFile(output, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0644)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		defer w.(*os.File).Close()
	}
	// get the benchmark for the desired format
	// process the output
	var bench benchutil.Benchmarker
	switch format {
	case "csv":
		bench = benchutil.NewCSVBench(w)
	case "md":
		bench = benchutil.NewMDBench(w)
		bench.(*benchutil.MDBench).GroupAsSectionName = nameSections
	default:
		bench = benchutil.NewStringBench(w)
	}
	bench.SectionPerGroup(section)
	bench.SectionHeaders(sectionHeaders)
	bench.IncludeSystemInfo(systemInfo)
	// CPU
	runCPUBenchmarks(bench)

	// Disk
	runDiskBenchmarks(bench)

	// Memory
	runMemBenchmarks(bench)

	// Network
	runNetBenchmarks(bench)

	// Platform
	runPlatformBenchmarks(bench)

	// Sysinfo
	runSysinfoBenchmarks(bench)

	fmt.Println("\ngenerating output...\n")
	err = bench.Out()
	if err != nil {
		fmt.Printf("error generating output: %s\n", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	_ "launchpad.net/juju-core/environs/ec2"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/worker/firewaller"
	"launchpad.net/juju-core/worker/provisioner"
	"launchpad.net/tomb"
	"time"
)

var retryDelay = 3 * time.Second

// MachineAgent is a cmd.Command responsible for running a machine agent.
type MachineAgent struct {
	tomb      tomb.Tomb
	Conf      AgentConf
	MachineId string
}

// Info returns usage information for the command.
func (a *MachineAgent) Info() *cmd.Info {
	return &cmd.Info{"machine", "", "run a juju machine agent", ""}
}

// Init initializes the command for running.
func (a *MachineAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	f.StringVar(&a.MachineId, "machine-id", "", "id of the machine to run")
	if err := f.Parse(true, args); err != nil {
		return err
	}
	if !state.IsMachineId(a.MachineId) {
		return fmt.Errorf("--machine-id option must be set, and expects a non-negative integer")
	}
	return a.Conf.checkArgs(f.Args())
}

// Stop stops the machine agent.
func (a *MachineAgent) Stop() error {
	a.tomb.Kill(nil)
	return a.tomb.Wait()
}

// Run runs a machine agent.
func (a *MachineAgent) Run(_ *cmd.Context) error {
	if err := a.Conf.read(state.MachineEntityName(a.MachineId)); err != nil {
		return err
	}
	defer log.Printf("cmd/jujud: machine agent exiting")
	defer a.tomb.Done()

	// TODO(rog): When the state server address is
	// available from the API, this will need to change.
	// The plan is this:
	// - The API server address will always be available.
	// - If the state server address is available in the configuration
	//	we'll use that to connect (that will happen at bootstrap time
	// 	only)
	// - Otherwise we'll do an initial connect to the API server (changing
	//	the password as required), and use
	//	that to fetch the state server address (and password
	//	and server cert and key too), before starting to run
	//	the jobs.

	apiDone := make(chan error, 1)
	if err := a.startAPIServer(apiDone); err != nil {
		return err
	}
	runLoopDone := make(chan error, 1)
	go func() {
		runLoopDone <- RunLoop(a.Conf.Conf, a)
	}()
	for apiDone != nil || runLoopDone != nil {
		var err error
		select{
		case err = <-apiDone:
			apiDone = nil
		case err = <-runLoopDone:
			runLoopDone = nil
		}
		a.tomb.Kill(err)
	}
	return a.tomb.Err()
}

func (a *MachineAgent) runOnce() error {
	// TODO (when API state is universal): try to open mongo state
	// first, set password with that, then run state server if
	// necessary; then open api and set password with that if
	// necessary.
	st, password, err := openState(state.MachineEntityName(a.MachineId), &a.Conf)
	if err != nil {
		return err
	}
	defer st.Close()
	m, err := st.Machine(a.MachineId)
	if state.IsNotFound(err) || err == nil && m.Life() == state.Dead {
		return worker.ErrDead
	}
	if err != nil {
		return err
	}
	if password != "" {
		if err := m.SetPassword(password); err != nil {
			return err
		}
	}
	log.Printf("cmd/jujud: requested workers for machine agent: ", m.Workers())
	var tasks []task
	// The API server provides a service that may be required
	// to open the API client, so we start it first if it's required.
	for _, w := range m.Workers() {
		if w == state.ServerWorker {
			srv, err := api.NewServer(st, apiAddr, cert, key)
			if err != nil {
				return err
			}
			tasks = append(tasks, t)
		}
	}
	apiSt, err := api.Open(a.APIInfo)
	if err != nil {
		stopc := make(chan struct{})
		close(stopc)
		if err := runTasks(stopc, tasks); err != nil {
			// The API server error is probably more interesting
			// than the API client connection failure.
			return err
		}
		return err
	}
	defer apiSt.Close()
	tasks = append(tasks, NewUpgrader(st, m, a.Conf.DataDir))
	for _, w := range m.Workers() {
		var t task
		switch w {
		case state.MachinerWorker:
			t = machiner.NewMachiner(m, &a.Conf.StateInfo, a.Conf.DataDir)
		case state.ProvisionerWorker:
			t = provisioner.NewProvisioner(st)
		case state.FirewallerWorker:
			t = firewaller.NewFirewaller(st)
		case state.ServerWorker:
			continue
		}
		if t == nil {
			log.Printf("cmd/jujud: ignoring unknown worker %q", w)
			continue
		}
		tasks = append(tasks, t)

	}
	return runTasks(a.tomb.Dying(), tasks...)
}

func (a *MachineAgent) RunOnce(st *state.State, e AgentState) error {
	m := e.(*state.Machine)
	log.Printf("cmd/jujud: running jobs for machine agent: %v", m.Jobs())
	tasks := []task{NewUpgrader(st, m, a.Conf.DataDir)}
	for _, j := range m.Jobs() {
		switch j {
		case state.JobHostUnits:
			tasks = append(tasks,
				newDeployer(st, m.WatchPrincipalUnits(), a.Conf.DataDir))
		case state.JobManageEnviron:
			tasks = append(tasks,
				provisioner.NewProvisioner(st),
				firewaller.NewFirewaller(st))
		default:
			log.Printf("cmd/jujud: ignoring unknown job %q", j)
		}
	}
	return runTasks(a.tomb.Dying(), tasks...)
}

func (a *MachineAgent) Entity(st *state.State) (AgentState, error) {
	return st.Machine(a.MachineId)
}

func (a *MachineAgent) EntityName() string {
	return state.MachineEntityName(a.MachineId)
}

func (a *MachineAgent) Tomb() *tomb.Tomb {
	return &a.tomb
}

func (a *MachineAgent) startAPIServer(apiDone chan<- error) error {
	// The initial API connection runs synchronously because
	// things will go wrong if we're concurrently modifying
	// the password.

	var st *state.State
	var m *state.Machine
	for {
		st0, entity, err := openState(a.Conf.Conf, a)
		if err == worker.ErrDead {
			return err
		}
		if err == nil {
			st = st0
			m = entity.(*state.Machine)
			break
		}
		log.Printf("cmd/jujud: %v", err)
		if isleep(retryDelay, a.tomb.Dying()) {
			return nil
		}
	}
	runAPI := false
	for _, job := range m.Jobs() {
		if job == state.APIServerJob {
			runAPI = true
		}
	}
	if !runAPI {
		go func() {
			<-a.tomb.Dying
			apiDone <- nil
		}()
		return
	}
	// TODO(rog) fetch server cert and key from state?
	if len(conf.ServerCert) == 0 || len(conf.ServerKey) == 0 {
		return fmt.Errorf("configuration does not have server cert/key")
	}
	if conf.APIInfo.Addr == "" {
		return fmt.Errorf("configuration does not have API server address")
	}
	// Use a copy of the configuration so that we're independent.
	conf := *a.Conf.Conf
	go func() {
		apiDone <- a.apiServer(st, &conf)
	}()
	return nil
}

func (a *MachineAgent) apiServer(st *state.State, conf *agent.Conf) error {
	defer func() {
		if st != nil {
			st.Close()
		}
	}()
	for {
		srv, err := api.NewServer(st, conf.APIInfo.Addr, conf.ServerCert, conf.ServerKey)
		if err != nil {
			st.Close()
			return err
		}
		select{
		case <-a.tomb.Dying():
			return srv.Stop()
		case <-srv.Dead():
			log.Printf("cmd/jujud: api server died: %v", srv.Wait())
		}
		if isleep(retryDelay, a.tomb.Dying()) {
			return nil
		}
	}
}
<commit_msg>cmd/jujud: remove comment<commit_after>package main

import (
	"fmt"
	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	_ "launchpad.net/juju-core/environs/ec2"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/worker/firewaller"
	"launchpad.net/juju-core/worker/provisioner"
	"launchpad.net/tomb"
	"time"
)

var retryDelay = 3 * time.Second

// MachineAgent is a cmd.Command responsible for running a machine agent.
type MachineAgent struct {
	tomb      tomb.Tomb
	Conf      AgentConf
	MachineId string
}

// Info returns usage information for the command.
func (a *MachineAgent) Info() *cmd.Info {
	return &cmd.Info{"machine", "", "run a juju machine agent", ""}
}

// Init initializes the command for running.
func (a *MachineAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	f.StringVar(&a.MachineId, "machine-id", "", "id of the machine to run")
	if err := f.Parse(true, args); err != nil {
		return err
	}
	if !state.IsMachineId(a.MachineId) {
		return fmt.Errorf("--machine-id option must be set, and expects a non-negative integer")
	}
	return a.Conf.checkArgs(f.Args())
}

// Stop stops the machine agent.
func (a *MachineAgent) Stop() error {
	a.tomb.Kill(nil)
	return a.tomb.Wait()
}

// Run runs a machine agent.
func (a *MachineAgent) Run(_ *cmd.Context) error {
	if err := a.Conf.read(state.MachineEntityName(a.MachineId)); err != nil {
		return err
	}
	defer log.Printf("cmd/jujud: machine agent exiting")
	defer a.tomb.Done()

	apiDone := make(chan error, 1)
	if err := a.startAPIServer(apiDone); err != nil {
		return err
	}
	runLoopDone := make(chan error, 1)
	go func() {
		runLoopDone <- RunLoop(a.Conf.Conf, a)
	}()
	for apiDone != nil || runLoopDone != nil {
		var err error
		select{
		case err = <-apiDone:
			apiDone = nil
		case err = <-runLoopDone:
			runLoopDone = nil
		}
		a.tomb.Kill(err)
	}
	return a.tomb.Err()
}

func (a *MachineAgent) runOnce() error {
	// TODO (when API state is universal): try to open mongo state
	// first, set password with that, then run state server if
	// necessary; then open api and set password with that if
	// necessary.
	st, password, err := openState(state.MachineEntityName(a.MachineId), &a.Conf)
	if err != nil {
		return err
	}
	defer st.Close()
	m, err := st.Machine(a.MachineId)
	if state.IsNotFound(err) || err == nil && m.Life() == state.Dead {
		return worker.ErrDead
	}
	if err != nil {
		return err
	}
	if password != "" {
		if err := m.SetPassword(password); err != nil {
			return err
		}
	}
	log.Printf("cmd/jujud: requested workers for machine agent: ", m.Workers())
	var tasks []task
	// The API server provides a service that may be required
	// to open the API client, so we start it first if it's required.
	for _, w := range m.Workers() {
		if w == state.ServerWorker {
			srv, err := api.NewServer(st, apiAddr, cert, key)
			if err != nil {
				return err
			}
			tasks = append(tasks, t)
		}
	}
	apiSt, err := api.Open(a.APIInfo)
	if err != nil {
		stopc := make(chan struct{})
		close(stopc)
		if err := runTasks(stopc, tasks); err != nil {
			// The API server error is probably more interesting
			// than the API client connection failure.
			return err
		}
		return err
	}
	defer apiSt.Close()
	tasks = append(tasks, NewUpgrader(st, m, a.Conf.DataDir))
	for _, w := range m.Workers() {
		var t task
		switch w {
		case state.MachinerWorker:
			t = machiner.NewMachiner(m, &a.Conf.StateInfo, a.Conf.DataDir)
		case state.ProvisionerWorker:
			t = provisioner.NewProvisioner(st)
		case state.FirewallerWorker:
			t = firewaller.NewFirewaller(st)
		case state.ServerWorker:
			continue
		}
		if t == nil {
			log.Printf("cmd/jujud: ignoring unknown worker %q", w)
			continue
		}
		tasks = append(tasks, t)

	}
	return runTasks(a.tomb.Dying(), tasks...)
}

func (a *MachineAgent) RunOnce(st *state.State, e AgentState) error {
	m := e.(*state.Machine)
	log.Printf("cmd/jujud: running jobs for machine agent: %v", m.Jobs())
	tasks := []task{NewUpgrader(st, m, a.Conf.DataDir)}
	for _, j := range m.Jobs() {
		switch j {
		case state.JobHostUnits:
			tasks = append(tasks,
				newDeployer(st, m.WatchPrincipalUnits(), a.Conf.DataDir))
		case state.JobManageEnviron:
			tasks = append(tasks,
				provisioner.NewProvisioner(st),
				firewaller.NewFirewaller(st))
		default:
			log.Printf("cmd/jujud: ignoring unknown job %q", j)
		}
	}
	return runTasks(a.tomb.Dying(), tasks...)
}

func (a *MachineAgent) Entity(st *state.State) (AgentState, error) {
	return st.Machine(a.MachineId)
}

func (a *MachineAgent) EntityName() string {
	return state.MachineEntityName(a.MachineId)
}

func (a *MachineAgent) Tomb() *tomb.Tomb {
	return &a.tomb
}

func (a *MachineAgent) startAPIServer(apiDone chan<- error) error {
	// The initial API connection runs synchronously because
	// things will go wrong if we're concurrently modifying
	// the password.

	var st *state.State
	var m *state.Machine
	for {
		st0, entity, err := openState(a.Conf.Conf, a)
		if err == worker.ErrDead {
			return err
		}
		if err == nil {
			st = st0
			m = entity.(*state.Machine)
			break
		}
		log.Printf("cmd/jujud: %v", err)
		if isleep(retryDelay, a.tomb.Dying()) {
			return nil
		}
	}
	runAPI := false
	for _, job := range m.Jobs() {
		if job == state.APIServerJob {
			runAPI = true
		}
	}
	if !runAPI {
		go func() {
			<-a.tomb.Dying
			apiDone <- nil
		}()
		return
	}
	// TODO(rog) fetch server cert and key from state?
	if len(conf.ServerCert) == 0 || len(conf.ServerKey) == 0 {
		return fmt.Errorf("configuration does not have server cert/key")
	}
	if conf.APIInfo.Addr == "" {
		return fmt.Errorf("configuration does not have API server address")
	}
	// Use a copy of the configuration so that we're independent.
	conf := *a.Conf.Conf
	go func() {
		apiDone <- a.apiServer(st, &conf)
	}()
	return nil
}

func (a *MachineAgent) apiServer(st *state.State, conf *agent.Conf) error {
	defer func() {
		if st != nil {
			st.Close()
		}
	}()
	for {
		srv, err := api.NewServer(st, conf.APIInfo.Addr, conf.ServerCert, conf.ServerKey)
		if err != nil {
			st.Close()
			return err
		}
		select{
		case <-a.tomb.Dying():
			return srv.Stop()
		case <-srv.Dead():
			log.Printf("cmd/jujud: api server died: %v", srv.Wait())
		}
		if isleep(retryDelay, a.tomb.Dying()) {
			return nil
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/json"
    "fmt"
    "github.com/coleifer/mastodon"
    "os"
    //"os/exec"
    "path/filepath"
    "strconv"
    "strings"
    "time"
)

type StatusSource func(*mastodon.Config) *mastodon.StatusInfo

var Modules = map[string]StatusSource{
    "battery": mastodon.Battery,
    "clock": mastodon.Clock,
    "cpu": mastodon.CPU,
    "disk": mastodon.Disk,
    "hostname": mastodon.Hostname,
    "ip": mastodon.IPAddress,
    "loadavg": mastodon.LoadAvg,
    "memory": mastodon.Memory,
    "uptime": mastodon.Uptime,
}

func getDefaultConfig() mastodon.Config {
    var config mastodon.Config
    config.Data = map[string]string{
        "interval": "1",
        "order": "cpu,memory,disk,battery,ip,loadavg,clock",
        "bar_size": "10",
        "color_good": "#00d000",
        "color_normal": "#cccccc",
        "color_bad": "#d00000",
        "color0": "#1e2320",
        "color1": "#705050",
        "color2": "#60b48a",
        "color3": "#dfaf8f",
        "color4": "#506070",
        "color5": "#dc8cc3",
        "color6": "#8cd0d3",
        "color7": "#dcdccc",
        "color8": "#709080",
        "color9": "#dca3a3",
        "color10": "#c3bf9f",
        "color11": "#f0dfaf",
        "color12": "#94bff3",
        "color13": "#ec93d3",
        "color14": "#93e0e3",
        "color15": "#ffffff",
        "cpu": "color2",
        "memory": "color4",
        "battery": "color3",
        "disk": "color5",
        "loadavg": "color6",
    }
    config.BarSize, _ = strconv.Atoi(config.Data["bar_size"])
    return config
}

func ReadConfig(c mastodon.Config) {
    configHome := os.Getenv("XDG_CONFIG_HOME")
    if configHome == "" {
        configHome = filepath.Join(os.Getenv("HOME"), ".config")
    }
    configFile := filepath.Join(configHome, "mastodon.conf")
    if mastodon.FileExists(configFile) {
        LineHandler := func(line string) bool {
            pieces := strings.Split(line, "=")
            key := strings.Trim(pieces[0], " \t\r")
            value := strings.Trim(pieces[1], " \t\r")
            if _, ok := c.Data[key]; ok {
                c.Data[key] = value
            }
            return true
        }
        mastodon.ReadLines(configFile, LineHandler)
    }
}

func ReadInterval(c mastodon.Config) time.Duration {
    interval, err := strconv.Atoi(c.Data["interval"])
    if err != nil {
        interval = 1
    }
    return time.Duration(interval) * time.Second
}

func PrintHeader() {
    fmt.Println("{\"version\":1}")
    fmt.Println("[")
}

func main() {
    config := getDefaultConfig()
    ReadConfig(config)
    duration := ReadInterval(config)

    module_names := strings.Split(config.Data["order"], ",")
    jsonArray := make([]map[string]string, len(module_names))
    PrintHeader()
    for {
        for idx, module_name := range(module_names) {
            si := Modules[module_name](&config)
            color := config.Data[config.Data[module_name]]
            if si.IsBad() {
                color = config.Data["color_bad"]
            }
            jsonArray[idx] = map[string]string{
                "full_text": si.FullText,
                "color": color,
            }
        }
        jsonData, _ := json.Marshal(jsonArray)
        fmt.Print(string(jsonData))
        fmt.Printf(",\n")
        time.Sleep(duration)
    }
}
<commit_msg>Fix for missing module colors<commit_after>package main

import (
    "encoding/json"
    "fmt"
    "github.com/coleifer/mastodon"
    "os"
    //"os/exec"
    "path/filepath"
    "strconv"
    "strings"
    "time"
)

type StatusSource func(*mastodon.Config) *mastodon.StatusInfo

var Modules = map[string]StatusSource{
    "battery": mastodon.Battery,
    "clock": mastodon.Clock,
    "cpu": mastodon.CPU,
    "disk": mastodon.Disk,
    "hostname": mastodon.Hostname,
    "ip": mastodon.IPAddress,
    "loadavg": mastodon.LoadAvg,
    "memory": mastodon.Memory,
    "uptime": mastodon.Uptime,
}

func getDefaultConfig() mastodon.Config {
    var config mastodon.Config
    config.Data = map[string]string{
        "interval": "1",
        "order": "cpu,memory,disk,battery,ip,loadavg,clock",
        "bar_size": "10",
        "color_good": "#00d000",
        "color_normal": "#cccccc",
        "color_bad": "#d00000",
        "color0": "#1e2320",
        "color1": "#705050",
        "color2": "#60b48a",
        "color3": "#dfaf8f",
        "color4": "#506070",
        "color5": "#dc8cc3",
        "color6": "#8cd0d3",
        "color7": "#dcdccc",
        "color8": "#709080",
        "color9": "#dca3a3",
        "color10": "#c3bf9f",
        "color11": "#f0dfaf",
        "color12": "#94bff3",
        "color13": "#ec93d3",
        "color14": "#93e0e3",
        "color15": "#ffffff",
        "cpu": "color2",
        "memory": "color4",
        "battery": "color3",
        "disk": "color5",
        "loadavg": "color6",
    }
    config.BarSize, _ = strconv.Atoi(config.Data["bar_size"])
    return config
}

func ReadConfig(c mastodon.Config) {
    configHome := os.Getenv("XDG_CONFIG_HOME")
    if configHome == "" {
        configHome = filepath.Join(os.Getenv("HOME"), ".config")
    }
    configFile := filepath.Join(configHome, "mastodon.conf")
    if mastodon.FileExists(configFile) {
        LineHandler := func(line string) bool {
            pieces := strings.Split(line, "=")
            key := strings.Trim(pieces[0], " \t\r")
            value := strings.Trim(pieces[1], " \t\r")
            if _, ok := c.Data[key]; ok {
                c.Data[key] = value
            }
            return true
        }
        mastodon.ReadLines(configFile, LineHandler)
    }
}

func ReadInterval(c mastodon.Config) time.Duration {
    interval, err := strconv.Atoi(c.Data["interval"])
    if err != nil {
        interval = 1
    }
    return time.Duration(interval) * time.Second
}

func PrintHeader() {
    fmt.Println("{\"version\":1}")
    fmt.Println("[")
}

func main() {
    config := getDefaultConfig()
    ReadConfig(config)
    duration := ReadInterval(config)

    module_names := strings.Split(config.Data["order"], ",")
    for _, module_name := range(module_names) {
        if _, ok := config.Data[module_name]; !ok {
            config.Data[module_name] = "color_normal"
        }
    }

    jsonArray := make([]map[string]string, len(module_names))
    PrintHeader()
    for {
        for idx, module_name := range(module_names) {
            si := Modules[module_name](&config)
            color := config.Data[config.Data[module_name]]
            if si.IsBad() {
                color = config.Data["color_bad"]
            }
            jsonArray[idx] = map[string]string{
                "full_text": si.FullText,
                "color": color,
            }
        }
        jsonData, _ := json.Marshal(jsonArray)
        fmt.Print(string(jsonData))
        fmt.Printf(",\n")
        time.Sleep(duration)
    }
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Lupino/periodic"
	"github.com/Lupino/periodic/cmd/periodic/subcmd"
	"github.com/Lupino/periodic/driver"
	"github.com/Lupino/periodic/driver/leveldb"
	"github.com/Lupino/periodic/driver/redis"
	"github.com/codegangsta/cli"
	"log"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"
)

func main() {
	app := cli.NewApp()
	app.Name = "periodic"
	app.Usage = "Periodic task system"
	app.Version = periodic.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "H",
			Value:  "unix:///tmp/periodic.sock",
			Usage:  "the server address eg: tcp://127.0.0.1:5000",
			EnvVar: "PERIODIC_PORT",
		},
		cli.StringFlag{
			Name:  "redis",
			Value: "tcp://127.0.0.1:6379",
			Usage: "The redis server address, required for driver redis",
		},
		cli.StringFlag{
			Name:  "driver",
			Value: "memstore",
			Usage: "The driver [memstore, leveldb, redis]",
		},
		cli.StringFlag{
			Name:  "dbpath",
			Value: "leveldb",
			Usage: "The db path, required for driver leveldb",
		},
		cli.BoolFlag{
			Name:  "d",
			Usage: "Enable daemon mode",
		},
		cli.IntFlag{
			Name:  "timeout",
			Value: 0,
			Usage: "The socket timeout",
		},
		cli.IntFlag{
			Name:   "cpus",
			Value:  runtime.NumCPU(),
			Usage:  "The runtime.GOMAXPROCS",
			EnvVar: "GOMAXPROCS",
		},
		cli.StringFlag{
			Name:  "cpuprofile",
			Value: "",
			Usage: "write cpu profile to file",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:  "status",
			Usage: "Show status",
			Action: func(c *cli.Context) {
				subcmd.ShowStatus(c.GlobalString("H"))
			},
		},
		{
			Name:  "submit",
			Usage: "Submit job",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
				cli.StringFlag{
					Name:  "n",
					Value: "",
					Usage: "job name",
				},
				cli.StringFlag{
					Name:  "args",
					Value: "",
					Usage: "job workload",
				},
				cli.StringFlag{
					Name:  "t",
					Value: "0",
					Usage: "job running timeout",
				},
				cli.IntFlag{
					Name:  "sched_later",
					Value: 0,
					Usage: "job sched_later",
				},
			},
			Action: func(c *cli.Context) {
				var name = c.String("n")
				var funcName = c.String("f")
				var opts = map[string]string{
					"args":    c.String("args"),
					"timeout": c.String("t"),
				}
				if len(name) == 0 || len(funcName) == 0 {
					cli.ShowCommandHelp(c, "submit")
					log.Fatal("Job name and func is require")
				}
				delay := c.Int("sched_later")
				var now = time.Now()
				var schedAt = int64(now.Unix()) + int64(delay)
				opts["schedat"] = strconv.FormatInt(schedAt, 10)
				subcmd.SubmitJob(c.GlobalString("H"), funcName, name, opts)
			},
		},
		{
			Name:  "remove",
			Usage: "Remove job",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
				cli.StringFlag{
					Name:  "n",
					Value: "",
					Usage: "job name",
				},
			},
			Action: func(c *cli.Context) {
				var name = c.String("n")
				var funcName = c.String("f")
				if len(name) == 0 || len(funcName) == 0 {
					cli.ShowCommandHelp(c, "remove")
					log.Fatal("Job name and func is require")
				}
				subcmd.RemoveJob(c.GlobalString("H"), funcName, name)
			},
		},
		{
			Name:  "drop",
			Usage: "Drop func",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
			},
			Action: func(c *cli.Context) {
				Func := c.String("f")
				if len(Func) == 0 {
					cli.ShowCommandHelp(c, "drop")
					log.Fatal("function name is required")
				}
				subcmd.DropFunc(c.GlobalString("H"), Func)
			},
		},
		{
			Name:  "run",
			Usage: "Run func",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name required",
				},
				cli.StringFlag{
					Name:  "exec",
					Value: "",
					Usage: "command required",
				},
				cli.IntFlag{
					Name:  "n",
					Value: runtime.NumCPU() * 2,
					Usage: "the size of goroutines. (optional)",
				},
			},
			Action: func(c *cli.Context) {
				Func := c.String("f")
				exec := c.String("exec")
				n := c.Int("n")
				if len(Func) == 0 {
					cli.ShowCommandHelp(c, "run")
					log.Fatal("function name is required")
				}
				if len(exec) == 0 {
					cli.ShowCommandHelp(c, "run")
					log.Fatal("command is required")
				}
				subcmd.Run(c.GlobalString("H"), Func, exec, n)
			},
		},
		{
			Name:  "dump",
			Usage: "Dump database to file.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "o",
					Value: "dump.db",
					Usage: "output file name required",
				},
			},
			Action: func(c *cli.Context) {
				subcmd.Dump(c.GlobalString("H"), c.String("o"))
			},
		},
		{
			Name:  "load",
			Usage: "Load file to database.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "i",
					Value: "dump.db",
					Usage: "input file name required",
				},
			},
			Action: func(c *cli.Context) {
				subcmd.Load(c.GlobalString("H"), c.String("i"))
			},
		},
	}
	app.Action = func(c *cli.Context) {
		if c.Bool("d") {
			if c.String("cpuprofile") != "" {
				f, err := os.Create(c.String("cpuprofile"))
				if err != nil {
					log.Fatal(err)
				}
				pprof.StartCPUProfile(f)
				defer pprof.StopCPUProfile()
			}
			var store driver.StoreDriver
			switch c.String("driver") {
			case "memstore":
				store = driver.NewMemStroeDriver()
				break
			case "redis":
				store = redis.NewDriver(c.String("redis"))
				break
			case "leveldb":
				store = leveldb.NewDriver(c.String("dbpath"))
				break
			default:
				store = driver.NewMemStroeDriver()
				break
			}

			runtime.GOMAXPROCS(c.Int("cpus"))
			timeout := time.Duration(c.Int("timeout"))
			periodicd := periodic.NewSched(c.String("H"), store, timeout)
			go periodicd.Serve()
			s := make(chan os.Signal, 1)
			signal.Notify(s, os.Interrupt, os.Kill)
			<-s
			periodicd.Close()
		} else {
			cli.ShowAppHelp(c)
		}
	}

	app.Run(os.Args)
}
<commit_msg>Fixed. DEPRECATED Action signature<commit_after>package main

import (
	"github.com/Lupino/periodic"
	"github.com/Lupino/periodic/cmd/periodic/subcmd"
	"github.com/Lupino/periodic/driver"
	"github.com/Lupino/periodic/driver/leveldb"
	"github.com/Lupino/periodic/driver/redis"
	"github.com/urfave/cli"
	"log"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"
)

func main() {
	app := cli.NewApp()
	app.Name = "periodic"
	app.Usage = "Periodic task system"
	app.Version = periodic.Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "H",
			Value:  "unix:///tmp/periodic.sock",
			Usage:  "the server address eg: tcp://127.0.0.1:5000",
			EnvVar: "PERIODIC_PORT",
		},
		cli.StringFlag{
			Name:  "redis",
			Value: "tcp://127.0.0.1:6379",
			Usage: "The redis server address, required for driver redis",
		},
		cli.StringFlag{
			Name:  "driver",
			Value: "memstore",
			Usage: "The driver [memstore, leveldb, redis]",
		},
		cli.StringFlag{
			Name:  "dbpath",
			Value: "leveldb",
			Usage: "The db path, required for driver leveldb",
		},
		cli.BoolFlag{
			Name:  "d",
			Usage: "Enable daemon mode",
		},
		cli.IntFlag{
			Name:  "timeout",
			Value: 0,
			Usage: "The socket timeout",
		},
		cli.IntFlag{
			Name:   "cpus",
			Value:  runtime.NumCPU(),
			Usage:  "The runtime.GOMAXPROCS",
			EnvVar: "GOMAXPROCS",
		},
		cli.StringFlag{
			Name:  "cpuprofile",
			Value: "",
			Usage: "write cpu profile to file",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:  "status",
			Usage: "Show status",
			Action: func(c *cli.Context) error {
				subcmd.ShowStatus(c.GlobalString("H"))
				return nil
			},
		},
		{
			Name:  "submit",
			Usage: "Submit job",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
				cli.StringFlag{
					Name:  "n",
					Value: "",
					Usage: "job name",
				},
				cli.StringFlag{
					Name:  "args",
					Value: "",
					Usage: "job workload",
				},
				cli.StringFlag{
					Name:  "t",
					Value: "0",
					Usage: "job running timeout",
				},
				cli.IntFlag{
					Name:  "sched_later",
					Value: 0,
					Usage: "job sched_later",
				},
			},
			Action: func(c *cli.Context) error {
				var name = c.String("n")
				var funcName = c.String("f")
				var opts = map[string]string{
					"args":    c.String("args"),
					"timeout": c.String("t"),
				}
				if len(name) == 0 || len(funcName) == 0 {
					cli.ShowCommandHelp(c, "submit")
					log.Fatal("Job name and func is require")
				}
				delay := c.Int("sched_later")
				var now = time.Now()
				var schedAt = int64(now.Unix()) + int64(delay)
				opts["schedat"] = strconv.FormatInt(schedAt, 10)
				subcmd.SubmitJob(c.GlobalString("H"), funcName, name, opts)
				return nil
			},
		},
		{
			Name:  "remove",
			Usage: "Remove job",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
				cli.StringFlag{
					Name:  "n",
					Value: "",
					Usage: "job name",
				},
			},
			Action: func(c *cli.Context) error {
				var name = c.String("n")
				var funcName = c.String("f")
				if len(name) == 0 || len(funcName) == 0 {
					cli.ShowCommandHelp(c, "remove")
					log.Fatal("Job name and func is require")
				}
				subcmd.RemoveJob(c.GlobalString("H"), funcName, name)
				return nil
			},
		},
		{
			Name:  "drop",
			Usage: "Drop func",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name",
				},
			},
			Action: func(c *cli.Context) error {
				Func := c.String("f")
				if len(Func) == 0 {
					cli.ShowCommandHelp(c, "drop")
					log.Fatal("function name is required")
				}
				subcmd.DropFunc(c.GlobalString("H"), Func)
				return nil
			},
		},
		{
			Name:  "run",
			Usage: "Run func",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "f",
					Value: "",
					Usage: "function name required",
				},
				cli.StringFlag{
					Name:  "exec",
					Value: "",
					Usage: "command required",
				},
				cli.IntFlag{
					Name:  "n",
					Value: runtime.NumCPU() * 2,
					Usage: "the size of goroutines. (optional)",
				},
			},
			Action: func(c *cli.Context) error {
				Func := c.String("f")
				exec := c.String("exec")
				n := c.Int("n")
				if len(Func) == 0 {
					cli.ShowCommandHelp(c, "run")
					log.Fatal("function name is required")
				}
				if len(exec) == 0 {
					cli.ShowCommandHelp(c, "run")
					log.Fatal("command is required")
				}
				subcmd.Run(c.GlobalString("H"), Func, exec, n)
				return nil
			},
		},
		{
			Name:  "dump",
			Usage: "Dump database to file.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "o",
					Value: "dump.db",
					Usage: "output file name required",
				},
			},
			Action: func(c *cli.Context) error {
				subcmd.Dump(c.GlobalString("H"), c.String("o"))
				return nil
			},
		},
		{
			Name:  "load",
			Usage: "Load file to database.",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "i",
					Value: "dump.db",
					Usage: "input file name required",
				},
			},
			Action: func(c *cli.Context) error {
				subcmd.Load(c.GlobalString("H"), c.String("i"))
				return nil
			},
		},
	}
	app.Action = func(c *cli.Context) error {
		if c.Bool("d") {
			if c.String("cpuprofile") != "" {
				f, err := os.Create(c.String("cpuprofile"))
				if err != nil {
					log.Fatal(err)
				}
				pprof.StartCPUProfile(f)
				defer pprof.StopCPUProfile()
			}
			var store driver.StoreDriver
			switch c.String("driver") {
			case "memstore":
				store = driver.NewMemStroeDriver()
				break
			case "redis":
				store = redis.NewDriver(c.String("redis"))
				break
			case "leveldb":
				store = leveldb.NewDriver(c.String("dbpath"))
				break
			default:
				store = driver.NewMemStroeDriver()
				break
			}

			runtime.GOMAXPROCS(c.Int("cpus"))
			timeout := time.Duration(c.Int("timeout"))
			periodicd := periodic.NewSched(c.String("H"), store, timeout)
			go periodicd.Serve()
			s := make(chan os.Signal, 1)
			signal.Notify(s, os.Interrupt, os.Kill)
			<-s
			periodicd.Close()
		} else {
			cli.ShowAppHelp(c)
		}
		return nil
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

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

// Config represents the configuration as set by command-line flags.
// All variables will be set, unless explicit noted.
type Config struct {
	// DataPath is path to node data. Always set.
	DataPath string

	// HTTPAddr is the bind network address for the HTTP Server.
	// It never includes a trailing HTTP or HTTPS.
	HTTPAddr string

	// HTTPAdv is the advertised HTTP server network.
	HTTPAdv string

	// TLS1011 indicates whether the node should support deprecated
	// encryption standards.
	TLS1011 bool

	// AuthFile is the path to the authentication file. May not be set.
	AuthFile string

	// X509CACert is the path the root-CA certficate file for when this
	// node contacts other nodes' HTTP servers. May not be set.
	X509CACert string

	// X509Cert is the path to the X509 cert for the HTTP server. May not be set.
	X509Cert string

	// X509Key is the path to the private key for the HTTP server. May not be set.
	X509Key string

	// NodeEncrypt indicates whether node encryption should be enabled.
	NodeEncrypt bool

	// NodeX509CACert is the path the root-CA certficate file for when this
	// node contacts other nodes' Raft servers. May not be set.
	NodeX509CACert string

	// NodeX509Cert is the path to the X509 cert for the Raft server. May not be set.
	NodeX509Cert string

	// NodeX509Key is the path to the X509 key for the Raft server. May not be set.
	NodeX509Key string

	// NodeID is the Raft ID for the node.
	NodeID string

	// RaftAddr is the bind network address for the Raft server.
	RaftAddr string

	// RaftAdv is the advertised Raft server address.
	RaftAdv string

	// JoinSrcIP sets the source IP address during Join request. May not be set.
	JoinSrcIP string

	// JoinAddr is the list addresses to use for a join attempt. Each address
	// will include the proto (HTTP or HTTPS) and will never include the node's
	// own HTTP server address. May not be set.
	JoinAddr string

	// JoinAs sets the user join attempts should be performed as. May not be set.
	JoinAs string

	// JoinAttempts is the number of times a node should attempt to join using a
	// given address.
	JoinAttempts int

	// JoinInterval is the time between retrying failed join operations.
	JoinInterval time.Duration

	// NoHTTPVerify disables checking other nodes' HTTP X509 certs for validity.
	NoHTTPVerify bool

	// NoNodeVerify disables checking other nodes' Node X509 certs for validity.
	NoNodeVerify bool

	// DisoMode sets the discovery mode. May not be set.
	DiscoMode string

	// DiscoKey sets the discovery prefix key.
	DiscoKey string

	// DiscoConfig sets the path to any discovery configuration file. May not be set.
	DiscoConfig string

	// Expvar enables go/expvar information. Defaults to true.
	Expvar bool

	// PprofEnabled enables Go PProf information. Defaults to true.
	PprofEnabled bool

	// OnDisk enables on-disk mode.
	OnDisk bool

	// OnDiskPath sets the path to the SQLite file. May not be set.
	OnDiskPath string

	// OnDiskStartup disables the in-memory on-disk startup optimization.
	OnDiskStartup bool

	// FKConstraints enables SQLite foreign key constraints.
	FKConstraints bool

	// RaftLogLevel sets the minimum logging level for the Raft subsystem.
	RaftLogLevel string

	// RaftNonVoter controls whether this node is a voting, read-only node.
	RaftNonVoter bool

	// RaftSnapThreshold is the number of outstanding log entries that trigger snapshot.
	RaftSnapThreshold uint64

	// RaftSnapInterval sets the threshold check interval.
	RaftSnapInterval time.Duration

	// RaftLeaderLeaseTimeout sets the leader lease timeout.
	RaftLeaderLeaseTimeout time.Duration

	// RaftHeartbeatTimeout sets the heartbeast timeout.
	RaftHeartbeatTimeout time.Duration

	// RaftElectionTimeout sets the election timeout.
	RaftElectionTimeout time.Duration

	// RaftApplyTimeout sets the Log-apply timeout.
	RaftApplyTimeout time.Duration

	// RaftOpenTimeout sets the Raft store open timeout.
	RaftOpenTimeout time.Duration

	// RaftShutdownOnRemove sets whether Raft should be shutdown if the node is removed
	RaftShutdownOnRemove bool

	// RaftNoFreelistSync disables syncing Raft database freelist to disk. When true,
	// it improves the database write performance under normal operation, but requires
	// a full database re-sync during recovery.
	RaftNoFreelistSync bool

	// CompressionSize sets request query size for compression attempt
	CompressionSize int

	// CompressionBatch sets request batch threshold for compression attempt.
	CompressionBatch int

	// ShowVersion instructs the node to show version information and exit.
	ShowVersion bool

	// CPUProfile enables CPU profiling.
	CPUProfile string

	//MemProfile enables memory profiling.
	MemProfile string
}

// HTTPURL returns the fully-formed, advertised HTTP API address for this config, including
// protocol, host and port.
func (c *Config) HTTPURL() string {
	apiProto := "http"
	if c.X509Cert != "" {
		apiProto = "https"
	}
	return fmt.Sprintf("%s://%s", apiProto, c.HTTPAdv)
}

// BuildInfo is build information for display at command line.
type BuildInfo struct {
	Version string
	Commit  string
	Branch  string
}

// ParseFlags parses the command line, and returns the configuration.
func ParseFlags(name, desc string, build *BuildInfo) (*Config, error) {
	if flag.Parsed() {
		return nil, fmt.Errorf("command-line flags already parsed")
	}
	config := Config{}

	flag.StringVar(&config.NodeID, "node-id", "", "Unique name for node. If not set, set to advertised Raft address")
	flag.StringVar(&config.HTTPAddr, "http-addr", "localhost:4001", "HTTP server bind address. To enable HTTPS, set X.509 cert and key")
	flag.StringVar(&config.HTTPAdv, "http-adv-addr", "", "Advertised HTTP address. If not set, same as HTTP server bind")
	flag.BoolVar(&config.TLS1011, "tls1011", false, "Support deprecated TLS versions 1.0 and 1.1")
	flag.StringVar(&config.X509CACert, "http-ca-cert", "", "Path to root X.509 certificate for HTTP endpoint")
	flag.StringVar(&config.X509Cert, "http-cert", "", "Path to X.509 certificate for HTTP endpoint")
	flag.StringVar(&config.X509Key, "http-key", "", "Path to X.509 private key for HTTP endpoint")
	flag.BoolVar(&config.NoHTTPVerify, "http-no-verify", false, "Skip verification of remote HTTPS cert when joining cluster")
	flag.BoolVar(&config.NodeEncrypt, "node-encrypt", false, "Enable node-to-node encryption")
	flag.StringVar(&config.NodeX509CACert, "node-ca-cert", "", "Path to root X.509 certificate for node-to-node encryption")
	flag.StringVar(&config.NodeX509Cert, "node-cert", "cert.pem", "Path to X.509 certificate for node-to-node encryption")
	flag.StringVar(&config.NodeX509Key, "node-key", "key.pem", "Path to X.509 private key for node-to-node encryption")
	flag.BoolVar(&config.NoNodeVerify, "node-no-verify", false, "Skip verification of a remote node cert")
	flag.StringVar(&config.AuthFile, "auth", "", "Path to authentication and authorization file. If not set, not enabled")
	flag.StringVar(&config.RaftAddr, "raft-addr", "localhost:4002", "Raft communication bind address")
	flag.StringVar(&config.RaftAdv, "raft-adv-addr", "", "Advertised Raft communication address. If not set, same as Raft bind")
	flag.StringVar(&config.JoinSrcIP, "join-source-ip", "", "Set source IP address during Join request")
	flag.StringVar(&config.JoinAddr, "join", "", "Comma-delimited list of nodes, through which a cluster can be joined (proto://host:port)")
	flag.StringVar(&config.JoinAs, "join-as", "", "Username in authentication file to join as. If not set, joins anonymously")
	flag.IntVar(&config.JoinAttempts, "join-attempts", 5, "Number of join attempts to make")
	flag.DurationVar(&config.JoinInterval, "join-interval", 5*time.Second, "Period between join attempts")
	flag.StringVar(&config.DiscoMode, "disco-mode", "", "Choose cluster discovery service. If not set, not used")
	flag.StringVar(&config.DiscoKey, "disco-key", "rqlite", "Key prefix for cluster discovery service")
	flag.StringVar(&config.DiscoConfig, "disco-config", "", "Set path to cluster discovery config file")
	flag.BoolVar(&config.Expvar, "expvar", true, "Serve expvar data on HTTP server")
	flag.BoolVar(&config.PprofEnabled, "pprof", true, "Serve pprof data on HTTP server")
	flag.BoolVar(&config.OnDisk, "on-disk", false, "Use an on-disk SQLite database")
	flag.StringVar(&config.OnDiskPath, "on-disk-path", "", "Path for SQLite on-disk database file. If not set, use file in data directory")
	flag.BoolVar(&config.OnDiskStartup, "on-disk-startup", false, "Do not initialize on-disk database in memory first at startup")
	flag.BoolVar(&config.FKConstraints, "fk", false, "Enable SQLite foreign key constraints")
	flag.BoolVar(&config.ShowVersion, "version", false, "Show version information and exit")
	flag.BoolVar(&config.RaftNonVoter, "raft-non-voter", false, "Configure as non-voting node")
	flag.DurationVar(&config.RaftHeartbeatTimeout, "raft-timeout", time.Second, "Raft heartbeat timeout")
	flag.DurationVar(&config.RaftElectionTimeout, "raft-election-timeout", time.Second, "Raft election timeout")
	flag.DurationVar(&config.RaftApplyTimeout, "raft-apply-timeout", 10*time.Second, "Raft apply timeout")
	flag.DurationVar(&config.RaftOpenTimeout, "raft-open-timeout", 120*time.Second, "Time for initial Raft logs to be applied. Use 0s duration to skip wait")
	flag.Uint64Var(&config.RaftSnapThreshold, "raft-snap", 8192, "Number of outstanding log entries that trigger snapshot")
	flag.DurationVar(&config.RaftSnapInterval, "raft-snap-int", 30*time.Second, "Snapshot threshold check interval")
	flag.DurationVar(&config.RaftLeaderLeaseTimeout, "raft-leader-lease-timeout", 0, "Raft leader lease timeout. Use 0s for Raft default")
	flag.BoolVar(&config.RaftShutdownOnRemove, "raft-remove-shutdown", false, "Shutdown Raft if node removed")
	flag.BoolVar(&config.RaftNoFreelistSync, "raft-no-freelist-sync", false, "Do not sync Raft log database freelist to disk")
	flag.StringVar(&config.RaftLogLevel, "raft-log-level", "INFO", "Minimum log level for Raft module")
	flag.IntVar(&config.CompressionSize, "compression-size", 150, "Request query size for compression attempt")
	flag.IntVar(&config.CompressionBatch, "compression-batch", 5, "Request batch threshold for compression attempt")
	flag.StringVar(&config.CPUProfile, "cpu-profile", "", "Path to file for CPU profiling information")
	flag.StringVar(&config.MemProfile, "mem-profile", "", "Path to file for memory profiling information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\n%s\n\n", desc)
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] <data directory>\n", name)
		flag.PrintDefaults()
	}
	flag.Parse()

	if config.ShowVersion {
		msg := fmt.Sprintf("%s %s %s %s %s (commit %s, branch %s, compiler %s)\n",
			name, build.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), build.Commit, build.Branch, runtime.Compiler)
		errorExit(0, msg)
	}

	if config.OnDiskPath != "" && !config.OnDisk {
		errorExit(1, "fatal: on-disk-path is set, but on-disk is not\n")
	}

	// Ensure the data path is set.
	if flag.NArg() < 1 {
		errorExit(1, "fatal: no data directory set\n")
	}
	config.DataPath = flag.Arg(0)

	// Ensure no args come after the data directory.
	if flag.NArg() > 1 {
		errorExit(1, "fatal: arguments after data directory are not accepted\n")
	}

	// Enforce policies regarding addresses
	if config.RaftAdv == "" {
		config.RaftAdv = config.RaftAddr
	}
	if config.HTTPAdv == "" {
		config.HTTPAdv = config.HTTPAddr
	}

	// Perfom some address validity checks.
	if strings.HasPrefix(strings.ToLower(config.HTTPAddr), "http") ||
		strings.HasPrefix(strings.ToLower(config.HTTPAdv), "http") {
		errorExit(1, "fatal: HTTP options should not include protocol (http:// or https://)\n")
	}
	if _, _, err := net.SplitHostPort(config.HTTPAddr); err != nil {
		errorExit(1, "HTTP bind address not valid")
	}
	if _, _, err := net.SplitHostPort(config.HTTPAdv); err != nil {
		errorExit(1, "HTTP advertised address not valid")
	}
	if _, _, err := net.SplitHostPort(config.RaftAddr); err != nil {
		errorExit(1, "Raft bind address not valid")
	}
	if _, _, err := net.SplitHostPort(config.RaftAdv); err != nil {
		errorExit(1, "Raft advertised address not valid")
	}

	// Node ID policy
	if config.NodeID == "" {
		config.NodeID = config.RaftAdv
	}

	return &config, nil
}

func errorExit(code int, msg string) {
	fmt.Fprintf(os.Stderr, msg)
	os.Exit(code)
}
<commit_msg>Correct comment style<commit_after>package main

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

// Config represents the configuration as set by command-line flags.
// All variables will be set, unless explicit noted.
type Config struct {
	// DataPath is path to node data. Always set.
	DataPath string

	// HTTPAddr is the bind network address for the HTTP Server.
	// It never includes a trailing HTTP or HTTPS.
	HTTPAddr string

	// HTTPAdv is the advertised HTTP server network.
	HTTPAdv string

	// TLS1011 indicates whether the node should support deprecated
	// encryption standards.
	TLS1011 bool

	// AuthFile is the path to the authentication file. May not be set.
	AuthFile string

	// X509CACert is the path the root-CA certficate file for when this
	// node contacts other nodes' HTTP servers. May not be set.
	X509CACert string

	// X509Cert is the path to the X509 cert for the HTTP server. May not be set.
	X509Cert string

	// X509Key is the path to the private key for the HTTP server. May not be set.
	X509Key string

	// NodeEncrypt indicates whether node encryption should be enabled.
	NodeEncrypt bool

	// NodeX509CACert is the path the root-CA certficate file for when this
	// node contacts other nodes' Raft servers. May not be set.
	NodeX509CACert string

	// NodeX509Cert is the path to the X509 cert for the Raft server. May not be set.
	NodeX509Cert string

	// NodeX509Key is the path to the X509 key for the Raft server. May not be set.
	NodeX509Key string

	// NodeID is the Raft ID for the node.
	NodeID string

	// RaftAddr is the bind network address for the Raft server.
	RaftAddr string

	// RaftAdv is the advertised Raft server address.
	RaftAdv string

	// JoinSrcIP sets the source IP address during Join request. May not be set.
	JoinSrcIP string

	// JoinAddr is the list addresses to use for a join attempt. Each address
	// will include the proto (HTTP or HTTPS) and will never include the node's
	// own HTTP server address. May not be set.
	JoinAddr string

	// JoinAs sets the user join attempts should be performed as. May not be set.
	JoinAs string

	// JoinAttempts is the number of times a node should attempt to join using a
	// given address.
	JoinAttempts int

	// JoinInterval is the time between retrying failed join operations.
	JoinInterval time.Duration

	// NoHTTPVerify disables checking other nodes' HTTP X509 certs for validity.
	NoHTTPVerify bool

	// NoNodeVerify disables checking other nodes' Node X509 certs for validity.
	NoNodeVerify bool

	// DisoMode sets the discovery mode. May not be set.
	DiscoMode string

	// DiscoKey sets the discovery prefix key.
	DiscoKey string

	// DiscoConfig sets the path to any discovery configuration file. May not be set.
	DiscoConfig string

	// Expvar enables go/expvar information. Defaults to true.
	Expvar bool

	// PprofEnabled enables Go PProf information. Defaults to true.
	PprofEnabled bool

	// OnDisk enables on-disk mode.
	OnDisk bool

	// OnDiskPath sets the path to the SQLite file. May not be set.
	OnDiskPath string

	// OnDiskStartup disables the in-memory on-disk startup optimization.
	OnDiskStartup bool

	// FKConstraints enables SQLite foreign key constraints.
	FKConstraints bool

	// RaftLogLevel sets the minimum logging level for the Raft subsystem.
	RaftLogLevel string

	// RaftNonVoter controls whether this node is a voting, read-only node.
	RaftNonVoter bool

	// RaftSnapThreshold is the number of outstanding log entries that trigger snapshot.
	RaftSnapThreshold uint64

	// RaftSnapInterval sets the threshold check interval.
	RaftSnapInterval time.Duration

	// RaftLeaderLeaseTimeout sets the leader lease timeout.
	RaftLeaderLeaseTimeout time.Duration

	// RaftHeartbeatTimeout sets the heartbeast timeout.
	RaftHeartbeatTimeout time.Duration

	// RaftElectionTimeout sets the election timeout.
	RaftElectionTimeout time.Duration

	// RaftApplyTimeout sets the Log-apply timeout.
	RaftApplyTimeout time.Duration

	// RaftOpenTimeout sets the Raft store open timeout.
	RaftOpenTimeout time.Duration

	// RaftShutdownOnRemove sets whether Raft should be shutdown if the node is removed
	RaftShutdownOnRemove bool

	// RaftNoFreelistSync disables syncing Raft database freelist to disk. When true,
	// it improves the database write performance under normal operation, but requires
	// a full database re-sync during recovery.
	RaftNoFreelistSync bool

	// CompressionSize sets request query size for compression attempt
	CompressionSize int

	// CompressionBatch sets request batch threshold for compression attempt.
	CompressionBatch int

	// ShowVersion instructs the node to show version information and exit.
	ShowVersion bool

	// CPUProfile enables CPU profiling.
	CPUProfile string

	// MemProfile enables memory profiling.
	MemProfile string
}

// HTTPURL returns the fully-formed, advertised HTTP API address for this config, including
// protocol, host and port.
func (c *Config) HTTPURL() string {
	apiProto := "http"
	if c.X509Cert != "" {
		apiProto = "https"
	}
	return fmt.Sprintf("%s://%s", apiProto, c.HTTPAdv)
}

// BuildInfo is build information for display at command line.
type BuildInfo struct {
	Version string
	Commit  string
	Branch  string
}

// ParseFlags parses the command line, and returns the configuration.
func ParseFlags(name, desc string, build *BuildInfo) (*Config, error) {
	if flag.Parsed() {
		return nil, fmt.Errorf("command-line flags already parsed")
	}
	config := Config{}

	flag.StringVar(&config.NodeID, "node-id", "", "Unique name for node. If not set, set to advertised Raft address")
	flag.StringVar(&config.HTTPAddr, "http-addr", "localhost:4001", "HTTP server bind address. To enable HTTPS, set X.509 cert and key")
	flag.StringVar(&config.HTTPAdv, "http-adv-addr", "", "Advertised HTTP address. If not set, same as HTTP server bind")
	flag.BoolVar(&config.TLS1011, "tls1011", false, "Support deprecated TLS versions 1.0 and 1.1")
	flag.StringVar(&config.X509CACert, "http-ca-cert", "", "Path to root X.509 certificate for HTTP endpoint")
	flag.StringVar(&config.X509Cert, "http-cert", "", "Path to X.509 certificate for HTTP endpoint")
	flag.StringVar(&config.X509Key, "http-key", "", "Path to X.509 private key for HTTP endpoint")
	flag.BoolVar(&config.NoHTTPVerify, "http-no-verify", false, "Skip verification of remote HTTPS cert when joining cluster")
	flag.BoolVar(&config.NodeEncrypt, "node-encrypt", false, "Enable node-to-node encryption")
	flag.StringVar(&config.NodeX509CACert, "node-ca-cert", "", "Path to root X.509 certificate for node-to-node encryption")
	flag.StringVar(&config.NodeX509Cert, "node-cert", "cert.pem", "Path to X.509 certificate for node-to-node encryption")
	flag.StringVar(&config.NodeX509Key, "node-key", "key.pem", "Path to X.509 private key for node-to-node encryption")
	flag.BoolVar(&config.NoNodeVerify, "node-no-verify", false, "Skip verification of a remote node cert")
	flag.StringVar(&config.AuthFile, "auth", "", "Path to authentication and authorization file. If not set, not enabled")
	flag.StringVar(&config.RaftAddr, "raft-addr", "localhost:4002", "Raft communication bind address")
	flag.StringVar(&config.RaftAdv, "raft-adv-addr", "", "Advertised Raft communication address. If not set, same as Raft bind")
	flag.StringVar(&config.JoinSrcIP, "join-source-ip", "", "Set source IP address during Join request")
	flag.StringVar(&config.JoinAddr, "join", "", "Comma-delimited list of nodes, through which a cluster can be joined (proto://host:port)")
	flag.StringVar(&config.JoinAs, "join-as", "", "Username in authentication file to join as. If not set, joins anonymously")
	flag.IntVar(&config.JoinAttempts, "join-attempts", 5, "Number of join attempts to make")
	flag.DurationVar(&config.JoinInterval, "join-interval", 5*time.Second, "Period between join attempts")
	flag.StringVar(&config.DiscoMode, "disco-mode", "", "Choose cluster discovery service. If not set, not used")
	flag.StringVar(&config.DiscoKey, "disco-key", "rqlite", "Key prefix for cluster discovery service")
	flag.StringVar(&config.DiscoConfig, "disco-config", "", "Set path to cluster discovery config file")
	flag.BoolVar(&config.Expvar, "expvar", true, "Serve expvar data on HTTP server")
	flag.BoolVar(&config.PprofEnabled, "pprof", true, "Serve pprof data on HTTP server")
	flag.BoolVar(&config.OnDisk, "on-disk", false, "Use an on-disk SQLite database")
	flag.StringVar(&config.OnDiskPath, "on-disk-path", "", "Path for SQLite on-disk database file. If not set, use file in data directory")
	flag.BoolVar(&config.OnDiskStartup, "on-disk-startup", false, "Do not initialize on-disk database in memory first at startup")
	flag.BoolVar(&config.FKConstraints, "fk", false, "Enable SQLite foreign key constraints")
	flag.BoolVar(&config.ShowVersion, "version", false, "Show version information and exit")
	flag.BoolVar(&config.RaftNonVoter, "raft-non-voter", false, "Configure as non-voting node")
	flag.DurationVar(&config.RaftHeartbeatTimeout, "raft-timeout", time.Second, "Raft heartbeat timeout")
	flag.DurationVar(&config.RaftElectionTimeout, "raft-election-timeout", time.Second, "Raft election timeout")
	flag.DurationVar(&config.RaftApplyTimeout, "raft-apply-timeout", 10*time.Second, "Raft apply timeout")
	flag.DurationVar(&config.RaftOpenTimeout, "raft-open-timeout", 120*time.Second, "Time for initial Raft logs to be applied. Use 0s duration to skip wait")
	flag.Uint64Var(&config.RaftSnapThreshold, "raft-snap", 8192, "Number of outstanding log entries that trigger snapshot")
	flag.DurationVar(&config.RaftSnapInterval, "raft-snap-int", 30*time.Second, "Snapshot threshold check interval")
	flag.DurationVar(&config.RaftLeaderLeaseTimeout, "raft-leader-lease-timeout", 0, "Raft leader lease timeout. Use 0s for Raft default")
	flag.BoolVar(&config.RaftShutdownOnRemove, "raft-remove-shutdown", false, "Shutdown Raft if node removed")
	flag.BoolVar(&config.RaftNoFreelistSync, "raft-no-freelist-sync", false, "Do not sync Raft log database freelist to disk")
	flag.StringVar(&config.RaftLogLevel, "raft-log-level", "INFO", "Minimum log level for Raft module")
	flag.IntVar(&config.CompressionSize, "compression-size", 150, "Request query size for compression attempt")
	flag.IntVar(&config.CompressionBatch, "compression-batch", 5, "Request batch threshold for compression attempt")
	flag.StringVar(&config.CPUProfile, "cpu-profile", "", "Path to file for CPU profiling information")
	flag.StringVar(&config.MemProfile, "mem-profile", "", "Path to file for memory profiling information")
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "\n%s\n\n", desc)
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] <data directory>\n", name)
		flag.PrintDefaults()
	}
	flag.Parse()

	if config.ShowVersion {
		msg := fmt.Sprintf("%s %s %s %s %s (commit %s, branch %s, compiler %s)\n",
			name, build.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), build.Commit, build.Branch, runtime.Compiler)
		errorExit(0, msg)
	}

	if config.OnDiskPath != "" && !config.OnDisk {
		errorExit(1, "fatal: on-disk-path is set, but on-disk is not\n")
	}

	// Ensure the data path is set.
	if flag.NArg() < 1 {
		errorExit(1, "fatal: no data directory set\n")
	}
	config.DataPath = flag.Arg(0)

	// Ensure no args come after the data directory.
	if flag.NArg() > 1 {
		errorExit(1, "fatal: arguments after data directory are not accepted\n")
	}

	// Enforce policies regarding addresses
	if config.RaftAdv == "" {
		config.RaftAdv = config.RaftAddr
	}
	if config.HTTPAdv == "" {
		config.HTTPAdv = config.HTTPAddr
	}

	// Perfom some address validity checks.
	if strings.HasPrefix(strings.ToLower(config.HTTPAddr), "http") ||
		strings.HasPrefix(strings.ToLower(config.HTTPAdv), "http") {
		errorExit(1, "fatal: HTTP options should not include protocol (http:// or https://)\n")
	}
	if _, _, err := net.SplitHostPort(config.HTTPAddr); err != nil {
		errorExit(1, "HTTP bind address not valid")
	}
	if _, _, err := net.SplitHostPort(config.HTTPAdv); err != nil {
		errorExit(1, "HTTP advertised address not valid")
	}
	if _, _, err := net.SplitHostPort(config.RaftAddr); err != nil {
		errorExit(1, "Raft bind address not valid")
	}
	if _, _, err := net.SplitHostPort(config.RaftAdv); err != nil {
		errorExit(1, "Raft advertised address not valid")
	}

	// Node ID policy
	if config.NodeID == "" {
		config.NodeID = config.RaftAdv
	}

	return &config, nil
}

func errorExit(code int, msg string) {
	fmt.Fprintf(os.Stderr, msg)
	os.Exit(code)
}
<|endoftext|>