<commit_before>package experiments

import (
	"time"
	"sort"
	"github.com/yaricom/goNEAT/neat/genetics"
	"io"
	"encoding/gob"
	"fmt"
)

// An Experiment is a collection of trials for one experiment. It's useful for statistical analysis of a series of
// experiments
type Experiment struct {
	Id   int
	Name string
	Trials
}

func (e Experiment) LastExecuted() time.Time {
	var u time.Time
	for _, e := range e.Trials {
		ut := e.LastExecuted()
		if u.Before(ut) {
			u = ut
		}
	}
	return u
}

// Finds the most fit organism among all epochs in this trial. It's also possible to get the best organism only among the ones
// which was able to solve the experiment's problem. Returns the best fit organism in this experiment among with ID of trial
// where it was found and boolean value to indicate if search was successful.
func (e Experiment) BestOrganism(onlySolvers bool) (*genetics.Organism, int, bool) {
	var orgs = make(genetics.Organisms, 0, len(e.Trials))
	for i, t := range e.Trials {
		org, found := t.BestOrganism(onlySolvers)
		if found {
			orgs = append(orgs, org)
			org.Flag = i
		}

	}
	if len(orgs) > 0 {
		sort.Sort(sort.Reverse(orgs))
		return orgs[0], orgs[0].Flag, true
	} else {
		return nil, -1, false
	}

}

func (e Experiment) Solved() bool {
	for _, t := range e.Trials {
		if t.Solved() {
			return true
		}
	}
	return false
}

// The fitness values of the best organisms for each trial
func (e Experiment) BestFitness() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = org.Fitness
		}
	}
	return x
}

// The age values of the organisms for each trial
func (e Experiment) BestAge() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Species.Age)
		}
	}
	return x
}

// The complexity values of the best organisms for each trial
func (e Experiment) BestComplexity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Phenotype.Complexity())
		}
	}
	return x
}

// Diversity returns the average number of species in each trial
func (e Experiment) Diversity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = t.Diversity().Mean()
	}
	return x
}

// Trials returns the number of epochs in each trial
func (e Experiment) Epochs() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = float64(len(t.Generations))
	}
	return x
}

// The number of trials solved
func (e Experiment) TrialsSolved() int {
	count := 0
	for _, t := range e.Trials {
		if t.Solved() {
			count++
		}
	}
	return count
}

// Returns average number of nodes, genes, organisms evaluations, and species diversity of winner genomes among all
// trials, i.e. for all trials where winning solution was found
func (e *Experiment) AvgWinner() (avg_nodes, avg_genes, avg_evals, avg_diversity float64) {
	total_nodes, total_genes, total_evals, total_diversity := 0, 0, 0, 0
	count := 0
	for i := 0; i < len(e.Trials); i++ {
		t := e.Trials[i]
		if t.Solved() {
			nodes, genes, evals, diversity := t.Winner()
			total_nodes += nodes
			total_genes += genes
			total_evals += evals
			total_diversity += diversity

			count++
		}
	}
	avg_nodes = float64(total_nodes) / float64(count)
	avg_genes = float64(total_genes) / float64(count)
	avg_evals = float64(total_evals) / float64(count)
	avg_diversity = float64(total_diversity) / float64(count)
	return avg_nodes, avg_genes, avg_evals, avg_diversity
}

// Prints experiment statistics
func (ex Experiment) PrintStatistics() {
	fmt.Printf("\n+++ Solved %d trials from %d +++\n", ex.TrialsSolved(), len(ex.Trials))
	// Print absolute champion statistics
	if org, trid, found := ex.BestOrganism(true); found {
		nodes, genes, evals, divers := ex.Trials[trid].Winner()
		fmt.Printf("\nChampion found in %d trial run\n\tWinner Nodes:\t%d\n\tWinner Genes:\t%d\n\tWinner Evals:\t%d\n\n\tDiversity:\t%d",
			trid, nodes, genes, evals, divers)
		fmt.Printf("\n\tComplexity:\t%d\n\tAge:\t\t%d\n\tFitness:\t%.1f\n",
			org.Phenotype.Complexity(), org.Species.Age, org.Fitness)
	} else {
		fmt.Println("\nNo winner found in the experiment!!!")
	}

	// Print average winner statistics
	mean_complexity, mean_diversity, mean_age, mean_fitness := 0.0, 0.0, 0.0, 0.0
	if len(ex.Trials) > 1 {
		avg_nodes, avg_genes, avg_evals, avg_divers := 0.0, 0.0, 0.0, 0.0
		count := 0.0
		for i := 0; i < len(ex.Trials); i++ {
			t := ex.Trials[i]
			if t.Solved() {
				nodes, genes, evals, diversity := t.Winner()
				avg_nodes += float64(nodes)
				avg_genes += float64(genes)
				avg_evals += float64(evals)
				avg_divers += float64(diversity)

				mean_complexity += float64(t.WinnerGeneration.Best.Phenotype.Complexity())
				mean_age += float64(t.WinnerGeneration.Best.Species.Age)
				mean_fitness += t.WinnerGeneration.Best.Fitness

				count++
			}
		}
		avg_nodes /= count
		avg_genes /= count
		avg_evals /= count
		avg_divers /= count
		fmt.Printf("\nAverage among winners\n\tWinner Nodes:\t%.1f\n\tWinner Genes:\t%.1f\n\tWinner Evals:\t%.1f\n\n\tDiversity:\t%.1f\n",
			avg_nodes, avg_genes, avg_evals, avg_divers)

		mean_complexity /= count
		mean_age /= count
		mean_fitness /=count
		fmt.Printf("\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n",
			mean_complexity, mean_age, mean_fitness)
	}

	// Print best organisms statistics per epoch per trial, i.e. every the best found
	for _, t := range ex.Trials {
		mean_complexity += t.BestComplexity().Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += t.BestAge().Mean()
		mean_fitness += t.BestFitness().Mean()
	}
	count := float64(len(ex.Trials))
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	mean_fitness /=count
	fmt.Printf("\nAverages of the most fit/best organisms found\n\tDiversity:\t%.1f\n\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n",
		mean_diversity, mean_complexity, mean_age, mean_fitness)

	// Print the average values for each population of organisms evaluated
	for _, t := range ex.Trials {
		fitness, age, complexity := t.Average()

		mean_complexity += complexity.Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += age.Mean()
		mean_fitness += fitness.Mean()
	}
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	mean_fitness /=count
	fmt.Printf("\nAverages for each population of organisms evaluated\n\tDiversity:\t%.1f\n\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n\n",
		mean_diversity, mean_complexity, mean_age, mean_fitness)

}

// Encodes experiment and writes to provided writer
func (ex Experiment) Write(w io.Writer) error {
	enc := gob.NewEncoder(w)
	return ex.Encode(enc)
}

// Encodes experiment with GOB encoding
func (ex Experiment) Encode(enc *gob.Encoder) error {
	err := enc.Encode(ex.Id)
	err = enc.Encode(ex.Name)

	// encode trials
	err = enc.Encode(len(ex.Trials))
	for _, t := range ex.Trials {
		err = t.Encode(enc)
		if err != nil {
			return err
		}
	}
	return err
}

// Reads experiment data from provided reader and decodes it
func (ex *Experiment) Read(r io.Reader) error {
	dec := gob.NewDecoder(r)
	return ex.Decode(dec)
}

// Decodes experiment data
func (ex *Experiment) Decode(dec *gob.Decoder) error {
	err := dec.Decode(&ex.Id)
	err = dec.Decode(&ex.Name)

	// decode Trials
	var t_num int
	err = dec.Decode(&t_num)
	if err != nil {
		return err
	}

	ex.Trials = make([]Trial, t_num)
	for i := 0; i < t_num; i++ {
		trial := Trial{}
		err = trial.Decode(dec)
		ex.Trials[i] = trial
	}
	return err
}

// Experiments is a sortable list of experiments by execution time and Id
type Experiments []Experiment

func (es Experiments) Len() int {
	return len(es)
}
func (es Experiments) Swap(i, j int) {
	es[i], es[j] = es[j], es[i]
}
func (es Experiments) Less(i, j int) bool {
	ui := es[i].LastExecuted()
	uj := es[j].LastExecuted()
	if ui.Equal(uj) {
		return es[i].Id < es[j].Id
	}
	return ui.Before(uj)
}<commit_msg>Removed uninformative statistics output.<commit_after>package experiments

import (
	"time"
	"sort"
	"github.com/yaricom/goNEAT/neat/genetics"
	"io"
	"encoding/gob"
	"fmt"
)

// An Experiment is a collection of trials for one experiment. It's useful for statistical analysis of a series of
// experiments
type Experiment struct {
	Id   int
	Name string
	Trials
}

func (e Experiment) LastExecuted() time.Time {
	var u time.Time
	for _, e := range e.Trials {
		ut := e.LastExecuted()
		if u.Before(ut) {
			u = ut
		}
	}
	return u
}

// Finds the most fit organism among all epochs in this trial. It's also possible to get the best organism only among the ones
// which was able to solve the experiment's problem. Returns the best fit organism in this experiment among with ID of trial
// where it was found and boolean value to indicate if search was successful.
func (e Experiment) BestOrganism(onlySolvers bool) (*genetics.Organism, int, bool) {
	var orgs = make(genetics.Organisms, 0, len(e.Trials))
	for i, t := range e.Trials {
		org, found := t.BestOrganism(onlySolvers)
		if found {
			orgs = append(orgs, org)
			org.Flag = i
		}

	}
	if len(orgs) > 0 {
		sort.Sort(sort.Reverse(orgs))
		return orgs[0], orgs[0].Flag, true
	} else {
		return nil, -1, false
	}

}

func (e Experiment) Solved() bool {
	for _, t := range e.Trials {
		if t.Solved() {
			return true
		}
	}
	return false
}

// The fitness values of the best organisms for each trial
func (e Experiment) BestFitness() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = org.Fitness
		}
	}
	return x
}

// The age values of the organisms for each trial
func (e Experiment) BestAge() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Species.Age)
		}
	}
	return x
}

// The complexity values of the best organisms for each trial
func (e Experiment) BestComplexity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Phenotype.Complexity())
		}
	}
	return x
}

// Diversity returns the average number of species in each trial
func (e Experiment) Diversity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = t.Diversity().Mean()
	}
	return x
}

// Trials returns the number of epochs in each trial
func (e Experiment) Epochs() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = float64(len(t.Generations))
	}
	return x
}

// The number of trials solved
func (e Experiment) TrialsSolved() int {
	count := 0
	for _, t := range e.Trials {
		if t.Solved() {
			count++
		}
	}
	return count
}

// Returns average number of nodes, genes, organisms evaluations, and species diversity of winner genomes among all
// trials, i.e. for all trials where winning solution was found
func (e *Experiment) AvgWinner() (avg_nodes, avg_genes, avg_evals, avg_diversity float64) {
	total_nodes, total_genes, total_evals, total_diversity := 0, 0, 0, 0
	count := 0
	for i := 0; i < len(e.Trials); i++ {
		t := e.Trials[i]
		if t.Solved() {
			nodes, genes, evals, diversity := t.Winner()
			total_nodes += nodes
			total_genes += genes
			total_evals += evals
			total_diversity += diversity

			count++
		}
	}
	avg_nodes = float64(total_nodes) / float64(count)
	avg_genes = float64(total_genes) / float64(count)
	avg_evals = float64(total_evals) / float64(count)
	avg_diversity = float64(total_diversity) / float64(count)
	return avg_nodes, avg_genes, avg_evals, avg_diversity
}

