<commit_before>package output

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/dustin/go-humanize"

	"github.com/thought-machine/please/src/cli"
	"github.com/thought-machine/please/src/core"
)

// We only set the terminal title for terminals that at least claim to be xterm
// (note that most terminals do for compatibility; some report as xterm-color, hence HasPrefix)
var terminalClaimsToBeXterm = strings.HasPrefix(os.Getenv("TERM"), "xterm")

type displayer struct {
	state                                   *core.BuildState
	targets                                 []buildingTarget
	numWorkers, numRemote, maxRows, maxCols int
	stats                                   bool
	lines, lastLines                        int // mutable - records how many rows we've printed this time
}

func display(ctx context.Context, state *core.BuildState, buildingTargets []buildingTarget) {
	backend := cli.NewLogBackend(len(buildingTargets))
	go func() {
		sig := make(chan os.Signal, 10)
		signal.Notify(sig, syscall.SIGWINCH)
		for {
			<-sig
			recalcWindowSize(backend)
		}
	}()
	recalcWindowSize(backend)
	backend.SetActive()

	d := &displayer{
		state:      state,
		targets:    buildingTargets,
		numWorkers: state.Config.Please.NumThreads,
		numRemote:  state.Config.Remote.NumExecutors,
		maxRows:    backend.MaxInteractiveRows,
		maxCols:    backend.Cols,
		stats:      state.Config.Display.SystemStats,
	}

	d.printLines()
	d.run(ctx, backend)
	setWindowTitle(state, false)
	// Clear it all out.
	d.moveToFirstLine()
	printf("${CLEAR_END}")
	backend.Deactivate()
}

func (d *displayer) run(ctx context.Context, backend *cli.LogBackend) {
	ticker := time.NewTicker(50 * time.Millisecond)
	defer ticker.Stop()
	done := ctx.Done()
	for {
		select {
		case <-done:
			return
		case <-ticker.C:
			d.moveToFirstLine()
			d.printLines()
			for _, line := range backend.Output {
				printf("${ERASE_AFTER}%s\n", line)
				d.lines++
			}
			// Clean out any lines that were visible last time but are not now.
			if d.lines < d.lastLines {
				for i := d.lines; i < d.lastLines; i++ {
					printf("${ERASE_AFTER}\n")
				}
				printf("\x1b[%dA", d.lastLines-d.lines) // Move back up again
			}
			setWindowTitle(d.state, true)
		}
	}
}

// moveToFirstLine resets back to the first line.
func (d *displayer) moveToFirstLine() {
	printf("\x1b[%dA", d.lines)
	d.lastLines = d.lines
	d.lines = 0
}

func (d *displayer) printLines() {
	now := time.Now()
	printf("Building [%d/%d, %3.1fs]:\n", d.state.NumDone(), d.state.NumActive(), time.Since(d.state.StartTime).Seconds())
	d.lines++
	if d.stats {
		printStat("CPU use", d.state.Stats.CPU.Used, d.state.Stats.CPU.Count)
		printStat("I/O", d.state.Stats.CPU.IOWait, d.state.Stats.CPU.Count)
		printStat("Mem use", d.state.Stats.Memory.UsedPercent, 1)
		if d.state.Stats.NumWorkerProcesses > 0 {
			printf("  ${BOLD_WHITE}Worker processes: %d${RESET}", d.state.Stats.NumWorkerProcesses)
		}
		if d.state.RemoteClient != nil {
			in, out := d.state.RemoteClient.DataRate()
			printf("  ${BOLD_WHITE}RPC data in: %6s/s out: %6s/s${RESET}", humanize.Bytes(uint64(in)), humanize.Bytes(uint64(out)))
		}
		printf("${ERASE_AFTER}\n")
		d.lines++
	}
	for i := 0; i < d.numWorkers && i < d.maxRows; i++ {
		d.printRow(i, now, false)
		d.lines++
	}
	if d.numRemote > 0 {
		printf("Remote processes [%d/%d active]:   \n", d.numRemoteActive(), d.numRemote)
		d.lines++
		for i := 0; i < d.numRemote && i < d.maxRows; i++ {
			d.printRow(d.numWorkers+i, now, true)
			d.lines++
		}
	}
	printf("${RESET}")
}

func (d *displayer) numRemoteActive() int {
	count := 0
	for i := 0; i < d.numRemote; i++ {
		if d.targets[d.numWorkers+i].Active {
			count++
		}
	}
	return count
}

func (d *displayer) printRow(i int, now time.Time, remote bool) {
	d.targets[i].Lock()
	// Take a local copy of the structure, which isn't *that* big, so we don't need to retain the lock
	// while we do potentially blocking things like printing.
	target := d.targets[i].buildingTargetData
	d.targets[i].Unlock()
	label := target.Label.Parent()
	duration := now.Sub(target.Started).Seconds()
	if target.Active && target.Target != nil && target.Target.ShowProgress && target.Target.Progress > 0.0 {
		if target.Target.Progress > 1.0 && target.Target.Progress < 100.0 && target.Target.Progress != target.LastProgress {
			proportionDone := target.Target.Progress / 100.0
			perPercent := float32(duration) / proportionDone
			d.targets[i].Eta = time.Duration(perPercent * (1.0 - proportionDone) * float32(time.Second)).Truncate(time.Second)
			d.targets[i].LastProgress = target.Target.Progress
		}
		if target.Eta > 0 {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${RESET} (%.1f%%, est %s remaining)${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description, target.Target.Progress, target.Eta)
		} else {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${RESET} (%.1f%% complete)${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description, target.Target.Progress)
		}
	} else if target.Active {
		d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${ERASE_AFTER}\n",
			duration, target.Colour, label, target.Description)
	} else if time.Since(target.Finished).Seconds() < 0.5 {
		// Only display finished targets for half a second after they're done.
		duration := target.Finished.Sub(target.Started).Seconds()
		if target.Failed {
			d.printf("${BOLD_RED}=> [%4.1fs] ${RESET}%s%s ${BOLD_RED}Failed${ERASE_AFTER}\n",
				duration, target.Colour, label)
		} else if target.Cached {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_GREY}%s${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description)
		} else {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${WHITE}%s${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description)
		}
	} else if !remote {
		printf("${BOLD_GREY}=|${ERASE_AFTER}\n")
	} else {
		d.lines-- // Didn't print it
	}
}

// printStat prints a single statistic with appropriate colours.
func printStat(caption string, stat float64, multiplier int) {
	colour := "${BOLD_GREEN}"
	if stat > 80.0*float64(multiplier) {
		colour = "${BOLD_RED}"
	} else if stat > 60.0*float64(multiplier) {
		colour = "${BOLD_YELLOW}"
	}
	printf("  ${BOLD_WHITE}%s:${RESET} %s%5.1f%%${RESET}", caption, colour, stat)
}

func recalcWindowSize(backend *cli.LogBackend) {
	rows, cols, _ := cli.WindowSize()
	backend.Lock()
	defer backend.Unlock()
	backend.Rows = rows - 4 // Give a little space at the edge for any off-by-ones
	backend.Cols = cols
	backend.RecalcLines()
}

// Limited-length printf that respects current window width.
// Output is truncated at the middle to fit within 'cols'.
func (d *displayer) printf(format string, args ...interface{}) {
	fmt.Fprint(os.Stderr, lprintfPrepare(d.maxCols, os.Expand(fmt.Sprintf(format, args...), replace)))
}

func lprintfPrepare(cols int, s string) string {
	if len(s) < cols {
		return s // it's short enough, nice and simple
	}
	// Okay, it's too long. Tricky thing: ANSI escape codes don't count for width
	// so we need to count without those. Bonus: make an effort to be unicode-aware.
	var b bytes.Buffer
	written := 0
	inAnsiCode := false
	for _, rune := range s {
		if inAnsiCode {
			b.WriteRune(rune)
			if rune == 'm' {
				inAnsiCode = false
			}
		} else if rune == '\x1b' {
			b.WriteRune(rune)
			inAnsiCode = true
		} else if rune == '\n' {
			b.WriteRune(rune)
		} else if written == cols-3 {
			b.WriteString("...")
			written += 3
		} else if written < cols-3 {
			b.WriteRune(rune)
			written++
		}
	}
	return b.String()
}

// setWindowTitle sets the title of the current shell window based on the current build state.
func setWindowTitle(state *core.BuildState, running bool) {
	if !state.Config.Display.UpdateTitle {
		return
	}
	if running {
		SetWindowTitle("plz: finishing up")
	} else {
		SetWindowTitle(fmt.Sprintf("plz: %d / %d tasks, %3.1fs", state.NumDone(), state.NumActive(), time.Since(state.StartTime).Seconds()))
	}
}

// SetWindowTitle sets the title of the current shell window.
func SetWindowTitle(title string) {
	if cli.StdErrIsATerminal && terminalClaimsToBeXterm {
		os.Stderr.Write([]byte(fmt.Sprintf("\033]0;%s\007", title)))
	}
}
<commit_msg>Don't display inactive normal build lines if remote workers are in use.<commit_after>package output

import (
	"bytes"
	"context"
	"fmt"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/dustin/go-humanize"

	"github.com/thought-machine/please/src/cli"
	"github.com/thought-machine/please/src/core"
)

// We only set the terminal title for terminals that at least claim to be xterm
// (note that most terminals do for compatibility; some report as xterm-color, hence HasPrefix)
var terminalClaimsToBeXterm = strings.HasPrefix(os.Getenv("TERM"), "xterm")

type displayer struct {
	state                                   *core.BuildState
	targets                                 []buildingTarget
	numWorkers, numRemote, maxRows, maxCols int
	stats                                   bool
	lines, lastLines                        int // mutable - records how many rows we've printed this time
}

func display(ctx context.Context, state *core.BuildState, buildingTargets []buildingTarget) {
	backend := cli.NewLogBackend(len(buildingTargets))
	go func() {
		sig := make(chan os.Signal, 10)
		signal.Notify(sig, syscall.SIGWINCH)
		for {
			<-sig
			recalcWindowSize(backend)
		}
	}()
	recalcWindowSize(backend)
	backend.SetActive()

	d := &displayer{
		state:      state,
		targets:    buildingTargets,
		numWorkers: state.Config.Please.NumThreads,
		numRemote:  state.Config.Remote.NumExecutors,
		maxRows:    backend.MaxInteractiveRows,
		maxCols:    backend.Cols,
		stats:      state.Config.Display.SystemStats,
	}

	d.printLines()
	d.run(ctx, backend)
	setWindowTitle(state, false)
	// Clear it all out.
	d.moveToFirstLine()
	printf("${CLEAR_END}")
	backend.Deactivate()
}

