<commit_before>/*
Copyright (C) 2016 Red Hat, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	goflag "flag"
	"io/ioutil"
	"os"

	"github.com/docker/machine/libmachine/log"
	"github.com/golang/glog"
	"github.com/jimmidyson/minishift/pkg/minikube/config"
	"github.com/jimmidyson/minishift/pkg/minikube/constants"
	"github.com/jimmidyson/minishift/pkg/minikube/update"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

var dirs = [...]string{
	constants.Minipath,
	constants.MakeMiniPath("certs"),
	constants.MakeMiniPath("machines"),
	constants.MakeMiniPath("cache"),
	constants.MakeMiniPath("cache", "iso"),
	constants.MakeMiniPath("cache", "localkube"),
	constants.MakeMiniPath("config")}

var (
	showLibmachineLogs bool
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "minishift",
	Short: "Minishift is a tool for managing local OpenShift clusters.",
	Long:  `Minishift is a CLI tool that provisions and manages single-node OpenShift clusters optimized for development workflows.`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		for _, path := range dirs {
			if err := os.MkdirAll(path, 0777); err != nil {
				glog.Exitf("Error creating minishift directory: %s", err)
			}
		}

		if !showLibmachineLogs {
			log.SetOutWriter(ioutil.Discard)
			log.SetErrWriter(ioutil.Discard)
		}
		update.MaybeUpdateFromGithub(os.Stdout)
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		glog.Exitln(err)
	}
}

func init() {
	RootCmd.PersistentFlags().BoolVarP(&showLibmachineLogs, "show-libmachine-logs", "", false, "Whether or not to show logs from libmachine.")
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	cobra.OnInitialize(initConfig)
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	viper.SetConfigName("config")
	viper.AddConfigPath(constants.MakeMiniPath("config"))
	err := viper.ReadInConfig()
	if err != nil {
		glog.Warningf("Error reading config file: %s", err)
	}
	viper.SetDefault(config.WantUpdateNotification, true)
	viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
}
<commit_msg>Added config path to warning message<commit_after>/*
Copyright (C) 2016 Red Hat, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
	goflag "flag"
	"io/ioutil"
	"os"

	"github.com/docker/machine/libmachine/log"
	"github.com/golang/glog"
	"github.com/jimmidyson/minishift/pkg/minikube/config"
	"github.com/jimmidyson/minishift/pkg/minikube/constants"
	"github.com/jimmidyson/minishift/pkg/minikube/update"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

var dirs = [...]string{
	constants.Minipath,
	constants.MakeMiniPath("certs"),
	constants.MakeMiniPath("machines"),
	constants.MakeMiniPath("cache"),
	constants.MakeMiniPath("cache", "iso"),
	constants.MakeMiniPath("cache", "localkube"),
	constants.MakeMiniPath("config")}

var (
	showLibmachineLogs bool
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "minishift",
	Short: "Minishift is a tool for managing local OpenShift clusters.",
	Long:  `Minishift is a CLI tool that provisions and manages single-node OpenShift clusters optimized for development workflows.`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		for _, path := range dirs {
			if err := os.MkdirAll(path, 0777); err != nil {
				glog.Exitf("Error creating minishift directory: %s", err)
			}
		}

		if !showLibmachineLogs {
			log.SetOutWriter(ioutil.Discard)
			log.SetErrWriter(ioutil.Discard)
		}
		update.MaybeUpdateFromGithub(os.Stdout)
	},
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		glog.Exitln(err)
	}
}

func init() {
	RootCmd.PersistentFlags().BoolVarP(&showLibmachineLogs, "show-libmachine-logs", "", false, "Whether or not to show logs from libmachine.")
	pflag.CommandLine.AddGoFlagSet(goflag.CommandLine)
	cobra.OnInitialize(initConfig)
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	configPath := constants.MakeMiniPath("config")
	viper.SetConfigName("config")
	viper.AddConfigPath(configPath)
	err := viper.ReadInConfig()
	if err != nil {
		glog.Warningf("Error reading config file at %s: %s", configPath, err)
	}
	viper.SetDefault(config.WantUpdateNotification, true)
	viper.SetDefault(config.ReminderWaitPeriodInHours, 24)
}
<|endoftext|>


<commit_before>// Copyright 2016 The NorthShore Authors 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 cmd

import (
	"log"

	"github.com/looplab/fsm"
)

// BlueprintState represents a state of the Blueprint
type BlueprintState byte

// StageState represents a state of the Stage
type StageState byte

const (
	// BlueprintStateNew is default state of the Blueprint
	BlueprintStateNew BlueprintState = iota
	// BlueprintStateProvision is the Blueprint status while provisioning
	BlueprintStateProvision
	// BlueprintStateActive is the Blueprint status when all Stages are up and ready
	BlueprintStateActive
	// BlueprintStateInactive is the Blueprint status when some Stage is down
	BlueprintStateInactive
)

const (
	// StageStateNew is default state of the Stage
	StageStateNew StageState = iota
	// StageStateCreated indicates that container is created
	StageStateCreated
	// StageStateRunning indicates that container is running
	StageStateRunning
	// StageStatePaused indicates that container is paused
	StageStatePaused
	// StageStateStoped indicates that container is stoped
	StageStateStoped
	// StageStateDeleted indicates that container is deleted
	StageStateDeleted
)

func (state BlueprintState) String() string {
	states := []string{
		"new",
		"provision",
		"active",
		"inactive",
	}
	return states[state]
}

func (state StageState) String() string {
	states := []string{
		"new",
		"created",
		"running",
		"paused",
		"stoped",
		"deleted",
	}
	return states[state]
}

// BlueprintPipeline represents a Blueprint Pipeline
type BlueprintPipeline struct {
	// State is current Pipeline status
	State BlueprintState
	// StagesStates represents statuses of Pipeline Stages
	StagesStates map[string]StageState
	// fSM is the finite state machine of Pipeline
	fSM *fsm.FSM
}

// NewBlueprintPipeline constructs a Blueprint Pipeline with Stages
func NewBlueprintPipeline(stages []string) *BlueprintPipeline {
	plStages := map[string]StageState{}
	for _, v := range stages {
		plStages[v] = StageStateNew
	}

	pl := &BlueprintPipeline{
		BlueprintStateNew,
		plStages,
		nil,
	}

	// https://godoc.org/github.com/looplab/fsm#NewFSM
	pl.fSM = fsm.NewFSM(
		"new",
		fsm.Events{
			{
				Name: "activate",
				Src:  []string{"inactive", "provision"},
				Dst:  "active",
			},
			{
				Name: "inactivate",
				Src:  []string{"active", "provision"},
				Dst:  "inactive",
			},
			{
				Name: "start",
				Src:  []string{"new"},
				Dst:  "provision",
			},
		},
		fsm.Callbacks{
			"after_event": func(e *fsm.Event) { pl.afterEvent(e) },
			"activate":    func(e *fsm.Event) { pl.afterActivate(e) },
			"inactivate":  func(e *fsm.Event) { pl.afterInactivate(e) },
			"start":       func(e *fsm.Event) { pl.afterStart(e) },
		},
	)

	return pl
}

func (pl *BlueprintPipeline) afterEvent(e *fsm.Event) {
	log.Printf("#BlueprintPipeline,#afterEvent %+v %+v", e, pl)
}

func (pl *BlueprintPipeline) afterActivate(e *fsm.Event) {
	stagesStates := e.Args[0].(map[string]StageState)
	for k, v := range stagesStates {
		pl.StagesStates[k] = v
	}

	for _, v := range pl.StagesStates {
		if v != StageStateRunning {
			e.Cancel()
			return
		}
	}
	pl.State = BlueprintStateActive
}

func (pl *BlueprintPipeline) afterInactivate(e *fsm.Event) {
	stagesStates := e.Args[0].(map[string]StageState)
	for k, v := range stagesStates {
		pl.StagesStates[k] = v
	}
	pl.State = BlueprintStateInactive
}

func (pl *BlueprintPipeline) afterStart(e *fsm.Event) {
	pl.State = BlueprintStateProvision
}

// Start creates and runs Stages in Blueprint Pipeline
func (pl *BlueprintPipeline) Start() {
	pl.fSM.Event("start")
}

// Update updates current Blueprint Pipeline status with Stages
func (pl *BlueprintPipeline) Update(stagesStates map[string]StageState) {
	for _, v := range stagesStates {
		switch v {
		case
			StageStatePaused,
			StageStateStoped,
			StageStateDeleted:
			pl.fSM.Event("inactivate", stagesStates)
			return
		}
	}
	pl.fSM.Event("activate", stagesStates)
}
<commit_msg>Fix events in FSM<commit_after>// Copyright 2016 The NorthShore Authors 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 cmd

import (
	"log"

	"github.com/looplab/fsm"
)

// BlueprintState represents a state of the Blueprint
type BlueprintState byte

// StageState represents a state of the Stage
type StageState byte

const (
	// BlueprintStateNew is default state of the Blueprint
	BlueprintStateNew BlueprintState = iota
	// BlueprintStateProvision is the Blueprint status while provisioning
	BlueprintStateProvision
	// BlueprintStateActive is the Blueprint status when all Stages are up and ready
	BlueprintStateActive
	// BlueprintStateInactive is the Blueprint status when some Stage is down
	BlueprintStateInactive
)

const (
	// StageStateNew is default state of the Stage
	StageStateNew StageState = iota
	// StageStateCreated indicates that container is created
	StageStateCreated
	// StageStateRunning indicates that container is running
	StageStateRunning
	// StageStatePaused indicates that container is paused
	StageStatePaused
	// StageStateStoped indicates that container is stoped
	StageStateStoped
	// StageStateDeleted indicates that container is deleted
	StageStateDeleted
)

func (state BlueprintState) String() string {
	states := []string{
		"new",
		"provision",
		"active",
		"inactive",
	}
	return states[state]
}

func (state StageState) String() string {
	states := []string{
		"new",
		"created",
		"running",
		"paused",
		"stoped",
		"deleted",
	}
	return states[state]
}

// BlueprintPipeline represents a Blueprint Pipeline
type BlueprintPipeline struct {
	// State is current Pipeline status
	State BlueprintState
	// StagesStates represents statuses of Pipeline Stages
	StagesStates map[string]StageState
	// fSM is the finite state machine of Pipeline
	fSM *fsm.FSM
}

// NewBlueprintPipeline constructs a Blueprint Pipeline with Stages
func NewBlueprintPipeline(stages []string) *BlueprintPipeline {
	plStages := map[string]StageState{}
	for _, v := range stages {
		plStages[v] = StageStateNew
	}

	pl := &BlueprintPipeline{
		BlueprintStateNew,
		plStages,
		nil,
	}

	// https://godoc.org/github.com/looplab/fsm#NewFSM
	pl.fSM = fsm.NewFSM(
		"new",
		fsm.Events{
			{
				Name: "activate",
				Src:  []string{"inactive", "provision"},
				Dst:  "active",
			},
			{
				Name: "inactivate",
				Src:  []string{"active", "provision"},
				Dst:  "inactive",
			},
			{
				Name: "start",
				Src:  []string{"new"},
				Dst:  "provision",
			},
		},
		fsm.Callbacks{
			"before_activate": func(e *fsm.Event) { pl.beforeActivate(e) },
			"after_event":     func(e *fsm.Event) { pl.afterEvent(e) },
			"activate":        func(e *fsm.Event) { pl.afterActivate(e) },
			"inactivate":      func(e *fsm.Event) { pl.afterInactivate(e) },
			"start":           func(e *fsm.Event) { pl.afterStart(e) },
		},
	)

	return pl
}

func (pl *BlueprintPipeline) afterEvent(e *fsm.Event) {
	log.Printf("#BlueprintPipeline,#afterEvent %+v %+v", e, pl)
}

func (pl *BlueprintPipeline) beforeActivate(e *fsm.Event) {
	for _, v := range pl.StagesStates {
		if v != StageStateRunning {
			e.Cancel()
		}
	}
}

func (pl *BlueprintPipeline) afterActivate(e *fsm.Event) {
	pl.State = BlueprintStateActive
}

func (pl *BlueprintPipeline) afterInactivate(e *fsm.Event) {
	pl.State = BlueprintStateInactive
}

func (pl *BlueprintPipeline) afterStart(e *fsm.Event) {
	pl.State = BlueprintStateProvision
}

// Start creates and runs Stages in Blueprint Pipeline
func (pl *BlueprintPipeline) Start() {
	pl.fSM.Event("start")
}

// Update updates current Blueprint Pipeline status with Stages
func (pl *BlueprintPipeline) Update(stagesStates map[string]StageState) {
	event := "activate"
	for k, v := range stagesStates {
		pl.StagesStates[k] = v
		switch v {
		case
			StageStatePaused,
			StageStateStoped,
			StageStateDeleted:
			event = "inactivate"
		}
	}

	err := pl.fSM.Event(event, stagesStates)
	if err != nil {
		log.Println("#BlueprintPipeline,#Update,#Error", err)
	}
}
<|endoftext|>


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

// The starlark command interprets a Starlark file.
// With no arguments, it starts a read-eval-print loop (REPL).
package main // import "go.starlark.net/cmd/starlark"

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"strings"

	"go.starlark.net/repl"
	"go.starlark.net/resolve"
	"go.starlark.net/starlark"
)

// flags
var (
	cpuprofile = flag.String("cpuprofile", "", "gather CPU profile in this file")
	showenv    = flag.Bool("showenv", false, "on success, print final global environment")
	execprog   = flag.String("c", "", "execute program `prog`")
)

// non-standard dialect flags
func init() {
	flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "allow floating-point numbers")
	flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type")
	flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions")
	flag.BoolVar(&resolve.AllowNestedDef, "nesteddef", resolve.AllowNestedDef, "allow nested def statements")
	flag.BoolVar(&resolve.AllowBitwise, "bitwise", resolve.AllowBitwise, "allow bitwise operations (&, |, ^, ~, <<, and >>)")
	flag.BoolVar(&resolve.AllowRecursion, "recursion", resolve.AllowRecursion, "allow while statements and recursive functions")
	flag.BoolVar(&resolve.AllowGlobalReassign, "globalreassign", resolve.AllowGlobalReassign, "allow reassignment of globals, and if/for/while statements at top level")
}

func main() {
	log.SetPrefix("starlark: ")
	log.SetFlags(0)
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal(err)
		}
		defer pprof.StopCPUProfile()
	}

	thread := &starlark.Thread{Load: repl.MakeLoad()}
	globals := make(starlark.StringDict)

	switch {
	case flag.NArg() == 1 || *execprog != "":
		var (
			filename string
			src      interface{}
			err      error
		)
		if *execprog != "" {
			// Execute provided program.
			filename = "cmdline"
			src = *execprog
		} else {
			// Execute specified file.
			filename = flag.Arg(0)
		}
		thread.Name = "exec " + filename
		globals, err = starlark.ExecFile(thread, filename, src, nil)
		if err != nil {
			repl.PrintError(err)
			os.Exit(1)
		}
	case flag.NArg() == 0:
		fmt.Println("Welcome to Starlark (go.starlark.net)")
		thread.Name = "REPL"
		repl.REPL(thread, globals)
	default:
		log.Fatal("want at most one Starlark file name")
	}

	// Print the global environment.
	if *showenv {
		for _, name := range globals.Keys() {
			if strings.HasPrefix(name, "_") {
				fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name])
			}
		}
	}
}
<commit_msg>cmd/starlark: fix sense of -showenv, flipped my mistake<commit_after>// Copyright 2017 The Bazel Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The starlark command interprets a Starlark file.
// With no arguments, it starts a read-eval-print loop (REPL).
package main // import "go.starlark.net/cmd/starlark"

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime/pprof"
	"strings"

	"go.starlark.net/repl"
	"go.starlark.net/resolve"
	"go.starlark.net/starlark"
)

// flags
var (
	cpuprofile = flag.String("cpuprofile", "", "gather CPU profile in this file")
	showenv    = flag.Bool("showenv", false, "on success, print final global environment")
	execprog   = flag.String("c", "", "execute program `prog`")
)

// non-standard dialect flags
func init() {
	flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "allow floating-point numbers")
	flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type")
	flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions")
	flag.BoolVar(&resolve.AllowNestedDef, "nesteddef", resolve.AllowNestedDef, "allow nested def statements")
	flag.BoolVar(&resolve.AllowBitwise, "bitwise", resolve.AllowBitwise, "allow bitwise operations (&, |, ^, ~, <<, and >>)")
	flag.BoolVar(&resolve.AllowRecursion, "recursion", resolve.AllowRecursion, "allow while statements and recursive functions")
	flag.BoolVar(&resolve.AllowGlobalReassign, "globalreassign", resolve.AllowGlobalReassign, "allow reassignment of globals, and if/for/while statements at top level")
}

func main() {
	log.SetPrefix("starlark: ")
	log.SetFlags(0)
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal(err)
		}
		defer pprof.StopCPUProfile()
	}

	thread := &starlark.Thread{Load: repl.MakeLoad()}
	globals := make(starlark.StringDict)

	switch {
	case flag.NArg() == 1 || *execprog != "":
		var (
			filename string
			src      interface{}
			err      error
		)
		if *execprog != "" {
			// Execute provided program.
			filename = "cmdline"
			src = *execprog
		} else {
			// Execute specified file.
			filename = flag.Arg(0)
		}
		thread.Name = "exec " + filename
		globals, err = starlark.ExecFile(thread, filename, src, nil)
		if err != nil {
			repl.PrintError(err)
			os.Exit(1)
		}
	case flag.NArg() == 0:
		fmt.Println("Welcome to Starlark (go.starlark.net)")
		thread.Name = "REPL"
		repl.REPL(thread, globals)
	default:
		log.Fatal("want at most one Starlark file name")
	}

	// Print the global environment.
	if *showenv {
		for _, name := range globals.Keys() {
			if !strings.HasPrefix(name, "_") {
				fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name])
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	_ "github.com/jackwilsdon/svnwatch/types"
)

func fatalf(format interface{}, a ...interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], fmt.Sprintf(fmt.Sprint(format), a...))
	os.Exit(1)
}

func main() {
	configDir := flag.String("config", "/etc/svnwatch", "the configuration directory for svnwatch")
	interval := flag.Int("interval", 0, "how often to check for updates (0 disables this and exists after a single check)")

	flag.Parse()

	watcher, err := loadWatcher(*configDir)

	if *interval < 0 {
		fatalf("%s: invalid interval: %d", os.Args[0], *interval)
	}

	if err != nil {
		fatalf(err)
	}

	for {
		if err := watcher.update(); err != nil {
			fatalf(err)
		}

		if err := watcher.save(*configDir); err != nil {
			fatalf(err)
		}

		if *interval > 0 {
			time.Sleep(time.Duration(*interval) * time.Second)
		} else {
			break
		}
	}
}
<commit_msg>Fix typo (exists -> exits)<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	_ "github.com/jackwilsdon/svnwatch/types"
)

func fatalf(format interface{}, a ...interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], fmt.Sprintf(fmt.Sprint(format), a...))
	os.Exit(1)
}

func main() {
	configDir := flag.String("config", "/etc/svnwatch", "the configuration directory for svnwatch")
	interval := flag.Int("interval", 0, "how often to check for updates (0 disables this and exits after a single check)")

	flag.Parse()

	watcher, err := loadWatcher(*configDir)

	if *interval < 0 {
		fatalf("%s: invalid interval: %d", os.Args[0], *interval)
	}

	if err != nil {
		fatalf(err)
	}

	for {
		if err := watcher.update(); err != nil {
			fatalf(err)
		}

		if err := watcher.save(*configDir); err != nil {
			fatalf(err)
		}

		if *interval > 0 {
			time.Sleep(time.Duration(*interval) * time.Second)
		} else {
			break
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	stdoutFirstLines []string // The first 10 lines of stdout
	stdoutLastLines  []string // The last 50 lines of stdout
	stdoutMut        sync.Mutex
)

const (
	countRestarts = 5
	loopThreshold = 15 * time.Second
)

func monitorMain() {
	os.Setenv("STNORESTART", "yes")
	os.Setenv("STMONITORED", "yes")
	l.SetPrefix("[monitor] ")

	args := os.Args
	var restarts [countRestarts]time.Time

	sign := make(chan os.Signal, 1)
	sigTerm := syscall.Signal(0xf)
	signal.Notify(sign, os.Interrupt, sigTerm, os.Kill)

	for {
		if t := time.Since(restarts[0]); t < loopThreshold {
			l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
			os.Exit(exitError)
		}

		copy(restarts[0:], restarts[1:])
		restarts[len(restarts)-1] = time.Now()

		cmd := exec.Command(args[0], args[1:]...)

		stderr, err := cmd.StderrPipe()
		if err != nil {
			l.Fatalln(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			l.Fatalln(err)
		}

		l.Infoln("Starting syncthing")
		err = cmd.Start()
		if err != nil {
			l.Fatalln(err)
		}

		stdoutMut.Lock()
		stdoutFirstLines = make([]string, 0, 10)
		stdoutLastLines = make([]string, 0, 50)
		stdoutMut.Unlock()

		go copyStderr(stderr)
		go copyStdout(stdout)

		exit := make(chan error)

		go func() {
			exit <- cmd.Wait()
		}()

		select {
		case s := <-sign:
			l.Infof("Signal %d received; exiting", s)
			cmd.Process.Kill()
			<-exit
			return

		case err = <-exit:
			if err == nil {
				// Successfull exit indicates an intentional shutdown
				return
			} else if exiterr, ok := err.(*exec.ExitError); ok {
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					switch status.ExitStatus() {
					case exitUpgrading:
						// Restart the monitor process to release the .old
						// binary as part of the upgrade process.
						l.Infoln("Restarting monitor...")
						os.Setenv("STNORESTART", "")
						err := exec.Command(args[0], args[1:]...).Start()
						if err != nil {
							l.Warnln("restart:", err)
						}
						return
					}
				}
			}
		}

		l.Infoln("Syncthing exited:", err)
		time.Sleep(1 * time.Second)

		// Let the next child process know that this is not the first time
		// it's starting up.
		os.Setenv("STRESTART", "yes")
	}
}

func copyStderr(stderr io.ReadCloser) {
	br := bufio.NewReader(stderr)

	var panicFd *os.File
	for {
		line, err := br.ReadString('\n')
		if err != nil {
			return
		}

		if panicFd == nil {
			os.Stderr.WriteString(line)

			if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
				panicFd, err = os.Create(filepath.Join(confDir, time.Now().Format("panic-20060102-150405.log")))
				if err != nil {
					l.Warnln("Create panic log:", err)
					continue
				}

				l.Warnf("Panic detected, writing to \"%s\"", panicFd.Name())
				l.Warnln("Please create an issue at https://github.com/syncthing/syncthing/issues/ with the panic log attached")

				panicFd.WriteString("Panic at " + time.Now().Format(time.RFC1123) + "\n")
				stdoutMut.Lock()
				for _, line := range stdoutFirstLines {
					panicFd.WriteString(line)
				}
				panicFd.WriteString("...\n")
				for _, line := range stdoutLastLines {
					panicFd.WriteString(line)
				}
			}
		}

		if panicFd != nil {
			panicFd.WriteString(line)
		}
	}
}

func copyStdout(stderr io.ReadCloser) {
	br := bufio.NewReader(stderr)
	for {
		line, err := br.ReadString('\n')
		if err != nil {
			return
		}

		stdoutMut.Lock()
		if len(stdoutFirstLines) < cap(stdoutFirstLines) {
			stdoutFirstLines = append(stdoutFirstLines, line)
		}
		if l := len(stdoutLastLines); l == cap(stdoutLastLines) {
			stdoutLastLines = stdoutLastLines[:l-1]
		}
		stdoutLastLines = append(stdoutLastLines, line)
		stdoutMut.Unlock()

		os.Stdout.WriteString(line)
	}
}
<commit_msg>Restarting monitor process is still considered a restart (fixes #809)<commit_after>// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"io"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"time"
)

var (
	stdoutFirstLines []string // The first 10 lines of stdout
	stdoutLastLines  []string // The last 50 lines of stdout
	stdoutMut        sync.Mutex
)

const (
	countRestarts = 5
	loopThreshold = 15 * time.Second
)

func monitorMain() {
	os.Setenv("STNORESTART", "yes")
	os.Setenv("STMONITORED", "yes")
	l.SetPrefix("[monitor] ")

	args := os.Args
	var restarts [countRestarts]time.Time

	sign := make(chan os.Signal, 1)
	sigTerm := syscall.Signal(0xf)
	signal.Notify(sign, os.Interrupt, sigTerm, os.Kill)

	for {
		if t := time.Since(restarts[0]); t < loopThreshold {
			l.Warnf("%d restarts in %v; not retrying further", countRestarts, t)
			os.Exit(exitError)
		}

		copy(restarts[0:], restarts[1:])
		restarts[len(restarts)-1] = time.Now()

		cmd := exec.Command(args[0], args[1:]...)

		stderr, err := cmd.StderrPipe()
		if err != nil {
			l.Fatalln(err)
		}

		stdout, err := cmd.StdoutPipe()
		if err != nil {
			l.Fatalln(err)
		}

		l.Infoln("Starting syncthing")
		err = cmd.Start()
		if err != nil {
			l.Fatalln(err)
		}

		// Let the next child process know that this is not the first time
		// it's starting up.
		os.Setenv("STRESTART", "yes")

		stdoutMut.Lock()
		stdoutFirstLines = make([]string, 0, 10)
		stdoutLastLines = make([]string, 0, 50)
		stdoutMut.Unlock()

		go copyStderr(stderr)
		go copyStdout(stdout)

		exit := make(chan error)

		go func() {
			exit <- cmd.Wait()
		}()

		select {
		case s := <-sign:
			l.Infof("Signal %d received; exiting", s)
			cmd.Process.Kill()
			<-exit
			return

		case err = <-exit:
			if err == nil {
				// Successfull exit indicates an intentional shutdown
				return
			} else if exiterr, ok := err.(*exec.ExitError); ok {
				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
					switch status.ExitStatus() {
					case exitUpgrading:
						// Restart the monitor process to release the .old
						// binary as part of the upgrade process.
						l.Infoln("Restarting monitor...")
						os.Setenv("STNORESTART", "")
						err := exec.Command(args[0], args[1:]...).Start()
						if err != nil {
							l.Warnln("restart:", err)
						}
						return
					}
				}
			}
		}

		l.Infoln("Syncthing exited:", err)
		time.Sleep(1 * time.Second)
	}
}

func copyStderr(stderr io.ReadCloser) {
	br := bufio.NewReader(stderr)

	var panicFd *os.File
	for {
		line, err := br.ReadString('\n')
		if err != nil {
			return
		}

		if panicFd == nil {
			os.Stderr.WriteString(line)

			if strings.HasPrefix(line, "panic:") || strings.HasPrefix(line, "fatal error:") {
				panicFd, err = os.Create(filepath.Join(confDir, time.Now().Format("panic-20060102-150405.log")))
				if err != nil {
					l.Warnln("Create panic log:", err)
					continue
				}

				l.Warnf("Panic detected, writing to \"%s\"", panicFd.Name())
				l.Warnln("Please create an issue at https://github.com/syncthing/syncthing/issues/ with the panic log attached")

				panicFd.WriteString("Panic at " + time.Now().Format(time.RFC1123) + "\n")
				stdoutMut.Lock()
				for _, line := range stdoutFirstLines {
					panicFd.WriteString(line)
				}
				panicFd.WriteString("...\n")
				for _, line := range stdoutLastLines {
					panicFd.WriteString(line)
				}
			}
		}

		if panicFd != nil {
			panicFd.WriteString(line)
		}
	}
}

func copyStdout(stderr io.ReadCloser) {
	br := bufio.NewReader(stderr)
	for {
		line, err := br.ReadString('\n')
		if err != nil {
			return
		}

		stdoutMut.Lock()
		if len(stdoutFirstLines) < cap(stdoutFirstLines) {
			stdoutFirstLines = append(stdoutFirstLines, line)
		}
		if l := len(stdoutLastLines); l == cap(stdoutLastLines) {
			stdoutLastLines = stdoutLastLines[:l-1]
		}
		stdoutLastLines = append(stdoutLastLines, line)
		stdoutMut.Unlock()

		os.Stdout.WriteString(line)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"

	"github.com/kisom/goutils/die"
	"github.com/kisom/utility37/workspace"
)

func usage() {
	name := filepath.Base(os.Args[0])
	fmt.Printf(`%s is a utility to report the unfinished tasks for the day.

Usage:
%s [-i] [-l] [-m] [-p priority] workspace

Flags:
    -h                   Print this usage message.
    -i                  Initialise a new workspace if needed.
    -l                  Print task annotations (long format).
    -m                  Display tasks in markdown format.
    -p priority         Filter tasks by priority; only tasks with at least
                        the specified priority.

%s
`, name, name, workspace.PriorityStrings)
}

func asMarkdown(tasks []*workspace.Task, long bool) {
	fmt.Printf("## TODO %s (%d tasks)\n",
		workspace.Today().Format(workspace.DateFormat),
		len(tasks),
	)

	for _, task := range tasks {
		fmt.Printf("#### %s\n", task)
		if long {
			for _, note := range task.Notes {
				fmt.Println(workspace.Wrap("+ "+note, "", 72))
			}
		}
	}
}

func main() {
	var shouldInit, long, markdown bool
	var priority = workspace.PriorityNormal.String()

	flag.Usage = usage
	flag.BoolVar(&shouldInit, "i", false, "Initialise new workspace if needed.")
	flag.BoolVar(&long, "l", false, "Show annotations of each task.")
	flag.BoolVar(&markdown, "m", false, "Print log as markdown.")
	flag.StringVar(&priority, "p", priority, "Filter tasks by priority.")
	flag.Parse()

	if flag.NArg() == 0 {
		die.With("Workspace name is required.")
	}

	pri := workspace.PriorityFromString(priority)

	ws, err := workspace.ReadFile(flag.Arg(0), shouldInit)
	die.If(err)

	entryID := ws.NewEntry()
	tasks := ws.EntryTasks(entryID).Unfinished().Filter(pri).Sort()
	if markdown {
		asMarkdown(tasks, long)
	} else {
		fmt.Printf("TODO %s (%d tasks):\n",
			workspace.Today().Format(workspace.DateFormat),
			len(tasks))
		for _, task := range tasks {
			fmt.Println("\t", task)
			if long {
				for _, note := range task.Notes {
					fmt.Println(workspace.Wrap("+ "+note, "\t\t", 72))
				}
			}
		}
	}
}
<commit_msg>today tool supports filtering by regexp.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/kisom/goutils/die"
	"github.com/kisom/utility37/workspace"
)

func usage() {
	name := filepath.Base(os.Args[0])
	fmt.Printf(`%s is a utility to report the unfinished tasks for the day.

Usage:
%s [-i] [-l] [-m] [-p priority] workspace [search string]

Flags:
    -h                   Print this usage message.
    -i                  Initialise a new workspace if needed.
    -l                  Print task annotations (long format).
    -m                  Display tasks in markdown format.
    -p priority         Filter tasks by priority; only tasks with at least
                        the specified priority.

%s

The search string, if provided, should be a regular expression that
will be used to filter out tasks.
`, name, name, workspace.PriorityStrings)
}

func asMarkdown(tasks []*workspace.Task, long bool) {
	fmt.Printf("## TODO %s (%d tasks)\n",
		workspace.Today().Format(workspace.DateFormat),
		len(tasks),
	)

	for _, task := range tasks {
		fmt.Printf("#### %s\n", task)
		if long {
			for _, note := range task.Notes {
				fmt.Println(workspace.Wrap("+ "+note, "", 72))
			}
		}
	}
}

func main() {
	var shouldInit, long, markdown bool
	var priority = workspace.PriorityNormal.String()

	flag.Usage = usage
	flag.BoolVar(&shouldInit, "i", false, "Initialise new workspace if needed.")
	flag.BoolVar(&long, "l", false, "Show annotations of each task.")
	flag.BoolVar(&markdown, "m", false, "Print log as markdown.")
	flag.StringVar(&priority, "p", priority, "Filter tasks by priority.")
	flag.Parse()

	if flag.NArg() == 0 {
		die.With("Workspace name is required.")
	}

	pri := workspace.PriorityFromString(priority)

	ws, err := workspace.ReadFile(flag.Arg(0), shouldInit)
	die.If(err)

	searchString := `.*`
	if flag.NArg() > 1 {
		args := flag.Args()
		searchString = strings.Join(args[1:], " ")
	}

	re, err := regexp.Compile(searchString)
	die.If(err)

	entryID := ws.NewEntry()
	tasks := ws.EntryTasks(entryID).Unfinished().Filter(pri).Sort()
	if markdown {
		asMarkdown(tasks, long)
	} else {
		fmt.Printf("TODO %s (%d tasks):\n",
			workspace.Today().Format(workspace.DateFormat),
			len(tasks))
		for _, task := range tasks {
			if !re.MatchString(task.Title) {
				continue
			}
			fmt.Println("\t", task)
			if long {
				for _, note := range task.Notes {
					fmt.Println(workspace.Wrap("+ "+note, "\t\t", 72))
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package agent

import (
	"encoding/json"
	"log"
	"strings"
	"sync"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/coreos/go-etcd/etcd"
)

// KeyPrefix is used to create the full service path.
const KeyPrefix = "/discover"

// EtcdBackend for service discovery.
type EtcdBackend struct {
	Client *etcd.Client
}

func servicePath(name, addr string) string {
	if addr == "" {
		return KeyPrefix + "/services/" + name
	}
	return KeyPrefix + "/services/" + name + "/" + addr
}

// Subscribe to changes in services of a given name.
func (b *EtcdBackend) Subscribe(name string) (UpdateStream, error) {
	stream := &etcdStream{ch: make(chan *ServiceUpdate), stop: make(chan bool)}

	go func() {
		nextIndex := uint64(1)
		response, _ := b.getCurrentState(name)
		if response != nil {
			for _, n := range response.Node.Nodes {
				if update := b.responseToUpdate(response, n); update != nil {
					stream.ch <- update
				}
			}
			nextIndex = response.EtcdIndex + 1
		}
		stream.ch <- &ServiceUpdate{}

		path := servicePath(name, "")
		for {
			watch := make(chan *etcd.Response)
			var watchErr error
			go func() {
				_, watchErr = b.Client.Watch(path, nextIndex, true, watch, stream.stop)
			}()
			for resp := range watch {
				if update := b.responseToUpdate(resp, resp.Node); update != nil {
					stream.ch <- update
				}
				nextIndex = resp.EtcdIndex + 1
			}
			select {
			case <-stream.stop:
				return
			default:
			}
			log.Printf("Restarting etcd watch %s due to error: %s", path, watchErr)
		}
	}()
	return stream, nil
}

type etcdStream struct {
	ch       chan *ServiceUpdate
	stop     chan bool
	stopOnce sync.Once
}

func (s *etcdStream) Chan() chan *ServiceUpdate { return s.ch }

func (s *etcdStream) Close() { s.stopOnce.Do(func() { close(s.stop) }) }

func (b *EtcdBackend) responseToUpdate(resp *etcd.Response, node *etcd.Node) *ServiceUpdate {
	// expected key structure: /PREFIX/services/NAME/ADDR
	splitKey := strings.SplitN(node.Key, "/", 5)
	if len(splitKey) < 5 {
		return nil
	}
	serviceName := splitKey[3]
	serviceAddr := splitKey[4]
	if "get" == resp.Action || ("set" == resp.Action || "update" == resp.Action) && (resp.PrevNode == nil || node.Value != resp.PrevNode.Value) {
		// GET is because getCurrentState returns responses of Action GET.
		// some SETs are heartbeats, so we ignore SETs where value didn't change.
		var serviceAttrs map[string]string
		err := json.Unmarshal([]byte(node.Value), &serviceAttrs)
		if err != nil {
			return nil
		}
		return &ServiceUpdate{
			Name:    serviceName,
			Addr:    serviceAddr,
			Online:  true,
			Attrs:   serviceAttrs,
			Created: uint(node.CreatedIndex),
		}
	} else if "delete" == resp.Action || "expire" == resp.Action {
		return &ServiceUpdate{
			Name: serviceName,
			Addr: serviceAddr,
		}
	} else {
		return nil
	}
}

func (b *EtcdBackend) getCurrentState(name string) (*etcd.Response, error) {
	return b.Client.Get(servicePath(name, ""), false, true)
}

// Register a service with etcd.
func (b *EtcdBackend) Register(name, addr string, attrs map[string]string) error {
	attrsJSON, err := json.Marshal(attrs)
	if err != nil {
		return err
	}
	attrsString := string(attrsJSON)
	path := servicePath(name, addr)
	ttl := uint64(HeartbeatIntervalSecs + MissedHearbeatTTL)

	_, err = b.Client.Update(path, attrsString, ttl)
	if e, ok := err.(*etcd.EtcdError); ok && e.ErrorCode == 100 {
		// This is a workaround for etcd issue #407: https://github.com/coreos/etcd/issues/407
		// If we just do a Set and don't try to Update first, createdIndex will get incremented
		// on each heartbeat, breaking leader election.
		_, err = b.Client.Set(path, attrsString, ttl)
	}
	return err
}

// Unregister a service with etcd.
func (b *EtcdBackend) Unregister(name, addr string) error {
	_, err := b.Client.Delete(servicePath(name, addr), false)
	return err
}
<commit_msg>discoverd: Handle etcd error 401<commit_after>package agent

import (
	"encoding/json"
	"log"
	"strings"
	"sync"

	"github.com/flynn/flynn/Godeps/_workspace/src/github.com/coreos/go-etcd/etcd"
)

// KeyPrefix is used to create the full service path.
const KeyPrefix = "/discover"

// EtcdBackend for service discovery.
type EtcdBackend struct {
	Client *etcd.Client
}

func servicePath(name, addr string) string {
	if addr == "" {
		return KeyPrefix + "/services/" + name
	}
	return KeyPrefix + "/services/" + name + "/" + addr
}

// Subscribe to changes in services of a given name.
func (b *EtcdBackend) Subscribe(name string) (UpdateStream, error) {
	stream := &etcdStream{ch: make(chan *ServiceUpdate), stop: make(chan bool)}
	go func() {
		send := func(u *ServiceUpdate) bool {
			if u == nil {
				return true
			}
			select {
			case stream.ch <- u:
				return true
			case <-stream.stop:
				return false
			}
		}

		var sentinel bool
		keys := make(map[string]uint64)
		newKeys := make(map[string]uint64)
	sync:
		for {
			nextIndex := uint64(1)
			response, _ := b.getCurrentState(name)
			if response != nil {
				for _, n := range response.Node.Nodes {
					if modified, ok := keys[n.Key]; ok && modified >= n.ModifiedIndex {
						continue
					}
					if !send(b.responseToUpdate(response, n, newKeys)) {
						return
					}
				}
				nextIndex = response.EtcdIndex + 1
			}
			if !sentinel {
				if !send(&ServiceUpdate{}) {
					return
				}
				sentinel = true
			}
			for k := range keys {
				if _, ok := newKeys[k]; ok {
					continue
				}
				serviceName, serviceAddr := splitServiceNameAddr(k)
				if serviceName == "" {
					continue
				}
				// instance was deleted, send offline update
				if !send(&ServiceUpdate{Name: serviceName, Addr: serviceAddr}) {
					return
				}
			}
			keys = newKeys
			newKeys = make(map[string]uint64)

			path := servicePath(name, "")
			for {
				watch := make(chan *etcd.Response)
				watchDone := make(chan struct{})
				var watchErr error
				go func() {
					_, watchErr = b.Client.Watch(path, nextIndex, true, watch, stream.stop)
					close(watchDone)
				}()
				for resp := range watch {
					if !send(b.responseToUpdate(resp, resp.Node, keys)) {
						return
					}
					nextIndex = resp.EtcdIndex + 1
				}
				<-watchDone
				select {
				case <-stream.stop:
					return
				default:
				}
				if e, ok := watchErr.(*etcd.EtcdError); ok && e.ErrorCode == 401 {
					// event log has been pruned beyond our waitIndex, force full sync
					log.Printf("Got etcd error 401, doing full sync")
					continue sync
				}
				log.Printf("Restarting etcd watch %s due to error: %s", path, watchErr)
			}
		}
	}()
	return stream, nil
}

type etcdStream struct {
	ch       chan *ServiceUpdate
	stop     chan bool
	stopOnce sync.Once
}

func (s *etcdStream) Chan() chan *ServiceUpdate { return s.ch }

func (s *etcdStream) Close() { s.stopOnce.Do(func() { close(s.stop) }) }

func (b *EtcdBackend) responseToUpdate(resp *etcd.Response, node *etcd.Node, keys map[string]uint64) *ServiceUpdate {
	keys[node.Key] = node.ModifiedIndex
	serviceName, serviceAddr := splitServiceNameAddr(node.Key)
	if serviceName == "" {
		return nil
	}
	if "get" == resp.Action || ("set" == resp.Action || "update" == resp.Action) && (resp.PrevNode == nil || node.Value != resp.PrevNode.Value) {
		// GET is because getCurrentState returns responses of Action GET.
		// some SETs are heartbeats, so we ignore SETs where value didn't change.
		var serviceAttrs map[string]string
		err := json.Unmarshal([]byte(node.Value), &serviceAttrs)
		if err != nil {
			return nil
		}
		return &ServiceUpdate{
			Name:    serviceName,
			Addr:    serviceAddr,
			Online:  true,
			Attrs:   serviceAttrs,
			Created: uint(node.CreatedIndex),
		}
	} else if "delete" == resp.Action || "expire" == resp.Action {
		delete(keys, node.Key)
		return &ServiceUpdate{
			Name: serviceName,
			Addr: serviceAddr,
		}
	} else {
		return nil
	}
}

func splitServiceNameAddr(key string) (string, string) {
	// expected key structure: /PREFIX/services/NAME/ADDR
	splitKey := strings.SplitN(key, "/", 5)
	if len(splitKey) < 5 {
		return "", ""
	}
	return splitKey[3], splitKey[4]
}

func (b *EtcdBackend) getCurrentState(name string) (*etcd.Response, error) {
	return b.Client.Get(servicePath(name, ""), false, true)
}

// Register a service with etcd.
func (b *EtcdBackend) Register(name, addr string, attrs map[string]string) error {
	attrsJSON, err := json.Marshal(attrs)
	if err != nil {
		return err
	}
	attrsString := string(attrsJSON)
	path := servicePath(name, addr)
	ttl := uint64(HeartbeatIntervalSecs + MissedHearbeatTTL)

	_, err = b.Client.Update(path, attrsString, ttl)
	if e, ok := err.(*etcd.EtcdError); ok && e.ErrorCode == 100 {
		// This is a workaround for etcd issue #407: https://github.com/coreos/etcd/issues/407
		// If we just do a Set and don't try to Update first, createdIndex will get incremented
		// on each heartbeat, breaking leader election.
		_, err = b.Client.Set(path, attrsString, ttl)
	}
	return err
}

// Unregister a service with etcd.
func (b *EtcdBackend) Unregister(name, addr string) error {
	_, err := b.Client.Delete(servicePath(name, addr), false)
	return err
}
<|endoftext|>


<commit_before>package webauth

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/Cloud-Foundations/keymaster/lib/paths"
	"golang.org/x/term"
	"gopkg.in/square/go-jose.v2/jwt"
)

const (
	authCookieName      = "auth_cookie"
	pathCloseTabRequest = "/closeTabRequest"
)

type authInfoJWT struct {
	Subject    string `json:"sub,omitempty"`
	Expiration int64  `json:"exp,omitempty"`
}

func authenticate(s state) (string, error) {
	gotCookie := make(chan struct{}, 1)
	s.gotCookie = gotCookie
	if err := s.startLocalServer(); err != nil {
		return "", err
	}
	token, err := s.getToken()
	if err != nil {
		return "", err
	}
	if err := s.startAuthRequest(token); err != nil {
		return "", err
	}
	timer := time.NewTimer(time.Second * 10)
	select {
	case <-gotCookie:
		if !timer.Stop() {
			<-timer.C
		}
		return s.targetUrls[0], nil
	case <-timer.C:
		if !s.happyCookie { // Delete a potentially poison cookie if present.
			os.Remove(s.tokenFilename)
		}
		return "", errors.New("timed out getting cookie")
	}
}

func parseToken(serialisedToken string) (*authInfoJWT, error) {
	token, err := jwt.ParseSigned(serialisedToken)
	if err != nil {
		return nil, err
	}
	var data authInfoJWT
	if err := token.UnsafeClaimsWithoutVerification(&data); err != nil {
		return nil, err
	}
	return &data, nil
}

func removeNewline(data []byte) []byte {
	if length := len(data); length < 1 {
		return data
	} else if data[length-1] == '\n' {
		return data[:length-1]
	}
	return data
}

func startCommand(cmd *exec.Cmd, timeout time.Duration) error {
	errorChannel := make(chan error, 1)
	timer := time.NewTimer(timeout)
	go func(errorChannel chan<- error) {
		errorChannel <- cmd.Run()
	}(errorChannel)
	select {
	case err := <-errorChannel:
		if !timer.Stop() {
			<-timer.C
		}
		return err
	case <-timer.C:
		return nil
	}
}

func (s *state) closeTabRequestHandler(w http.ResponseWriter,
	req *http.Request) {
	w.Write([]byte(receiveAuthPageText))
}

func (s *state) getToken() (string, error) {
	if token, err := s.readToken(); err != nil {
		s.logger.Println(err)
	} else if token != "" {
		return token, nil
	}
	cmd := exec.Command(s.webauthBrowser[0], s.webauthBrowser[1:]...)
	cmd.Args = append(cmd.Args,
		fmt.Sprintf("%s%s", s.targetUrls[0], paths.ShowAuthToken))
	if err := startCommand(cmd, time.Millisecond*200); err != nil {
		return "", err
	}
	var token string
	var inputData []byte
	for {
		fmt.Printf("Enter token: ")
		var err error
		inputData, err = term.ReadPassword(int(syscall.Stdin))
		if err != nil {
			return "", err
		}
		fmt.Println()
		token = string(removeNewline(inputData))
		if _, err := parseToken(token); err != nil {
			s.logger.Printf("Token appears invalid. Try again: %s\n", err)
		} else {
			break
		}
	}
	s.tokenToWrite = inputData // Write later once fully verified.
	return token, nil
}

func (s *state) readToken() (string, error) {
	fileData, err := ioutil.ReadFile(s.tokenFilename)
	if err != nil {
		if os.IsNotExist(err) {
			return "", nil
		}
		return "", err
	}
	token := string(removeNewline(fileData))
	parsedToken, err := parseToken(token)
	if err != nil {
		return "", err
	}
	if time.Until(time.Unix(parsedToken.Expiration, 0)) < 0 {
		return "", nil
	}
	return token, nil
}

func (s *state) receiveAuthHandler(w http.ResponseWriter, req *http.Request) {
	s.logger.Debugln(1, "started receiveAuthHandler()")
	s.happyCookie = true
	if len(s.tokenToWrite) > 0 { // If we are here, Keymaster liked the token.
		err := ioutil.WriteFile(s.tokenFilename, s.tokenToWrite, 0600)
		if err != nil {
			s.logger.Println(err)
		}
	}
	// Fetch form/query data.
	if err := req.ParseForm(); err != nil {
		s.logger.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Error parsing form"))
		return
	}
	var authCookieValue string
	if val, ok := req.Form["auth_cookie"]; !ok {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("No auth_cookie"))
		return
	} else {
		if len(val) > 1 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Just one auth_cookie allowed"))
			return
		}
		authCookieValue = val[0]
	}
	authCookie := &http.Cookie{Name: "auth_cookie", Value: authCookieValue}
	for _, targetUrl := range s.targetUrls {
		targetURL, err := url.Parse(targetUrl)
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Error parsing URL"))
			s.logger.Println(err)
			return
		}
		s.client.Jar.SetCookies(targetURL, []*http.Cookie{authCookie})
	}
	s.gotCookie <- struct{}{}
	http.Redirect(w, req, pathCloseTabRequest, http.StatusPermanentRedirect)
}

func (s *state) serve(listener net.Listener, serveMux *http.ServeMux) {
	if err := http.Serve(listener, serveMux); err != nil {
		panic(err)
	}
}

func (s *state) startAuthRequest(token string) error {
	cmd := exec.Command(s.webauthBrowser[0], s.webauthBrowser[1:]...)
	cmd.Args = append(cmd.Args,
		fmt.Sprintf("%s%s?port=%s&token=%s",
			s.targetUrls[0], paths.SendAuthDocument, s.portNumber, token))
	return startCommand(cmd, time.Millisecond*200)
}

func (s *state) startLocalServer() error {
	listener, err := net.Listen("tcp", "localhost:")
	if err != nil {
		return err
	}
	_, port, err := net.SplitHostPort(listener.Addr().String())
	if err != nil {
		return err
	}
	s.logger.Debugf(0, "listening on localhost:%s\n", port)
	s.portNumber = port
	serveMux := http.NewServeMux()
	serveMux.HandleFunc(paths.ReceiveAuthDocument, s.receiveAuthHandler)
	serveMux.HandleFunc(pathCloseTabRequest, s.closeTabRequestHandler)
	go s.serve(listener, serveMux)
	return nil
}

const receiveAuthPageText = `

Please close this tab

`
<commit_msg>keymaster: specify user hint to browser and extend grace period.<commit_after>package webauth

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/Cloud-Foundations/keymaster/lib/paths"
	"golang.org/x/term"
	"gopkg.in/square/go-jose.v2/jwt"
)

const (
	authCookieName      = "auth_cookie"
	pathCloseTabRequest = "/closeTabRequest"
)

type authInfoJWT struct {
	Subject    string `json:"sub,omitempty"`
	Expiration int64  `json:"exp,omitempty"`
}

func authenticate(s state) (string, error) {
	gotCookie := make(chan struct{}, 1)
	s.gotCookie = gotCookie
	if err := s.startLocalServer(); err != nil {
		return "", err
	}
	token, err := s.getToken()
	if err != nil {
		return "", err
	}
	if err := s.startAuthRequest(token); err != nil {
		return "", err
	}
	timer := time.NewTimer(time.Minute)
	select {
	case <-gotCookie:
		if !timer.Stop() {
			<-timer.C
		}
		return s.targetUrls[0], nil
	case <-timer.C:
		if !s.happyCookie { // Delete a potentially poison cookie if present.
			os.Remove(s.tokenFilename)
		}
		return "", errors.New("timed out getting cookie")
	}
}

func parseToken(serialisedToken string) (*authInfoJWT, error) {
	token, err := jwt.ParseSigned(serialisedToken)
	if err != nil {
		return nil, err
	}
	var data authInfoJWT
	if err := token.UnsafeClaimsWithoutVerification(&data); err != nil {
		return nil, err
	}
	return &data, nil
}

func removeNewline(data []byte) []byte {
	if length := len(data); length < 1 {
		return data
	} else if data[length-1] == '\n' {
		return data[:length-1]
	}
	return data
}

func startCommand(cmd *exec.Cmd, timeout time.Duration) error {
	errorChannel := make(chan error, 1)
	timer := time.NewTimer(timeout)
	go func(errorChannel chan<- error) {
		errorChannel <- cmd.Run()
	}(errorChannel)
	select {
	case err := <-errorChannel:
		if !timer.Stop() {
			<-timer.C
		}
		return err
	case <-timer.C:
		return nil
	}
}

func (s *state) closeTabRequestHandler(w http.ResponseWriter,
	req *http.Request) {
	w.Write([]byte(receiveAuthPageText))
}

func (s *state) getToken() (string, error) {
	if token, err := s.readToken(); err != nil {
		s.logger.Println(err)
	} else if token != "" {
		return token, nil
	}
	cmd := exec.Command(s.webauthBrowser[0], s.webauthBrowser[1:]...)
	cmd.Args = append(cmd.Args,
		fmt.Sprintf("%s%s?user=%s", s.targetUrls[0], paths.ShowAuthToken,
			s.userName))
	if err := startCommand(cmd, time.Millisecond*200); err != nil {
		return "", err
	}
	var token string
	var inputData []byte
	for {
		fmt.Printf("Enter token: ")
		var err error
		inputData, err = term.ReadPassword(int(syscall.Stdin))
		if err != nil {
			return "", err
		}
		fmt.Println()
		token = string(removeNewline(inputData))
		if _, err := parseToken(token); err != nil {
			s.logger.Printf("Token appears invalid. Try again: %s\n", err)
		} else {
			break
		}
	}
	s.tokenToWrite = inputData // Write later once fully verified.
	return token, nil
}

func (s *state) readToken() (string, error) {
	fileData, err := ioutil.ReadFile(s.tokenFilename)
	if err != nil {
		if os.IsNotExist(err) {
			return "", nil
		}
		return "", err
	}
	token := string(removeNewline(fileData))
	parsedToken, err := parseToken(token)
	if err != nil {
		return "", err
	}
	if time.Until(time.Unix(parsedToken.Expiration, 0)) < 0 {
		return "", nil
	}
	return token, nil
}

func (s *state) receiveAuthHandler(w http.ResponseWriter, req *http.Request) {
	s.logger.Debugln(1, "started receiveAuthHandler()")
	s.happyCookie = true
	if len(s.tokenToWrite) > 0 { // If we are here, Keymaster liked the token.
		err := ioutil.WriteFile(s.tokenFilename, s.tokenToWrite, 0600)
		if err != nil {
			s.logger.Println(err)
		}
	}
	// Fetch form/query data.
	if err := req.ParseForm(); err != nil {
		s.logger.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Error parsing form"))
		return
	}
	var authCookieValue string
	if val, ok := req.Form["auth_cookie"]; !ok {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("No auth_cookie"))
		return
	} else {
		if len(val) > 1 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Just one auth_cookie allowed"))
			return
		}
		authCookieValue = val[0]
	}
	authCookie := &http.Cookie{Name: "auth_cookie", Value: authCookieValue}
	for _, targetUrl := range s.targetUrls {
		targetURL, err := url.Parse(targetUrl)
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Error parsing URL"))
			s.logger.Println(err)
			return
		}
		s.client.Jar.SetCookies(targetURL, []*http.Cookie{authCookie})
	}
	s.gotCookie <- struct{}{}
	http.Redirect(w, req, pathCloseTabRequest, http.StatusPermanentRedirect)
}

func (s *state) serve(listener net.Listener, serveMux *http.ServeMux) {
	if err := http.Serve(listener, serveMux); err != nil {
		panic(err)
	}
}

func (s *state) startAuthRequest(token string) error {
	cmd := exec.Command(s.webauthBrowser[0], s.webauthBrowser[1:]...)
	cmd.Args = append(cmd.Args,
		fmt.Sprintf("%s%s?port=%s&user=%s&token=%s",
			s.targetUrls[0], paths.SendAuthDocument, s.portNumber, s.userName,
			token))
	return startCommand(cmd, time.Millisecond*200)
}

func (s *state) startLocalServer() error {
	listener, err := net.Listen("tcp", "localhost:")
	if err != nil {
		return err
	}
	_, port, err := net.SplitHostPort(listener.Addr().String())
	if err != nil {
		return err
	}
	s.logger.Debugf(0, "listening on localhost:%s\n", port)
	s.portNumber = port
	serveMux := http.NewServeMux()
	serveMux.HandleFunc(paths.ReceiveAuthDocument, s.receiveAuthHandler)
	serveMux.HandleFunc(pathCloseTabRequest, s.closeTabRequestHandler)
	go s.serve(listener, serveMux)
	return nil
}

const receiveAuthPageText = `

Please close this tab

`
<|endoftext|>


<commit_before>package network

import (
	"bytes"
	"encoding/binary"
	"errors"
)

const (
	LittleEndian = iota
	BigEndian
)

type (
	Parser struct {
		buffer *bytes.Buffer
		endian int
	}
)

func NewParser(buf []byte) *Parser {
	parser := new(Parser)
	parser.buffer = bytes.NewBuffer(buf)
	parser.endian = LittleEndian

	return parser
}

func (p *Parser) Buffer() *bytes.Buffer {
	return p.buffer
}

func (p *Parser) Bytes() []byte {
	return p.buffer.Bytes()
}

func (p *Parser) Endian() int {
	return p.endian
}

func (p *Parser) SetEndian(endian int) *Parser {
	p.endian = endian

	return p
}

func (p *Parser) Read(val interface{}) (err error) {
	switch val.(type) {
	case *int:
		valAun := val.(*int)
		if valAun == nil {
			err = errors.New("Int value is nil")
			return
		}

		var bufInt []byte
		if bufInt = p.buffer.Next(4); len(bufInt) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = int(binary.BigEndian.Uint32(bufInt))
		} else {
			(*valAun) = int(binary.LittleEndian.Uint32(bufInt))
		}

	case *int16:
		valAun := val.(*int16)
		if valAun == nil {
			err = errors.New("Int16 value is nil")
			return
		}

	case *int32:
		valAun := val.(*int32)
		if valAun == nil {
			err = errors.New("Int32 value is nil")
			return
		}

		var bufInt32 []byte
		if bufInt32 = p.buffer.Next(4); len(bufInt32) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = int32(binary.BigEndian.Uint32(bufInt32))
		} else {
			(*valAun) = int32(binary.LittleEndian.Uint32(bufInt32))
		}

	case *int64:
		valAun := val.(*int64)
		if valAun == nil {
			err = errors.New("Int64 value is nil")
			return
		}

	case *uint:
		valAun := val.(*uint)
		if valAun == nil {
			err = errors.New("Uint value is nil")
			return
		}

	case *uint16:
		valAun := val.(*uint16)
		if valAun == nil {
			err = errors.New("Uint16 value is nil")
			return
		}

	case *uint32:
		valAun := val.(*uint32)
		if valAun == nil {
			err = errors.New("Uint32 value is nil")
			return
		}

	case *uint64:
		valAun := val.(*uint64)
		if valAun == nil {
			err = errors.New("Uint64 value is nil")
			return
		}

	}

	return
}

func (p *Parser) Write(val interface{}) {
	switch val.(type) {
	case int:
		valAun := val.(int)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int8:
		valAun := val.(int8)

		p.buffer.WriteByte(byte(valAun))

	case int16:
		valAun := val.(int16)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
		} else {
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int32:
		valAun := val.(int32)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int64:
		valAun := val.(int64)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 56))
		} else {
			p.buffer.WriteByte(byte(valAun >> 56))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint:
		valAun := val.(uint)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint8:
		valAun := val.(uint8)

		p.buffer.WriteByte(byte(valAun))

	case uint16:
		valAun := val.(uint16)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
		} else {
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint32:
		valAun := val.(uint32)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint64:
		valAun := val.(uint64)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 56))
		} else {
			p.buffer.WriteByte(byte(valAun >> 56))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	}
}
<commit_msg>Update network library for float type<commit_after>package network

import (
	"bytes"
	"encoding/binary"
	"errors"
	"math"
)

const (
	LittleEndian = iota
	BigEndian
)

type (
	Parser struct {
		buffer *bytes.Buffer
		endian int
	}
)

func NewParser(buf []byte) *Parser {
	parser := new(Parser)
	parser.buffer = bytes.NewBuffer(buf)
	parser.endian = LittleEndian

	return parser
}

func (p *Parser) Buffer() *bytes.Buffer {
	return p.buffer
}

func (p *Parser) Bytes() []byte {
	return p.buffer.Bytes()
}

func (p *Parser) Endian() int {
	return p.endian
}

func (p *Parser) SetEndian(endian int) *Parser {
	p.endian = endian

	return p
}

func (p *Parser) Read(val interface{}) (err error) {
	switch val.(type) {
	case *int:
		valAun := val.(*int)
		if valAun == nil {
			err = errors.New("Int value is nil")
			return
		}

		var bufInt []byte
		if bufInt = p.buffer.Next(4); len(bufInt) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = int(binary.LittleEndian.Uint32(bufInt))
		} else {
			(*valAun) = int(binary.BigEndian.Uint32(bufInt))
		}

	case *int16:
		valAun := val.(*int16)
		if valAun == nil {
			err = errors.New("Int16 value is nil")
			return
		}

	case *int32:
		valAun := val.(*int32)
		if valAun == nil {
			err = errors.New("Int32 value is nil")
			return
		}

		var bufInt32 []byte
		if bufInt32 = p.buffer.Next(4); len(bufInt32) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = int32(binary.LittleEndian.Uint32(bufInt32))
		} else {
			(*valAun) = int32(binary.BigEndian.Uint32(bufInt32))
		}

	case *int64:
		valAun := val.(*int64)
		if valAun == nil {
			err = errors.New("Int64 value is nil")
			return
		}

	case *uint:
		valAun := val.(*uint)
		if valAun == nil {
			err = errors.New("Uint value is nil")
			return
		}

	case *uint16:
		valAun := val.(*uint16)
		if valAun == nil {
			err = errors.New("Uint16 value is nil")
			return
		}

	case *uint32:
		valAun := val.(*uint32)
		if valAun == nil {
			err = errors.New("Uint32 value is nil")
			return
		}

	case *uint64:
		valAun := val.(*uint64)
		if valAun == nil {
			err = errors.New("Uint64 value is nil")
			return
		}

	case *float32:
		valAun := val.(*float32)
		if valAun == nil {
			err = errors.New("Uint64 value is nil")
			return
		}

		var bufFloat32 []byte
		if bufFloat32 = p.buffer.Next(4); len(bufFloat32) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = math.Float32frombits(binary.BigEndian.Uint32(bufFloat32))
		} else {
			(*valAun) = math.Float32frombits(binary.LittleEndian.Uint32(bufFloat32))
		}

	case *float64:
		valAun := val.(*float64)
		if valAun == nil {
			err = errors.New("Uint64 value is nil")
			return
		}

		var bufFloat64 []byte
		if bufFloat64 = p.buffer.Next(8); len(bufFloat64) < 4 {
			err = errors.New("Not enough bytes in buffer")
			return
		}

		if p.Endian() == BigEndian {
			(*valAun) = math.Float64frombits(binary.BigEndian.Uint64(bufFloat64))
		} else {
			(*valAun) = math.Float64frombits(binary.LittleEndian.Uint64(bufFloat64))
		}

	}

	return
}

func (p *Parser) Write(val interface{}) {
	switch val.(type) {
	case int:
		valAun := val.(int)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int8:
		valAun := val.(int8)

		p.buffer.WriteByte(byte(valAun))

	case int16:
		valAun := val.(int16)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
		} else {
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int32:
		valAun := val.(int32)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case int64:
		valAun := val.(int64)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 56))
		} else {
			p.buffer.WriteByte(byte(valAun >> 56))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint:
		valAun := val.(uint)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint8:
		valAun := val.(uint8)

		p.buffer.WriteByte(byte(valAun))

	case uint16:
		valAun := val.(uint16)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
		} else {
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint32:
		valAun := val.(uint32)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
		} else {
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case uint64:
		valAun := val.(uint64)

		if p.Endian() == BigEndian {
			p.buffer.WriteByte(byte(valAun))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 56))
		} else {
			p.buffer.WriteByte(byte(valAun >> 56))
			p.buffer.WriteByte(byte(valAun >> 48))
			p.buffer.WriteByte(byte(valAun >> 40))
			p.buffer.WriteByte(byte(valAun >> 32))
			p.buffer.WriteByte(byte(valAun >> 24))
			p.buffer.WriteByte(byte(valAun >> 16))
			p.buffer.WriteByte(byte(valAun >> 8))
			p.buffer.WriteByte(byte(valAun))
		}

	case float32:
		valAun := val.(float32)

		bitsFloat32 := math.Float32bits(valAun)
		bufFloat32 := make([]byte, 4)

		if p.Endian() == BigEndian {
			binary.BigEndian.PutUint32(bufFloat32, bitsFloat32)
		} else {
			binary.LittleEndian.PutUint32(bufFloat32, bitsFloat32)
		}

		p.buffer.Write(bufFloat32)

	case float64:
		valAun := val.(float64)

		bitsFloat64 := math.Float64bits(valAun)
		bufFloat64 := make([]byte, 8)

		if p.Endian() == BigEndian {
			binary.BigEndian.PutUint64(bufFloat64, bitsFloat64)
		} else {
			binary.LittleEndian.PutUint64(bufFloat64, bitsFloat64)
		}

		p.buffer.Write(bufFloat64)

	}
}
<|endoftext|>


<commit_before>package sweetiebot

import (
	"math/rand"
	"strconv"
	"strings"

	"github.com/bwmarrin/discordgo"
)

type GiveCommand struct {
}

func (c *GiveCommand) Name() string {
	return "Give"
}
func (c *GiveCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	if len(args) < 1 {
		return "[](/sadbot) `You didn't give me anything!`", false
	}
	if info.config.MaxBucket == 0 {
		return "```I don't have a bucket right now.```", false
	}

	arg := ExtraSanitize(strings.Join(args, " "))
	if len(arg) > info.config.MaxBucketLength {
		return "```That's too big! Give me something smaller!'```", false
	}

	_, ok := info.config.Collections["bucket"][arg]
	if ok {
		return "```I already have " + arg + "!```", false
	}

	if len(info.config.Collections["bucket"]) >= info.config.MaxBucket {
		dropped := BucketDropRandom(info)
		info.config.Collections["bucket"][arg] = true
		info.SaveConfig()
		return "```I dropped " + dropped + " and picked up " + arg + ".```", false
	}

	info.config.Collections["bucket"][arg] = true
	info.SaveConfig()
	return "```I picked up " + arg + ".```", false
}
func (c *GiveCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[arbitrary string]", "Gives sweetie an object. If sweetie is carrying too many things, she will drop one of them at random.")
}
func (c *GiveCommand) UsageShort() string { return "Gives something to sweetie." }
func (c *GiveCommand) Roles() []string    { return []string{} }
func (c *GiveCommand) Channels() []string { return []string{"mylittlebot", "bot-debug"} }

func BucketDropRandom(info *GuildInfo) string {
	index := rand.Intn(len(info.config.Collections["bucket"]))
	i := 0
	for k, _ := range info.config.Collections["bucket"] {
		if i == index {
			delete(info.config.Collections["bucket"], k)
			info.SaveConfig()
			return k
		}
		i++
	}
	return ""
}

type DropCommand struct {
}

func (c *DropCommand) Name() string {
	return "Drop"
}

func (c *DropCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	if len(info.config.Collections["bucket"]) == 0 {
		return "```I'm not carrying anything.```", false
	}
	if len(args) < 1 {
		return "```Dropped " + BucketDropRandom(info) + ".```", false
	}
	arg := strings.Join(args, " ")
	_, ok := info.config.Collections["bucket"][arg]
	if !ok {
		return "```I don't have " + arg + "!```", false
	}
	delete(info.config.Collections["bucket"], arg)
	info.SaveConfig()
	return "```Dropped " + arg + ".```", false
}
func (c *DropCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[arbitrary string]", "Drops the specified object from sweetie. If no object is given, makes sweetie drop something at random.")
}
func (c *DropCommand) UsageShort() string { return "Drops something from sweetie's bucket." }

type ListCommand struct {
}

func (c *ListCommand) Name() string {
	return "List"
}
func (c *ListCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	things := MapToSlice(info.config.Collections["bucket"])
	if len(things) == 0 {
		return "```I'm not carrying anything.```", false
	}
	if len(things) == 1 {
		return "```I'm carrying " + things[0] + ".```", false
	}

	return "```I'm carrying " + strings.Join(things[:len(things)-1], ", ") + " and " + things[len(things)-1] + ".```", false
}
func (c *ListCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "", "Lists everything that sweetie has.")
}
func (c *ListCommand) UsageShort() string { return "Lists everything sweetie has." }

type FightCommand struct {
	monster string
	hp      int
}

func (c *FightCommand) Name() string {
	return "Fight"
}
func (c *FightCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	things := MapToSlice(info.config.Collections["bucket"])
	if len(things) == 0 {
		return "```I have nothing to fight with!```", false
	}
	if len(c.monster) > 0 && len(args) > 0 {
		return "I'm already fighting " + c.monster + ", I have to defeat them first!", false
	}
	if len(c.monster) == 0 {
		if len(args) > 0 {
			c.monster = strings.Join(args, " ")
		} else {
			c.monster = sb.db.GetRandomSpeaker()
		}
		c.hp = 10 + rand.Intn(info.config.MaxFightHP)
		return "```I have engaged " + c.monster + ", who has " + strconv.Itoa(c.hp) + " HP!```", false
	}

	damage := 1 + rand.Intn(info.config.MaxFightDamage)
	c.hp -= damage
	end := " and deal " + strconv.Itoa(damage) + " damage!"
	monster := c.monster
	if c.hp <= 0 {
		end += " " + monster + " has been defeated!"
		c.monster = ""
	}
	end += "```"
	thing := things[rand.Intn(len(things))]
	switch rand.Intn(7) {
	case 0:
		return "```I throw " + BucketDropRandom(info) + " at " + monster + end, false
	case 1:
		return "```I stab " + monster + " with " + thing + end, false
	case 2:
		return "```I use " + thing + " on " + monster + end, false
	case 3:
		return "```I summon " + thing + end, false
	case 4:
		return "```I cast " + thing + end, false
	case 5:
		return "```I parry a blow and counterattack with " + thing + end, false
	case 6:
		return "```I detonate a " + thing + end, false
	}
	return "```Stuff happens" + end, false
}
func (c *FightCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[name]", "Fights a random pony, or [name] if it is provided.")
}
func (c *FightCommand) UsageShort() string { return "Fights a random pony." }
<commit_msg>Prevent !fight from breaking sweetiebot<commit_after>package sweetiebot

import (
	"math/rand"
	"strconv"
	"strings"

	"github.com/bwmarrin/discordgo"
)

type GiveCommand struct {
}

func (c *GiveCommand) Name() string {
	return "Give"
}
func (c *GiveCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	if len(args) < 1 {
		return "[](/sadbot) `You didn't give me anything!`", false
	}
	if info.config.MaxBucket == 0 {
		return "```I don't have a bucket right now.```", false
	}

	arg := ExtraSanitize(strings.Join(args, " "))
	if len(arg) > info.config.MaxBucketLength {
		return "```That's too big! Give me something smaller!'```", false
	}

	_, ok := info.config.Collections["bucket"][arg]
	if ok {
		return "```I already have " + arg + "!```", false
	}

	if len(info.config.Collections["bucket"]) >= info.config.MaxBucket {
		dropped := BucketDropRandom(info)
		info.config.Collections["bucket"][arg] = true
		info.SaveConfig()
		return "```I dropped " + dropped + " and picked up " + arg + ".```", false
	}

	info.config.Collections["bucket"][arg] = true
	info.SaveConfig()
	return "```I picked up " + arg + ".```", false
}
func (c *GiveCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[arbitrary string]", "Gives sweetie an object. If sweetie is carrying too many things, she will drop one of them at random.")
}
func (c *GiveCommand) UsageShort() string { return "Gives something to sweetie." }
func (c *GiveCommand) Roles() []string    { return []string{} }
func (c *GiveCommand) Channels() []string { return []string{"mylittlebot", "bot-debug"} }

func BucketDropRandom(info *GuildInfo) string {
	index := rand.Intn(len(info.config.Collections["bucket"]))
	i := 0
	for k, _ := range info.config.Collections["bucket"] {
		if i == index {
			delete(info.config.Collections["bucket"], k)
			info.SaveConfig()
			return k
		}
		i++
	}
	return ""
}

type DropCommand struct {
}

func (c *DropCommand) Name() string {
	return "Drop"
}

func (c *DropCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	if len(info.config.Collections["bucket"]) == 0 {
		return "```I'm not carrying anything.```", false
	}
	if len(args) < 1 {
		return "```Dropped " + BucketDropRandom(info) + ".```", false
	}
	arg := strings.Join(args, " ")
	_, ok := info.config.Collections["bucket"][arg]
	if !ok {
		return "```I don't have " + arg + "!```", false
	}
	delete(info.config.Collections["bucket"], arg)
	info.SaveConfig()
	return "```Dropped " + arg + ".```", false
}
func (c *DropCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[arbitrary string]", "Drops the specified object from sweetie. If no object is given, makes sweetie drop something at random.")
}
func (c *DropCommand) UsageShort() string { return "Drops something from sweetie's bucket." }

type ListCommand struct {
}

func (c *ListCommand) Name() string {
	return "List"
}
func (c *ListCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	things := MapToSlice(info.config.Collections["bucket"])
	if len(things) == 0 {
		return "```I'm not carrying anything.```", false
	}
	if len(things) == 1 {
		return "```I'm carrying " + things[0] + ".```", false
	}

	return "```I'm carrying " + strings.Join(things[:len(things)-1], ", ") + " and " + things[len(things)-1] + ".```", false
}
func (c *ListCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "", "Lists everything that sweetie has.")
}
func (c *ListCommand) UsageShort() string { return "Lists everything sweetie has." }

type FightCommand struct {
	monster string
	hp      int
}

func (c *FightCommand) Name() string {
	return "Fight"
}
func (c *FightCommand) Process(args []string, msg *discordgo.Message, info *GuildInfo) (string, bool) {
	things := MapToSlice(info.config.Collections["bucket"])
	if len(things) == 0 {
		return "```I have nothing to fight with!```", false
	}
	if len(c.monster) > 0 && len(args) > 0 {
		return "I'm already fighting " + c.monster + ", I have to defeat them first!", false
	}
	if info.config.MaxFightDamage <= 0 || info.config.MaxFightHP <= 0 {
		return "```MaxFightDamage and MaxFightHP must be greater than zero!```", false
	}
	if len(c.monster) == 0 {
		if len(args) > 0 {
			c.monster = strings.Join(args, " ")
		} else {
			c.monster = sb.db.GetRandomSpeaker()
		}
		c.hp = 10 + rand.Intn(info.config.MaxFightHP)
		return "```I have engaged " + c.monster + ", who has " + strconv.Itoa(c.hp) + " HP!```", false
	}

	damage := 1 + rand.Intn(info.config.MaxFightDamage)
	c.hp -= damage
	end := " and deal " + strconv.Itoa(damage) + " damage!"
	monster := c.monster
	if c.hp <= 0 {
		end += " " + monster + " has been defeated!"
		c.monster = ""
	}
	end += "```"
	thing := things[rand.Intn(len(things))]
	switch rand.Intn(7) {
	case 0:
		return "```I throw " + BucketDropRandom(info) + " at " + monster + end, false
	case 1:
		return "```I stab " + monster + " with " + thing + end, false
	case 2:
		return "```I use " + thing + " on " + monster + end, false
	case 3:
		return "```I summon " + thing + end, false
	case 4:
		return "```I cast " + thing + end, false
	case 5:
		return "```I parry a blow and counterattack with " + thing + end, false
	case 6:
		return "```I detonate a " + thing + end, false
	}
	return "```Stuff happens" + end, false
}
func (c *FightCommand) Usage(info *GuildInfo) string {
	return info.FormatUsage(c, "[name]", "Fights a random pony, or [name] if it is provided.")
}
func (c *FightCommand) UsageShort() string { return "Fights a random pony." }
<|endoftext|>


<commit_before>package manager

import (
	"github.com/sellweek/TOGY/config"
	"os"
	"time"
)

type Manager struct {
	kbChan              chan bool
	broadcastKilled     chan bool
	reload              chan bool
	activePresentations []string
	config              *config.Config
}

//RunContinuosly loads a local config file specified in cp,
//starts up and keeps running the broadcast,
//handling all the updates and scheduling.
func RunContinuosly(cp string) (err error) {
	for {
		var (
			c   *config.Config
			mgr *Manager
		)
		c, err = config.Get(cp)
		if err != nil {
			return
		}
		c.Notice("Reloading manager")
		mgr, err = New(c)
		if err != nil {
			return
		}

		mgr.Run()
	}
	return
}

func (m *Manager) Run() {
	m.Start()
	<-m.reload
	m.killBroadcast()
}

func New(c *config.Config) (m *Manager, err error) {
	m = new(Manager)
	m.config = c
	m.kbChan = make(chan bool)
	m.reload = make(chan bool)
	m.broadcastKilled = make(chan bool)
	m.activePresentations, err = getBroadcastDirs(c)
	return
}

func (m *Manager) Start() {
	m.startBroadcast()
	ut := time.Tick(m.config.UpdateInterval)
	go updateManager(m, ut)
}

func (m *Manager) killBroadcast() {
	m.config.Debug("Killing broadcast manager")
	m.kbChan <- true
	m.config.Debug("Waiting for broadcast manager response")
	<-m.broadcastKilled
	m.config.Debug("Broadcast manager killed")
}

func (m *Manager) startBroadcast() {
	st := time.Tick(time.Second * 10)
	go broadcastManager(m, st)
}

func getBroadcastDirs(c *config.Config) (ids []string, err error) {
	dir, err := os.Open(c.BroadcastDir)
	if err != nil {
		return
	}

	ids, err = dir.Readdirnames(0)
	return
}
<commit_msg>Improved docs in manager.go<commit_after>//Package manager contains all the "moving parts" of TOGY client.
//It handles rotating, updating and partially also scheduling of the broadcasts.
//It spawns 3 goroutines:
//
//rotator, which handles rotation of different presentations.
//
//broadcastManager, which handles scheduling.
//It starts and stops the rotator and turns the screen on and off.
//
//updateManager, which handles periodically checks server for any changes and handles them.
package manager

import (
	"github.com/sellweek/TOGY/config"
	"os"
	"time"
)

//Manager is the struct containing chans used for communication between
//goroutines, the list of active presentations and a pointer to the current
//config.
type Manager struct {
	kbChan              chan bool
	broadcastKilled     chan bool
	reload              chan bool
	activePresentations []string
	config              *config.Config
}

//RunContinuosly loads a local config file specified in cp,
//starts up and keeps running the broadcast,
//handling all the updates and scheduling.
func RunContinuosly(cp string) (err error) {
	for {
		var (
			c   *config.Config
			mgr *Manager
		)
		c, err = config.Get(cp)
		if err != nil {
			return
		}
		c.Notice("Reloading manager")
		mgr, err = New(c)
		if err != nil {
			return
		}

		mgr.Run()
	}
	return
}

//Run starts the Manager and waits for a signal to reload config.
//At that point, it stops the goroutines and returns.
func (m *Manager) Run() {
	m.Start()
	<-m.reload
	m.killBroadcast()
}

//New returns a fully populated Manager, prepared to be run.
func New(c *config.Config) (m *Manager, err error) {
	m = new(Manager)
	m.config = c
	m.kbChan = make(chan bool)
	m.reload = make(chan bool)
	m.broadcastKilled = make(chan bool)
	m.activePresentations, err = getBroadcastDirs(c)
	return
}

//Start spawns goroutines used by Manager.
func (m *Manager) Start() {
	m.startBroadcast()
	ut := time.Tick(m.config.UpdateInterval)
	go updateManager(m, ut)
}

//killBroadcast stops all the goroutines and turns off the screen.
func (m *Manager) killBroadcast() {
	m.config.Debug("Killing broadcast manager")
	m.kbChan <- true
	m.config.Debug("Waiting for broadcast manager response")
	<-m.broadcastKilled
	m.config.Debug("Broadcast manager killed")
}

//startBroadcast starts broadcastManager.
func (m *Manager) startBroadcast() {
	st := time.Tick(time.Second * 10)
	go broadcastManager(m, st)
}

//getBroadcastDirs returns a slice containing names of folders in
//c.BroadcastDir
func getBroadcastDirs(c *config.Config) (ids []string, err error) {
	dir, err := os.Open(c.BroadcastDir)
	if err != nil {
		return
	}

	ids, err = dir.Readdirnames(0)
	return
}
<|endoftext|>