// Prints experiment statistics
func (ex Experiment) PrintStatistics() {
	fmt.Printf("\n+++ Solved %d trials from %d +++\n", ex.TrialsSolved(), len(ex.Trials))
	// Print absolute champion statistics
	if org, trid, found := ex.BestOrganism(true); found {
		nodes, genes, evals, divers := ex.Trials[trid].Winner()
		fmt.Printf("\nChampion found in %d trial run\n\tWinner Nodes:\t%d\n\tWinner Genes:\t%d\n\tWinner Evals:\t%d\n\n\tDiversity:\t%d",
			trid, nodes, genes, evals, divers)
		fmt.Printf("\n\tComplexity:\t%d\n\tAge:\t\t%d\n\tFitness:\t%.1f\n",
			org.Phenotype.Complexity(), org.Species.Age, org.Fitness)
	} else {
		fmt.Println("\nNo winner found in the experiment!!!")
	}

	// Print average winner statistics
	mean_complexity, mean_diversity, mean_age, mean_fitness := 0.0, 0.0, 0.0, 0.0
	if len(ex.Trials) > 1 {
		avg_nodes, avg_genes, avg_evals, avg_divers := 0.0, 0.0, 0.0, 0.0
		count := 0.0
		for i := 0; i < len(ex.Trials); i++ {
			t := ex.Trials[i]
			if t.Solved() {
				nodes, genes, evals, diversity := t.Winner()
				avg_nodes += float64(nodes)
				avg_genes += float64(genes)
				avg_evals += float64(evals)
				avg_divers += float64(diversity)

				mean_complexity += float64(t.WinnerGeneration.Best.Phenotype.Complexity())
				mean_age += float64(t.WinnerGeneration.Best.Species.Age)
				mean_fitness += t.WinnerGeneration.Best.Fitness

				count++
			}
		}
		avg_nodes /= count
		avg_genes /= count
		avg_evals /= count
		avg_divers /= count
		fmt.Printf("\nAverage among winners\n\tWinner Nodes:\t%.1f\n\tWinner Genes:\t%.1f\n\tWinner Evals:\t%.1f\n\n\tDiversity:\t%.1f\n",
			avg_nodes, avg_genes, avg_evals, avg_divers)

		mean_complexity /= count
		mean_age /= count
		mean_fitness /=count
		fmt.Printf("\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n",
			mean_complexity, mean_age, mean_fitness)
	}

	// Print the average values for each population of organisms evaluated
	count := float64(len(ex.Trials))
	for _, t := range ex.Trials {
		fitness, age, complexity := t.Average()

		mean_complexity += complexity.Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += age.Mean()
		mean_fitness += fitness.Mean()
	}
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	mean_fitness /=count
	fmt.Printf("\nAverages for all organisms evaluated during experiment\n\tDiversity:\t%.1f\n\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n\n",
		mean_diversity, mean_complexity, mean_age, mean_fitness)

}

// Encodes experiment and writes to provided writer
func (ex Experiment) Write(w io.Writer) error {
	enc := gob.NewEncoder(w)
	return ex.Encode(enc)
}

// Encodes experiment with GOB encoding
func (ex Experiment) Encode(enc *gob.Encoder) error {
	err := enc.Encode(ex.Id)
	err = enc.Encode(ex.Name)

	// encode trials
	err = enc.Encode(len(ex.Trials))
	for _, t := range ex.Trials {
		err = t.Encode(enc)
		if err != nil {
			return err
		}
	}
	return err
}

// Reads experiment data from provided reader and decodes it
func (ex *Experiment) Read(r io.Reader) error {
	dec := gob.NewDecoder(r)
	return ex.Decode(dec)
}

// Decodes experiment data
func (ex *Experiment) Decode(dec *gob.Decoder) error {
	err := dec.Decode(&ex.Id)
	err = dec.Decode(&ex.Name)

	// decode Trials
	var t_num int
	err = dec.Decode(&t_num)
	if err != nil {
		return err
	}

	ex.Trials = make([]Trial, t_num)
	for i := 0; i < t_num; i++ {
		trial := Trial{}
		err = trial.Decode(dec)
		ex.Trials[i] = trial
	}
	return err
}

// Experiments is a sortable list of experiments by execution time and Id
type Experiments []Experiment

func (es Experiments) Len() int {
	return len(es)
}
func (es Experiments) Swap(i, j int) {
	es[i], es[j] = es[j], es[i]
}
func (es Experiments) Less(i, j int) bool {
	ui := es[i].LastExecuted()
	uj := es[j].LastExecuted()
	if ui.Equal(uj) {
		return es[i].Id < es[j].Id
	}
	return ui.Before(uj)
}<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/ying32/govcl/vcl"
	"github.com/ying32/govcl/vcl/types"
)

func main() {
	vcl.Application.Initialize()
	vcl.Application.SetFormScaled(true)
	mainForm := vcl.Application.CreateForm()
	mainForm.SetWidth(700)
	mainForm.SetHeight(500)
	mainForm.WorkAreaCenter()
	mainForm.SetCaption("九九乘法表")

	grid := vcl.NewStringGrid(mainForm)
	grid.SetParent(mainForm)
	grid.SetAlign(types.AlClient)

	// 这里设置的是作为字段，像头一样的
	//grid.SetFixedCols(1)
	//grid.SetFixedRows(1)

	// 10x10
	grid.SetColCount(10)
	grid.SetRowCount(10)

	var i, j int32
	// 横第一行
	for i = 0; i < grid.ColCount(); i++ {
		grid.SetCells(i, 0, fmt.Sprintf("%d", i))
	}
	// 竖第一行
	for j = 0; j < grid.RowCount(); j++ {
		grid.SetCells(0, j, fmt.Sprintf("%d", j))
	}
	// 九九乘法表
	for i = 1; i <= 9; i++ {
		for j = i; j <= 9; j++ {
			grid.SetCells(i, j, fmt.Sprintf("%dx%d=%d", i, j, i*j))
		}
	}

	vcl.Application.Run()
}
<commit_msg>Update stringgrid sample<commit_after>package main

import (
	"fmt"

	"github.com/ying32/govcl/vcl"
	"github.com/ying32/govcl/vcl/types"
)

func main() {
	vcl.Application.Initialize()
	vcl.Application.SetFormScaled(true)
	mainForm := vcl.Application.CreateForm()
	mainForm.SetWidth(700)
	mainForm.SetHeight(500)
	mainForm.WorkAreaCenter()
	mainForm.SetCaption("九九乘法表")
	mainForm.ScaleSelf()
	grid := vcl.NewStringGrid(mainForm)
	grid.SetParent(mainForm)
	grid.SetAlign(types.AlClient)

	// 这里设置的是作为字段，像头一样的
	//grid.SetFixedCols(1)
	//grid.SetFixedRows(1)

	// 10x10
	grid.SetColCount(10)
	grid.SetRowCount(10)

	var i, j int32
	// 横第一行
	for i = 0; i < grid.ColCount(); i++ {
		grid.SetCells(i, 0, fmt.Sprintf("%d", i))
	}
	// 竖第一行
	for j = 0; j < grid.RowCount(); j++ {
		grid.SetCells(0, j, fmt.Sprintf("%d", j))
	}
	// 九九乘法表
	for i = 1; i <= 9; i++ {
		for j = i; j <= 9; j++ {
			grid.SetCells(i, j, fmt.Sprintf("%dx%d=%d", i, j, i*j))
		}
	}

	vcl.Application.Run()
}
<|endoftext|>


<commit_before>package game

type Outcome int

const (
	NullOutcome Outcome = iota
	WhiteWins
	BlackWins
	Tie
)

func (o Outcome) Winner() Player {
	if o == WhiteWins {
		return White
	} else if o == BlackWins {
		return Black
	} else {
		return NullPlayer
	}
}

func (o Outcome) Loser() Player {
	return o.Winner().Next()
}
<commit_msg>feat(game) add String() method to game.Outcome<commit_after>package game

type Outcome int

const (
	NullOutcome Outcome = iota
	WhiteWins
	BlackWins
	Tie
)

func (o Outcome) Winner() Player {
	if o == WhiteWins {
		return White
	} else if o == BlackWins {
		return Black
	} else {
		return NullPlayer
	}
}

func (o Outcome) Loser() Player {
	return o.Winner().Next()
}

func (o Outcome) String() string {
	if o == WhiteWins {
		return "white wins"
	} else if o == BlackWins {
		return "black wins"
	} else {
		return "null outcome"
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/service"
)

// Keep this around to simplify things
var G = libkb.G

var cmd libcmdline.Command

type Canceler interface {
	Cancel() error
}

func main() {

	g := G
	g.Init()

	go HandleSignals()
	err := mainInner(g)
	e2 := g.Shutdown()
	if err == nil {
		err = e2
	}
	if err != nil {
		g.Log.Error(err.Error())
		os.Exit(2)
	}
}

func mainInner(g *libkb.GlobalContext) error {

	cl := libcmdline.NewCommandLine(true, client.GetExtraFlags())
	cl.AddCommands(client.GetCommands(cl))
	cl.AddCommands(service.GetCommands(cl))

	var err error
	cmd, err = cl.Parse(os.Args)
	if err != nil {
		err = fmt.Errorf("Error parsing command line arguments: %s\n", err)
		return err
	}

	if cmd == nil {
		err = fmt.Errorf("No command selected")
		return err
	}

	if !cl.IsService() {
		client.InitUI()
	}

	if err = g.ConfigureAll(cl, cmd); err != nil {
		return err
	}

	if g.Env.GetStandalone() || cl.IsService() {
		err = cmd.Run()
	} else {
		// No sense in starting the daemon just to stop it
		fc := cl.GetForkCmd()
		if fc == libcmdline.ForceFork || (g.Env.GetAutoFork() && fc != libcmdline.NoFork) {
			if err = client.ForkServerNix(cl); err != nil {
				return err
			}
		}
		err = cmd.RunClient()
	}
	return err
}

func HandleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for {
		s := <-c
		if s != nil {
			G.Log.Debug("\n\ntrapped signal %v", s)

			// if the current command has a Cancel function, then call it:
			if canc, ok := cmd.(Canceler); ok {
				G.Log.Debug("canceling running command")
				if err := canc.Cancel(); err != nil {
					G.Log.Warning("error canceling command: %s", err)
				}
			}

			G.Log.Debug("calling shutdown")
			G.Shutdown()
			G.Log.Error("interrupted")
			os.Exit(3)
		}
	}
}
<commit_msg>cleaned up debug message<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"

	"github.com/keybase/client/go/client"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/service"
)

// Keep this around to simplify things
var G = libkb.G

var cmd libcmdline.Command

type Canceler interface {
	Cancel() error
}

func main() {

	g := G
	g.Init()

	go HandleSignals()
	err := mainInner(g)
	e2 := g.Shutdown()
	if err == nil {
		err = e2
	}
	if err != nil {
		g.Log.Error(err.Error())
		os.Exit(2)
	}
}

func mainInner(g *libkb.GlobalContext) error {

	cl := libcmdline.NewCommandLine(true, client.GetExtraFlags())
	cl.AddCommands(client.GetCommands(cl))
	cl.AddCommands(service.GetCommands(cl))

	var err error
	cmd, err = cl.Parse(os.Args)
	if err != nil {
		err = fmt.Errorf("Error parsing command line arguments: %s\n", err)
		return err
	}

	if cmd == nil {
		err = fmt.Errorf("No command selected")
		return err
	}

	if !cl.IsService() {
		client.InitUI()
	}

	if err = g.ConfigureAll(cl, cmd); err != nil {
		return err
	}

	if g.Env.GetStandalone() || cl.IsService() {
		err = cmd.Run()
	} else {
		// No sense in starting the daemon just to stop it
		fc := cl.GetForkCmd()
		if fc == libcmdline.ForceFork || (g.Env.GetAutoFork() && fc != libcmdline.NoFork) {
			if err = client.ForkServerNix(cl); err != nil {
				return err
			}
		}
		err = cmd.RunClient()
	}
	return err
}

func HandleSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	for {
		s := <-c
		if s != nil {
			G.Log.Debug("trapped signal %v", s)

			// if the current command has a Cancel function, then call it:
			if canc, ok := cmd.(Canceler); ok {
				G.Log.Debug("canceling running command")
				if err := canc.Cancel(); err != nil {
					G.Log.Warning("error canceling command: %s", err)
				}
			}

			G.Log.Debug("calling shutdown")
			G.Shutdown()
			G.Log.Error("interrupted")
			os.Exit(3)
		}
	}
}
<|endoftext|>


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