func (d *displayer) run(ctx context.Context, backend *cli.LogBackend) {
	ticker := time.NewTicker(50 * time.Millisecond)
	defer ticker.Stop()
	done := ctx.Done()
	for {
		select {
		case <-done:
			return
		case <-ticker.C:
			d.moveToFirstLine()
			d.printLines()
			for _, line := range backend.Output {
				printf("${ERASE_AFTER}%s\n", line)
				d.lines++
			}
			// Clean out any lines that were visible last time but are not now.
			if d.lines < d.lastLines {
				for i := d.lines; i < d.lastLines; i++ {
					printf("${ERASE_AFTER}\n")
				}
				printf("\x1b[%dA", d.lastLines-d.lines) // Move back up again
			}
			setWindowTitle(d.state, true)
		}
	}
}

// moveToFirstLine resets back to the first line.
func (d *displayer) moveToFirstLine() {
	printf("\x1b[%dA", d.lines)
	d.lastLines = d.lines
	d.lines = 0
}

func (d *displayer) printLines() {
	now := time.Now()
	printf("Building [%d/%d, %3.1fs]:\n", d.state.NumDone(), d.state.NumActive(), time.Since(d.state.StartTime).Seconds())
	d.lines++
	if d.stats {
		printStat("CPU use", d.state.Stats.CPU.Used, d.state.Stats.CPU.Count)
		printStat("I/O", d.state.Stats.CPU.IOWait, d.state.Stats.CPU.Count)
		printStat("Mem use", d.state.Stats.Memory.UsedPercent, 1)
		if d.state.Stats.NumWorkerProcesses > 0 {
			printf("  ${BOLD_WHITE}Worker processes: %d${RESET}", d.state.Stats.NumWorkerProcesses)
		}
		if d.state.RemoteClient != nil {
			in, out := d.state.RemoteClient.DataRate()
			printf("  ${BOLD_WHITE}RPC data in: %6s/s out: %6s/s${RESET}", humanize.Bytes(uint64(in)), humanize.Bytes(uint64(out)))
		}
		printf("${ERASE_AFTER}\n")
		d.lines++
	}
	anyRemote := d.numRemote > 0
	for i := 0; i < d.numWorkers && i < d.maxRows; i++ {
		d.printRow(i, now, anyRemote)
		d.lines++
	}
	if anyRemote {
		printf("Remote processes [%d/%d active]:   \n", d.numRemoteActive(), d.numRemote)
		d.lines++
		for i := 0; i < d.numRemote && i < d.maxRows; i++ {
			d.printRow(d.numWorkers+i, now, true)
			d.lines++
		}
	}
	printf("${RESET}")
}

func (d *displayer) numRemoteActive() int {
	count := 0
	for i := 0; i < d.numRemote; i++ {
		if d.targets[d.numWorkers+i].Active {
			count++
		}
	}
	return count
}

func (d *displayer) printRow(i int, now time.Time, remote bool) {
	d.targets[i].Lock()
	// Take a local copy of the structure, which isn't *that* big, so we don't need to retain the lock
	// while we do potentially blocking things like printing.
	target := d.targets[i].buildingTargetData
	d.targets[i].Unlock()
	label := target.Label.Parent()
	duration := now.Sub(target.Started).Seconds()
	if target.Active && target.Target != nil && target.Target.ShowProgress && target.Target.Progress > 0.0 {
		if target.Target.Progress > 1.0 && target.Target.Progress < 100.0 && target.Target.Progress != target.LastProgress {
			proportionDone := target.Target.Progress / 100.0
			perPercent := float32(duration) / proportionDone
			d.targets[i].Eta = time.Duration(perPercent * (1.0 - proportionDone) * float32(time.Second)).Truncate(time.Second)
			d.targets[i].LastProgress = target.Target.Progress
		}
		if target.Eta > 0 {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${RESET} (%.1f%%, est %s remaining)${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description, target.Target.Progress, target.Eta)
		} else {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${RESET} (%.1f%% complete)${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description, target.Target.Progress)
		}
	} else if target.Active {
		d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${ERASE_AFTER}\n",
			duration, target.Colour, label, target.Description)
	} else if time.Since(target.Finished).Seconds() < 0.5 {
		// Only display finished targets for half a second after they're done.
		duration := target.Finished.Sub(target.Started).Seconds()
		if target.Failed {
			d.printf("${BOLD_RED}=> [%4.1fs] ${RESET}%s%s ${BOLD_RED}Failed${ERASE_AFTER}\n",
				duration, target.Colour, label)
		} else if target.Cached {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_GREY}%s${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description)
		} else {
			d.printf("${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${WHITE}%s${ERASE_AFTER}\n",
				duration, target.Colour, label, target.Description)
		}
	} else if !remote {
		printf("${BOLD_GREY}=|${ERASE_AFTER}\n")
	} else {
		d.lines-- // Didn't print it
	}
}

// printStat prints a single statistic with appropriate colours.
func printStat(caption string, stat float64, multiplier int) {
	colour := "${BOLD_GREEN}"
	if stat > 80.0*float64(multiplier) {
		colour = "${BOLD_RED}"
	} else if stat > 60.0*float64(multiplier) {
		colour = "${BOLD_YELLOW}"
	}
	printf("  ${BOLD_WHITE}%s:${RESET} %s%5.1f%%${RESET}", caption, colour, stat)
}

func recalcWindowSize(backend *cli.LogBackend) {
	rows, cols, _ := cli.WindowSize()
	backend.Lock()
	defer backend.Unlock()
	backend.Rows = rows - 4 // Give a little space at the edge for any off-by-ones
	backend.Cols = cols
	backend.RecalcLines()
}

// Limited-length printf that respects current window width.
// Output is truncated at the middle to fit within 'cols'.
func (d *displayer) printf(format string, args ...interface{}) {
	fmt.Fprint(os.Stderr, lprintfPrepare(d.maxCols, os.Expand(fmt.Sprintf(format, args...), replace)))
}

func lprintfPrepare(cols int, s string) string {
	if len(s) < cols {
		return s // it's short enough, nice and simple
	}
	// Okay, it's too long. Tricky thing: ANSI escape codes don't count for width
	// so we need to count without those. Bonus: make an effort to be unicode-aware.
	var b bytes.Buffer
	written := 0
	inAnsiCode := false
	for _, rune := range s {
		if inAnsiCode {
			b.WriteRune(rune)
			if rune == 'm' {
				inAnsiCode = false
			}
		} else if rune == '\x1b' {
			b.WriteRune(rune)
			inAnsiCode = true
		} else if rune == '\n' {
			b.WriteRune(rune)
		} else if written == cols-3 {
			b.WriteString("...")
			written += 3
		} else if written < cols-3 {
			b.WriteRune(rune)
			written++
		}
	}
	return b.String()
}

// setWindowTitle sets the title of the current shell window based on the current build state.
func setWindowTitle(state *core.BuildState, running bool) {
	if !state.Config.Display.UpdateTitle {
		return
	}
	if running {
		SetWindowTitle("plz: finishing up")
	} else {
		SetWindowTitle(fmt.Sprintf("plz: %d / %d tasks, %3.1fs", state.NumDone(), state.NumActive(), time.Since(state.StartTime).Seconds()))
	}
}

// SetWindowTitle sets the title of the current shell window.
func SetWindowTitle(title string) {
	if cli.StdErrIsATerminal && terminalClaimsToBeXterm {
		os.Stderr.Write([]byte(fmt.Sprintf("\033]0;%s\007", title)))
	}
}
<|endoftext|>


<commit_before>package auth

import (
	"encoding/json"
	"golang.org/x/oauth2"
	"io/ioutil"
	"os"
)

func FileSource(path string, token *oauth2.Token, conf *oauth2.Config) oauth2.TokenSource {
	return &fileSource{
		tokenPath:   path,
		tokenSource: conf.TokenSource(oauth2.NoContext, token),
	}
}

type fileSource struct {
	tokenPath   string
	tokenSource oauth2.TokenSource
}

func (self *fileSource) Token() (*oauth2.Token, error) {
	token, err := self.tokenSource.Token()
	if err != nil {
		return token, err
	}

	// Save token to file
	SaveToken(self.tokenPath, token)

	return token, nil
}

func ReadFile(path string) ([]byte, bool, error) {
	if !fileExists(path) {
		return nil, false, nil
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, true, err
	}
	return content, true, nil
}

func ReadToken(path string) (*oauth2.Token, bool, error) {

	content, exists, err := ReadFile(path)
	if err != nil {
		return nil, exists, err
	}

	token := &oauth2.Token{}
	return token, exists, json.Unmarshal(content, token)
}

func SaveToken(path string, token *oauth2.Token) error {
	data, err := json.MarshalIndent(token, "", "  ")
	if err != nil {
		return err
	}

	if err = mkdir(path); err != nil {
		return err
	}

	// Write to temp file first
	tmpFile := path + ".tmp"
	err = ioutil.WriteFile(tmpFile, data, 0600)
	if err != nil {
		os.Remove(tmpFile)
		return err
	}

	// Move file to correct path
	return os.Rename(tmpFile, path)
}
<commit_msg>auth/file_source: don't try to read non-existent files<commit_after>package auth

import (
	"encoding/json"
	"golang.org/x/oauth2"
	"io/ioutil"
	"os"
)

func FileSource(path string, token *oauth2.Token, conf *oauth2.Config) oauth2.TokenSource {
	return &fileSource{
		tokenPath:   path,
		tokenSource: conf.TokenSource(oauth2.NoContext, token),
	}
}

type fileSource struct {
	tokenPath   string
	tokenSource oauth2.TokenSource
}

func (self *fileSource) Token() (*oauth2.Token, error) {
	token, err := self.tokenSource.Token()
	if err != nil {
		return token, err
	}

	// Save token to file
	SaveToken(self.tokenPath, token)

	return token, nil
}

func ReadFile(path string) ([]byte, bool, error) {
	if !fileExists(path) {
		return nil, false, nil
	}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, true, err
	}
	return content, true, nil
}

func ReadToken(path string) (*oauth2.Token, bool, error) {

	content, exists, err := ReadFile(path)
	if err != nil || exists == false {
		return nil, exists, err
	}

	token := &oauth2.Token{}
	return token, exists, json.Unmarshal(content, token)
}

func SaveToken(path string, token *oauth2.Token) error {
	data, err := json.MarshalIndent(token, "", "  ")
	if err != nil {
		return err
	}

	if err = mkdir(path); err != nil {
		return err
	}

	// Write to temp file first
	tmpFile := path + ".tmp"
	err = ioutil.WriteFile(tmpFile, data, 0600)
	if err != nil {
		os.Remove(tmpFile)
		return err
	}

	// Move file to correct path
	return os.Rename(tmpFile, path)
}
<|endoftext|>