package tao

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"

	"github.com/jlmucb/cloudproxy/go/tao/auth"
	"github.com/jlmucb/cloudproxy/go/util"
)

// ConnAuth controls authentication and authorization options for connections.
type ConnAuth struct {
	// Authenticate controls whether local host authenticates to remote using a
	// Tao delegation. If true, keys must be provided in Dial or Listen.
	Authenticate bool

	// delegation is used by remote to authenticate local side
	delegation *Attestation

	// AuthenticatePeer controls whether local requires remote to authenticate
	// using a Tao delegation. If false, guard is ignored.
	AuthenticatePeer bool

	// guard and verifier are used by local to authenticate remote side
	guard    Guard
	verifier *Verifier
}

// A Listener implements net.Listener for Tao connections. Each time it accepts
// a connection, it exchanges Tao attestation chains and checks the attestation
// for the certificate of the client against its Guard. The guard in this
// case should be the guard of the Tao domain. This listener allows connections
// from any program that is authorized under the Tao to execute.
type Listener struct {
	// ConnAuth controls authentication and authorization options for accepted
	// connections.
	ConnAuth

	net.Listener
}

// Conn implements net.Conn but performs a Tao (and TLS) handshake before the
// first read or write.
type Conn struct {
	peer *auth.Prin

	isServer bool

	handshakeComplete bool
	handshakeErr      error

	// ConnAuth reports authentication and authorization options for this
	// connection.
	ConnAuth

	// The underlying tls connection. Use this only for querying properties. In
	// particular, don't use the read and write functions, since they don't
	// ensure the proper handshaking has been done.
	*tls.Conn

	//util.MessageFraming
	util.FramedStream
}

/*
func (c *Conn) WriteString(s string) (int, error) {
	return util.WriteString(c, s)
}

func (c *Conn) ReadString() (string, error) {
	return util.ReadString(c)
}

func (c *Conn) WriteMessage(m proto.Message) (int, error) {
	return util.WriteMessage(c, m)
}

func (c *Conn) ReadMessage(m proto.Message) error {
	return util.ReadMessage(c, m)
}
*/

// Handshake performs a Tao (and TLS) handshake. This occurs only once, before
// the first read or write. Users don't usually need to call this directly,
// since other functions call this as necessary.
func (conn *Conn) Handshake() error {
	// Tao handshake protocol:
	// 0. TLS handshake (executed automatically on first message)
	// 1. Client -> Server: "delgation", Tao delegation for X.509 certificate.
	// 2. Server: checks for a Tao-authorized program.
	// 3. Server -> Client: "delgation", Tao delegation for X.509 certificate.
	// 4. Client: checks for a Tao-authorized program.
	//
	// Alternate steps 1 and 2 if client authentication is not needed:
	// 1'. Client -> Server: "anonymous"
	// 2'. Server: checks if policy allows anonymous connections
	//
	// Alternate steps 3 and 4 if server authentication is not needed:
	// 3'. Server -> Client: "anonymous"
	// 4'. Client: checks if policy allows anonymous connections
	if !conn.handshakeComplete {
		// Use a new framing stream on the underlying tls to avoid recursing.
		ms := util.NewMessageStream(conn.Conn)
		if conn.isServer {
			conn.sendCredentials(ms)
			conn.recvCredentials(ms)
		} else {
			conn.sendCredentials(ms)
			conn.recvCredentials(ms)
		}
		conn.handshakeComplete = true
		conn.handshakeErr = ms.Err()
		if conn.handshakeErr != nil {
			conn.Close()
			conn.SetErr(conn.handshakeErr)
		}
	}
	return conn.handshakeErr
}

func (conn *Conn) sendCredentials(ms util.MessageStream) {
	if conn.Authenticate && conn.delegation != nil {
		ms.WriteString("delegation")
		ms.WriteMessage(conn.delegation)
	} else if conn.Authenticate {
		ms.WriteString("key")
	} else {
		ms.WriteString("anonymous")
	}
}

func (conn *Conn) recvCredentials(ms util.MessageStream) {
	m, err := ms.ReadString()
	if err != nil {
		return
	}
	if m == "delegation" {
		var a Attestation
		if err = ms.ReadMessage(&a); err != nil {
			return
		}
		// Validate the peer certificate
		peerCert := conn.ConnectionState().PeerCertificates[0]
		p, err := ValidatePeerAttestation(&a, peerCert)
		if err != nil {
			ms.SetErr(err)
			return
		}
		if conn.guard != nil {
			if conn.verifier != nil {
				if err = AddEndorsements(conn.guard, &a, conn.verifier); err != nil {
					ms.SetErr(err)
					return
				}
			}
			if !conn.guard.IsAuthorized(p, "Connect", nil) {
				ms.SetErr(errors.New("principal delegator in client attestation is not authorized to connect"))
				return
			}
		}
		conn.peer = &p
	} else if m == "key" {
		peerCert := conn.ConnectionState().PeerCertificates[0]
		v, err := FromX509(peerCert)
		if err != nil {
			ms.SetErr(errors.New("can't decode key from peer certificate"))
			return
		}
		p := v.ToPrincipal()
		conn.peer = &p
	} else if m == "anonymous" {
		if conn.guard != nil {
			err = errors.New("peer did not provide tao delegation")
			ms.SetErr(err)
			return
		}
	} else {
		err = errors.New("unrecognized authentication handshake: " + m)
		ms.SetErr(err)
		return
	}
}

func (conn *Conn) Peer() *auth.Prin {
	if err := conn.Handshake(); err != nil {
		return nil
	}
	return conn.peer
}

func (conn *Conn) Read(b []byte) (n int, err error) {
	if err := conn.Handshake(); err != nil {
		return 0, err
	}
	return conn.Conn.Read(b)
}

func (conn *Conn) Write(b []byte) (n int, err error) {
	if err := conn.Handshake(); err != nil {
		return 0, err
	}
	return conn.Conn.Write(b)
}

// Listen returns a new Tao-based Listener that uses an underlying crypto/tls
// net.Listener to authenticate connections. If keys are not nil, then the
// server will authenticate to clients using the keys. If guard is nil, clients
// need not provide authentication. If guard is not nil, clients must
// authenticate to the server and the guard must authorize the connection. If a
// Verifier key is also provided, attestations provided by clients and signed by
// that verifier will be added to the guard rule set. If conf is nil, a tls
// configuration will be created.
func Listen(network, laddr string, keys *Keys, g Guard, v *Verifier, conf *tls.Config) (*Listener, error) {
	if conf == nil {
		var err error
		conf, err = keys.TLSServerConfig(nil)
		if err != nil {
			return nil, err
		}
	}
	var del *Attestation
	if keys != nil {
		del = keys.Delegation
	}
	l, err := tls.Listen(network, laddr, conf)
	if err != nil {
		return nil, err
	}
	return &Listener{
		Listener: l,
		ConnAuth: ConnAuth{
			Authenticate:     keys != nil,
			delegation:       del,
			AuthenticatePeer: g != nil,
			guard:            g,
			verifier:         v,
		},
	}, nil
}

// ValidatePeerAttestation checks a Attestation for a given Listener against
// an X.509 certificate from a TLS channel.
func ValidatePeerAttestation(a *Attestation, cert *x509.Certificate) (auth.Prin, error) {
	stmt, err := a.Validate()
	if err != nil {
		return auth.Prin{}, err
	}

	// Insist that the message of the statement be a SpeaksFor and that the
	// initial term be an auth.Prin of type key. Note that Validate has already
	// checked the expirations and the times and the general well-formedness of
	// the attestation.
	sf, ok := stmt.Message.(auth.Speaksfor)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Speaksfor as a message")
	}

	// This key must contain the serialized X.509 certificate.
	kprin, ok := sf.Delegate.(auth.Prin)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin as its delegate")
	}

	if kprin.Type != "key" {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin of type 'key' as its delegate")
	}

	if _, ok := kprin.Key.(auth.Bytes); !ok {
		return auth.Prin{}, errors.New("a peer attestation must have a Key of type auth.Bytes")
	}

	prin, ok := sf.Delegator.(auth.Prin)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin as its delegator")
	}

	// The bytes of the delegate are the result of ToPrincipal on
	// Keys.SigningKey. Check that this represents the same key as the one
	// in the certificate.
	verifier, err := FromPrincipal(kprin)
	if err != nil {
		return auth.Prin{}, err
	}
	if !verifier.Equals(cert) {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin.Key of type auth.Bytes where the bytes match the auth.Prin representation of the X.509 certificate")
	}

	return prin, nil
}

// Accept waits for a connect, accepts it using the underlying Conn and checks
// the attestations and the statement. The resulting net.Conn implements
// tao.Conn, which implements util.MessageStream and embeds tls.Conn.
func (l *Listener) Accept() (net.Conn, error) {
	conn, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}
	c := &Conn{
		isServer: true,
		ConnAuth: l.ConnAuth,
		Conn:     conn.(*tls.Conn),
	}
	c.FramedStream = util.FramedStream{util.MessageFraming{}, c}
	// Handshake later so we don't block the accept loop
	return c, nil
}
<commit_msg>additional tracing<commit_after>// Copyright (c) 2014, Google, Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tao

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"net"

	"github.com/jlmucb/cloudproxy/go/tao/auth"
	"github.com/jlmucb/cloudproxy/go/util"
	"github.com/kevinawalsh/profiling"
)

// ConnAuth controls authentication and authorization options for connections.
type ConnAuth struct {
	// Authenticate controls whether local host authenticates to remote using a
	// Tao delegation. If true, keys must be provided in Dial or Listen.
	Authenticate bool

	// delegation is used by remote to authenticate local side
	delegation *Attestation

	// AuthenticatePeer controls whether local requires remote to authenticate
	// using a Tao delegation. If false, guard is ignored.
	AuthenticatePeer bool

	// guard and verifier are used by local to authenticate remote side
	guard    Guard
	verifier *Verifier
}

// A Listener implements net.Listener for Tao connections. Each time it accepts
// a connection, it exchanges Tao attestation chains and checks the attestation
// for the certificate of the client against its Guard. The guard in this
// case should be the guard of the Tao domain. This listener allows connections
// from any program that is authorized under the Tao to execute.
type Listener struct {
	// ConnAuth controls authentication and authorization options for accepted
	// connections.
	ConnAuth

	net.Listener
}

// Conn implements net.Conn but performs a Tao (and TLS) handshake before the
// first read or write.
type Conn struct {
	peer *auth.Prin

	isServer bool

	handshakeComplete bool
	handshakeErr      error

	// ConnAuth reports authentication and authorization options for this
	// connection.
	ConnAuth

	// The underlying tls connection. Use this only for querying properties. In
	// particular, don't use the read and write functions, since they don't
	// ensure the proper handshaking has been done.
	*tls.Conn

	//util.MessageFraming
	util.FramedStream

	T *profiling.Trace
}

/*
func (c *Conn) WriteString(s string) (int, error) {
	return util.WriteString(c, s)
}

func (c *Conn) ReadString() (string, error) {
	return util.ReadString(c)
}

func (c *Conn) WriteMessage(m proto.Message) (int, error) {
	return util.WriteMessage(c, m)
}

func (c *Conn) ReadMessage(m proto.Message) error {
	return util.ReadMessage(c, m)
}
*/

// Handshake performs a Tao (and TLS) handshake. This occurs only once, before
// the first read or write. Users don't usually need to call this directly,
// since other functions call this as necessary.
func (conn *Conn) Handshake() error {
	// Tao handshake protocol:
	// 0. TLS handshake (executed automatically on first message)
	// 1. Client -> Server: "delgation", Tao delegation for X.509 certificate.
	// 2. Server: checks for a Tao-authorized program.
	// 3. Server -> Client: "delgation", Tao delegation for X.509 certificate.
	// 4. Client: checks for a Tao-authorized program.
	//
	// Alternate steps 1 and 2 if client authentication is not needed:
	// 1'. Client -> Server: "anonymous"
	// 2'. Server: checks if policy allows anonymous connections
	//
	// Alternate steps 3 and 4 if server authentication is not needed:
	// 3'. Server -> Client: "anonymous"
	// 4'. Client: checks if policy allows anonymous connections
	if !conn.handshakeComplete {
		if conn.T != nil {
			conn.T.Start()
		}
		// Use a new framing stream on the underlying tls to avoid recursing.
		ms := util.NewMessageStream(conn.Conn)
		if conn.isServer {
			conn.sendCredentials(ms)
			if conn.T != nil {
				conn.T.Sample("sent tao creds")
			}
			conn.recvCredentials(ms)
		} else {
			conn.sendCredentials(ms)
			if conn.T != nil {
				conn.T.Sample("sent tao creds")
			}
			conn.recvCredentials(ms)
		}
		conn.handshakeComplete = true
		conn.handshakeErr = ms.Err()
		if conn.handshakeErr != nil {
			conn.Close()
			conn.SetErr(conn.handshakeErr)
		}
		if conn.T != nil {
			conn.T.Sample("done tao handshake")
		}
	}
	return conn.handshakeErr
}

func (conn *Conn) sendCredentials(ms util.MessageStream) {
	if conn.Authenticate && conn.delegation != nil {
		ms.WriteString("delegation")
		ms.WriteMessage(conn.delegation)
	} else if conn.Authenticate {
		ms.WriteString("key")
	} else {
		ms.WriteString("anonymous")
	}
}

func (conn *Conn) recvCredentials(ms util.MessageStream) {
	m, err := ms.ReadString()
	if err != nil {
		return
	}
	if m == "delegation" {
		var a Attestation
		if err = ms.ReadMessage(&a); err != nil {
			return
		}
		// Validate the peer certificate
		peerCert := conn.ConnectionState().PeerCertificates[0]
		p, err := ValidatePeerAttestation(&a, peerCert)
		if err != nil {
			ms.SetErr(err)
			return
		}
		if conn.guard != nil {
			if conn.verifier != nil {
				if err = AddEndorsements(conn.guard, &a, conn.verifier); err != nil {
					ms.SetErr(err)
					return
				}
			}
			if !conn.guard.IsAuthorized(p, "Connect", nil) {
				ms.SetErr(errors.New("principal delegator in client attestation is not authorized to connect"))
				return
			}
		}
		conn.peer = &p
	} else if m == "key" {
		peerCert := conn.ConnectionState().PeerCertificates[0]
		v, err := FromX509(peerCert)
		if err != nil {
			ms.SetErr(errors.New("can't decode key from peer certificate"))
			return
		}
		p := v.ToPrincipal()
		conn.peer = &p
	} else if m == "anonymous" {
		if conn.guard != nil {
			err = errors.New("peer did not provide tao delegation")
			ms.SetErr(err)
			return
		}
	} else {
		err = errors.New("unrecognized authentication handshake: " + m)
		ms.SetErr(err)
		return
	}
}

func (conn *Conn) Peer() *auth.Prin {
	if err := conn.Handshake(); err != nil {
		return nil
	}
	return conn.peer
}

func (conn *Conn) Read(b []byte) (n int, err error) {
	if err := conn.Handshake(); err != nil {
		return 0, err
	}
	return conn.Conn.Read(b)
}

func (conn *Conn) Write(b []byte) (n int, err error) {
	if err := conn.Handshake(); err != nil {
		return 0, err
	}
	return conn.Conn.Write(b)
}

// Listen returns a new Tao-based Listener that uses an underlying crypto/tls
// net.Listener to authenticate connections. If keys are not nil, then the
// server will authenticate to clients using the keys. If guard is nil, clients
// need not provide authentication. If guard is not nil, clients must
// authenticate to the server and the guard must authorize the connection. If a
// Verifier key is also provided, attestations provided by clients and signed by
// that verifier will be added to the guard rule set. If conf is nil, a tls
// configuration will be created.
func Listen(network, laddr string, keys *Keys, g Guard, v *Verifier, conf *tls.Config) (*Listener, error) {
	if conf == nil {
		var err error
		conf, err = keys.TLSServerConfig(nil)
		if err != nil {
			return nil, err
		}
	}
	var del *Attestation
	if keys != nil {
		del = keys.Delegation
	}
	l, err := tls.Listen(network, laddr, conf)
	if err != nil {
		return nil, err
	}
	return &Listener{
		Listener: l,
		ConnAuth: ConnAuth{
			Authenticate:     keys != nil,
			delegation:       del,
			AuthenticatePeer: g != nil,
			guard:            g,
			verifier:         v,
		},
	}, nil
}

// ValidatePeerAttestation checks a Attestation for a given Listener against
// an X.509 certificate from a TLS channel.
func ValidatePeerAttestation(a *Attestation, cert *x509.Certificate) (auth.Prin, error) {
	stmt, err := a.Validate()
	if err != nil {
		return auth.Prin{}, err
	}

	// Insist that the message of the statement be a SpeaksFor and that the
	// initial term be an auth.Prin of type key. Note that Validate has already
	// checked the expirations and the times and the general well-formedness of
	// the attestation.
	sf, ok := stmt.Message.(auth.Speaksfor)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Speaksfor as a message")
	}

	// This key must contain the serialized X.509 certificate.
	kprin, ok := sf.Delegate.(auth.Prin)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin as its delegate")
	}

	if kprin.Type != "key" {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin of type 'key' as its delegate")
	}

	if _, ok := kprin.Key.(auth.Bytes); !ok {
		return auth.Prin{}, errors.New("a peer attestation must have a Key of type auth.Bytes")
	}

	prin, ok := sf.Delegator.(auth.Prin)
	if !ok {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin as its delegator")
	}

	// The bytes of the delegate are the result of ToPrincipal on
	// Keys.SigningKey. Check that this represents the same key as the one
	// in the certificate.
	verifier, err := FromPrincipal(kprin)
	if err != nil {
		return auth.Prin{}, err
	}
	if !verifier.Equals(cert) {
		return auth.Prin{}, errors.New("a peer attestation must have an auth.Prin.Key of type auth.Bytes where the bytes match the auth.Prin representation of the X.509 certificate")
	}

	return prin, nil
}

// Accept waits for a connect, accepts it using the underlying Conn and checks
// the attestations and the statement. The resulting net.Conn implements
// tao.Conn, which implements util.MessageStream and embeds tls.Conn.
func (l *Listener) Accept() (net.Conn, error) {
	conn, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}
	c := &Conn{
		isServer: true,
		ConnAuth: l.ConnAuth,
		Conn:     conn.(*tls.Conn),
	}
	c.FramedStream = util.FramedStream{util.MessageFraming{}, c}
	// Handshake later so we don't block the accept loop
	return c, nil
}
<|endoftext|>


<commit_before>package teams

import (
	//"fmt"
	"bytes"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"
	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	"github.com/keybase/saltpack/encoding/basex"
)

const SeitanRawIKeyLength = 10
const SeitanEncodedIKeyLength = 16

// Key-Base 34 encoding. lower case letters and digits except for 0 and 1.
const KBase34EncodeStd = "abcdefghijklmnopqrstuvwxyz23456789"

var Base34Encoding = basex.NewEncoding(KBase34EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
type SeitanPEIKey struct {
	_struct           bool `codec:",toarray"`
	Version           uint
	TeamKeyGeneration keybase1.PerTeamKeyGeneration
	RandomNonce       keybase1.BoxNonce
	EIKey             []byte
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base34Encoding.Encode(encodedKey[:], rawKey)

	var verify [10]byte
	_, err = Base34Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !bytes.Equal(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// "Stretched Invite Key"
type SeitanSIKey [32]byte

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, 4, 8, 1, 32)
	if err != nil {
		return sikey, err
	}
	if len(ret) != 32 {
		return sikey, errors.New("internal error - scrypt did not return 32 bytes")
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	eikey := secretbox.Seal(nil, []byte(ikey), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:           1,
		TeamKeyGeneration: appKey.KeyGeneration,
		RandomNonce:       nonce,
		EIKey:             eikey,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) DecryptIKey(ctx context.Context, team *Team) (ikey SeitanIKey, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ikey, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EIKey, &naclNonce, &encKey)
	if !ok {
		return ikey, errors.New("failed to decrypt seitan ikey")
	}

	ikey = SeitanIKey(plain)
	return ikey, nil
}
<commit_msg>Imports cleanup<commit_after>package teams

import (
	"bytes"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

const SeitanRawIKeyLength = 10
const SeitanEncodedIKeyLength = 16

// Key-Base 34 encoding. lower case letters and digits except for 0 and 1.
const KBase34EncodeStd = "abcdefghijklmnopqrstuvwxyz23456789"

var Base34Encoding = basex.NewEncoding(KBase34EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
type SeitanPEIKey struct {
	_struct           bool `codec:",toarray"`
	Version           uint
	TeamKeyGeneration keybase1.PerTeamKeyGeneration
	RandomNonce       keybase1.BoxNonce
	EIKey             []byte
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base34Encoding.Encode(encodedKey[:], rawKey)

	var verify [10]byte
	_, err = Base34Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !bytes.Equal(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

// "Stretched Invite Key"
type SeitanSIKey [32]byte

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, 4, 8, 1, 32)
	if err != nil {
		return sikey, err
	}
	if len(ret) != 32 {
		return sikey, errors.New("internal error - scrypt did not return 32 bytes")
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	eikey := secretbox.Seal(nil, []byte(ikey), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:           1,
		TeamKeyGeneration: appKey.KeyGeneration,
		RandomNonce:       nonce,
		EIKey:             eikey,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) DecryptIKey(ctx context.Context, team *Team) (ikey SeitanIKey, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ikey, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EIKey, &naclNonce, &encKey)
	if !ok {
		return ikey, errors.New("failed to decrypt seitan ikey")
	}

	ikey = SeitanIKey(plain)
	return ikey, nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pb "github.com/brotherlogic/gobuildslave/proto"
	pbgs "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

// RunJob - runs the job
func (s *Server) RunJob(ctx context.Context, req *pb.RunRequest) (*pb.RunResponse, error) {
	if !req.GetJob().GetBreakout() &&
		(s.Registry.Identifier == "clust6" ||
			s.Registry.Identifier == "clust3" ||
			s.Registry.Identifier == "clust7" ||
			s.Registry.Identifier == "clust8" ||
			s.Registry.Identifier == "clust4") {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "we only run the basic set of jobs")
	}

	if req.GetBits() > 0 && s.Bits != int(req.GetBits()) {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "Cannot run %v bits on this server", req.GetBits())
	}

	if !s.doesBuild && !req.Job.Breakout {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "Refusing to build")
	}
	s.nMut.Lock()
	defer s.nMut.Unlock()
	if _, ok := s.njobs[req.GetJob().GetName()]; ok {
		return &pb.RunResponse{}, fmt.Errorf("Already running this job!")
	}

	if len(s.njobs) > s.maxJobs && !req.GetJob().GetBreakout() {
		return nil, status.Errorf(codes.FailedPrecondition, "We're running %v jobs, can't run no more", len(s.njobs))
	}

	s.CtxLog(ctx, "Running %v")

	s.njobs[req.GetJob().GetName()] = &pb.JobAssignment{Job: req.GetJob(), LastTransitionTime: time.Now().Unix(), Bits: int32(s.Bits)}
	go s.nmonitor(s.njobs[req.GetJob().GetName()])

	return &pb.RunResponse{}, nil
}

// KillJob - kills the job
func (s *Server) KillJob(ctx context.Context, req *pb.KillRequest) (*pb.KillResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()

	if _, ok := s.njobs[req.GetJob().GetName()]; !ok {
		return nil, fmt.Errorf("Job was not running")
	}

	s.njobs[req.GetJob().GetName()].State = pb.State_KILLING
	return &pb.KillResponse{}, nil
}

//UpdateJob - updates the job
func (s *Server) UpdateJob(ctx context.Context, req *pb.UpdateRequest) (*pb.UpdateResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()
	if _, ok := s.njobs[req.GetJob().GetName()]; !ok {
		return nil, fmt.Errorf("Job was not running")
	}

	s.njobs[req.GetJob().GetName()].State = pb.State_UPDATE_STARTING
	return &pb.UpdateResponse{}, nil
}

// ListJobs - lists the jobs
func (s *Server) ListJobs(ctx context.Context, req *pb.ListRequest) (*pb.ListResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()
	resp := &pb.ListResponse{}
	for _, job := range s.njobs {
		resp.Jobs = append(resp.Jobs, job)
	}
	return resp, nil
}

func extractBitRate(output string) (string, string) {
	matcher := regexp.MustCompile("Rate=(.*?) ")
	matches := matcher.FindStringSubmatch(output)

	matcher2 := regexp.MustCompile("Access Point. ([A-F0-9:]*)")
	matches2 := matcher2.FindStringSubmatch(output)
	if len(matches) > 0 && len(matches2) > 0 {
		return strings.TrimRight(matches[1], " "), strings.TrimRight(matches2[1], " ")
	}
	return "", ""
}

// SlaveConfig gets the config for this slave
func (s *Server) SlaveConfig(ctx context.Context, req *pb.ConfigRequest) (*pb.ConfigResponse, error) {
	disks := s.disker.getDisks()
	requirements := make([]*pb.Requirement, 0)
	for _, disk := range disks {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_DISK, Properties: disk})
	}
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_SERVER, Properties: s.Registry.Identifier})
	if s.Registry.Identifier == "argon" {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_EXTERNAL, Properties: "external_ready"})
	}

	data, err := exec.Command("/usr/bin/lsusb").Output()
	if err != nil {
		return nil, fmt.Errorf("error listing usb components: %v", err)
	}
	s.CtxLog(ctx, fmt.Sprintf("USBRES: %v", string(data)))
	if strings.Contains(string(data), "TSP100II") {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_RECEIPT_PRINTER})
	}

	out, _ := exec.Command("/sbin/iwconfig").Output()
	br, ap := extractBitRate(string(out))
	s.accessPoint = ap
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_NETWORK, Properties: br})
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_ACCESS_POINT, Properties: ap})

	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_BITS, Properties: fmt.Sprintf("%v", s.Bits)})

	out, _ = exec.Command("cat", "/sys/firmware/devicetree/base/model").Output()
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_HOST_TYPE, Properties: string(out)})

	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_ZONE, Properties: s.Registry.Zone})

	return &pb.ConfigResponse{Config: &pb.SlaveConfig{Requirements: requirements}}, nil
}