<commit_before>package operationlock

import (
	"fmt"
	"sync"
	"time"

	"github.com/lxc/lxd/lxd/project"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
)

// TimeoutSeconds number of seconds that the operation lock will be kept for without calling Reset().
const TimeoutSeconds = 30

// Action indicates the operation action type.
type Action string

// ActionStart for starting an instance.
const ActionStart Action = "start"

// ActionStop for stopping an instance.
const ActionStop Action = "stop"

// ActionRestart for restarting an instance.
const ActionRestart Action = "restart"

// ActionRestore for restoring an instance.
const ActionRestore Action = "restore"

// ErrNonReusuableSucceeded is returned when no operation is created due to having to wait for a matching
// non-reusuable operation that has now completed successfully.
var ErrNonReusuableSucceeded error = fmt.Errorf("A matching non-reusable operation has now succeeded")

var instanceOperationsLock sync.Mutex
var instanceOperations = make(map[string]*InstanceOperation)

// InstanceOperation operation locking.
type InstanceOperation struct {
	action       Action
	chanDone     chan error
	chanReset    chan struct{}
	err          error
	projectName  string
	instanceName string
	reusable     bool
}

// Create creates a new operation lock for an Instance if one does not already exist and returns it.
// The lock will be released after TimeoutSeconds or when Done() is called, which ever occurs first.
// If createReusuable is set as true then future lock attempts can specify the reuseExisting argument as true
// which will then trigger a reset of the timeout to TimeoutSeconds on the existing lock and return it.
func Create(projectName string, instanceName string, action Action, createReusuable bool, reuseExisting bool) (*InstanceOperation, error) {
	if projectName == "" || instanceName == "" {
		return nil, fmt.Errorf("Invalid project or instance name")
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(projectName, instanceName)

	op := instanceOperations[opKey]
	if op != nil {
		if op.reusable && reuseExisting {
			// Reset operation timeout without releasing lock or deadlocking using Reset() function.
			op.chanReset <- struct{}{}
			logger.Debug("Instance operation lock reused", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable})

			return op, nil
		}

		return nil, fmt.Errorf("Instance is busy running a %q operation", op.action)
	}

	op = &InstanceOperation{}
	op.projectName = projectName
	op.instanceName = instanceName
	op.action = action
	op.reusable = createReusuable
	op.chanDone = make(chan error, 0)
	op.chanReset = make(chan struct{}, 0)

	instanceOperations[opKey] = op
	logger.Debug("Instance operation lock created", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable})

	go func(op *InstanceOperation) {
		for {
			select {
			case <-op.chanDone:
				return
			case <-op.chanReset:
				continue
			case <-time.After(time.Second * TimeoutSeconds):
				op.Done(fmt.Errorf("Instance %q operation timed out after %d seconds", op.action, TimeoutSeconds))
				return
			}
		}
	}(op)

	return op, nil
}

// CreateWaitGet is a weird function which does what we happen to want most of the time.
//
// If the instance has an operation of the same type and it's not reusable
// or the caller doesn't want to reuse it, the function will wait and
// indicate that it did so.
//
// If the instance has an operation of one of the alternate types, then
// the operation is returned to the user.
//
// If the instance doesn't have an operation, has an operation of a different
// type that is not in the alternate list or has the right type and is
// being reused, then this behaves as a Create call.
func CreateWaitGet(projectName string, instanceName string, action string, altActions []string, reusable bool, reuse bool) (bool, *InstanceOperation, error) {
	op := Get(projectName, instanceName)

	// No existing operation, call create.
	if op == nil {
		op, err := Create(projectName, instanceName, action, reusable, reuse)
		return false, op, err
	}

	// Operation matches and not reusable or asked to reuse, wait.
	if op.action == action && (!reuse || !op.reusable) {
		err := op.Wait()
		return true, nil, err
	}

	// Operation matches one the alternate actions, return the operation.
	if shared.StringInSlice(op.action, altActions) {
		return false, op, nil
	}

	// Send the rest to Create
	op, err := Create(projectName, instanceName, action, reusable, reuse)

	return false, op, err
}

// Get retrieves an existing lock or returns nil if no lock exists.
func Get(projectName string, instanceName string) *InstanceOperation {
	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(projectName, instanceName)

	return instanceOperations[opKey]
}

// Action returns operation's action.
func (op *InstanceOperation) Action() Action {
	return op.action
}

// ActionMatch returns true if operations' action matches on of the matchActions.
func (op *InstanceOperation) ActionMatch(matchActions ...Action) bool {
	for _, matchAction := range matchActions {
		if op.action == matchAction {
			return true
		}
	}

	return false
}

// Reset resets the operation timeout to give another TimeoutSeconds seconds until it expires.
func (op *InstanceOperation) Reset() error {
	// This function can be called on a nil struct.
	if op == nil {
		return nil
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(op.projectName, op.instanceName)

	// Check if already done
	runningOp, ok := instanceOperations[opKey]
	if !ok || runningOp != op {
		return fmt.Errorf("Operation is already done or expired")
	}

	op.chanReset <- struct{}{}
	return nil
}

// Wait waits for an operation to finish.
func (op *InstanceOperation) Wait() error {
	// This function can be called on a nil struct.
	if op == nil {
		return nil
	}

	<-op.chanDone

	return op.err
}

// Done indicates the operation has finished.
func (op *InstanceOperation) Done(err error) {
	// This function can be called on a nil struct.
	if op == nil {
		return
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(op.projectName, op.instanceName)

	// Check if already done.
	runningOp, ok := instanceOperations[opKey]
	if !ok || runningOp != op {
		return
	}

	op.err = err
	delete(instanceOperations, opKey) // Delete before closing chanDone.
	close(op.chanDone)
	logger.Debug("Instance operation lock finished", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable, "err": err})
}
<commit_msg>lxd/instance/operationlock: Reworks CreateWaitGet<commit_after>package operationlock

import (
	"fmt"
	"sync"
	"time"

	"github.com/lxc/lxd/lxd/project"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
)

// TimeoutSeconds number of seconds that the operation lock will be kept for without calling Reset().
const TimeoutSeconds = 30

// Action indicates the operation action type.
type Action string

// ActionStart for starting an instance.
const ActionStart Action = "start"

// ActionStop for stopping an instance.
const ActionStop Action = "stop"

// ActionRestart for restarting an instance.
const ActionRestart Action = "restart"

// ActionRestore for restoring an instance.
const ActionRestore Action = "restore"

// ErrNonReusuableSucceeded is returned when no operation is created due to having to wait for a matching
// non-reusuable operation that has now completed successfully.
var ErrNonReusuableSucceeded error = fmt.Errorf("A matching non-reusable operation has now succeeded")

var instanceOperationsLock sync.Mutex
var instanceOperations = make(map[string]*InstanceOperation)

// InstanceOperation operation locking.
type InstanceOperation struct {
	action       Action
	chanDone     chan error
	chanReset    chan struct{}
	err          error
	projectName  string
	instanceName string
	reusable     bool
}

// Create creates a new operation lock for an Instance if one does not already exist and returns it.
// The lock will be released after TimeoutSeconds or when Done() is called, which ever occurs first.
// If createReusuable is set as true then future lock attempts can specify the reuseExisting argument as true
// which will then trigger a reset of the timeout to TimeoutSeconds on the existing lock and return it.
func Create(projectName string, instanceName string, action Action, createReusuable bool, reuseExisting bool) (*InstanceOperation, error) {
	if projectName == "" || instanceName == "" {
		return nil, fmt.Errorf("Invalid project or instance name")
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(projectName, instanceName)

	op := instanceOperations[opKey]
	if op != nil {
		if op.reusable && reuseExisting {
			// Reset operation timeout without releasing lock or deadlocking using Reset() function.
			op.chanReset <- struct{}{}
			logger.Debug("Instance operation lock reused", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable})

			return op, nil
		}

		return nil, fmt.Errorf("Instance is busy running a %q operation", op.action)
	}

	op = &InstanceOperation{}
	op.projectName = projectName
	op.instanceName = instanceName
	op.action = action
	op.reusable = createReusuable
	op.chanDone = make(chan error, 0)
	op.chanReset = make(chan struct{}, 0)

	instanceOperations[opKey] = op
	logger.Debug("Instance operation lock created", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable})

	go func(op *InstanceOperation) {
		for {
			select {
			case <-op.chanDone:
				return
			case <-op.chanReset:
				continue
			case <-time.After(time.Second * TimeoutSeconds):
				op.Done(fmt.Errorf("Instance %q operation timed out after %d seconds", op.action, TimeoutSeconds))
				return
			}
		}
	}(op)

	return op, nil
}

// CreateWaitGet is a weird function which does what we happen to want most of the time.
//
// If the instance has an operation of the same type and it's not reusable
// or the caller doesn't want to reuse it, the function will wait and
// indicate that it did so.
//
// If the instance has an existing operation of one of the inheritableActions types, then the operation is returned
// to the user. This allows an operation started in one function/routine to be inherited by another.
//
// If the instance doesn't have an ongoing operation, has an operation of a different type that is not in the
// inheritableActions list or has the right type and is being reused, then this behaves as a Create call.
//
// Returns ErrWaitedForMatching if it waited for a matching operation to finish and it's finished successfully and
// so didn't return create a new operation.
func CreateWaitGet(projectName string, instanceName string, action Action, inheritableActions []Action, createReusuable bool, reuseExisting bool) (*InstanceOperation, error) {
	op := Get(projectName, instanceName)

	// No existing operation, call create.
	if op == nil {
		op, err := Create(projectName, instanceName, action, createReusuable, reuseExisting)
		return op, err
	}

	// Operation action matches but is not reusable or we have been asked not to reuse,
	// so wait and return result.
	if op.action == action && (!reuseExisting || !op.reusable) {
		err := op.Wait()
		if err != nil {
			return nil, err
		}

		// The matching operation ended without error, but this means we've not created a new
		// operation for this request, so return a special error indicating this scenario.
		return nil, ErrNonReusuableSucceeded
	}

	// Operation action matches one the inheritable actions, return the operation.
	if op.ActionMatch(inheritableActions...) {
		logger.Debug("Instance operation lock inherited", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable, "inheritedByAction": action})

		return op, nil
	}

	// Send the rest to Create to try and create a new operation.
	op, err := Create(projectName, instanceName, action, createReusuable, reuseExisting)

	return op, err
}

// Get retrieves an existing lock or returns nil if no lock exists.
func Get(projectName string, instanceName string) *InstanceOperation {
	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(projectName, instanceName)

	return instanceOperations[opKey]
}

// Action returns operation's action.
func (op *InstanceOperation) Action() Action {
	return op.action
}