func (s *Server) FullShutdown(ctx context.Context, req *pb.ShutdownRequest) (*pb.ShutdownResponse, error) {
	defer func() {
		time.Sleep(time.Minute)

		exec.Command("sudo", "shutdown", "-h", "now").Run()
	}()

	jobs, err := s.ListJobs(ctx, &pb.ListRequest{})
	if err != nil {
		return nil, err
	}

	s.CtxLog(ctx, fmt.Sprintf("Shutting down %v jobs", len(jobs.GetJobs())))

	wg := &sync.WaitGroup{}
	for _, job := range jobs.GetJobs() {
		if job.GetPort() != 0 {
			wg.Add(1)

			go func(job *pb.JobAssignment) {
				conn, err := utils.LFDial(fmt.Sprintf("%v:%v", job.GetHost(), job.GetPort()))
				if err != nil {
					return
				}
				s.CtxLog(ctx, fmt.Sprintf("Calling shutdown on %v", job))
				gsclient := pbgs.NewGoserverServiceClient(conn)
				_, err = gsclient.Shutdown(ctx, &pbgs.ShutdownRequest{})
				if err != nil {
					s.CtxLog(ctx, fmt.Sprintf("Failed shutdown: %v", err))
				}
			}(job)
		} else {
			s.CtxLog(ctx, fmt.Sprintf("Not shutting down %v", job))
		}
	}

	wg.Wait()

	return &pb.ShutdownResponse{}, nil
}
<commit_msg>Log shutdown<commit_after>package main

import (
	"context"
	"fmt"
	"os/exec"
	"regexp"
	"strings"
	"sync"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	pb "github.com/brotherlogic/gobuildslave/proto"
	pbgs "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

// RunJob - runs the job
func (s *Server) RunJob(ctx context.Context, req *pb.RunRequest) (*pb.RunResponse, error) {
	if !req.GetJob().GetBreakout() &&
		(s.Registry.Identifier == "clust6" ||
			s.Registry.Identifier == "clust3" ||
			s.Registry.Identifier == "clust7" ||
			s.Registry.Identifier == "clust8" ||
			s.Registry.Identifier == "clust4") {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "we only run the basic set of jobs")
	}

	if req.GetBits() > 0 && s.Bits != int(req.GetBits()) {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "Cannot run %v bits on this server", req.GetBits())
	}

	if !s.doesBuild && !req.Job.Breakout {
		return &pb.RunResponse{}, status.Errorf(codes.FailedPrecondition, "Refusing to build")
	}
	s.nMut.Lock()
	defer s.nMut.Unlock()
	if _, ok := s.njobs[req.GetJob().GetName()]; ok {
		return &pb.RunResponse{}, fmt.Errorf("Already running this job!")
	}

	if len(s.njobs) > s.maxJobs && !req.GetJob().GetBreakout() {
		return nil, status.Errorf(codes.FailedPrecondition, "We're running %v jobs, can't run no more", len(s.njobs))
	}

	s.CtxLog(ctx, "Running %v")

	s.njobs[req.GetJob().GetName()] = &pb.JobAssignment{Job: req.GetJob(), LastTransitionTime: time.Now().Unix(), Bits: int32(s.Bits)}
	go s.nmonitor(s.njobs[req.GetJob().GetName()])

	return &pb.RunResponse{}, nil
}

// KillJob - kills the job
func (s *Server) KillJob(ctx context.Context, req *pb.KillRequest) (*pb.KillResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()

	if _, ok := s.njobs[req.GetJob().GetName()]; !ok {
		return nil, fmt.Errorf("Job was not running")
	}

	s.njobs[req.GetJob().GetName()].State = pb.State_KILLING
	return &pb.KillResponse{}, nil
}

//UpdateJob - updates the job
func (s *Server) UpdateJob(ctx context.Context, req *pb.UpdateRequest) (*pb.UpdateResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()
	if _, ok := s.njobs[req.GetJob().GetName()]; !ok {
		return nil, fmt.Errorf("Job was not running")
	}

	s.njobs[req.GetJob().GetName()].State = pb.State_UPDATE_STARTING
	return &pb.UpdateResponse{}, nil
}

// ListJobs - lists the jobs
func (s *Server) ListJobs(ctx context.Context, req *pb.ListRequest) (*pb.ListResponse, error) {
	s.nMut.Lock()
	defer s.nMut.Unlock()
	resp := &pb.ListResponse{}
	for _, job := range s.njobs {
		resp.Jobs = append(resp.Jobs, job)
	}
	return resp, nil
}

func extractBitRate(output string) (string, string) {
	matcher := regexp.MustCompile("Rate=(.*?) ")
	matches := matcher.FindStringSubmatch(output)

	matcher2 := regexp.MustCompile("Access Point. ([A-F0-9:]*)")
	matches2 := matcher2.FindStringSubmatch(output)
	if len(matches) > 0 && len(matches2) > 0 {
		return strings.TrimRight(matches[1], " "), strings.TrimRight(matches2[1], " ")
	}
	return "", ""
}

// SlaveConfig gets the config for this slave
func (s *Server) SlaveConfig(ctx context.Context, req *pb.ConfigRequest) (*pb.ConfigResponse, error) {
	disks := s.disker.getDisks()
	requirements := make([]*pb.Requirement, 0)
	for _, disk := range disks {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_DISK, Properties: disk})
	}
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_SERVER, Properties: s.Registry.Identifier})
	if s.Registry.Identifier == "argon" {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_EXTERNAL, Properties: "external_ready"})
	}

	data, err := exec.Command("/usr/bin/lsusb").Output()
	if err != nil {
		return nil, fmt.Errorf("error listing usb components: %v", err)
	}
	s.CtxLog(ctx, fmt.Sprintf("USBRES: %v", string(data)))
	if strings.Contains(string(data), "TSP100II") {
		requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_RECEIPT_PRINTER})
	}

	out, _ := exec.Command("/sbin/iwconfig").Output()
	br, ap := extractBitRate(string(out))
	s.accessPoint = ap
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_NETWORK, Properties: br})
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_ACCESS_POINT, Properties: ap})

	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_BITS, Properties: fmt.Sprintf("%v", s.Bits)})

	out, _ = exec.Command("cat", "/sys/firmware/devicetree/base/model").Output()
	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_HOST_TYPE, Properties: string(out)})

	requirements = append(requirements, &pb.Requirement{Category: pb.RequirementCategory_ZONE, Properties: s.Registry.Zone})

	return &pb.ConfigResponse{Config: &pb.SlaveConfig{Requirements: requirements}}, nil
}

func (s *Server) FullShutdown(ctx context.Context, req *pb.ShutdownRequest) (*pb.ShutdownResponse, error) {
	defer func() {
		s.CtxLog(ctx, "Running shutdown")
		time.Sleep(time.Minute)

		err := exec.Command("sudo", "shutdown", "-h", "now").Run()
		s.CtxLog(ctx, fmt.Sprintf("Shutdown: %v", err))
	}()

	jobs, err := s.ListJobs(ctx, &pb.ListRequest{})
	if err != nil {
		return nil, err
	}

	s.CtxLog(ctx, fmt.Sprintf("Shutting down %v jobs", len(jobs.GetJobs())))

	wg := &sync.WaitGroup{}
	for _, job := range jobs.GetJobs() {
		if job.GetPort() != 0 {
			wg.Add(1)

			go func(job *pb.JobAssignment) {
				conn, err := utils.LFDial(fmt.Sprintf("%v:%v", job.GetHost(), job.GetPort()))
				if err != nil {
					return
				}
				s.CtxLog(ctx, fmt.Sprintf("Calling shutdown on %v", job))
				gsclient := pbgs.NewGoserverServiceClient(conn)
				_, err = gsclient.Shutdown(ctx, &pbgs.ShutdownRequest{})
				if err != nil {
					s.CtxLog(ctx, fmt.Sprintf("Failed shutdown: %v", err))
				}
			}(job)
		} else {
			s.CtxLog(ctx, fmt.Sprintf("Not shutting down %v", job))
		}
	}

	wg.Wait()

	return &pb.ShutdownResponse{}, nil
}
<|endoftext|>


<commit_before>package gocloud

import (
	"errors"
	"fmt"
	"github.com/scorelab/gocloud/aws"
	"github.com/scorelab/gocloud/google"
	"github.com/scorelab/gocloud/auth"
)

//Gocloud is a interface which hide differece between different cloud providers.
type Gocloud interface {
	Createnode(request interface{}) (resp interface{}, err error)
	Startnode(request interface{}) (resp interface{}, err error)
	Stopnode(request interface{}) (resp interface{}, err error)
	Deletenode(request interface{}) (resp interface{}, err error)
	Rebootnode(request interface{}) (resp interface{}, err error)
}

const (
	//Amazonprovider reperents Amazon cloud.
	Amazonprovider = "aws"
	//Googleprovider reperents Google cloud.
	Googleprovider = "google"
)

func init() {
	auth.LoadConfig()
}

//CloudProvider return the instance of respepted cloud and map to the Gocloud so we can call the method like createnote on CloudProvider instance
//this is a delegation of cloud provider.
func CloudProvider(provider string) (Gocloud, error) {

	switch provider {
	case Amazonprovider:
		return new(aws.AWS), nil

	case Googleprovider:
		return new(google.Google), nil

	default:
		return nil, errors.New(fmt.Sprintf("provider %s not recognized\n", provider))
	}

}
<commit_msg>authentication<commit_after>package gocloud

import (
	"errors"
	"fmt"
	"github.com/scorelab/gocloud/aws"
	"github.com/scorelab/gocloud/google"
//"github.com/scorelab/gocloud/auth"
)

//Gocloud is a interface which hide differece between different cloud providers.
type Gocloud interface {
	Createnode(request interface{}) (resp interface{}, err error)
	Startnode(request interface{}) (resp interface{}, err error)
	Stopnode(request interface{}) (resp interface{}, err error)
	Deletenode(request interface{}) (resp interface{}, err error)
	Rebootnode(request interface{}) (resp interface{}, err error)
}