// ActionMatch returns true if operations' action matches on of the matchActions.
func (op *InstanceOperation) ActionMatch(matchActions ...Action) bool {
	for _, matchAction := range matchActions {
		if op.action == matchAction {
			return true
		}
	}

	return false
}

// Reset resets the operation timeout to give another TimeoutSeconds seconds until it expires.
func (op *InstanceOperation) Reset() error {
	// This function can be called on a nil struct.
	if op == nil {
		return nil
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(op.projectName, op.instanceName)

	// Check if already done
	runningOp, ok := instanceOperations[opKey]
	if !ok || runningOp != op {
		return fmt.Errorf("Operation is already done or expired")
	}

	op.chanReset <- struct{}{}
	return nil
}

// Wait waits for an operation to finish.
func (op *InstanceOperation) Wait() error {
	// This function can be called on a nil struct.
	if op == nil {
		return nil
	}

	<-op.chanDone

	return op.err
}

// Done indicates the operation has finished.
func (op *InstanceOperation) Done(err error) {
	// This function can be called on a nil struct.
	if op == nil {
		return
	}

	instanceOperationsLock.Lock()
	defer instanceOperationsLock.Unlock()

	opKey := project.Instance(op.projectName, op.instanceName)

	// Check if already done.
	runningOp, ok := instanceOperations[opKey]
	if !ok || runningOp != op {
		return
	}

	op.err = err
	delete(instanceOperations, opKey) // Delete before closing chanDone.
	close(op.chanDone)
	logger.Debug("Instance operation lock finished", log.Ctx{"project": op.projectName, "instance": op.instanceName, "action": op.action, "reusable": op.reusable, "err": err})
}
<|endoftext|>


<commit_before>package asapi

import (
	"gogs.xiaoyuanjijiehao.com/aag/ant-queen/pkg/conf"
)

// AntQueenInit 使用antQueen框架时可以使用该方法初始化
// key 文件名 不指定默认使用antlinkerauth.toml
func AntQueenInit(key ...string) {
	file := "antlinkerauth.toml"
	if len(key) == 1 {
		file = key[0]
	}
	cfg := loadCfg(file)
	initAuth(&cfg)
}

func loadCfg(key string) (cfg authorizeConfig) {
	if err := conf.Get(key).UnmarshalTOML(&cfg); err != nil {
		if err != conf.ErrNotExist {
			panic(err)
		}
	}
	return
}

type authorizeConfig struct {
	Enable          bool   `json:"enable,omitempty"`
	URL             string `json:"url,omitempty" yaml:"url"`
	ClientID        string `json:"client_id,omitempty" yaml:"client_id"`
	ClientSecret    string `json:"client_secret,omitempty" yaml:"client_secret"`
	Identify        string `json:"identify,omitempty" yaml:"identify"`
	IsEnabledCache  bool   `json:"is_enabled_cache,omitempty"`  // 是否启用缓存
	CacheGCInterval int    `json:"cache_gc_interval,omitempty"` // 缓存gc间隔(单位秒)
	MaxConns        int    `json:"max_conns,omitempty"`
}

func initAuth(config *authorizeConfig) {
	cache := true
	if !config.IsEnabledCache {
		cache = false
	}
	interval := 60
	if config.CacheGCInterval > 0 {
		interval = config.CacheGCInterval
	}
	InitAPI(&Config{
		ASURL:           config.URL,
		ClientID:        config.ClientID,
		ClientSecret:    config.ClientSecret,
		ServiceIdentify: config.Identify,
		IsEnabledCache:  cache,
		CacheGCInterval: interval,
		MaxConns:        config.MaxConns,
	})
}
<commit_msg>修复toml格式解析失败错误<commit_after>package asapi

import (
	"gogs.xiaoyuanjijiehao.com/aag/ant-queen/pkg/conf"
)

// AntQueenInit 使用antQueen框架时可以使用该方法初始化
// key 文件名 不指定默认使用antlinkerauth.toml
func AntQueenInit(key ...string) {
	file := "antlinkerauth.toml"
	if len(key) == 1 {
		file = key[0]
	}
	cfg := loadCfg(file)
	initAuth(&cfg)
}

func loadCfg(key string) (cfg authorizeConfig) {
	if err := conf.Get(key).UnmarshalTOML(&cfg); err != nil {
		if err != conf.ErrNotExist {
			panic(err)
		}
	}
	return
}

type authorizeConfig struct {
	Enable          bool   `toml:"enable,omitempty" json:"enable,omitempty"`
	URL             string `toml:"url,omitempty" json:"url,omitempty" yaml:"url"`
	ClientID        string `toml:"client_id,omitempty" json:"client_id,omitempty" yaml:"client_id"`
	ClientSecret    string `toml:"client_secret,omitempty" json:"client_secret,omitempty" yaml:"client_secret"`
	Identify        string `toml:"identify,omitempty" json:"identify,omitempty" yaml:"identify"`
	IsEnabledCache  bool   `toml:"is_enabled_cache,omitempty" json:"is_enabled_cache,omitempty"`   // 是否启用缓存
	CacheGCInterval int    `toml:"cache_gc_interval,omitempty" json:"cache_gc_interval,omitempty"` // 缓存gc间隔(单位秒)
	MaxConns        int    `toml:"max_conns,omitempty" json:"max_conns,omitempty"`
}

func initAuth(config *authorizeConfig) {
	cache := true
	if !config.IsEnabledCache {
		cache = false
	}
	interval := 60
	if config.CacheGCInterval > 0 {
		interval = config.CacheGCInterval
	}
	InitAPI(&Config{
		ASURL:           config.URL,
		ClientID:        config.ClientID,
		ClientSecret:    config.ClientSecret,
		ServiceIdentify: config.Identify,
		IsEnabledCache:  cache,
		CacheGCInterval: interval,
		MaxConns:        config.MaxConns,
	})
}
<|endoftext|>


<commit_before>// Copyright 2015 tsuru 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 storage

import (
	"sync"
	"time"

	"gopkg.in/mgo.v2"
)

var (
	conn   = make(map[string]*session) // pool of connections
	mut    sync.RWMutex                // for pool thread safety
	ticker *time.Ticker                // for garbage collection
)

type session struct {
	s    *mgo.Session
	used time.Time
}

const period time.Duration = 7 * 24 * time.Hour

// Storage holds the connection with the database.
type Storage struct {
	session *mgo.Session
	dbname  string
}

// Collection represents a database collection. It embeds mgo.Collection for
// operations, and holds a session to MongoDB. The user may close the session
// using the method close.
type Collection struct {
	*mgo.Collection
}

// Close closes the session with the database.
func (c *Collection) Close() {
	c.Collection.Database.Session.Close()
}

func open(addr, dbname string) (*Storage, error) {
	sess, err := mgo.Dial(addr)
	if err != nil {
		return nil, fmt.Errorf("mongodb: %s", err)
	}
	copy := sess.Clone()
	storage := &Storage{session: copy, dbname: dbname}
	mut.Lock()
	conn[addr] = &session{s: sess, used: time.Now()}
	mut.Unlock()
	return storage, nil
}

// Open dials to the MongoDB database, and return the connection (represented
// by the type Storage).
//
// addr is a MongoDB connection URI, and dbname is the name of the database.
//
// This function returns a pointer to a Storage, or a non-nil error in case of
// any failure.
func Open(addr, dbname string) (storage *Storage, err error) {
	defer func() {
		if r := recover(); r != nil {
			storage, err = open(addr, dbname)
		}
	}()
	mut.RLock()
	if session, ok := conn[addr]; ok {
		mut.RUnlock()
		if err = session.s.Ping(); err == nil {
			mut.Lock()
			session.used = time.Now()
			conn[addr] = session
			mut.Unlock()
			copy := session.s.Clone()
			return &Storage{copy, dbname}, nil
		}
		return open(addr, dbname)
	}
	mut.RUnlock()
	return open(addr, dbname)
}

// Close closes the storage, releasing the connection.
func (s *Storage) Close() {
	s.session.Close()
}

// Collection returns a collection by its name.
//
// If the collection does not exist, MongoDB will create it.
func (s *Storage) Collection(name string) *Collection {
	return &Collection{s.session.DB(s.dbname).C(name)}
}

func init() {
	ticker = time.NewTicker(time.Hour)
	go retire(ticker)
}

// retire retires old connections
func retire(t *time.Ticker) {
	for range t.C {
		now := time.Now()
		var old []string
		mut.RLock()
		for k, v := range conn {
			if now.Sub(v.used) >= period {
				old = append(old, k)
			}
		}
		mut.RUnlock()
		mut.Lock()
		for _, c := range old {
			conn[c].s.Close()
			delete(conn, c)
		}
		mut.Unlock()
	}
}
<commit_msg>db/storage: add import of fmt<commit_after>// Copyright 2015 tsuru 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 storage

import (
	"sync"
	"time"
	"fmt"

	"gopkg.in/mgo.v2"
)

var (
	conn   = make(map[string]*session) // pool of connections
	mut    sync.RWMutex                // for pool thread safety
	ticker *time.Ticker                // for garbage collection
)

type session struct {
	s    *mgo.Session
	used time.Time
}

const period time.Duration = 7 * 24 * time.Hour

// Storage holds the connection with the database.
type Storage struct {
	session *mgo.Session
	dbname  string
}

// Collection represents a database collection. It embeds mgo.Collection for
// operations, and holds a session to MongoDB. The user may close the session
// using the method close.
type Collection struct {
	*mgo.Collection
}

// Close closes the session with the database.
func (c *Collection) Close() {
	c.Collection.Database.Session.Close()
}

func open(addr, dbname string) (*Storage, error) {
	sess, err := mgo.Dial(addr)
	if err != nil {
		return nil, fmt.Errorf("mongodb: %s", err)
	}
	copy := sess.Clone()
	storage := &Storage{session: copy, dbname: dbname}
	mut.Lock()
	conn[addr] = &session{s: sess, used: time.Now()}
	mut.Unlock()
	return storage, nil
}

// Open dials to the MongoDB database, and return the connection (represented
// by the type Storage).
//
// addr is a MongoDB connection URI, and dbname is the name of the database.
//
// This function returns a pointer to a Storage, or a non-nil error in case of
// any failure.
func Open(addr, dbname string) (storage *Storage, err error) {
	defer func() {
		if r := recover(); r != nil {
			storage, err = open(addr, dbname)
		}
	}()
	mut.RLock()
	if session, ok := conn[addr]; ok {
		mut.RUnlock()
		if err = session.s.Ping(); err == nil {
			mut.Lock()
			session.used = time.Now()
			conn[addr] = session
			mut.Unlock()
			copy := session.s.Clone()
			return &Storage{copy, dbname}, nil
		}
		return open(addr, dbname)
	}
	mut.RUnlock()
	return open(addr, dbname)
}

// Close closes the storage, releasing the connection.
func (s *Storage) Close() {
	s.session.Close()
}

// Collection returns a collection by its name.
//
// If the collection does not exist, MongoDB will create it.
func (s *Storage) Collection(name string) *Collection {
	return &Collection{s.session.DB(s.dbname).C(name)}
}

func init() {
	ticker = time.NewTicker(time.Hour)
	go retire(ticker)
}

// retire retires old connections
func retire(t *time.Ticker) {
	for range t.C {
		now := time.Now()
		var old []string
		mut.RLock()
		for k, v := range conn {
			if now.Sub(v.used) >= period {
				old = append(old, k)
			}
		}
		mut.RUnlock()
		mut.Lock()
		for _, c := range old {
			conn[c].s.Close()
			delete(conn, c)
		}
		mut.Unlock()
	}
}
<|endoftext|>


<commit_before>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program 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 Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package serialbee is a Bee that can send & receive data on a serial port.
package serialbee

import (
	"bytes"
	"encoding/binary"
	"io"
	"strings"
	"time"

	"github.com/huin/goserial"

	"github.com/muesli/beehive/bees"
)

// SerialBee is a Bee that can send & receive data on a serial port.
type SerialBee struct {
	bees.Bee

	conn io.ReadWriteCloser

	device   string
	baudrate int
}

// Action triggers the action passed to it.
func (mod *SerialBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}
	text := ""

	switch action.Name {
	case "send":
		action.Options.Bind("text", &text)

		bufOut := new(bytes.Buffer)
		err := binary.Write(bufOut, binary.LittleEndian, []byte(text))
		if err != nil {
			panic(err)
		}

		_, err = mod.conn.Write(bufOut.Bytes())
		if err != nil {
			panic(err)
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

// Run executes the Bee's event loop.
func (mod *SerialBee) Run(eventChan chan bees.Event) {
	if mod.baudrate == 0 || mod.device == "" {
		return
	}

	var err error
	c := &goserial.Config{Name: mod.device, Baud: mod.baudrate}
	mod.conn, err = goserial.OpenPort(c)
	if err != nil {
		mod.LogFatal(err)
	}
	time.Sleep(1 * time.Second)

	for {
		//FIXME: don't block
		select {
		case <-mod.SigChan:
			return

		default:
		}

		text := ""
		c := []byte{0}
		for {
			_, err := mod.conn.Read(c)
			if err != nil {
				time.Sleep(1 * time.Second)
				continue
			}
			if c[0] == 10 || c[0] == 13 {
				break
			}

			text += string(c[0])
		}

		if len(text) > 0 {
			text = strings.TrimSpace(text)

			ev := bees.Event{
				Bee:  mod.Name(),
				Name: "message",
				Options: []bees.Placeholder{
					{
						Name:  "port",
						Type:  "string",
						Value: mod.device,
					},
					{
						Name:  "text",
						Type:  "string",
						Value: text,
					},
				},
			}
			eventChan <- ev
		}
		time.Sleep(1 * time.Second)
	}
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *SerialBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("device", &mod.device)
	options.Bind("baudrate", &mod.baudrate)
}
<commit_msg>Don't block in SerialBee so it can be gracefully stopped<commit_after>/*
 *    Copyright (C) 2014-2017 Christian Muehlhaeuser
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program 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 Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors:
 *      Christian Muehlhaeuser <muesli@gmail.com>
 */

// Package serialbee is a Bee that can send & receive data on a serial port.
package serialbee

import (
	"bytes"
	"encoding/binary"
	"io"

	"github.com/huin/goserial"

	"github.com/muesli/beehive/bees"
)

// SerialBee is a Bee that can send & receive data on a serial port.
type SerialBee struct {
	bees.Bee

	conn io.ReadWriteCloser

	device   string
	baudrate int
}

// Action triggers the action passed to it.
func (mod *SerialBee) Action(action bees.Action) []bees.Placeholder {
	outs := []bees.Placeholder{}
	text := ""

	switch action.Name {
	case "send":
		action.Options.Bind("text", &text)

		bufOut := new(bytes.Buffer)
		err := binary.Write(bufOut, binary.LittleEndian, []byte(text))
		if err != nil {
			panic(err)
		}

		_, err = mod.conn.Write(bufOut.Bytes())
		if err != nil {
			panic(err)
		}

	default:
		panic("Unknown action triggered in " + mod.Name() + ": " + action.Name)
	}

	return outs
}

func (mod *SerialBee) handleEvents(eventChan chan bees.Event) error {
	text := ""
	c := []byte{0}
	for {
		_, err := mod.conn.Read(c)
		if err != nil {
			return err
		}
		if c[0] == 10 || c[0] == 13 {
			break
		}

		text += string(c[0])
	}

	if len(text) > 0 {
		ev := bees.Event{
			Bee:  mod.Name(),
			Name: "message",
			Options: []bees.Placeholder{
				{
					Name:  "port",
					Type:  "string",
					Value: mod.device,
				},
				{
					Name:  "text",
					Type:  "string",
					Value: text,
				},
			},
		}
		eventChan <- ev
	}

	return nil
}

// Run executes the Bee's event loop.
func (mod *SerialBee) Run(eventChan chan bees.Event) {
	if mod.baudrate == 0 || mod.device == "" {
		return
	}

	var err error
	c := &goserial.Config{Name: mod.device, Baud: mod.baudrate}
	mod.conn, err = goserial.OpenPort(c)
	if err != nil {
		mod.LogFatal(err)
	}
	defer mod.conn.Close()

	go func() {
		for {
			if err := mod.handleEvents(eventChan); err != nil {
				return
			}
		}
	}()

	select {
	case <-mod.SigChan:
		return
	}
}

// ReloadOptions parses the config options and initializes the Bee.
func (mod *SerialBee) ReloadOptions(options bees.BeeOptions) {
	mod.SetOptions(options)

	options.Bind("device", &mod.device)
	options.Bind("baudrate", &mod.baudrate)
}
<|endoftext|>


<commit_before>package digitalocean

import (
	"fmt"
	"log"
	"time"

	"github.com/digitalocean/godo"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDigitalOceanFloatingIp() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanFloatingIpCreate,
		Update: resourceDigitalOceanFloatingIpUpdate,
		Read:   resourceDigitalOceanFloatingIpRead,
		Delete: resourceDigitalOceanFloatingIpDelete,

		Schema: map[string]*schema.Schema{
			"ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"droplet_id": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Create a FloatingIP In a Region")
	regionOpts := &godo.FloatingIPCreateRequest{
		Region: d.Get("region").(string),
	}

	log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
	floatingIp, _, err := client.FloatingIPs.Create(regionOpts)
	if err != nil {
		return fmt.Errorf("Error creating FloatingIP: %s", err)
	}

	d.SetId(floatingIp.IP)

	if v, ok := d.GetOk("droplet_id"); ok {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
		action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
		if err != nil {
			return fmt.Errorf(
				"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if d.HasChange("droplet_id") {
		if v, ok := d.GetOk("droplet_id"); ok {
			log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int))
			action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
			if err != nil {
				return fmt.Errorf(
					"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
			}
		} else {
			log.Printf("[INFO] Unassigning the Floating IP %s", d.Id())
			action, _, err := client.FloatingIPActions.Unassign(d.Id())
			if err != nil {
				return fmt.Errorf(
					"Error Unassigning FloatingIP (%s): %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Unassigned: %s", d.Id(), unassignedErr)
			}
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
	floatingIp, _, err := client.FloatingIPs.Get(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving FloatingIP: %s", err)
	}

	if floatingIp.Droplet != nil {
		log.Printf("[INFO] A droplet was detected on the FloatingIP so setting the Region based on the Droplet")
		log.Printf("[INFO] The region of the Droplet is %s", floatingIp.Droplet.Region.Slug)
		d.Set("region", floatingIp.Droplet.Region.Slug)
	} else {
		d.Set("region", floatingIp.Region.Slug)
	}

	d.Set("ip_address", floatingIp.IP)

	return nil
}

func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if _, ok := d.GetOk("droplet_id"); ok {
		log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
		action, _, err := client.FloatingIPActions.Unassign(d.Id())
		if err != nil {
			return fmt.Errorf(
				"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be unassigned: %s", d.Id(), unassignedErr)
		}
	}

	log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
	_, err := client.FloatingIPs.Delete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting FloatingIP: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForFloatingIPReady(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, actionId int) (interface{}, error) {
	log.Printf(
		"[INFO] Waiting for FloatingIP (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     []string{target},
		Refresh:    newFloatingIPStateRefreshFunc(d, attribute, meta, actionId),
		Timeout:    60 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,

		NotFoundChecks: 60,
	}

	return stateConf.WaitForState()
}

func newFloatingIPStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}, actionId int) resource.StateRefreshFunc {
	client := meta.(*godo.Client)
	return func() (interface{}, string, error) {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet")
		action, _, err := client.FloatingIPActions.Get(d.Id(), actionId)
		if err != nil {
			return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
		}

		log.Printf("[INFO] The FloatingIP Action Status is %s", action.Status)
		return &action, action.Status, nil
	}
}
<commit_msg>provider/digitalocean: Reassign Floating IP when droplet changes (#7411)<commit_after>package digitalocean

import (
	"fmt"
	"log"
	"time"

	"github.com/digitalocean/godo"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceDigitalOceanFloatingIp() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanFloatingIpCreate,
		Update: resourceDigitalOceanFloatingIpUpdate,
		Read:   resourceDigitalOceanFloatingIpRead,
		Delete: resourceDigitalOceanFloatingIpDelete,

		Schema: map[string]*schema.Schema{
			"ip_address": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"droplet_id": &schema.Schema{
				Type:     schema.TypeInt,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanFloatingIpCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Create a FloatingIP In a Region")
	regionOpts := &godo.FloatingIPCreateRequest{
		Region: d.Get("region").(string),
	}

	log.Printf("[DEBUG] FloatingIP Create: %#v", regionOpts)
	floatingIp, _, err := client.FloatingIPs.Create(regionOpts)
	if err != nil {
		return fmt.Errorf("Error creating FloatingIP: %s", err)
	}

	d.SetId(floatingIp.IP)

	if v, ok := d.GetOk("droplet_id"); ok {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet %d", v.(int))
		action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
		if err != nil {
			return fmt.Errorf(
				"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if d.HasChange("droplet_id") {
		if v, ok := d.GetOk("droplet_id"); ok {
			log.Printf("[INFO] Assigning the Floating IP %s to the Droplet %d", d.Id(), v.(int))
			action, _, err := client.FloatingIPActions.Assign(d.Id(), v.(int))
			if err != nil {
				return fmt.Errorf(
					"Error Assigning FloatingIP (%s) to the droplet: %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Assigned: %s", d.Id(), unassignedErr)
			}
		} else {
			log.Printf("[INFO] Unassigning the Floating IP %s", d.Id())
			action, _, err := client.FloatingIPActions.Unassign(d.Id())
			if err != nil {
				return fmt.Errorf(
					"Error Unassigning FloatingIP (%s): %s", d.Id(), err)
			}

			_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
			if unassignedErr != nil {
				return fmt.Errorf(
					"Error waiting for FloatingIP (%s) to be Unassigned: %s", d.Id(), unassignedErr)
			}
		}
	}

	return resourceDigitalOceanFloatingIpRead(d, meta)
}

func resourceDigitalOceanFloatingIpRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	log.Printf("[INFO] Reading the details of the FloatingIP %s", d.Id())
	floatingIp, _, err := client.FloatingIPs.Get(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving FloatingIP: %s", err)
	}

	if floatingIp.Droplet != nil {
		log.Printf("[INFO] A droplet was detected on the FloatingIP so setting the Region based on the Droplet")
		log.Printf("[INFO] The region of the Droplet is %s", floatingIp.Droplet.Region.Slug)
		d.Set("region", floatingIp.Droplet.Region.Slug)
		d.Set("droplet_id", floatingIp.Droplet.ID)

	} else {
		d.Set("region", floatingIp.Region.Slug)
	}

	d.Set("ip_address", floatingIp.IP)

	return nil
}

func resourceDigitalOceanFloatingIpDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*godo.Client)

	if _, ok := d.GetOk("droplet_id"); ok {
		log.Printf("[INFO] Unassigning the Floating IP from the Droplet")
		action, _, err := client.FloatingIPActions.Unassign(d.Id())
		if err != nil {
			return fmt.Errorf(
				"Error Unassigning FloatingIP (%s) from the droplet: %s", d.Id(), err)
		}

		_, unassignedErr := waitForFloatingIPReady(d, "completed", []string{"new", "in-progress"}, "status", meta, action.ID)
		if unassignedErr != nil {
			return fmt.Errorf(
				"Error waiting for FloatingIP (%s) to be unassigned: %s", d.Id(), unassignedErr)
		}
	}

	log.Printf("[INFO] Deleting FloatingIP: %s", d.Id())
	_, err := client.FloatingIPs.Delete(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting FloatingIP: %s", err)
	}

	d.SetId("")
	return nil
}

func waitForFloatingIPReady(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}, actionId int) (interface{}, error) {
	log.Printf(
		"[INFO] Waiting for FloatingIP (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     []string{target},
		Refresh:    newFloatingIPStateRefreshFunc(d, attribute, meta, actionId),
		Timeout:    60 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,

		NotFoundChecks: 60,
	}

	return stateConf.WaitForState()
}

func newFloatingIPStateRefreshFunc(
	d *schema.ResourceData, attribute string, meta interface{}, actionId int) resource.StateRefreshFunc {
	client := meta.(*godo.Client)
	return func() (interface{}, string, error) {

		log.Printf("[INFO] Assigning the Floating IP to the Droplet")
		action, _, err := client.FloatingIPActions.Get(d.Id(), actionId)
		if err != nil {
			return nil, "", fmt.Errorf("Error retrieving FloatingIP (%s) ActionId (%d): %s", d.Id(), actionId, err)
		}

		log.Printf("[INFO] The FloatingIP Action Status is %s", action.Status)
		return &action, action.Status, nil
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/lib/pq"
)

func importJSON(c *cli.Context) {
	cli.CommandHelpTemplate = strings.Replace(cli.CommandHelpTemplate, "[arguments...]", "<json-file>", -1)

	filename := c.Args().First()
	if filename == "" {
		cli.ShowCommandHelp(c, "json")
		os.Exit(1)
	}

	schema := c.GlobalString("schema")
	tableName := parseTableName(c, filename)

	db, err := connect(parseConnStr(c), schema)
	failOnError(err, "Could not connect to db")
	defer db.Close()

	columns := []string{"data"}
	createTable, err := createJSONTable(db, schema, tableName, columns[0])
	failOnError(err, "Could not create table statement")

	_, err = createTable.Exec()
	failOnError(err, "Could not create table")

	txn, err := db.Begin()
	failOnError(err, "Could not start transaction")

	stmt, err := txn.Prepare(pq.CopyInSchema(schema, tableName, columns...))
	failOnError(err, "Could not prepare copy in statement")

	file, err := os.Open(filename)
	failOnError(err, "Cannot open file")
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		var record map[string]interface{}
		value := scanner.Text()
		err := json.Unmarshal([]byte(value), &record)

		if err != nil {
			if c.GlobalBool("ignore-errors") {
				os.Stderr.WriteString(value)
			} else {
				msg := fmt.Sprintf("Invalid JSON: %s", value)
				log.Fatalln(msg)
				panic(msg)
			}
		} else {
			row, err := json.Marshal(record)
			failOnError(err, "Can not deserialize")

			_, err = stmt.Exec(row)
			failOnError(err, "Could add bulk insert")
		}
	}
	failOnError(scanner.Err(), "Could not parse")

	_, err = stmt.Exec()
	failOnError(err, "Could not exec the bulk copy")

	err = stmt.Close()
	failOnError(err, "Could not close")

	err = txn.Commit()
	failOnError(err, "Could not commit transaction")
}
<commit_msg>json import now uses JSONB goodness<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/codegangsta/cli"
	_ "github.com/jmoiron/sqlx/types"
	"github.com/lib/pq"
)

func isValidJSON(b []byte) bool {
	var v interface{}
	err := json.Unmarshal(b, &v)
	return err == nil
}

func importJSON(c *cli.Context) {
	cli.CommandHelpTemplate = strings.Replace(cli.CommandHelpTemplate, "[arguments...]", "<json-file>", -1)

	filename := c.Args().First()
	if filename == "" {
		cli.ShowCommandHelp(c, "json")
		os.Exit(1)
	}

	schema := c.GlobalString("schema")
	tableName := parseTableName(c, filename)

	db, err := connect(parseConnStr(c), schema)
	failOnError(err, "Could not connect to db")
	defer db.Close()

	columns := []string{"data"}
	createTable, err := createJSONTable(db, schema, tableName, columns[0])
	failOnError(err, "Could not create table statement")

	_, err = createTable.Exec()
	failOnError(err, "Could not create table")

	txn, err := db.Begin()
	failOnError(err, "Could not start transaction")

	stmt, err := txn.Prepare(pq.CopyInSchema(schema, tableName, columns...))
	failOnError(err, "Could not prepare copy in statement")

	file, err := os.Open(filename)
	failOnError(err, "Cannot open file")
	defer file.Close()

	reader := bufio.NewReader(file)
	for {
		line, err := reader.ReadBytes('\n')

		if err == io.EOF {
			err = nil
			break
		}
		failOnError(err, "Could not read line")

		handleError := func() {
			if c.GlobalBool("ignore-errors") {
				os.Stderr.WriteString(string(line))
			} else {
				msg := fmt.Sprintf("Invalid JSON %s: %s", err, line)
				log.Fatalln(msg)
				panic(msg)
			}
		}

		if !isValidJSON(line) {
			handleError()
		}

		_, err = stmt.Exec(string(line))
		if err != nil {
			handleError()
		}

		failOnError(err, "Could add bulk insert")
	}

	_, err = stmt.Exec()
	failOnError(err, "Could not exec the bulk copy")

	err = stmt.Close()
	failOnError(err, "Could not close")

	err = txn.Commit()
	failOnError(err, "Could not commit transaction")
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	log "github.com/couchbase/clog"
	"github.com/couchbaselabs/cbgt"
)

func MainUUID(baseName, dataDir string) (string, error) {
	uuid := cbgt.NewUUID()
	uuidPath := dataDir + string(os.PathSeparator) + baseName + ".uuid"
	uuidBuf, err := ioutil.ReadFile(uuidPath)
	if err == nil {
		uuid = strings.TrimSpace(string(uuidBuf))
		if uuid == "" {
			return "", fmt.Errorf("error: could not parse uuidPath: %s",
				uuidPath)
		}
		log.Printf("main: manager uuid: %s", uuid)
		log.Printf("main: manager uuid was reloaded")
	} else {
		log.Printf("main: manager uuid: %s", uuid)
		log.Printf("main: manager uuid was generated")
	}
	err = ioutil.WriteFile(uuidPath, []byte(uuid), 0600)
	if err != nil {
		return "", fmt.Errorf("error: could not write uuidPath: %s\n"+
			"  Please check that your -data/-dataDir parameter (%q)\n"+
			"  is to a writable directory where %s can store\n"+
			"  index data.",
			uuidPath, dataDir, baseName)
	}
	return uuid, nil
}
<commit_msg>doc comment for cmd.MainUUID<commit_after>//  Copyright (c) 2015 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package cmd

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	log "github.com/couchbase/clog"
	"github.com/couchbaselabs/cbgt"
)

// MainUUID is a helper function for cmd-line tool developers, that
// reuses a previous "baseName.idd" file from the dataDir if it
// exists, or generates a brand new UUID (and persists it).
func MainUUID(baseName, dataDir string) (string, error) {
	uuid := cbgt.NewUUID()
	uuidPath := dataDir + string(os.PathSeparator) + baseName + ".uuid"
	uuidBuf, err := ioutil.ReadFile(uuidPath)
	if err == nil {
		uuid = strings.TrimSpace(string(uuidBuf))
		if uuid == "" {
			return "", fmt.Errorf("error: could not parse uuidPath: %s",
				uuidPath)
		}
		log.Printf("main: manager uuid: %s", uuid)
		log.Printf("main: manager uuid was reloaded")
	} else {
		log.Printf("main: manager uuid: %s", uuid)
		log.Printf("main: manager uuid was generated")
	}
	err = ioutil.WriteFile(uuidPath, []byte(uuid), 0600)
	if err != nil {
		return "", fmt.Errorf("error: could not write uuidPath: %s\n"+
			"  Please check that your -data/-dataDir parameter (%q)\n"+
			"  is to a writable directory where %s can store\n"+
			"  index data.",
			uuidPath, dataDir, baseName)
	}
	return uuid, nil
}
<|endoftext|>


<commit_before>// Package main has two sides:
// - User mode: shell
// - tool mode: unix socket server for handling namespace operations
// When started, the program choses their side based on the argv[0].
// The name "rc" indicates a user shell and the name -nrc- indicates
// the namespace server tool.
package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/NeowayLabs/nash"
)

var (
	// version is set at build time
	VersionString = "No version provided"

	version bool
	debug   bool
	file    string
	addr    string
)

func init() {
	flag.BoolVar(&version, "version", false, "Show version")
	flag.BoolVar(&debug, "debug", false, "enable debug")
	flag.StringVar(&file, "file", "", "script file")

	if os.Args[0] == "-nashd-" || (len(os.Args) > 1 && os.Args[1] == "-daemon") {
		flag.Bool("daemon", false, "force enable nashd mode")
		flag.StringVar(&addr, "addr", "", "rcd unix file")
	}
}

func main() {
	var err error

	flag.Parse()

	if version {
		fmt.Printf("%s\n", VersionString)
		os.Exit(0)
	}

	shell := nash.NewShell(debug)

	home := os.Getenv("HOME")

	if home != "" {
		initFile := home + "/.nash/init"

		if _, err := os.Stat(initFile); err == nil {
			fmt.Printf("Here: %s\n", err.Error())

			err = shell.Execute(initFile)

			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed to evaluate '%s': %s\n", initFile, err.Error())
				os.Exit(1)
			}
		}
	}

	if addr != "" {
		startNashd(shell, addr)
	} else if file == "" {
		err = cli(shell)
	} else {
		err = shell.Execute(file)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}
<commit_msg>Fix init bug<commit_after>// Package main has two sides:
// - User mode: shell
// - tool mode: unix socket server for handling namespace operations
// When started, the program choses their side based on the argv[0].
// The name "rc" indicates a user shell and the name -nrc- indicates
// the namespace server tool.
package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/NeowayLabs/nash"
)

var (
	// version is set at build time
	VersionString = "No version provided"

	version bool
	debug   bool
	file    string
	addr    string
)

func init() {
	flag.BoolVar(&version, "version", false, "Show version")
	flag.BoolVar(&debug, "debug", false, "enable debug")
	flag.StringVar(&file, "file", "", "script file")

	if os.Args[0] == "-nashd-" || (len(os.Args) > 1 && os.Args[1] == "-daemon") {
		flag.Bool("daemon", false, "force enable nashd mode")
		flag.StringVar(&addr, "addr", "", "rcd unix file")
	}
}

func main() {
	flag.Parse()

	if version {
		fmt.Printf("%s\n", VersionString)
		os.Exit(0)
	}

	shell := nash.NewShell(debug)

	home := os.Getenv("HOME")

	if home != "" {
		initFile := home + "/.nash/init"

		if _, err := os.Stat(initFile); err == nil {
			fmt.Printf("Here: %s\n", err.Error())

			err = shell.Execute(initFile)

			if err != nil {
				fmt.Fprintf(os.Stderr, "Failed to evaluate '%s': %s\n", initFile, err.Error())
				os.Exit(1)
			}
		}
	}

	var err error

	if addr != "" {
		startNashd(shell, addr)
	} else if file == "" {
		err = cli(shell)
	} else {
		err = shell.Execute(file)
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package tvdb_test

import (
	"testing"

	"github.com/danesparza/tvdb"
)

func TestTVDB_Login_ReturnsToken(t *testing.T) {
	//	Arrange
	request := tvdb.AuthRequest{}

	//	Act
	client := tvdb.Client{}
	response, err := client.Login(request)

	//	Assert
	if err != nil {
		t.Errorf("Error logging in: %v", err)
	}

	if response.Token == "" {
		t.Errorf("The token is blank, and shouldn't be")
	} else {
		t.Logf("Got a token back: %v", response.Token)
	}
}

func TestTVDB_SeriesSearch_ReturnsInformation(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesSearchRequest{
		Name: "Looney Tunes"}

	//	Act
	client := tvdb.Client{}
	matches, err := client.SeriesSearch(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(matches) == 0 {
		t.Errorf("There are no matches")
	}

	if matches[0].ID != 72514 {
		t.Errorf("Didn't get the series ID back that we expected")
	}
}

func TestTVDB_EpisodesForSeries_ReturnsInformation(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 72514}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) == 0 {
		t.Errorf("There are no responses")
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	if response[0].ID != 5657563 {
		t.Errorf("Didn't get the episode ID back that we expected")
	}
}

func TestTVDB_EpisodesForSeries_ReturnsExpectedCount(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 78874}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) != 18 {
		t.Errorf("18 episodes expected, but got %v instead", len(response))
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	if response[0].ID != 297989 {
		t.Errorf("Didn't get the episode ID back that we expected, but got %v instead", response[0].ID)
	}
}

func TestTVDB_EpisodesForSeries_CanMap(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 72514}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) == 0 {
		t.Errorf("Didn't get any episodes")
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	//	Load up the map
	episodes := make(map[string]tvdb.BasicEpisode)
	for _, episode := range response {
		episodes[episode.EpisodeName] = episode
	}

	t.Logf("Created a map with %v items in it", len(episodes))

	//	Check to see if the episode name exists
	//	and then get its season/episode number:
	episodeToFind := "Upswept Hare"
	if episode, ok := episodes[episodeToFind]; ok {
		if episode.AiredSeason != 1953 || episode.AiredEpisodeNumber != 7 {
			t.Errorf("The episode and season don't match what we expect. Expected s1953e7 - Found: s%ve%v", episode.AiredSeason, episode.AiredEpisodeNumber)
		}
	} else {
		t.Errorf("Didn't find the episode '%v'", episodeToFind)
	}
}
<commit_msg>Updated tests<commit_after>package tvdb_test

import (
	"testing"

	"github.com/danesparza/tvdb"
)

func TestTVDB_Login_ReturnsToken(t *testing.T) {
	//	Arrange
	request := tvdb.AuthRequest{}

	//	Act
	client := tvdb.Client{}
	response, err := client.Login(request)

	//	Assert
	if err != nil {
		t.Errorf("Error logging in: %v", err)
	}

	if response.Token == "" {
		t.Errorf("The token is blank, and shouldn't be")
	} else {
		t.Logf("Got a token back: %v", response.Token)
	}
}

func TestTVDB_SeriesSearch_ReturnsInformation(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesSearchRequest{
		Name: "Looney Tunes"}

	//	Act
	client := tvdb.Client{}
	responses, err := client.SeriesSearch(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(responses) == 0 {
		t.Errorf("There are no matches")
	}

	if responses[0].ID != 72514 {
		t.Errorf("Didn't get the series ID back that we expected")
	}

	//	Loop through the responses:
	for _, response := range responses {
		t.Logf("Series name: %v", response.SeriesName)
	}
}

func TestTVDB_EpisodesForSeries_ReturnsInformation(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 72514}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) == 0 {
		t.Errorf("There are no responses")
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	if response[0].ID != 5657563 {
		t.Errorf("Didn't get the episode ID back that we expected")
	}
}

func TestTVDB_EpisodesForSeries_ReturnsExpectedCount(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 78874}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) != 18 {
		t.Errorf("18 episodes expected, but got %v instead", len(response))
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	if response[0].ID != 297989 {
		t.Errorf("Didn't get the episode ID back that we expected, but got %v instead", response[0].ID)
	}
}