const (
	//Amazonprovider reperents Amazon cloud.
	Amazonprovider = "aws"
	//Googleprovider reperents Google cloud.
	Googleprovider = "google"
)

/*
func init() {
	auth.LoadConfig()
}
*/
//CloudProvider return the instance of respepted cloud and map to the Gocloud so we can call the method like createnote on CloudProvider instance
//this is a delegation of cloud provider.
func CloudProvider(provider string) (Gocloud, error) {

	switch provider {
	case Amazonprovider:
		return new(aws.AWS), nil

	case Googleprovider:
		return new(google.Google), nil

	default:
		return nil, errors.New(fmt.Sprintf("provider %s not recognized\n", provider))
	}

}
<|endoftext|>


<commit_before>package google

import (
	"errors"
	"fmt"
	computeBeta "google.golang.org/api/compute/v0.beta"
	"google.golang.org/api/compute/v1"
)

const METADATA_FINGERPRINT_RETRIES = 10

// Since the google compute API uses optimistic locking, there is a chance
// we need to resubmit our updated metadata. To do this, you need to provide
// an update function that attempts to submit your metadata
func MetadataRetryWrapper(update func() error) error {
	attempt := 0
	for attempt < METADATA_FINGERPRINT_RETRIES {
		err := update()
		if err == nil {
			return nil
		}

		if !isFingerprintError(err) {
			// Something else went wrong, don't retry
			return err
		}

		attempt++
	}

	return fmt.Errorf("Failed to update metadata after %d retries", attempt)
}

// Update the metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func MetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *compute.Metadata) {
	curMDMap := make(map[string]string)
	// Load metadata on server into map
	for _, kv := range serverMD.Items {
		// If the server state has a key that we had in our old
		// state, but not in our new state, we should delete it
		_, okOld := oldMDMap[kv.Key]
		_, okNew := newMDMap[kv.Key]
		if okOld && !okNew {
			continue
		} else {
			curMDMap[kv.Key] = *kv.Value
		}
	}

	// Insert new metadata into existing metadata (overwriting when needed)
	for key, val := range newMDMap {
		curMDMap[key] = val.(string)
	}

	// Reformat old metadata into a list
	serverMD.Items = nil
	for key, val := range curMDMap {
		v := val
		serverMD.Items = append(serverMD.Items, &compute.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}
}

// Update the beta metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func BetaMetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *computeBeta.Metadata) {
	curMDMap := make(map[string]string)
	// Load metadata on server into map
	for _, kv := range serverMD.Items {
		// If the server state has a key that we had in our old
		// state, but not in our new state, we should delete it
		_, okOld := oldMDMap[kv.Key]
		_, okNew := newMDMap[kv.Key]
		if okOld && !okNew {
			continue
		} else {
			curMDMap[kv.Key] = *kv.Value
		}
	}

	// Insert new metadata into existing metadata (overwriting when needed)
	for key, val := range newMDMap {
		curMDMap[key] = val.(string)
	}

	// Reformat old metadata into a list
	serverMD.Items = nil
	for key, val := range curMDMap {
		v := val
		serverMD.Items = append(serverMD.Items, &computeBeta.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}
}