func TestTVDB_EpisodesForSeries_CanMap(t *testing.T) {
	//	Arrange
	request := tvdb.SeriesEpisodesRequest{
		SeriesID: 72514}

	//	Act
	client := tvdb.Client{}
	response, err := client.EpisodesForSeries(request)

	//	Assert
	if err != nil {
		t.Errorf("Error getting search results: %v", err)
	}

	if len(response) == 0 {
		t.Errorf("Didn't get any episodes")
	} else {
		t.Logf("Got %v episodes back", len(response))
	}

	//	Load up the map
	episodes := make(map[string]tvdb.BasicEpisode)
	for _, episode := range response {
		episodes[episode.EpisodeName] = episode
	}

	t.Logf("Created a map with %v items in it", len(episodes))

	//	Check to see if the episode name exists
	//	and then get its season/episode number:
	episodeToFind := "Upswept Hare"
	if episode, ok := episodes[episodeToFind]; ok {
		if episode.AiredSeason != 1953 || episode.AiredEpisodeNumber != 7 {
			t.Errorf("The episode and season don't match what we expect. Expected s1953e7 - Found: s%ve%v", episode.AiredSeason, episode.AiredEpisodeNumber)
		}
	} else {
		t.Errorf("Didn't find the episode '%v'", episodeToFind)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"time"

	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	"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"

	// register providers
	_ "launchpad.net/juju-core/environs/ec2"
)

var retryDuration = 3 * time.Second

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	tomb        tomb.Tomb
	Conf        AgentConf
	provisioner *provisioner.Provisioner
	firewaller  *firewaller.Firewaller
}

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

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// Stop stops the provisionig agent by stopping the provisioner
// and the firewaller.
func (a *ProvisioningAgent) Stop() error {
	a.tomb.Kill(nil)
	return a.tomb.Wait()
}

// Run run a provisioning agent with a provisioner and a firewaller.
// If either fails, both will be shutdown and restarted.
func (a *ProvisioningAgent) Run(_ *cmd.Context) (err error) {
	defer a.tomb.Done()
	for {
		err = a.runOnce()
		if a.tomb.Err() != tomb.ErrStillAlive {
			// Stop requested by user.
			return err
		}
		time.Sleep(retryDuration)
		log.Printf("restarting provisioner and firewaller after error: %v", err)
	}
	panic("unreachable")
}

// runOnce runs a provisioner and firewaller once.
func (a *ProvisioningAgent) runOnce() (stoperr error) {
	st, err := state.Open(&a.Conf.StateInfo)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: opened state")
	defer func() {
		if e := st.Close(); err != nil {
			err = e
		}
		log.Debugf("provisioning: closed state")
	}()

	a.provisioner, err = provisioner.NewProvisioner(st)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: started provisioner")
	defer func() {
		if e := a.provisioner.Stop(); err != nil {
			err = e
		}
		log.Debugf("provisioning: stopped provisioner")
	}()

	a.firewaller, err = firewaller.NewFirewaller(st)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: started firewaller")
	defer func() {
		if e := a.firewaller.Stop(); err != nil {
			err = e
		}
		log.Debugf("provisioning: stopped firewaller")
	}()

	select {
	case <-a.tomb.Dying():
	case <-a.provisioner.Dying():
	case <-a.firewaller.Dying():
	}

	return
}
<commit_msg>cmd/jujud/provisioner: don't ignore error<commit_after>package main