func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems {
	metadata := make([]*compute.MetadataItems, len(m))
	// Append new metadata to existing metadata
	for key, val := range m {
		v := val.(string)
		metadata = append(metadata, &compute.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}

	return metadata
}

func flattenMetadataBeta(metadata *computeBeta.Metadata) map[string]string {
	metadataMap := make(map[string]string)
	for _, item := range metadata.Items {
		metadataMap[item.Key] = *item.Value
	}
	return metadataMap
}

// This function differs from flattenMetadataBeta only in that it takes
// compute.metadata rather than computeBeta.metadata as an argument. It should
// be removed in favour of flattenMetadataBeta if/when all resources using it get
// beta support.
func flattenMetadata(metadata *compute.Metadata) map[string]interface{} {
	metadataMap := make(map[string]interface{})
	for _, item := range metadata.Items {
		metadataMap[item.Key] = *item.Value
	}
	return metadataMap
}

func resourceInstanceMetadata(d TerraformResourceData) (*computeBeta.Metadata, error) {
	m := &computeBeta.Metadata{}
	mdMap := d.Get("metadata").(map[string]interface{})
	if v, ok := d.GetOk("metadata_startup_script"); ok && v.(string) != "" {
		if ss, ok := mdMap["startup-script"]; ok && ss != "" {
			return nil, errors.New("Cannot provide both metadata_startup_script and metadata.startup-script.")
		}
		mdMap["startup-script"] = v
	}
	if len(mdMap) > 0 {
		m.Items = make([]*computeBeta.MetadataItems, 0, len(mdMap))
		for key, val := range mdMap {
			v := val.(string)
			m.Items = append(m.Items, &computeBeta.MetadataItems{
				Key:   key,
				Value: &v,
			})
		}

		// Set the fingerprint. If the metadata has never been set before
		// then this will just be blank.
		m.Fingerprint = d.Get("metadata_fingerprint").(string)
	}

	return m, nil
}
<commit_msg>allow empty metadata.startup-script (#91)<commit_after>package google

import (
	"errors"
	"fmt"

	computeBeta "google.golang.org/api/compute/v0.beta"
	"google.golang.org/api/compute/v1"
)

const METADATA_FINGERPRINT_RETRIES = 10

// Since the google compute API uses optimistic locking, there is a chance
// we need to resubmit our updated metadata. To do this, you need to provide
// an update function that attempts to submit your metadata
func MetadataRetryWrapper(update func() error) error {
	attempt := 0
	for attempt < METADATA_FINGERPRINT_RETRIES {
		err := update()
		if err == nil {
			return nil
		}

		if !isFingerprintError(err) {
			// Something else went wrong, don't retry
			return err
		}

		attempt++
	}

	return fmt.Errorf("Failed to update metadata after %d retries", attempt)
}

// Update the metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func MetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *compute.Metadata) {
	curMDMap := make(map[string]string)
	// Load metadata on server into map
	for _, kv := range serverMD.Items {
		// If the server state has a key that we had in our old
		// state, but not in our new state, we should delete it
		_, okOld := oldMDMap[kv.Key]
		_, okNew := newMDMap[kv.Key]
		if okOld && !okNew {
			continue
		} else {
			curMDMap[kv.Key] = *kv.Value
		}
	}

	// Insert new metadata into existing metadata (overwriting when needed)
	for key, val := range newMDMap {
		curMDMap[key] = val.(string)
	}

	// Reformat old metadata into a list
	serverMD.Items = nil
	for key, val := range curMDMap {
		v := val
		serverMD.Items = append(serverMD.Items, &compute.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}
}

// Update the beta metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func BetaMetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *computeBeta.Metadata) {
	curMDMap := make(map[string]string)
	// Load metadata on server into map
	for _, kv := range serverMD.Items {
		// If the server state has a key that we had in our old
		// state, but not in our new state, we should delete it
		_, okOld := oldMDMap[kv.Key]
		_, okNew := newMDMap[kv.Key]
		if okOld && !okNew {
			continue
		} else {
			curMDMap[kv.Key] = *kv.Value
		}
	}

	// Insert new metadata into existing metadata (overwriting when needed)
	for key, val := range newMDMap {
		curMDMap[key] = val.(string)
	}

	// Reformat old metadata into a list
	serverMD.Items = nil
	for key, val := range curMDMap {
		v := val
		serverMD.Items = append(serverMD.Items, &computeBeta.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}
}

func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems {
	metadata := make([]*compute.MetadataItems, len(m))
	// Append new metadata to existing metadata
	for key, val := range m {
		v := val.(string)
		metadata = append(metadata, &compute.MetadataItems{
			Key:   key,
			Value: &v,
		})
	}

	return metadata
}

func flattenMetadataBeta(metadata *computeBeta.Metadata) map[string]string {
	metadataMap := make(map[string]string)
	for _, item := range metadata.Items {
		metadataMap[item.Key] = *item.Value
	}
	return metadataMap
}

// This function differs from flattenMetadataBeta only in that it takes
// compute.metadata rather than computeBeta.metadata as an argument. It should
// be removed in favour of flattenMetadataBeta if/when all resources using it get
// beta support.
func flattenMetadata(metadata *compute.Metadata) map[string]interface{} {
	metadataMap := make(map[string]interface{})
	for _, item := range metadata.Items {
		metadataMap[item.Key] = *item.Value
	}
	return metadataMap
}

func resourceInstanceMetadata(d TerraformResourceData) (*computeBeta.Metadata, error) {
	m := &computeBeta.Metadata{}
	mdMap := d.Get("metadata").(map[string]interface{})
	if v, ok := d.GetOk("metadata_startup_script"); ok && v.(string) != "" {
		if _, ok := mdMap["startup-script"]; ok {
			return nil, errors.New("Cannot provide both metadata_startup_script and metadata.startup-script.")
		}
		mdMap["startup-script"] = v
	}
	if len(mdMap) > 0 {
		m.Items = make([]*computeBeta.MetadataItems, 0, len(mdMap))
		for key, val := range mdMap {
			v := val.(string)
			m.Items = append(m.Items, &computeBeta.MetadataItems{
				Key:   key,
				Value: &v,
			})
		}

		// Set the fingerprint. If the metadata has never been set before
		// then this will just be blank.
		m.Fingerprint = d.Get("metadata_fingerprint").(string)
	}

	return m, nil
}
<|endoftext|>


<commit_before>package gopm_index

import (
    "encoding/json"
)

type PackageMeta struct {
    Name         string   `json:"name"`
    Description  string   `json:"description"`
    Category     string   `json:"category"`
    Keywords     []string `json:"keywords"`
    Author       []string `json:"author"`
    Contributors [][]byte `json:"contributors"`
    Repositories []string `json:"repositories"`
    Bugs         string   `json:"bugs"`
}

/*
Convert PackageMeta to json
*/
func (meta *PackageMeta) ToJson() (content []byte, err error) {
    content, err = json.Marshal(meta)
    return
}

func (meta *PackageMeta) FromJson(content []byte) error {
    return json.Unmarshal(content, meta)
}
<commit_msg>[test] change PackageMeta field from [][]byte to []string<commit_after>package gopm_index

import (
    "encoding/json"
)

type PackageMeta struct {
    Name         string   `json:"name"`
    Description  string   `json:"description"`
    Category     string   `json:"category"`
    Keywords     []string `json:"keywords"`
    Author       []string `json:"author"`
    Contributors []string `json:"contributors"`
    Repositories []string `json:"repositories"`
    Bugs         string   `json:"bugs"`
}

/*
Convert PackageMeta to json
*/
func (meta *PackageMeta) ToJson() (content []byte, err error) {
    content, err = json.Marshal(meta)
    return
}

func (meta *PackageMeta) FromJson(content []byte) error {
    return json.Unmarshal(content, meta)
}
<|endoftext|>


<commit_before>package scoop_protocol

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"strings"
	"time"

	"github.com/twitchscience/scoop_protocol/msg_signer"
)

type ColumnDefinition struct {
	InboundName           string
	OutboundName          string
	Transformer           string // this should match one of the types in redshift types
	ColumnCreationOptions string
}

type Config struct {
	EventName string
	Columns   []ColumnDefinition
}

type RowCopyRequest struct {
	KeyName   string
	TableName string
}

type ManifestRowCopyRequest struct {
	ManifestURL string
	TableName   string
}

type LoadCheckRequest struct {
	ManifestURL string
}

type LoadCheckResponse struct {
	LoadStatus  LoadStatus
	ManifestURL string
}

//Scoop healthcheck for ingester healthcheck json unmarshal
type ConnError struct {
	RedshiftDBConnError, IngesterDBConnError *string
}

type LoadStatus string

const (
	LoadNotFound   LoadStatus = "load-not-found"
	LoadFailed     LoadStatus = "load-failed"
	LoadInProgress LoadStatus = "load-in-progress"
	LoadComplete   LoadStatus = "load-complete"
)

type ScoopSigner interface {
	GetConfig(io.Reader) (*Config, error)
	GetRowCopyRequest(io.Reader) (*RowCopyRequest, error)
	SignJsonBody(interface{}) ([]byte, error)
	SignBody([]byte) ([]byte, error)
}

type FakeScoopSigner struct{}

type AuthScoopSigner struct {
	TimeSigner *msg_signer.TimeSigner
	Exp        time.Duration
}

var (
	BadVerified        error = errors.New("Bad Signature")
	transformerTypeMap       = map[string]string{
		"ipCity":       "varchar(64)",
		"ipCountry":    "varchar(2)",
		"ipRegion":     "varchar(64)",
		"ipAsn":        "varchar(128)",
		"ipAsnInteger": "int",
		"f@timestamp":  "datetime",
	}
)

// For now we are turning off the signer
func GetScoopSigner() ScoopSigner {
	return &FakeScoopSigner{}
}

func (s *AuthScoopSigner) SignJsonBody(o interface{}) ([]byte, error) {
	req, err := json.Marshal(o)
	if err != nil {
		return nil, err
	}
	return s.SignBody(req)
}

func (s *AuthScoopSigner) SignBody(b []byte) ([]byte, error) {
	return s.TimeSigner.Sign(b), nil
}

func (s *AuthScoopSigner) GetConfig(body io.Reader) (*Config, error) {
	msg, verified := s.TimeSigner.PagedVerify(body, s.Exp)
	if !verified {
		return nil, BadVerified
	}

	c := new(Config)
	err := json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *AuthScoopSigner) GetRowCopyRequest(body io.Reader) (*RowCopyRequest, error) {
	msg, verified := s.TimeSigner.PagedVerify(body, s.Exp)
	if !verified {
		return nil, BadVerified
	}

	c := new(RowCopyRequest)
	err := json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *FakeScoopSigner) SignJsonBody(o interface{}) ([]byte, error) {
	req, err := json.Marshal(o)
	if err != nil {
		return nil, err
	}
	return s.SignBody(req)
}

// does nothing
func (s *FakeScoopSigner) SignBody(b []byte) ([]byte, error) {
	return b, nil
}

func (s *FakeScoopSigner) GetConfig(b io.Reader) (*Config, error) {
	c := new(Config)
	msg, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *FakeScoopSigner) GetRowCopyRequest(b io.Reader) (*RowCopyRequest, error) {
	c := new(RowCopyRequest)
	msg, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (c *Config) GetColumnCreationString() string {
	out := bytes.NewBuffer(make([]byte, 0, 256))
	out.WriteRune('(')
	for i, col := range c.Columns {
		out.WriteString(col.GetCreationForm())
		if i+1 != len(c.Columns) {
			out.WriteRune(',')
		}
	}
	out.WriteRune(')')
	return out.String()
}

func (col *ColumnDefinition) GetCreationForm() string {
	buf := bytes.NewBuffer(make([]byte, 0, 16))
	buf.WriteString(col.OutboundName)
	buf.WriteString(" ")
	if translatedType, ok := transformerTypeMap[col.Transformer]; ok {
		buf.WriteString(translatedType)
	} else if len(col.Transformer) > 0 && col.Transformer[0] == 'f' && col.Transformer[1] == '@' {
		// Its a function transformer
		canonicalName := col.Transformer[:strings.LastIndex(col.Transformer, "@")]
		if translatedType, ok := transformerTypeMap[canonicalName]; ok {
			buf.WriteString(translatedType)
		} else {
			buf.WriteString(col.Transformer)
		}
	} else {
		buf.WriteString(col.Transformer)
	}
	if len(col.ColumnCreationOptions) > 1 {
		buf.WriteString(col.ColumnCreationOptions)
	}
	return buf.String()
}
<commit_msg>Remove annotation and change name for better style<commit_after>package scoop_protocol

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"strings"
	"time"

	"github.com/twitchscience/scoop_protocol/msg_signer"
)

type ColumnDefinition struct {
	InboundName           string
	OutboundName          string
	Transformer           string // this should match one of the types in redshift types
	ColumnCreationOptions string
}

type Config struct {
	EventName string
	Columns   []ColumnDefinition
}

type RowCopyRequest struct {
	KeyName   string
	TableName string
}

type ManifestRowCopyRequest struct {
	ManifestURL string
	TableName   string
}

type LoadCheckRequest struct {
	ManifestURL string
}

type LoadCheckResponse struct {
	LoadStatus  LoadStatus
	ManifestURL string
}

type ScoopHealthCheck struct {
	RedshiftDBConnError *string
	IngesterDBConnError *string
}

type LoadStatus string

const (
	LoadNotFound   LoadStatus = "load-not-found"
	LoadFailed     LoadStatus = "load-failed"
	LoadInProgress LoadStatus = "load-in-progress"
	LoadComplete   LoadStatus = "load-complete"
)

type ScoopSigner interface {
	GetConfig(io.Reader) (*Config, error)
	GetRowCopyRequest(io.Reader) (*RowCopyRequest, error)
	SignJsonBody(interface{}) ([]byte, error)
	SignBody([]byte) ([]byte, error)
}

type FakeScoopSigner struct{}

type AuthScoopSigner struct {
	TimeSigner *msg_signer.TimeSigner
	Exp        time.Duration
}

var (
	BadVerified        error = errors.New("Bad Signature")
	transformerTypeMap       = map[string]string{
		"ipCity":       "varchar(64)",
		"ipCountry":    "varchar(2)",
		"ipRegion":     "varchar(64)",
		"ipAsn":        "varchar(128)",
		"ipAsnInteger": "int",
		"f@timestamp":  "datetime",
	}
)

// For now we are turning off the signer
func GetScoopSigner() ScoopSigner {
	return &FakeScoopSigner{}
}

func (s *AuthScoopSigner) SignJsonBody(o interface{}) ([]byte, error) {
	req, err := json.Marshal(o)
	if err != nil {
		return nil, err
	}
	return s.SignBody(req)
}

func (s *AuthScoopSigner) SignBody(b []byte) ([]byte, error) {
	return s.TimeSigner.Sign(b), nil
}

func (s *AuthScoopSigner) GetConfig(body io.Reader) (*Config, error) {
	msg, verified := s.TimeSigner.PagedVerify(body, s.Exp)
	if !verified {
		return nil, BadVerified
	}

	c := new(Config)
	err := json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *AuthScoopSigner) GetRowCopyRequest(body io.Reader) (*RowCopyRequest, error) {
	msg, verified := s.TimeSigner.PagedVerify(body, s.Exp)
	if !verified {
		return nil, BadVerified
	}

	c := new(RowCopyRequest)
	err := json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *FakeScoopSigner) SignJsonBody(o interface{}) ([]byte, error) {
	req, err := json.Marshal(o)
	if err != nil {
		return nil, err
	}
	return s.SignBody(req)
}

// does nothing
func (s *FakeScoopSigner) SignBody(b []byte) ([]byte, error) {
	return b, nil
}

func (s *FakeScoopSigner) GetConfig(b io.Reader) (*Config, error) {
	c := new(Config)
	msg, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (s *FakeScoopSigner) GetRowCopyRequest(b io.Reader) (*RowCopyRequest, error) {
	c := new(RowCopyRequest)
	msg, err := ioutil.ReadAll(b)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(msg, c)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (c *Config) GetColumnCreationString() string {
	out := bytes.NewBuffer(make([]byte, 0, 256))
	out.WriteRune('(')
	for i, col := range c.Columns {
		out.WriteString(col.GetCreationForm())
		if i+1 != len(c.Columns) {
			out.WriteRune(',')
		}
	}
	out.WriteRune(')')
	return out.String()
}

func (col *ColumnDefinition) GetCreationForm() string {
	buf := bytes.NewBuffer(make([]byte, 0, 16))
	buf.WriteString(col.OutboundName)
	buf.WriteString(" ")
	if translatedType, ok := transformerTypeMap[col.Transformer]; ok {
		buf.WriteString(translatedType)
	} else if len(col.Transformer) > 0 && col.Transformer[0] == 'f' && col.Transformer[1] == '@' {
		// Its a function transformer
		canonicalName := col.Transformer[:strings.LastIndex(col.Transformer, "@")]
		if translatedType, ok := transformerTypeMap[canonicalName]; ok {
			buf.WriteString(translatedType)
		} else {
			buf.WriteString(col.Transformer)
		}
	} else {
		buf.WriteString(col.Transformer)
	}
	if len(col.ColumnCreationOptions) > 1 {
		buf.WriteString(col.ColumnCreationOptions)
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package goship

import (
	"fmt"
	"path/filepath"

	"github.com/coreos/go-etcd/etcd"
)

// gitHubPaginationLimit is the default pagination limit for requests to the GitHub API that return multiple items.
const (
	gitHubPaginationLimit = 30
	pivotalCommentURL     = "https://www.pivotaltracker.com/services/v5/projects/%s/stories/%s/comments"
	gitHubAPITokenEnvVar  = "GITHUB_API_TOKEN"
)

// Host stores information on a host, such as URI and the latest commit revision.
type Host struct {
	URI             string
	LatestCommit    string
	GitHubCommitURL string
	GitHubDiffURL   string
	ShortCommitHash string
}

// Environment stores information about an individual environment, such as its name and whether it is deployable.
type Environment struct {
	Name               string
	Deploy             string
	RepoPath           string
	Hosts              []Host
	Branch             string
	Revision           string
	LatestGitHubCommit string
	IsDeployable       bool
}

// Project stores information about a GitHub project, such as its GitHub URL and repo name.
type Project struct {
	Name         string
	GitHubURL    string
	RepoName     string
	RepoOwner    string
	Environments []Environment
}

// gitHubCommitURL takes a project and returns the GitHub URL for its latest commit hash.
func (h *Host) LatestGitHubCommitURL(p Project) string {
	return fmt.Sprintf("%s/commit/%s", p.GitHubURL, h.LatestCommit)
}

// gitHubDiffURL takes a project and an environment and returns the GitHub diff URL
// for the latest commit on the host compared to the latest commit on GitHub.
func (h *Host) LatestGitHubDiffURL(p Project, e Environment) string {
	var s string
	if h.LatestCommit != e.LatestGitHubCommit {
		s = fmt.Sprintf("%s/compare/%s...%s", p.GitHubURL, h.LatestCommit, e.LatestGitHubCommit)
	}
	return s
}

// Deployable returns true if the latest commit for any of the hosts in an environment
// differs from the latest commit on GitHub, and false if all of the commits match.
func (e *Environment) Deployable() bool {
	for _, h := range e.Hosts {
		if e.LatestGitHubCommit != h.LatestCommit {
			return true
		}
	}
	return false
}

// ShortCommitHash returns a shortened version of the latest commit hash on a host.
func (h *Host) LatestShortCommitHash() string {
	if len(h.LatestCommit) == 0 {
		return ""
	}
	return h.LatestCommit[:7]
}

// config contains the information from config.yml.
type Config struct {
	Projects   []Project
	DeployUser string
	Notify     string
	Pivotal    *PivotalConfiguration
}

type PivotalConfiguration struct {
	Project string
	Token   string
}

type ETCDInterface interface {
	Get(string, bool, bool) (*etcd.Response, error)
}

// ProjectFromName takes a project name as a string and returns
// a Project by that name if it can find one.
func ProjectFromName(projects []Project, projectName string) (*Project, error) {
	for _, project := range projects {
		if project.Name == projectName {
			return &project, nil
		}
	}
	return nil, fmt.Errorf("No project found: %s", projectName)
}

// EnvironmentFromName takes an environment and project name as a string and returns
// an Environment by the given environment name under a project with the given
// project name if it can find one.
func EnvironmentFromName(projects []Project, projectName, environmentName string) (*Environment, error) {
	p, err := ProjectFromName(projects, projectName)
	if err != nil {
		return nil, err
	}
	for _, environment := range p.Environments {
		if environment.Name == environmentName {
			return &environment, nil
		}
	}
	return nil, fmt.Errorf("No environment found: %s", environmentName)
}

// connects to ETCD and returns the appropriate structs and strings.
func ParseETCD(client ETCDInterface) (c Config, err error) {
	baseInfo, err := client.Get("/", false, false)
	if err != nil {
		return c, err
	}
	deployUser := ""
	pivotalProject := ""
	token := ""
	notify := ""
	for _, b := range baseInfo.Node.Nodes {
		switch filepath.Base(b.Key) {
		case "deploy_user":
			deployUser = b.Value
		case "pivotal_project":
			pivotalProject = filepath.Base(b.Value)
		case "token":
			token = filepath.Base(b.Value)
		case "notify":
			notify = filepath.Base(b.Value)
		}
	}

	allProjects := []Project{}
	//  Get Projects //
	projectNodes, err := client.Get("/projects", false, false)
	if err != nil {
		return c, err
	}
	for _, p := range projectNodes.Node.Nodes {
		name := filepath.Base(p.Key)
		projectNode, err := client.Get("/projects/"+name, false, false)
		if err != nil {
			return c, err
		}
		projectInfo := projectNode.Node.Nodes
		repoOwner := ""
		repoName := ""
		for _, k := range projectInfo {
			switch filepath.Base(k.Key) {
			case "repo_owner":
				repoOwner = filepath.Base(k.Value)
			case "repo_name":
				repoName = filepath.Base(k.Value)
			}
		}
		githubURL := fmt.Sprintf("https://github.com/%s/%s", repoOwner, repoName)
		proj := Project{Name: name, GitHubURL: githubURL, RepoName: repoName, RepoOwner: repoOwner}
		environments, err := client.Get("/projects/"+name+"/environments", false, false)
		if err != nil {
			return c, err
		}
		allEnvironments := []Environment{}
		for _, e := range environments.Node.Nodes {
			envSettings, err := client.Get("/projects/"+name+"/environments/"+filepath.Base(e.Key), false, false)
			envName := filepath.Base(e.Key)
			revision := "head"
			branch := "master"
			deploy := ""
			repoPath := ""
			for _, n := range envSettings.Node.Nodes {
				switch filepath.Base(n.Key) {
				case "revision":
					revision = n.Value
				case "branch":
					branch = n.Value
				case "deploy":
					deploy = n.Value
				case "repo_path":
					repoPath = n.Value
				}
			}
			//  Get Hosts per Environment.
			hosts, err := client.Get("/projects/"+name+"/environments/"+envName+"/hosts", false, false)
			if err != nil {
				return c, err
			}
			allHosts := []Host{}
			for _, h := range hosts.Node.Nodes {
				host := Host{URI: filepath.Base(h.Key)}
				allHosts = append(allHosts, host)
			}
			env := Environment{Name: envName, Deploy: deploy, RepoPath: repoPath, Branch: branch, Revision: revision}
			env.Hosts = allHosts
			allEnvironments = append(allEnvironments, env)
		}
		proj.Environments = allEnvironments
		allProjects = append(allProjects, proj)
	}
	piv := new(PivotalConfiguration)
	piv.Project = pivotalProject
	piv.Token = token
	c.Projects = allProjects
	c.DeployUser = deployUser
	c.Notify = notify
	c.Pivotal = piv

	return c, nil
}
<commit_msg>Redo a functions<commit_after>package goship

import (
	"fmt"
	"path/filepath"

	"github.com/coreos/go-etcd/etcd"
)

// gitHubPaginationLimit is the default pagination limit for requests to the GitHub API that return multiple items.
const (
	gitHubPaginationLimit = 30
	pivotalCommentURL     = "https://www.pivotaltracker.com/services/v5/projects/%s/stories/%s/comments"
	gitHubAPITokenEnvVar  = "GITHUB_API_TOKEN"
)

// Host stores information on a host, such as URI and the latest commit revision.
type Host struct {
	URI             string
	LatestCommit    string
	GitHubCommitURL string
	GitHubDiffURL   string
	ShortCommitHash string
}

// Environment stores information about an individual environment, such as its name and whether it is deployable.
type Environment struct {
	Name               string
	Deploy             string
	RepoPath           string
	Hosts              []Host
	Branch             string
	Revision           string
	LatestGitHubCommit string
	IsDeployable       bool
}

// Project stores information about a GitHub project, such as its GitHub URL and repo name.
type Project struct {
	Name         string
	GitHubURL    string
	RepoName     string
	RepoOwner    string
	Environments []Environment
}

// gitHubCommitURL takes a project and returns the GitHub URL for its latest commit hash.
func (h *Host) LatestGitHubCommitURL(p Project) string {
	return fmt.Sprintf("%s/commit/%s", p.GitHubURL, h.LatestCommit)
}

// gitHubDiffURL takes a project and an environment and returns the GitHub diff URL
// for the latest commit on the host compared to the latest commit on GitHub.
func (h *Host) LatestGitHubDiffURL(p Project, e Environment) string {
	var s string
	if h.LatestCommit != e.LatestGitHubCommit {
		s = fmt.Sprintf("%s/compare/%s...%s", p.GitHubURL, h.LatestCommit, e.LatestGitHubCommit)
	}
	return s
}

// Deployable returns true if the latest commit for any of the hosts in an environment
// differs from the latest commit on GitHub, and false if all of the commits match.
func (e *Environment) Deployable() bool {
	for _, h := range e.Hosts {
		if e.LatestGitHubCommit != h.LatestCommit {
			return true
		}
	}
	return false
}

// ShortCommitHash returns a shortened version of the latest commit hash on a host.
func (h *Host) LatestShortCommitHash() string {
	if len(h.LatestCommit) == 0 {
		return ""
	}
	return h.LatestCommit[:7]
}

// config contains the information from config.yml.
type Config struct {
	Projects   []Project
	DeployUser string
	Notify     string
	Pivotal    *PivotalConfiguration
}

type PivotalConfiguration struct {
	Project string
	Token   string
}

type ETCDInterface interface {
	Get(string, bool, bool) (*etcd.Response, error)
}

// ProjectFromName takes a project name as a string and returns
// a Project by that name if it can find one.
func ProjectFromName(projects []Project, projectName string) (*Project, error) {
	for _, project := range projects {
		if project.Name == projectName {
			return &project, nil
		}
	}
	return nil, fmt.Errorf("No project found: %s", projectName)
}

// EnvironmentFromName takes an environment and project name as a string and returns
// an Environment by the given environment name under a project with the given
// project name if it can find one.
func EnvironmentFromName(projects []Project, projectName, environmentName string) (*Environment, error) {
	p, err := ProjectFromName(projects, projectName)
	if err != nil {
		return nil, err
	}
	for _, environment := range p.Environments {
		if environment.Name == environmentName {
			return &environment, nil
		}
	}
	return nil, fmt.Errorf("No environment found: %s", environmentName)
}

// connects to ETCD and returns the appropriate structs and strings.
func ParseETCD(client ETCDInterface) (c Config, err error) {
	baseInfo, err := client.Get("/", false, false)
	if err != nil {
		return c, err
	}
	deployUser := ""
	pivotalProject := ""
	token := ""
	notify := ""
	for _, b := range baseInfo.Node.Nodes {
		switch filepath.Base(b.Key) {
		case "deploy_user":
			deployUser = b.Value
		case "pivotal_project":
			pivotalProject = filepath.Base(b.Value)
		case "token":
			token = filepath.Base(b.Value)
		case "notify":
			notify = filepath.Base(b.Value)
		}
	}

	allProjects := []Project{}
	//  Get Projects //
	projectNodes, err := client.Get("/projects", false, false)
	if err != nil {
		return c, err
	}
	for _, p := range projectNodes.Node.Nodes {
		name := filepath.Base(p.Key)
		projectNode, err := client.Get("/projects/"+name, false, false)
		if err != nil {
			return c, err
		}
		projectInfo := projectNode.Node.Nodes
		repoOwner := ""
		repoName := ""
		for _, k := range projectInfo {
			switch filepath.Base(k.Key) {
			case "repo_owner":
				repoOwner = filepath.Base(k.Value)
			case "repo_name":
				repoName = filepath.Base(k.Value)
			}
		}
		githubURL := fmt.Sprintf("https://github.com/%s/%s", repoOwner, repoName)
		proj := Project{Name: name, GitHubURL: githubURL, RepoName: repoName, RepoOwner: repoOwner}
		environments, err := client.Get("/projects/"+name+"/environments", false, false)
		if err != nil {
			return c, err
		}
		allEnvironments := []Environment{}
		for _, e := range environments.Node.Nodes {
			envSettings, err := client.Get("/projects/"+name+"/environments/"+filepath.Base(e.Key), false, false)
			envName := filepath.Base(e.Key)
			revision := "head"
			branch := "master"
			deploy := ""
			repoPath := ""
			for _, n := range envSettings.Node.Nodes {
				switch filepath.Base(n.Key) {
				case "revision":
					revision = n.Value
				case "branch":
					branch = n.Value
				case "deploy":
					deploy = n.Value
				case "repo_path":
					repoPath = n.Value
				}
			}
			//  Get Hosts per Environment.
			hosts, err := client.Get("/projects/"+name+"/environments/"+envName+"/hosts", false, false)
			if err != nil {
				return c, err
			}
			allHosts := []Host{}
			for _, h := range hosts.Node.Nodes {
				host := Host{URI: filepath.Base(h.Key)}
				allHosts = append(allHosts, host)
			}
			env := Environment{Name: envName, Deploy: deploy, RepoPath: repoPath, Branch: branch, Revision: revision}
			env.Hosts = allHosts
			allEnvironments = append(allEnvironments, env)
		}
		proj.Environments = allEnvironments
		allProjects = append(allProjects, proj)
	}
	piv := new(PivotalConfiguration)
	piv.Project = pivotalProject
	piv.Token = token
	c.Projects = allProjects
	c.DeployUser = deployUser
	c.Notify = notify
	c.Pivotal = piv

	return c, err
}
<|endoftext|>


<commit_before>package utils

import "github.com/weave-lab/gossip/log"

// The buffer size of the primitive input and output chans.
const c_ELASTIC_CHANSIZE = 3

// A dynamic channel that does not block on send, but has an unlimited buffer capacity.
// ElasticChan uses a dynamic slice to buffer signals received on the input channel until
// the output channel is ready to process them.
type ElasticChan struct {
	In      chan interface{}
	Out     chan interface{}
	buffer  []interface{}
	stopped bool
}

// Initialise the Elastic channel, and start the management goroutine.
func (c *ElasticChan) Init() {
	c.In = make(chan interface{}, c_ELASTIC_CHANSIZE)
	c.Out = make(chan interface{}, c_ELASTIC_CHANSIZE)
	c.buffer = make([]interface{}, 0)

	go c.manage()
}

// Poll for input from one end of the channel and add it to the buffer.
// Also poll sending buffered signals out over the output chan.
func (c *ElasticChan) manage() {
	for {
		if len(c.buffer) > 0 {
			// The buffer has something in it, so try to send as well as
			// receive.
			// (Receive first in order to minimize blocked Send() calls).
			select {
			case in, ok := <-c.In:
				if !ok {
					log.Debug("Chan %p will dispose", c)
					break
				}
				log.Debug("Chan %p gets '%v'", c, in)
				c.buffer = append(c.buffer, in)
			case c.Out <- c.buffer[0]:
				log.Debug("Chan %p sends '%v'", c, c.buffer[0])
				c.buffer = c.buffer[1:]
			}
		} else {
			// The buffer is empty, so there's nothing to send.
			// Just wait to receive.
			in, ok := <-c.In
			if !ok {
				log.Debug("Chan %p will dispose", c)
				break
			}
			log.Debug("Chan %p gets '%v'", c, in)
			c.buffer = append(c.buffer, in)
		}
	}

	c.dispose()
}

func (c *ElasticChan) dispose() {
	log.Debug("Chan %p disposing...", c)
	for len(c.buffer) > 0 {
		c.Out <- c.buffer[0]
		c.buffer = c.buffer[1:]
	}
	log.Debug("Chan %p disposed", c)
}
<commit_msg>remove elasticchan<commit_after><|endoftext|>