import (
	"time"

	"launchpad.net/gnuflag"
	"launchpad.net/juju-core/cmd"
	"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"

	// register providers
	_ "launchpad.net/juju-core/environs/ec2"
)

var retryDuration = 3 * time.Second

// ProvisioningAgent is a cmd.Command responsible for running a provisioning agent.
type ProvisioningAgent struct {
	tomb        tomb.Tomb
	Conf        AgentConf
	provisioner *provisioner.Provisioner
	firewaller  *firewaller.Firewaller
}

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

// Init initializes the command for running.
func (a *ProvisioningAgent) Init(f *gnuflag.FlagSet, args []string) error {
	a.Conf.addFlags(f)
	if err := f.Parse(true, args); err != nil {
		return err
	}
	return a.Conf.checkArgs(f.Args())
}

// Stop stops the provisionig agent by stopping the provisioner
// and the firewaller.
func (a *ProvisioningAgent) Stop() error {
	a.tomb.Kill(nil)
	return a.tomb.Wait()
}

// Run run a provisioning agent with a provisioner and a firewaller.
// If either fails, both will be shutdown and restarted.
func (a *ProvisioningAgent) Run(_ *cmd.Context) (err error) {
	defer a.tomb.Done()
	for {
		err = a.runOnce()
		if a.tomb.Err() != tomb.ErrStillAlive {
			// Stop requested by user.
			return err
		}
		time.Sleep(retryDuration)
		log.Printf("restarting provisioner and firewaller after error: %v", err)
	}
	panic("unreachable")
}

// runOnce runs a provisioner and firewaller once.
func (a *ProvisioningAgent) runOnce() (stoperr error) {
	st, err := state.Open(&a.Conf.StateInfo)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: opened state")
	defer func() {
		if e := st.Close(); err != nil {
			stoperr = e
		}
		log.Debugf("provisioning: closed state")
	}()

	a.provisioner, err = provisioner.NewProvisioner(st)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: started provisioner")
	defer func() {
		if e := a.provisioner.Stop(); err != nil {
			stoperr = e
		}
		log.Debugf("provisioning: stopped provisioner")
	}()

	a.firewaller, err = firewaller.NewFirewaller(st)
	if err != nil {
		return err
	}
	log.Debugf("provisioning: started firewaller")
	defer func() {
		if e := a.firewaller.Stop(); err != nil {
			stoperr = e
		}
		log.Debugf("provisioning: stopped firewaller")
	}()

	select {
	case <-a.tomb.Dying():
	case <-a.provisioner.Dying():
	case <-a.firewaller.Dying():
	}

	return
}
<|endoftext|>


<commit_before>// 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 mac_test

import (
	"fmt"
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/google/tink/go/core/registry"
	"github.com/google/tink/go/mac"
	"github.com/google/tink/go/testutil"
	cmacpb "github.com/google/tink/go/proto/aes_cmac_go_proto"
	commonpb "github.com/google/tink/go/proto/common_go_proto"
	hmacpb "github.com/google/tink/go/proto/hmac_go_proto"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

func TestTemplates(t *testing.T) {
	template := mac.HMACSHA256Tag128KeyTemplate()
	if err := checkHMACTemplate(template, 32, 16, commonpb.HashType_SHA256); err != nil {
		t.Errorf("incorrect HMACSHA256Tag128KeyTemplate: %s", err)
	}
	template = mac.HMACSHA256Tag256KeyTemplate()
	if err := checkHMACTemplate(template, 32, 32, commonpb.HashType_SHA256); err != nil {
		t.Errorf("incorrect HMACSHA256Tag256KeyTemplate: %s", err)
	}
	template = mac.HMACSHA512Tag256KeyTemplate()
	if err := checkHMACTemplate(template, 64, 32, commonpb.HashType_SHA512); err != nil {
		t.Errorf("incorrect HMACSHA512Tag256KeyTemplate: %s", err)
	}
	template = mac.HMACSHA512Tag512KeyTemplate()
	if err := checkHMACTemplate(template, 64, 64, commonpb.HashType_SHA512); err != nil {
		t.Errorf("incorrect HMACSHA512Tag512KeyTemplate: %s", err)
	}
	template = mac.AESCMACTag128KeyTemplate()
	if err := checkCMACTemplate(template, 32, 16); err != nil {
		t.Errorf("incorrect AESCMACTag128KeyTemplate: %s", err)
	}
}

func checkHMACTemplate(template *tinkpb.KeyTemplate,
	keySize uint32,
	tagSize uint32,
	hashType commonpb.HashType) error {
	if template.TypeUrl != testutil.HMACTypeURL {
		return fmt.Errorf("TypeUrl is incorrect")
	}
	if template.OutputPrefixType != tinkpb.OutputPrefixType_TINK {
		return fmt.Errorf("OutputPrefixType is incorrect")
	}
	format := new(hmacpb.HmacKeyFormat)
	if err := proto.Unmarshal(template.Value, format); err != nil {
		return fmt.Errorf("unable to unmarshal serialized key format")
	}
	if format.KeySize != keySize ||
		format.Params.Hash != hashType ||
		format.Params.TagSize != tagSize {
		return fmt.Errorf("KeyFormat is incorrect")
	}
	keymanager, err := registry.GetKeyManager(testutil.HMACTypeURL)
	if err != nil {
		return fmt.Errorf("Could not obtain HMAC key manager: %v", err)
	}
	_, err = keymanager.NewKey(template.Value)
	if err != nil {
		return fmt.Errorf("HMAC key manager cannot create key: %v", err)
	}
	return nil
}

func checkCMACTemplate(template *tinkpb.KeyTemplate, keySize uint32, tagSize uint32) error {
	if template.TypeUrl != testutil.AESCMACTypeURL {
		return fmt.Errorf("TypeUrl is incorrect")
	}
	format := new(cmacpb.AesCmacKeyFormat)
	if err := proto.Unmarshal(template.Value, format); err != nil {
		return fmt.Errorf("unable to unmarshal serialized key format")
	}
	if format.KeySize != keySize ||
		format.Params.TagSize != tagSize {
		return fmt.Errorf("KeyFormat is incorrect")
	}
	keymanager, err := registry.GetKeyManager(testutil.AESCMACTypeURL)
	if err != nil {
		return fmt.Errorf("Could not obtain AES CMAC key manager: %v", err)
	}
	_, err = keymanager.NewKey(template.Value)
	if err != nil {
		return fmt.Errorf("AES CMAC key manager cannot create key: %v", err)
	}
	return nil
}
<commit_msg>Use testdata to test MAC KeyTemplates in Go.<commit_after>// 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 mac_test

import (
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/google/tink/go/keyset"
	"github.com/google/tink/go/mac"
	"github.com/google/tink/go/testutil"
	tinkpb "github.com/google/tink/go/proto/tink_go_proto"
)

func TestKeyTemplates(t *testing.T) {
	var testCases = []struct {
		name     string
		template *tinkpb.KeyTemplate
	}{
		{name: "HMAC_SHA256_128BITTAG",
			template: mac.HMACSHA256Tag128KeyTemplate()},
		{name: "HMAC_SHA256_256BITTAG",
			template: mac.HMACSHA256Tag256KeyTemplate()},
		{name: "HMAC_SHA512_256BITTAG",
			template: mac.HMACSHA512Tag256KeyTemplate()},
		{name: "HMAC_SHA512_512BITTAG",
			template: mac.HMACSHA512Tag512KeyTemplate()},
		{name: "AES_CMAC",
			template: mac.AESCMACTag128KeyTemplate()},
	}
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			want, err := testutil.KeyTemplateProto("mac", tc.name)
			if err != nil {
				t.Fatalf("testutil.KeyTemplateProto('mac', tc.name) failed: %s", err)
			}
			if !proto.Equal(want, tc.template) {
				t.Errorf("template %s is not equal to '%s'", tc.name, tc.template)
			}

			handle, err := keyset.NewHandle(tc.template)
			if err != nil {
				t.Fatalf("keyset.NewHandle(tc.template) failed: %v", err)
			}
			primitive, err := mac.New(handle)
			if err != nil {
				t.Fatalf("mac.New(handle) failed: %v", err)
			}

			msg := []byte("this data needs to be authenticated")
			tag, err := primitive.ComputeMAC(msg)
			if err != nil {
				t.Fatalf("primitive.ComputeMAC(msg) failed: %v", err)
			}
			if primitive.VerifyMAC(tag, msg); err != nil {
				t.Errorf("primitive.VerifyMAC(tag, msg) failed: %v", err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package english

import (
	"github.com/kljensen/snowball/snowballword"
)

// Step 1a is noralization of various special "s"-endings.
//
func step1a(w *snowballword.SnowballWord) bool {

	suffix, suffixRunes := w.FirstSuffix("sses", "ied", "ies", "us", "ss", "s")
	switch suffix {

	case "sses":

		// Replace by ss
		w.ReplaceSuffixRunes(suffixRunes, []rune("ss"), true)
		return true

	case "ies", "ied":

		// Replace by i if preceded by more than one letter,
		// otherwise by ie (so ties -> tie, cries -> cri).

		var repl string
		if len(w.RS) > 4 {
			repl = "i"
		} else {
			repl = "ie"
		}
		w.ReplaceSuffixRunes(suffixRunes, []rune(repl), true)
		return true

	case "us", "ss":

		// Do nothing
		return false

	case "s":

		// Delete if the preceding word part contains a vowel
		// not immediately before the s (so gas and this retain
		// the s, gaps and kiwis lose it)
		//
		for i := 0; i < len(w.RS)-2; i++ {
			if isLowerVowel(w.RS[i]) {
				w.RemoveLastNRunes(len(suffixRunes))
				return true
			}
		}
	}
	return false
}
<commit_msg>fix typo<commit_after>package english

import (
	"github.com/kljensen/snowball/snowballword"
)

// Step 1a is normalization of various special "s"-endings.
//
func step1a(w *snowballword.SnowballWord) bool {

	suffix, suffixRunes := w.FirstSuffix("sses", "ied", "ies", "us", "ss", "s")
	switch suffix {

	case "sses":

		// Replace by ss
		w.ReplaceSuffixRunes(suffixRunes, []rune("ss"), true)
		return true

	case "ies", "ied":

		// Replace by i if preceded by more than one letter,
		// otherwise by ie (so ties -> tie, cries -> cri).

		var repl string
		if len(w.RS) > 4 {
			repl = "i"
		} else {
			repl = "ie"
		}
		w.ReplaceSuffixRunes(suffixRunes, []rune(repl), true)
		return true

	case "us", "ss":

		// Do nothing
		return false

	case "s":

		// Delete if the preceding word part contains a vowel
		// not immediately before the s (so gas and this retain
		// the s, gaps and kiwis lose it)
		//
		for i := 0; i < len(w.RS)-2; i++ {
			if isLowerVowel(w.RS[i]) {
				w.RemoveLastNRunes(len(suffixRunes))
				return true
			}
		}
	}
	return false
}
<|endoftext|>