<commit_before>package cmd

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"

	"github.com/megamsys/libgo/fs"
	"github.com/sajari/fuzzy"
	"launchpad.net/gnuflag"
)

var ErrAbortCommand = errors.New("")
var errUnauthorized = errors.New("unauthorized")

type exiter interface {
	Exit(int)
}

type osExiter struct{}

func (e osExiter) Exit(code int) {
	os.Exit(code)
}

type Lookup func(context *Context) error

type Mode func(modelvl int)

type Manager struct {
	Commands map[string]Command
	topics   map[string]string
	name     string
	stdout   io.Writer
	stderr   io.Writer
	stdin    io.Reader
	version  string
	e        exiter
	original string
	wrong    bool
	lookup   Lookup
	contexts []*Context
	mode     Mode
}

func NewManager(name, ver string, stdout, stderr io.Writer, stdin io.Reader, lookup Lookup, mode Mode) *Manager {
	manager := &Manager{name: name, version: ver, stdout: stdout, stderr: stderr, stdin: stdin, lookup: lookup, mode: mode}
	manager.Register(&help{manager})
	manager.Register(&version{manager})
	return manager
}

func BuildBaseManager(name, version string, lookup Lookup, mode Mode) *Manager {
	m := NewManager(name, version, os.Stdout, os.Stderr, os.Stdin, lookup, mode)
	return m
}

func (m *Manager) Register(command Command) {
	if m.Commands == nil {
		m.Commands = make(map[string]Command)
	}
	name := command.Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
}

func (m *Manager) RegisterDeprecated(command Command, oldName string) {
	if m.Commands == nil {
		m.Commands = make(map[string]Command)
	}
	name := command.Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
	m.Commands[oldName] = &DeprecatedCommand{Command: command, oldName: oldName}
}

func (m *Manager) RegisterTopic(name, content string) {
	if m.topics == nil {
		m.topics = make(map[string]string)
	}
	_, found := m.topics[name]
	if found {
		panic(fmt.Sprintf("topic already registered: %s", name))
	}
	m.topics[name] = content
}

func (m *Manager) Run(args []string) {
	var (
		status         int
		verbosity      int
		displayHelp    bool
		displayVersion bool
	)
	if len(args) == 0 {
		args = append(args, "help")
	}
	flagset := gnuflag.NewFlagSet("megamd flags", gnuflag.ContinueOnError)
	flagset.SetOutput(m.stderr)
	flagset.IntVar(&verbosity, "verbosity", 0, "Verbosity level: 1 => print debug")
	flagset.IntVar(&verbosity, "v", 0, "Verbosity level: 1 => print debug")
	flagset.BoolVar(&displayHelp, "help", false, "Display help and exit")
	flagset.BoolVar(&displayHelp, "h", false, "Display help and exit")
	flagset.BoolVar(&displayVersion, "version", false, "Print version and exit")
	parseErr := flagset.Parse(false, args)
	if parseErr != nil {
		fmt.Fprint(m.stderr, parseErr)
		m.finisher().Exit(2)
		return
	}
	args = flagset.Args()
	if displayHelp {
		args = append([]string{"help"}, args...)
	} else if displayVersion {
		args = []string{"version"}
	}
	name := args[0]
	command, ok := m.Commands[name]
	if !ok {
		if m.lookup != nil {
			context := m.newContext(args, m.stdout, m.stderr, m.stdin)
			err := m.lookup(context)
			if err != nil {
				msg := ""
				if os.IsNotExist(err) {
					msg = fmt.Sprintf("%s: %q is not a megamd command. See %q.\n", os.Args[0], args[0], "megamd help")
					var keys []string
					for key := range m.Commands {
						keys = append(keys, key)
					}
					sort.Strings(keys)
					for _, key := range keys {
						levenshtein := fuzzy.Levenshtein(&key, &args[0])
						if levenshtein < 3 || strings.Contains(key, args[0]) {
							if !strings.Contains(msg, "Did you mean?") {
								msg += fmt.Sprintf("\nDid you mean?\n")
							}
							msg += fmt.Sprintf("\t%s\n", key)
						}
					}
				} else {
					msg = err.Error()
				}
				fmt.Fprint(m.stderr, msg)
				m.finisher().Exit(1)
			}
			return
		}
		fmt.Fprintf(m.stderr, "Error: command %q does not exist\n", args[0])
		m.finisher().Exit(1)
		return
	}
	args = args[1:]
	info := command.Info()
	command, args, err := m.handleFlags(command, name, args)
	if err != nil {
		fmt.Fprint(m.stderr, err)
		m.finisher().Exit(1)
		return
	}
	if length := len(args); (length < info.MinArgs || (info.MaxArgs > 0 && length > info.MaxArgs)) &&
		name != "help" {
		m.wrong = true
		m.original = info.Name
		command = m.Commands["help"]
		args = []string{name}
		status = 1
	}
	context := m.newContext(args, m.stdout, m.stderr, m.stdin)

	if m.mode != nil {
		m.mode(verbosity)
	}

	err = command.Run(context)
	if err != nil {
		errorMsg := err.Error()
		if !strings.HasSuffix(errorMsg, "\n") {
			errorMsg += "\n"
		}
		if err != ErrAbortCommand {
			io.WriteString(m.stderr, "Error: "+errorMsg)
		}
		status = 1
	}

	m.finisher().Exit(status)
}

func (m *Manager) newContext(args []string, stdout io.Writer, stderr io.Writer, stdin io.Reader) *Context {
	ctx := &Context{args, stdout, stderr, stdin}
	m.contexts = append(m.contexts, ctx)
	return ctx
}

func (m *Manager) handleFlags(command Command, name string, args []string) (Command, []string, error) {
	var flagset *gnuflag.FlagSet
	if flagged, ok := command.(FlaggedCommand); ok {
		flagset = flagged.Flags()
	} else {
		flagset = gnuflag.NewFlagSet(name, gnuflag.ExitOnError)
	}
	var helpRequested bool
	flagset.SetOutput(m.stderr)
	if flagset.Lookup("help") == nil {
		flagset.BoolVar(&helpRequested, "help", false, "Display help and exit")
	}
	if flagset.Lookup("h") == nil {
		flagset.BoolVar(&helpRequested, "h", false, "Display help and exit")
	}
	err := flagset.Parse(true, args)
	if err != nil {
		return nil, nil, err
	}
	if helpRequested {
		command = m.Commands["help"]
		args = []string{name}
	} else {
		args = flagset.Args()
	}
	return command, args, nil
}

func (m *Manager) finisher() exiter {
	/*	if writer, ok := m.stdout.(*io.Writer); ok {
			writer.close()
		}
		for _, ctx := range m.contexts {
			if writer, ok := ctx.Stdout.(*io.Writer); ok {
				writer.close()
			}
		}*/
	if m.e == nil {
		m.e = osExiter{}
	}
	return m.e
}

type Command interface {
	Info() *Info
	Run(context *Context) error
}

type FlaggedCommand interface {
	Command
	Flags() *gnuflag.FlagSet
}

type DeprecatedCommand struct {
	Command
	oldName string
}

func (c *DeprecatedCommand) Run(context *Context) error {
	fmt.Fprintf(context.Stderr, "WARNING: %q has been deprecated, please use %q instead.\n\n", c.oldName, c.Command.Info().Name)
	return c.Command.Run(context)
}

func (c *DeprecatedCommand) Flags() *gnuflag.FlagSet {
	if cmd, ok := c.Command.(FlaggedCommand); ok {
		return cmd.Flags()
	}
	return gnuflag.NewFlagSet("", gnuflag.ContinueOnError)
}

type Context struct {
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
	Stdin  io.Reader
}

type Info struct {
	Name    string
	MinArgs int
	MaxArgs int
	Usage   string
	Desc    string
}

// Implementing the Commandable interface allows extending
// the megamd command line interface
type Commandable interface {
	Commands() []Command
}

// Implementing the AdminCommandable interface allows extending
// the megamd admin command line interface
type AdminCommandable interface {
	AdminCommands() []Command
}

type help struct {
	manager *Manager
}

func (c *help) Info() *Info {
	return &Info{Name: "help", Usage: "command [args]"}
}

func (c *help) Run(context *Context) error {
	const deprecatedMsg = "WARNING: %q is deprecated. Showing help for %q instead.\n\n"
	output := fmt.Sprintf("%s version %s.\n\n", c.manager.name, c.manager.version)
	if c.manager.wrong {
		output += fmt.Sprint("ERROR: wrong number of arguments.\n\n")
	}
	if len(context.Args) > 0 {
		if cmd, ok := c.manager.Commands[context.Args[0]]; ok {
			if deprecated, ok := cmd.(*DeprecatedCommand); ok {
				fmt.Fprintf(context.Stderr, deprecatedMsg, deprecated.oldName, cmd.Info().Name)
			}
			info := cmd.Info()
			output += fmt.Sprintf("Usage: %s %s\n", c.manager.name, info.Usage)
			output += fmt.Sprintf("\n%s\n", info.Desc)
			flags := c.parseFlags(cmd)
			if flags != "" {
				output += fmt.Sprintf("\n%s", flags)
			}
			if info.MinArgs > 0 {
				output += fmt.Sprintf("\nMinimum # of arguments: %d", info.MinArgs)
			}
			if info.MaxArgs > 0 {
				output += fmt.Sprintf("\nMaximum # of arguments: %d", info.MaxArgs)
			}
			output += fmt.Sprint("\n")
		} else if topic, ok := c.manager.topics[context.Args[0]]; ok {
			output += topic
		} else {
			return fmt.Errorf("command %q does not exist.", context.Args[0])
		}
	} else {
		output += fmt.Sprintf("Usage: %s %s\n\nAvailable commands:\n", c.manager.name, c.Info().Usage)
		var commands []string
		for name, cmd := range c.manager.Commands {
			if _, ok := cmd.(*DeprecatedCommand); !ok {
				commands = append(commands, name)
			}
		}
		sort.Strings(commands)
		maxCmdSize := 20
		for _, command := range commands {
			if len(command) > maxCmdSize {
				maxCmdSize = len(command)
			}
		}
		for _, command := range commands {
			description := c.manager.Commands[command].Info().Desc
			description = strings.Split(description, "\n")[0]
			description = strings.Split(description, ".")[0]
			if len(description) > 2 {
				description = strings.ToUpper(description[:1]) + description[1:]
			}
			fmtStr := fmt.Sprintf("  %%-%ds %%s\n", maxCmdSize)
			output += fmt.Sprintf(fmtStr, command, description)
		}
		output += fmt.Sprintf("\nUse %s help <commandname> to get more information about a command.\n", c.manager.name)
		if len(c.manager.topics) > 0 {
			output += fmt.Sprintln("\nAvailable topics:")
			for topic := range c.manager.topics {
				output += fmt.Sprintf("  %s\n", topic)
			}
			output += fmt.Sprintf("\nUse %s help <topicname> to get more information about a topic.\n", c.manager.name)
		}
	}
	io.WriteString(context.Stdout, output)
	return nil
}

func (c *help) parseFlags(command Command) string {
	var output string
	if cmd, ok := command.(FlaggedCommand); ok {
		var buf bytes.Buffer
		flagset := cmd.Flags()
		flagset.SetOutput(&buf)
		flagset.PrintDefaults()
		if buf.String() != "" {
			output = fmt.Sprintf("Flags:\n\n%s", buf.String())
		}
	}
	return strings.Replace(output, "\n", "\n  ", -1)
}

type version struct {
	manager *Manager
}

func (c *version) Info() *Info {
	return &Info{
		Name:    "version",
		MinArgs: 0,
		Usage:   "version",
		Desc:    "display the current version",
	}
}

func (c *version) Run(context *Context) error {
	fmt.Fprintf(context.Stdout, "%s version %s.\n", c.manager.name, c.manager.version)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}
<commit_msg>added a colored help<commit_after>package cmd

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"sort"
	"strings"

	"github.com/megamsys/libgo/fs"
	"github.com/sajari/fuzzy"
	"launchpad.net/gnuflag"
)

var ErrAbortCommand = errors.New("")
var errUnauthorized = errors.New("unauthorized")

type exiter interface {
	Exit(int)
}

type osExiter struct{}

func (e osExiter) Exit(code int) {
	os.Exit(code)
}

type Lookup func(context *Context) error

type Mode func(modelvl int)

type Manager struct {
	Commands map[string]Command
	topics   map[string]string
	name     string
	stdout   io.Writer
	stderr   io.Writer
	stdin    io.Reader
	version  string
	e        exiter
	original string
	wrong    bool
	lookup   Lookup
	contexts []*Context
	mode     Mode
}

func NewManager(name, ver string, stdout, stderr io.Writer, stdin io.Reader, lookup Lookup, mode Mode) *Manager {
	manager := &Manager{name: name, version: ver, stdout: stdout, stderr: stderr, stdin: stdin, lookup: lookup, mode: mode}
	manager.Register(&help{manager})
	manager.Register(&version{manager})
	return manager
}

func BuildBaseManager(name, version string, lookup Lookup, mode Mode) *Manager {
	m := NewManager(name, version, os.Stdout, os.Stderr, os.Stdin, lookup, mode)
	return m
}

func (m *Manager) Register(command Command) {
	if m.Commands == nil {
		m.Commands = make(map[string]Command)
	}
	name := command.Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
}

func (m *Manager) RegisterDeprecated(command Command, oldName string) {
	if m.Commands == nil {
		m.Commands = make(map[string]Command)
	}
	name := command.Info().Name
	_, found := m.Commands[name]
	if found {
		panic(fmt.Sprintf("command already registered: %s", name))
	}
	m.Commands[name] = command
	m.Commands[oldName] = &DeprecatedCommand{Command: command, oldName: oldName}
}

func (m *Manager) RegisterTopic(name, content string) {
	if m.topics == nil {
		m.topics = make(map[string]string)
	}
	_, found := m.topics[name]
	if found {
		panic(fmt.Sprintf("topic already registered: %s", name))
	}
	m.topics[name] = content
}

func (m *Manager) Run(args []string) {
	var (
		status         int
		verbosity      int
		displayHelp    bool
		displayVersion bool
	)
	if len(args) == 0 {
		args = append(args, "help")
	}
	flagset := gnuflag.NewFlagSet("megamd flags", gnuflag.ContinueOnError)
	flagset.SetOutput(m.stderr)
	flagset.IntVar(&verbosity, "verbosity", 0, "Verbosity level: 1 => print debug")
	flagset.IntVar(&verbosity, "v", 0, "Verbosity level: 1 => print debug")
	flagset.BoolVar(&displayHelp, "help", false, "Display help and exit")
	flagset.BoolVar(&displayHelp, "h", false, "Display help and exit")
	flagset.BoolVar(&displayVersion, "version", false, "Print version and exit")
	parseErr := flagset.Parse(false, args)
	if parseErr != nil {
		fmt.Fprint(m.stderr, parseErr)
		m.finisher().Exit(2)
		return
	}
	args = flagset.Args()
	if displayHelp {
		args = append([]string{"help"}, args...)
	} else if displayVersion {
		args = []string{"version"}
	}
	name := args[0]
	command, ok := m.Commands[name]
	if !ok {
		if m.lookup != nil {
			context := m.newContext(args, m.stdout, m.stderr, m.stdin)
			err := m.lookup(context)
			if err != nil {
				msg := ""
				if os.IsNotExist(err) {
					msg = fmt.Sprintf("%s: %q is not a megamd command. See %q.\n", os.Args[0], args[0], "megamd help")
					var keys []string
					for key := range m.Commands {
						keys = append(keys, key)
					}
					sort.Strings(keys)
					for _, key := range keys {
						levenshtein := fuzzy.Levenshtein(&key, &args[0])
						if levenshtein < 3 || strings.Contains(key, args[0]) {
							if !strings.Contains(msg, "Did you mean?") {
								msg += fmt.Sprintf("\nDid you mean?\n")
							}
							msg += fmt.Sprintf("\t%s\n", key)
						}
					}
				} else {
					msg = err.Error()
				}
				fmt.Fprint(m.stderr, msg)
				m.finisher().Exit(1)
			}
			return
		}
		fmt.Fprintf(m.stderr, "Error: command %q does not exist\n", args[0])
		m.finisher().Exit(1)
		return
	}
	args = args[1:]
	info := command.Info()
	command, args, err := m.handleFlags(command, name, args)
	if err != nil {
		fmt.Fprint(m.stderr, err)
		m.finisher().Exit(1)
		return
	}
	if length := len(args); (length < info.MinArgs || (info.MaxArgs > 0 && length > info.MaxArgs)) &&
		name != "help" {
		m.wrong = true
		m.original = info.Name
		command = m.Commands["help"]
		args = []string{name}
		status = 1
	}
	context := m.newContext(args, m.stdout, m.stderr, m.stdin)

	if m.mode != nil {
		m.mode(verbosity)
	}

	err = command.Run(context)
	if err != nil {
		errorMsg := err.Error()
		if !strings.HasSuffix(errorMsg, "\n") {
			errorMsg += "\n"
		}
		if err != ErrAbortCommand {
			io.WriteString(m.stderr, "Error: "+errorMsg)
		}
		status = 1
	}

	m.finisher().Exit(status)
}

func (m *Manager) newContext(args []string, stdout io.Writer, stderr io.Writer, stdin io.Reader) *Context {
	ctx := &Context{args, stdout, stderr, stdin}
	m.contexts = append(m.contexts, ctx)
	return ctx
}

func (m *Manager) handleFlags(command Command, name string, args []string) (Command, []string, error) {
	var flagset *gnuflag.FlagSet
	if flagged, ok := command.(FlaggedCommand); ok {
		flagset = flagged.Flags()
	} else {
		flagset = gnuflag.NewFlagSet(name, gnuflag.ExitOnError)
	}
	var helpRequested bool
	flagset.SetOutput(m.stderr)
	if flagset.Lookup("help") == nil {
		flagset.BoolVar(&helpRequested, "help", false, "Display help and exit")
	}
	if flagset.Lookup("h") == nil {
		flagset.BoolVar(&helpRequested, "h", false, "Display help and exit")
	}
	err := flagset.Parse(true, args)
	if err != nil {
		return nil, nil, err
	}
	if helpRequested {
		command = m.Commands["help"]
		args = []string{name}
	} else {
		args = flagset.Args()
	}
	return command, args, nil
}

func (m *Manager) finisher() exiter {
	/*	if writer, ok := m.stdout.(*io.Writer); ok {
			writer.close()
		}
		for _, ctx := range m.contexts {
			if writer, ok := ctx.Stdout.(*io.Writer); ok {
				writer.close()
			}
		}*/
	if m.e == nil {
		m.e = osExiter{}
	}
	return m.e
}

type Command interface {
	Info() *Info
	Run(context *Context) error
}

type FlaggedCommand interface {
	Command
	Flags() *gnuflag.FlagSet
}

type DeprecatedCommand struct {
	Command
	oldName string
}

func (c *DeprecatedCommand) Run(context *Context) error {
	fmt.Fprintf(context.Stderr, "WARNING: %q has been deprecated, please use %q instead.\n\n", c.oldName, c.Command.Info().Name)
	return c.Command.Run(context)
}

func (c *DeprecatedCommand) Flags() *gnuflag.FlagSet {
	if cmd, ok := c.Command.(FlaggedCommand); ok {
		return cmd.Flags()
	}
	return gnuflag.NewFlagSet("", gnuflag.ContinueOnError)
}

type Context struct {
	Args   []string
	Stdout io.Writer
	Stderr io.Writer
	Stdin  io.Reader
}

type Info struct {
	Name    string
	MinArgs int
	MaxArgs int
	Usage   string
	Desc    string
}

// Implementing the Commandable interface allows extending
// the megamd command line interface
type Commandable interface {
	Commands() []Command
}

// Implementing the AdminCommandable interface allows extending
// the megamd admin command line interface
type AdminCommandable interface {
	AdminCommands() []Command
}

type help struct {
	manager *Manager
}

func (c *help) Info() *Info {
	return &Info{Name: "help", Usage: "command [args]"}
}

func (c *help) Run(context *Context) error {
	const deprecatedMsg = "WARNING: %q is deprecated. Showing help for %q instead.\n\n"
	output := fmt.Sprintf("%s version %s.\n\n",
		Colorfy(c.manager.name, "yellow", "", "bold"),
		Colorfy(c.manager.version, "blue", "", "bold"))
	if c.manager.wrong {
		output += fmt.Sprint("%s: %s.\n\n", Colorfy("ERROR", "red", "", "bold"),
			Colorfy("wrong number of arguments", "white", "", "bold"))
	}
	if len(context.Args) > 0 {
		if cmd, ok := c.manager.Commands[context.Args[0]]; ok {
			if deprecated, ok := cmd.(*DeprecatedCommand); ok {
				fmt.Fprintf(context.Stderr, deprecatedMsg, deprecated.oldName, cmd.Info().Name)
			}
			info := cmd.Info()
			output += fmt.Sprintf("%s %s %s\n",
				Colorfy("Usage:", "white", "", "bold"),
				Colorfy(c.manager.name, "yellow", "", "bold"),
				Colorfy(info.Usage, "cyan", "", ""))
			output += fmt.Sprintf("\n%s\n", info.Desc)
			flags := c.parseFlags(cmd)
			if flags != "" {
				output += fmt.Sprintf("\n%s", flags)
			}
			if info.MinArgs > 0 {
				output += fmt.Sprintf("\nMinimum # of arguments: %d", info.MinArgs)
			}
			if info.MaxArgs > 0 {
				output += fmt.Sprintf("\nMaximum # of arguments: %d", info.MaxArgs)
			}
			output += fmt.Sprint("\n")
		} else if topic, ok := c.manager.topics[context.Args[0]]; ok {
			output += topic
		} else {
			return fmt.Errorf("command %q does not exist.", context.Args[0])
		}
	} else {
		output += fmt.Sprintf("Usage: %s %s\n\nAvailable commands:\n", c.manager.name, c.Info().Usage)
		var commands []string
		for name, cmd := range c.manager.Commands {
			if _, ok := cmd.(*DeprecatedCommand); !ok {
				commands = append(commands, name)
			}
		}
		sort.Strings(commands)
		maxCmdSize := 20
		for _, command := range commands {
			if len(command) > maxCmdSize {
				maxCmdSize = len(command)
			}
		}
		for _, command := range commands {
			description := c.manager.Commands[command].Info().Desc
			description = strings.Split(description, "\n")[0]
			description = strings.Split(description, ".")[0]
			if len(description) > 2 {
				description = strings.ToUpper(description[:1]) + description[1:]
			}
			fmtStr := fmt.Sprintf("  %%-%ds %%s\n", maxCmdSize)
			output += fmt.Sprintf(fmtStr, command, description)
		}
		output += fmt.Sprintf("\nUse %s help <commandname> to get more information about a command.\n", c.manager.name)
		if len(c.manager.topics) > 0 {
			output += fmt.Sprintln("\nAvailable topics:")
			for topic := range c.manager.topics {
				output += fmt.Sprintf("  %s\n", topic)
			}
			output += fmt.Sprintf("\nUse %s help <topicname> to get more information about a topic.\n", c.manager.name)
		}
	}
	io.WriteString(context.Stdout, output)
	return nil
}

func (c *help) parseFlags(command Command) string {
	var output string
	if cmd, ok := command.(FlaggedCommand); ok {
		var buf bytes.Buffer
		flagset := cmd.Flags()
		flagset.SetOutput(&buf)
		flagset.PrintDefaults()
		if buf.String() != "" {
			output = fmt.Sprintf("Flags:\n\n%s", buf.String())
		}
	}
	return strings.Replace(output, "\n", "\n  ", -1)
}

type version struct {
	manager *Manager
}

func (c *version) Info() *Info {
	return &Info{
		Name:    "version",
		MinArgs: 0,
		Usage:   "version",
		Desc:    "display the current version",
	}
}

func (c *version) Run(context *Context) error {
	fmt.Fprintf(context.Stdout, "%s version %s.\n", c.manager.name, c.manager.version)
	return nil
}

func ExtractProgramName(path string) string {
	parts := strings.Split(path, "/")
	return parts[len(parts)-1]
}

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/deepthawtz/kv/store"
	consul "github.com/hashicorp/consul/api"
	"github.com/spf13/cobra"
)

var (
	prefix string
)

// getCmd represents the get command
var getCmd = &cobra.Command{
	Use:   "get [KEY]",
	Short: "get key/value pairs for a given key prefix (e.g., env/myapp/stage)",
	Long:  `get all key/value pairs or for specific key if provided`,
	Run:   Get,
}

func init() {
	RootCmd.AddCommand(getCmd)

	getCmd.Flags().StringVarP(&prefix, "prefix", "p", "", "prefix to get key/values from")
}

// Get fetches key values
func Get(cmd *cobra.Command, args []string) {
	if prefix == "" {
		fmt.Println("must supply key/value path --prefix")
		os.Exit(-1)
	}

	client := store.NewConsulClient()
	kvs, err := get(client, args...)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	for _, x := range kvs {
		fmt.Println(x)
	}
}

func get(client *consul.KV, args ...string) ([]*store.KVPair, error) {
	var (
		wildcards []string
		specific  []string
		kvpairs   consul.KVPairs
	)

	all, _, err := client.List(prefix, nil)

	// filter just the key/values with matching prefix
	var scoped consul.KVPairs
	for _, kv := range all {
		if len(kv.Value) > 0 {
			p := len(strings.Split(prefix, "/"))
			k := len(strings.Split(string(kv.Key), "/"))
			if p == k-1 {
				scoped = append(scoped, kv)
			}
		}
	}

	if len(args) == 0 {
		kvpairs = scoped
	} else {
		for _, x := range args {
			if strings.Contains(x, "*") {
				x = strings.Replace(x, "*", ".*", -1)
				wildcards = append(wildcards, x)
			} else {
				specific = append(specific, x)
			}
		}

		for _, wc := range wildcards {
			for _, k := range scoped {
				m, err := regexp.MatchString(wc, k.Key)
				if err != nil {
					return nil, err
				}
				if m {
					kvpairs = append(kvpairs, k)
				}
			}
		}

		for _, s := range specific {
			for _, k := range scoped {
				key := strings.Join([]string{prefix, s}, "/")
				if key == string(k.Key) {
					kvpairs = append(kvpairs, k)
				}
			}
		}
	}

	if err != nil {
		return nil, err
	}

	var kvs []*store.KVPair
	for _, kvp := range kvpairs {
		if len(kvp.Value) > 0 {
			v := string(kvp.Value)
			kvs = append(kvs, &store.KVPair{Key: kvp.Key, Value: v})
		}
	}

	return kvs, nil
}
<commit_msg>break up get code into smaller functions<commit_after>// Copyright © 2016 Dylan Clendenin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/deepthawtz/kv/store"
	consul "github.com/hashicorp/consul/api"
	"github.com/spf13/cobra"
)

var (
	prefix string
)

// getCmd represents the get command
var getCmd = &cobra.Command{
	Use:   "get [KEY]",
	Short: "get key/value pairs for a given key prefix (e.g., env/myapp/stage)",
	Long:  `get all key/value pairs or for specific key if provided`,
	Run:   Get,
}

func init() {
	RootCmd.AddCommand(getCmd)

	getCmd.Flags().StringVarP(&prefix, "prefix", "p", "", "prefix to get key/values from")
}

// Get fetches key values
func Get(cmd *cobra.Command, args []string) {
	if prefix == "" {
		fmt.Println("must supply key/value path --prefix")
		os.Exit(-1)
	}

	client := store.NewConsulClient()
	kvs, err := get(client, args...)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}

	for _, x := range kvs {
		fmt.Println(x)
	}
}

func get(client *consul.KV, args ...string) ([]*store.KVPair, error) {
	all, _, err := client.List(prefix, nil)
	if err != nil {
		return nil, err
	}

	scoped := scopedKeys(all)
	kvpairs, err := matchingKVPairs(scoped, args)
	if err != nil {
		return nil, err
	}

	var kvs []*store.KVPair
	for _, kvp := range kvpairs {
		if len(kvp.Value) > 0 {
			v := string(kvp.Value)
			kvs = append(kvs, &store.KVPair{Key: kvp.Key, Value: v})
		}
	}

	return kvs, nil
}

func scopedKeys(keys consul.KVPairs) consul.KVPairs {
	// filter just the key/values with matching prefix
	var scoped consul.KVPairs
	for _, kv := range keys {
		if len(kv.Value) > 0 {
			p := len(strings.Split(prefix, "/"))
			k := len(strings.Split(string(kv.Key), "/"))
			if p == k-1 {
				scoped = append(scoped, kv)
			}
		}
	}
	return scoped
}

// partitionArgs filters args and returns both args containing wildcards
// and args without wildcards (specific)
func partitionArgs(args []string) (wildcards []string, specific []string) {
	for _, x := range args {
		if strings.Contains(x, "*") {
			x = strings.Replace(x, "*", ".*", -1)
			wildcards = append(wildcards, x)
		} else {
			specific = append(specific, x)
		}
	}

	return wildcards, specific
}

func matchingKVPairs(scoped consul.KVPairs, args []string) (consul.KVPairs, error) {
	var kvpairs consul.KVPairs
	if len(args) == 0 {
		return scoped, nil
	}

	wildcards, specific := partitionArgs(args)
	for _, wc := range wildcards {
		for _, k := range scoped {
			m, err := regexp.MatchString(wc, k.Key)
			if err != nil {
				return nil, err
			}
			if m {
				kvpairs = append(kvpairs, k)
			}
		}
	}

	for _, s := range specific {
		for _, k := range scoped {
			key := strings.Join([]string{prefix, s}, "/")
			if key == string(k.Key) {
				kvpairs = append(kvpairs, k)
			}
		}
	}

	return kvpairs, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"log"

	"github.com/spf13/cobra"
	"github.com/zhongwei/goreader/netdata"
	"github.com/zhongwei/goreader/store"
)

var (
    url string
)

var getCmd = &cobra.Command{
	Use:   "get",
	Short: "A brief description of your command",
	Long: ` and usage of using your command. For example: Cobra is a CLI library for Go that empockly create a Cobra application.`,
	Run: func(cmd *cobra.Command, args []string) {
		    log.Println("get content from : " + url)
        siteContent := netdata.Get(url)
        store.Save(url, siteContent)
	},
}

func init() {
	RootCmd.AddCommand(getCmd)
  getCmd.PersistentFlags().String("foo", "", "A help for foo")
  getCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
  getCmd.Flags().StringVarP(&url, "url", "u", "", "Get site url address.")
}
<commit_msg>support input multiple url one time<commit_after>package cmd

import (
	"fmt"
	"reflect"

	"github.com/spf13/cobra"
	"github.com/zhongwei/goreader/netdata"
	"github.com/zhongwei/goreader/store"
)

var (
	urls []string
)

var getCmd = &cobra.Command{
	Use:   "get",
	Short: "A brief description of your command",
	Long:  ` and usage of using your command. For example: Cobra is a CLI library for Go that empockly create a Cobra application.`,
	Run: func(cmd *cobra.Command, args []string) {
		for no, url := range urls {
			fmt.Printf("get content from index : %d\n", no)
			fmt.Println("type:", reflect.TypeOf(no))
			fmt.Println("get content from : " + url)
			siteContent := netdata.Get(url)
			store.Save(url, siteContent)
		}
	},
}

func init() {
	RootCmd.AddCommand(getCmd)
	getCmd.PersistentFlags().String("foo", "", "A help for foo")
	getCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
	getCmd.Flags().StringSliceVarP(&urls, "urls", "u", []string{}, "Get site url address.")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsf/termbox-go"
	"log"
	"math/rand"
	"strconv"
	"time"
)

const (
	ColorWall  = termbox.ColorRed
	ColorEmpty = termbox.ColorBlack
	ColorSnake = termbox.ColorGreen
	ColorFood  = termbox.ColorYellow
)

type Cell struct {
	X     int
	Y     int
	Clear bool
	Color termbox.Attribute
}

type Segment struct {
	X   int
	Y   int
	Dir int
}

func gameOver(snake []Segment, board [][]Cell) {
	for i := range snake {
		termbox.SetCell(snake[i].X, snake[i].Y, 0x0000, termbox.ColorBlack, termbox.ColorRed)
	}
	termbox.Flush()
	return
}

func renderScore(score uint64) {
	scoreStr := strconv.FormatUint(score, 10)
	for i := range scoreStr {
		termbox.SetCell(i, 0, rune(scoreStr[i]), termbox.ColorBlack, ColorWall)
	}
}

func moveSnake(snake []Segment, board [][]Cell, lastDir *int) {
	score := uint64(0)
	renderScore(score)
	ticker := time.NewTicker(100 * time.Millisecond)
	food := false
	for {
		if !food {
			randX := rand.Intn(len(board[0]))
			randY := rand.Intn(len(board))
			for !board[randY][randX].Clear {
				randX = rand.Intn(len(board[0]))
				randY = rand.Intn(len(board))
			}
			board[randY][randX].Clear = false
			board[randY][randX].Color = ColorFood
			termbox.SetCell(randX, randY, 0x0000, termbox.ColorBlack, ColorFood)
			food = true
		}
		for i := 0; i < len(snake); i++ {
			if i == len(snake)-1 {
				board[snake[i].Y][snake[i].X].Color = ColorEmpty
				board[snake[i].Y][snake[i].X].Clear = true
				termbox.SetCell(snake[i].X, snake[i].Y, 0x0000, termbox.ColorBlack, ColorEmpty)
			}
			switch snake[i].Dir {
			case 0:
				snake[i].Y = snake[i].Y - 1
				break
			case 1:
				snake[i].X = snake[i].X + 1
				break
			case 2:
				snake[i].Y = snake[i].Y + 1
				break
			case 3:
				snake[i].X = snake[i].X - 1
				break
			}
			if i == 0 {
				if !board[snake[0].Y][snake[0].X].Clear { //collision
					if board[snake[0].Y][snake[0].X].Color == ColorFood { //with food
						food = false
						newX := snake[len(snake)-1].X
						newY := snake[len(snake)-1].Y
						switch snake[len(snake)-1].Dir {
						case 0:
							newY = newY + 1
							break
						case 1:
							newX = newX - 1
							break
						case 2:
							newY = newY - 1
							break
						case 3:
							newX = newX + 1
							break
						}
						snake = append(snake, Segment{newX, newY, snake[len(snake)-1].Dir})
						board[newY][newX].Color = ColorSnake
						board[newY][newX].Clear = false
						score++
						renderScore(score)
					} else { //with wall
						switch snake[0].Dir { //undo move of head segment
						case 0:
							snake[0].Y = snake[0].Y + 1
							break
						case 1:
							snake[0].X = snake[0].X - 1
							break
						case 2:
							snake[0].Y = snake[0].Y - 1
							break
						case 3:
							snake[0].X = snake[0].X + 1
							break
						}
						gameOver(snake, board)
						return
					}
				}
				board[snake[0].Y][snake[0].X].Color = ColorSnake
				board[snake[0].Y][snake[0].X].Clear = false
				termbox.SetCell(snake[0].X, snake[0].Y, 0x0000, termbox.ColorBlack, ColorSnake)
			}
		}
		for j := len(snake) - 1; j > 0; j-- {
			snake[j].Dir = snake[j-1].Dir
		}
		*lastDir = snake[0].Dir
		termbox.Flush()
		<-ticker.C
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())
	err := termbox.Init()
	if err != nil {
		log.Panicln(err)
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc)

	boardSizeY := 40
	boardSizeX := boardSizeY * 2
	termSizeX, termSizeY := termbox.Size()
	if termSizeY < boardSizeY {
		boardSizeY = termSizeY
	}
	if termSizeX < boardSizeX {
		boardSizeX = termSizeX
	}
	board := make([][]Cell, boardSizeY)
	for y := range board {
		board[y] = make([]Cell, boardSizeX)
		for x := range board[y] {
			if x == 0 || y == 0 || x == (boardSizeX)-1 || y == boardSizeY-1 {
				board[y][x] = Cell{x, y, false, ColorWall}
			} else {
				board[y][x] = Cell{x, y, true, ColorEmpty}
			}
		}
	}
	snake := make([]Segment, 7, 1024)
	for i := range snake {
		snake[i] = Segment{40 - i, 20, 1}
		board[20][40-i].Color = ColorSnake
		board[20][40-i].Clear = false
	}
	for _, row := range board {
		for _, cell := range row {
			termbox.SetCell(cell.X, cell.Y, 0x0000, termbox.ColorBlack, cell.Color)
		}
	}
	termbox.Flush()
	lastDir := snake[0].Dir
	go moveSnake(snake, board, &lastDir)
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyArrowUp:
				if lastDir != 2 {
					snake[0].Dir = 0
				}
				break
			case termbox.KeyArrowRight:
				if lastDir != 3 {
					snake[0].Dir = 1
				}
				break
			case termbox.KeyArrowDown:
				if lastDir != 0 {
					snake[0].Dir = 2
				}
				break
			case termbox.KeyArrowLeft:
				if lastDir != 1 {
					snake[0].Dir = 3
				}
				break
			case termbox.KeyCtrlC:
				return
			}
		case termbox.EventError:
			log.Panic(ev.Err)
			break
		}
	}
}
<commit_msg>use space instead of null as filler<commit_after>package main

import (
	"github.com/nsf/termbox-go"
	"log"
	"math/rand"
	"strconv"
	"time"
)

const (
	ColorWall  = termbox.ColorRed
	ColorEmpty = termbox.ColorBlack
	ColorSnake = termbox.ColorGreen
	ColorFood  = termbox.ColorYellow
)

type Cell struct {
	X     int
	Y     int
	Clear bool
	Color termbox.Attribute
}

type Segment struct {
	X   int
	Y   int
	Dir int
}

func gameOver(snake []Segment, board [][]Cell) {
	for i := range snake {
		termbox.SetCell(snake[i].X, snake[i].Y, 0x0020, termbox.ColorBlack, termbox.ColorRed)
	}
	termbox.Flush()
	return
}

func renderScore(score uint64) {
	scoreStr := strconv.FormatUint(score, 10)
	for i := range scoreStr {
		termbox.SetCell(i, 0, rune(scoreStr[i]), termbox.ColorBlack, ColorWall)
	}
}

func moveSnake(snake []Segment, board [][]Cell, lastDir *int) {
	score := uint64(0)
	renderScore(score)
	ticker := time.NewTicker(100 * time.Millisecond)
	food := false
	for {
		if !food {
			randX := rand.Intn(len(board[0]))
			randY := rand.Intn(len(board))
			for !board[randY][randX].Clear {
				randX = rand.Intn(len(board[0]))
				randY = rand.Intn(len(board))
			}
			board[randY][randX].Clear = false
			board[randY][randX].Color = ColorFood
			termbox.SetCell(randX, randY, 0x0020, termbox.ColorBlack, ColorFood)
			food = true
		}
		for i := 0; i < len(snake); i++ {
			if i == len(snake)-1 {
				board[snake[i].Y][snake[i].X].Color = ColorEmpty
				board[snake[i].Y][snake[i].X].Clear = true
				termbox.SetCell(snake[i].X, snake[i].Y, 0x0020, termbox.ColorBlack, ColorEmpty)
			}
			switch snake[i].Dir {
			case 0:
				snake[i].Y = snake[i].Y - 1
				break
			case 1:
				snake[i].X = snake[i].X + 1
				break
			case 2:
				snake[i].Y = snake[i].Y + 1
				break
			case 3:
				snake[i].X = snake[i].X - 1
				break
			}
			if i == 0 {
				if !board[snake[0].Y][snake[0].X].Clear { //collision
					if board[snake[0].Y][snake[0].X].Color == ColorFood { //with food
						food = false
						newX := snake[len(snake)-1].X
						newY := snake[len(snake)-1].Y
						switch snake[len(snake)-1].Dir {
						case 0:
							newY = newY + 1
							break
						case 1:
							newX = newX - 1
							break
						case 2:
							newY = newY - 1
							break
						case 3:
							newX = newX + 1
							break
						}
						snake = append(snake, Segment{newX, newY, snake[len(snake)-1].Dir})
						board[newY][newX].Color = ColorSnake
						board[newY][newX].Clear = false
						score++
						renderScore(score)
					} else { //with wall
						switch snake[0].Dir { //undo move of head segment
						case 0:
							snake[0].Y = snake[0].Y + 1
							break
						case 1:
							snake[0].X = snake[0].X - 1
							break
						case 2:
							snake[0].Y = snake[0].Y - 1
							break
						case 3:
							snake[0].X = snake[0].X + 1
							break
						}
						gameOver(snake, board)
						return
					}
				}
				board[snake[0].Y][snake[0].X].Color = ColorSnake
				board[snake[0].Y][snake[0].X].Clear = false
				termbox.SetCell(snake[0].X, snake[0].Y, 0x0020, termbox.ColorBlack, ColorSnake)
			}
		}
		for j := len(snake) - 1; j > 0; j-- {
			snake[j].Dir = snake[j-1].Dir
		}
		*lastDir = snake[0].Dir
		termbox.Flush()
		<-ticker.C
	}
}

func main() {
	rand.Seed(time.Now().UnixNano())
	err := termbox.Init()
	if err != nil {
		log.Panicln(err)
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc)

	boardSizeY := 40
	boardSizeX := boardSizeY * 2
	termSizeX, termSizeY := termbox.Size()
	if termSizeY < boardSizeY {
		boardSizeY = termSizeY
	}
	if termSizeX < boardSizeX {
		boardSizeX = termSizeX
	}
	board := make([][]Cell, boardSizeY)
	for y := range board {
		board[y] = make([]Cell, boardSizeX)
		for x := range board[y] {
			if x == 0 || y == 0 || x == (boardSizeX)-1 || y == boardSizeY-1 {
				board[y][x] = Cell{x, y, false, ColorWall}
			} else {
				board[y][x] = Cell{x, y, true, ColorEmpty}
			}
		}
	}
	snake := make([]Segment, 7, 1024)
	for i := range snake {
		snake[i] = Segment{40 - i, 20, 1}
		board[20][40-i].Color = ColorSnake
		board[20][40-i].Clear = false
	}
	for _, row := range board {
		for _, cell := range row {
			termbox.SetCell(cell.X, cell.Y, 0x0020, termbox.ColorBlack, cell.Color)
		}
	}
	termbox.Flush()
	lastDir := snake[0].Dir
	go moveSnake(snake, board, &lastDir)
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyArrowUp:
				if lastDir != 2 {
					snake[0].Dir = 0
				}
				break
			case termbox.KeyArrowRight:
				if lastDir != 3 {
					snake[0].Dir = 1
				}
				break
			case termbox.KeyArrowDown:
				if lastDir != 0 {
					snake[0].Dir = 2
				}
				break
			case termbox.KeyArrowLeft:
				if lastDir != 1 {
					snake[0].Dir = 3
				}
				break
			case termbox.KeyCtrlC:
				return
			}
		case termbox.EventError:
			log.Panic(ev.Err)
			break
		}
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
 * Author: Alex Yatskov <alex@foosoft.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

type command []string

func (c *command) process(dir string, flags int) error {
	if len(*c) < 1 {
		return fmt.Errorf("command element is invalid")
	}

	cmd := exec.Command((*c)[0], (*c)[1:]...)
	cmd.Dir = dir
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout

	if flags&flagVerbose == flagVerbose {
		log.Printf("executing command %s", strings.Join(*c, " "))
	}

	return cmd.Run()
}
<commit_msg>Fixing issues with stdin<commit_after>/*
 * Copyright (c) 2015 Alex Yatskov <alex@foosoft.net>
 * Author: Alex Yatskov <alex@foosoft.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

type command []string

func (c *command) process(dir string, flags int) error {
	if len(*c) < 1 {
		return fmt.Errorf("command element is invalid")
	}

	cmd := exec.Command((*c)[0], (*c)[1:]...)
	cmd.Dir = dir
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	cmd.Stdin = os.Stdin

	if flags&flagVerbose == flagVerbose {
		log.Printf("executing command %s", strings.Join(*c, " "))
	}

	return cmd.Run()
}
<|endoftext|>


<commit_before>package vt100

import (
	"errors"
	"fmt"
	"image/color"
	"regexp"
	"strconv"
	"strings"

	"github.com/golang/glog"
)

const (
	// When the terminal asks that the color be set to a number,
	// that number less the base is the vt100.Color type we should
	// set for the corresponding region (background or foreground)
	fgBase = 30
	bgBase = 40
)

// command is a type of object that knows how to display itself
// to the terminal.
type command interface {
	display(v *VT100)
}

// runeCommand is a simple command that just writes a rune
// to the current cell and advances the cursor.
type runeCommand rune

func (r runeCommand) display(v *VT100) {
	v.put(rune(r))
}

// escapeCommand is a control sequence command. It includes a variety
// of control and escape sequences that move and modify the cursor
// or the terminal.
type escapeCommand struct {
	cmd  rune
	args string
}

type intHandler func(*VT100, []int)

var (
	// intHandlers are handlers for which all arguments are numbers.
	// This is most of them -- all the ones that we process. Eventually,
	// we may add handlers that support non-int args. Those handlers
	// will instead receive []string, and they'll have to choose on their
	// own how they might be parsed.
	intHandlers = map[rune]intHandler{
		's': save,
		'7': save,
		'u': unsave,
		'8': unsave,
		'A': relativeMove(-1, 0),
		'B': relativeMove(1, 0),
		'C': relativeMove(0, 1),
		'D': relativeMove(0, -1),
		'K': eraseColumns,
		'J': eraseLines,
		'H': home,
		'f': home,
		'm': updateAttributes,
	}
)

func save(v *VT100, _ []int) {
	v.save()
}

func unsave(v *VT100, _ []int) {
	v.unsave()
}

var (
	codeColors = []color.RGBA{
		Black,
		Red,
		Green,
		Yellow,
		Blue,
		Magenta,
		Cyan,
		White,
	}
)

// A command to update the attributes of the cursor based on the arg list.
func updateAttributes(v *VT100, args []int) {
	f := &v.Cursor.F

	for _, x := range args {
		switch x {
		case 0:
			*f = Format{}
		case 1:
			f.Intensity = Bright
		case 2:
			f.Intensity = Dim
		case 22:
			f.Intensity = Normal
		case 4:
			f.Underscore = true
		case 24:
			f.Underscore = false
		case 5, 6:
			f.Blink = true // We don't distinguish between blink speeds.
		case 25:
			f.Blink = false
		case 8:
			f.Conceal = true
		case 28:
			f.Conceal = false
		case 30, 31, 32, 33, 34, 35, 36, 37:
			f.Fg = codeColors[x-30]
		case 39:
			f.Fg = FgDefault
		case 40, 41, 42, 43, 44, 45, 46, 47:
			f.Bg = codeColors[x-40]
		case 49:
			f.Bg = BgDefault
			// 38 and 48 not supported. Maybe someday.
		}
	}
}

func relativeMove(y, x int) func(*VT100, []int) {
	return func(v *VT100, args []int) {
		c := 1
		if len(args) >= 1 {
			c = args[0]
		}
		v.move(y*c, x*c)
	}
}

func eraseColumns(v *VT100, args []int) {
	d := eraseForward
	if len(args) > 0 {
		d = eraseDirection(args[0])
	}
	v.eraseColumns(d)
}

func eraseLines(v *VT100, args []int) {
	d := eraseForward
	if len(args) > 0 {
		d = eraseDirection(args[0])
	}
	v.eraseLines(d)
}

func home(v *VT100, args []int) {
	var y, x int
	if len(args) >= 2 {
		y, x = args[0], args[1]
	}
	v.home(y, x)
}

func (c escapeCommand) display(v *VT100) {
	f, ok := intHandlers[c.cmd]
	if !ok {
		c.log(errors.New("unsupported command"))
		return
	}

	args, err := c.argInts()
	if err != nil {
		err = fmt.Errorf("while parsing int args: %v", err)
		c.log(err)
		v.Err = err
	}

	f(v, args)
}

// log logs a problem with a escapeCommand at the warning level. Generally speaking,
// only parse errors and unsupported commands will be logged. The idea here
// is that, through logs, we'll be able to figure out what codes are unsupported
// but actually used that we need to implement.
func (c escapeCommand) log(e error) {
	glog.Warningf("[%v] %s", e)
}

var csArgsRe = regexp.MustCompile("^([^0-9]*)(.*)$")

// argInts parses c.args as a slice of at least arity ints. If the number
// of ; separated arguments is less than arity, the remaining elements of
// the result will be zero. errors only on integer parsing failure.
func (c escapeCommand) argInts() ([]int, error) {
	if len(c.args) == 0 {
		return make([]int, 0), nil
	}
	args := strings.Split(c.args, ";")
	out := make([]int, len(args))
	for i, s := range args {
		x, err := strconv.ParseInt(s, 10, 0)
		if err != nil {
			return nil, err
		}
		out[i] = int(x)
	}
	return out, nil
}

// newEscapeCommand makes a new control sequence command from cmd and args.
func newEscapeCommand(cmd rune, args string) escapeCommand {
	return escapeCommand{cmd, args}
}

type controlCommand rune

const (
	backspace      controlCommand = '\b'
	_horizontalTab                = '\t'
	linefeed                      = '\n'
	_verticalTab                  = '\v'
	_formfeed                     = '\f'
	carriageReturn                = '\r'
)

func (c controlCommand) display(v *VT100) {
	switch c {
	case backspace:
		v.backspace()
	case linefeed:
		v.Cursor.Y++
		v.Cursor.X = 0
	case carriageReturn:
		v.Cursor.X = 0
	default:
		v.Err = fmt.Errorf("control code not implemented %0x", uint(c))
		glog.Warning(v.Err)
	}

}
<commit_msg>home is 1 indexed, not zero.<commit_after>package vt100

import (
	"errors"
	"fmt"
	"image/color"
	"regexp"
	"strconv"
	"strings"

	"github.com/golang/glog"
)

const (
	// When the terminal asks that the color be set to a number,
	// that number less the base is the vt100.Color type we should
	// set for the corresponding region (background or foreground)
	fgBase = 30
	bgBase = 40
)

// command is a type of object that knows how to display itself
// to the terminal.
type command interface {
	display(v *VT100)
}

// runeCommand is a simple command that just writes a rune
// to the current cell and advances the cursor.
type runeCommand rune

func (r runeCommand) display(v *VT100) {
	v.put(rune(r))
}

// escapeCommand is a control sequence command. It includes a variety
// of control and escape sequences that move and modify the cursor
// or the terminal.
type escapeCommand struct {
	cmd  rune
	args string
}

type intHandler func(*VT100, []int)

var (
	// intHandlers are handlers for which all arguments are numbers.
	// This is most of them -- all the ones that we process. Eventually,
	// we may add handlers that support non-int args. Those handlers
	// will instead receive []string, and they'll have to choose on their
	// own how they might be parsed.
	intHandlers = map[rune]intHandler{
		's': save,
		'7': save,
		'u': unsave,
		'8': unsave,
		'A': relativeMove(-1, 0),
		'B': relativeMove(1, 0),
		'C': relativeMove(0, 1),
		'D': relativeMove(0, -1),
		'K': eraseColumns,
		'J': eraseLines,
		'H': home,
		'f': home,
		'm': updateAttributes,
	}
)

func save(v *VT100, _ []int) {
	v.save()
}

func unsave(v *VT100, _ []int) {
	v.unsave()
}

var (
	codeColors = []color.RGBA{
		Black,
		Red,
		Green,
		Yellow,
		Blue,
		Magenta,
		Cyan,
		White,
	}
)

// A command to update the attributes of the cursor based on the arg list.
func updateAttributes(v *VT100, args []int) {
	f := &v.Cursor.F

	for _, x := range args {
		switch x {
		case 0:
			*f = Format{}
		case 1:
			f.Intensity = Bright
		case 2:
			f.Intensity = Dim
		case 22:
			f.Intensity = Normal
		case 4:
			f.Underscore = true
		case 24:
			f.Underscore = false
		case 5, 6:
			f.Blink = true // We don't distinguish between blink speeds.
		case 25:
			f.Blink = false
		case 8:
			f.Conceal = true
		case 28:
			f.Conceal = false
		case 30, 31, 32, 33, 34, 35, 36, 37:
			f.Fg = codeColors[x-30]
		case 39:
			f.Fg = FgDefault
		case 40, 41, 42, 43, 44, 45, 46, 47:
			f.Bg = codeColors[x-40]
		case 49:
			f.Bg = BgDefault
			// 38 and 48 not supported. Maybe someday.
		}
	}
}

func relativeMove(y, x int) func(*VT100, []int) {
	return func(v *VT100, args []int) {
		c := 1
		if len(args) >= 1 {
			c = args[0]
		}
		v.move(y*c, x*c)
	}
}

func eraseColumns(v *VT100, args []int) {
	d := eraseForward
	if len(args) > 0 {
		d = eraseDirection(args[0])
	}
	v.eraseColumns(d)
}

func eraseLines(v *VT100, args []int) {
	d := eraseForward
	if len(args) > 0 {
		d = eraseDirection(args[0])
	}
	v.eraseLines(d)
}

func home(v *VT100, args []int) {
	var y, x int
	if len(args) >= 2 {
		y, x = args[0]-1, args[1]-1 // home args are 1-indexed.
	}
	v.home(y, x)
}

func (c escapeCommand) display(v *VT100) {
	f, ok := intHandlers[c.cmd]
	if !ok {
		c.log(errors.New("unsupported command"))
		return
	}

	args, err := c.argInts()
	if err != nil {
		err = fmt.Errorf("while parsing int args: %v", err)
		c.log(err)
		v.Err = err
	}

	f(v, args)
}

// log logs a problem with a escapeCommand at the warning level. Generally speaking,
// only parse errors and unsupported commands will be logged. The idea here
// is that, through logs, we'll be able to figure out what codes are unsupported
// but actually used that we need to implement.
func (c escapeCommand) log(e error) {
	glog.Warningf("[%v] %s", e)
}

var csArgsRe = regexp.MustCompile("^([^0-9]*)(.*)$")

// argInts parses c.args as a slice of at least arity ints. If the number
// of ; separated arguments is less than arity, the remaining elements of
// the result will be zero. errors only on integer parsing failure.
func (c escapeCommand) argInts() ([]int, error) {
	if len(c.args) == 0 {
		return make([]int, 0), nil
	}
	args := strings.Split(c.args, ";")
	out := make([]int, len(args))
	for i, s := range args {
		x, err := strconv.ParseInt(s, 10, 0)
		if err != nil {
			return nil, err
		}
		out[i] = int(x)
	}
	return out, nil
}

// newEscapeCommand makes a new control sequence command from cmd and args.
func newEscapeCommand(cmd rune, args string) escapeCommand {
	return escapeCommand{cmd, args}
}

type controlCommand rune

const (
	backspace      controlCommand = '\b'
	_horizontalTab                = '\t'
	linefeed                      = '\n'
	_verticalTab                  = '\v'
	_formfeed                     = '\f'
	carriageReturn                = '\r'
)

func (c controlCommand) display(v *VT100) {
	switch c {
	case backspace:
		v.backspace()
	case linefeed:
		v.Cursor.Y++
		v.Cursor.X = 0
	case carriageReturn:
		v.Cursor.X = 0
	default:
		v.Err = fmt.Errorf("control code not implemented %0x", uint(c))
		glog.Warning(v.Err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
	jobs   map[string]*pb.JobDetails
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().GetName())
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job.GetSpec())
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_KILLING:
			s.runner.kill(job.GetSpec())
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job.GetSpec())
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		}
	}
}

func getHash(file string) (string, error) {
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {
		log.Printf("Error in home: %v", home)
	}
	gpath := home + "/gobuild"

	f, err := os.Open(strings.Replace(file, "$GOPATH", gpath, 1))
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return string(h.Sum(nil)), nil
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.64:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	log.Printf("Searching for %v", entry)
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		log.Printf("Lookup failed for %v,%v -> %v", name, server, err)
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func isAlive(spec *pb.JobSpec) bool {
	elems := strings.Split(spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], spec.Server)

	log.Printf("Unable to find: %v -> %v", elems, dPort)
	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		_, err = c.IsAlive(context.Background(), &pbs.Alive{})
		log.Printf("UPDATED: %v,%v -> %v", dServer, dPort, err)
		return err == nil
	}

	//Mark as false if we can't locate the job
	return false
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)

	if c.command == nil {
		return
	}

	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {
		log.Printf("Error in home: %v", home)
	}
	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("RUNNING %v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()
	log.Printf("RUN STARTED:  %v", c.background)

	if !c.background {
		str := ""

		if out != nil {
			buf := new(bytes.Buffer)
			buf.ReadFrom(out)
			str = buf.String()
		}

		if out2 != nil {
			buf2 := new(bytes.Buffer)
			buf2.ReadFrom(out2)
			str2 := buf2.String()
			log.Printf("%v and %v", str, str2)

		}
		c.command.Wait()
		c.output = str
		c.complete = true
	}
	log.Printf("RUN IS DONE")
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute)

		var rebuildList []*pb.JobSpec
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			log.Printf("Job (started %v, now %v) %v", job.started, time.Now(), job)
			if time.Since(job.started) > time.Hour {
				log.Printf("Added to rebuild list (%v)", job)
				rebuildList = append(rebuildList, job.details.Spec)
				hashList = append(hashList, job.hash)
			}
		}

		log.Printf("Rebuilding %v", rebuildList)
		for i := range rebuildList {
			s.runner.Rebuild(rebuildList[i], hashList[i])
		}
	}
}

func main() {
	var quiet = flag.Bool("quiet", false, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}, make(map[string]*pb.JobDetails)}
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<commit_msg>Added some logging<commit_after>package main

import (
	"bytes"
	"crypto/md5"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
	jobs   map[string]*pb.JobDetails
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().GetName())
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job.GetSpec())
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_KILLING:
			s.runner.kill(job.GetSpec())
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job.GetSpec())
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		}
	}
}

func getHash(file string) (string, error) {
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {
		log.Printf("Error in home: %v", home)
	}
	gpath := home + "/gobuild"

	f, err := os.Open(strings.Replace(file, "$GOPATH", gpath, 1))
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	if _, err := io.Copy(h, f); err != nil {
		return "", err
	}

	return string(h.Sum(nil)), nil
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.64:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	log.Printf("Searching for %v", entry)
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		log.Printf("Lookup failed for %v,%v -> %v", name, server, err)
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func isAlive(spec *pb.JobSpec) bool {
	elems := strings.Split(spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], spec.Server)

	log.Printf("Unable to find: %v -> %v", elems, dPort)
	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		_, err = c.IsAlive(context.Background(), &pbs.Alive{})
		log.Printf("UPDATED: %v,%v -> %v", dServer, dPort, err)
		return err == nil
	}

	//Mark as false if we can't locate the job
	return false
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)

	if c.command == nil {
		return
	}

	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {
		log.Printf("Error in home: %v", home)
	}
	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("RUNNING %v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()
	log.Printf("RUN STARTED:  %v", c.background)

	if !c.background {
		str := ""

		if out != nil {
			buf := new(bytes.Buffer)
			buf.ReadFrom(out)
			str = buf.String()
		}

		if out2 != nil {
			buf2 := new(bytes.Buffer)
			buf2.ReadFrom(out2)
			str2 := buf2.String()
			log.Printf("%v and %v", str, str2)

		}
		log.Print("RUN HAS STARTING TO WAIT")
		c.command.Wait()
		log.Printf("RUN DONE WAITING")
		c.output = str
		c.complete = true
	}
	log.Printf("RUN IS DONE")
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute)

		var rebuildList []*pb.JobSpec
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			log.Printf("Job (started %v, now %v) %v", job.started, time.Now(), job)
			if time.Since(job.started) > time.Hour {
				log.Printf("Added to rebuild list (%v)", job)
				rebuildList = append(rebuildList, job.details.Spec)
				hashList = append(hashList, job.hash)
			}
		}

		log.Printf("Rebuilding %v", rebuildList)
		for i := range rebuildList {
			s.runner.Rebuild(rebuildList[i], hashList[i])
		}
	}
}

func main() {
	var quiet = flag.Bool("quiet", false, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}, make(map[string]*pb.JobDetails)}
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<|endoftext|>


<commit_before>package daemon

import (
	"os"
)

func AddCommand(f Flag, sig os.Signal, handler SignalHandlerFunc) {
	if f != nil {
		AddFlag(f, sig)
	}
	if handler != nil {
		SetSigHandler(handler, sig)
	}
}

type Flag interface {
	IsSet() bool
}

func BoolFlag(f *bool) Flag {
	return &boolFlag{f}
}

func StringFlag(f *string, v string) Flag {
	return &stringFlag{f, v}
}

type boolFlag struct {
	b *bool
}

func (f *boolFlag) IsSet() bool {
	if f == nil {
		return false
	}
	return *f.b
}

type stringFlag struct {
	s *string
	v string
}

func (f *stringFlag) IsSet() bool {
	if f == nil {
		return false
	}
	return *f.s == f.v
}

var flags = make(map[Flag]os.Signal)

func Flags() map[Flag]os.Signal {
	return flags
}

func AddFlag(f Flag, sig os.Signal) {
	flags[f] = sig
}

func SendCommands(p *os.Process) (err error) {
	for _, sig := range signals() {
		if err = p.Signal(sig); err != nil {
			return
		}
	}
	return
}

func ActiveFlags() (ret []Flag) {
	ret = make([]Flag, 0, 1)
	for f := range flags {
		if f.IsSet() {
			ret = append(ret, f)
		}
	}
	return
}

func signals() (ret []os.Signal) {
	ret = make([]os.Signal, 0, 1)
	for f, sig := range flags {
		if f.IsSet() {
			ret = append(ret, sig)
		}
	}
	return
}
<commit_msg>Added a documentation into the file command.go<commit_after>package daemon

import (
	"os"
)

// AddCommand is wrapper on AddFlag and SetSigHandler functions.
func AddCommand(f Flag, sig os.Signal, handler SignalHandlerFunc) {
	if f != nil {
		AddFlag(f, sig)
	}
	if handler != nil {
		SetSigHandler(handler, sig)
	}
}

// Flag is the interface implemented by an object that has two state:
// 'set' and 'unset'.
type Flag interface {
	IsSet() bool
}

// BoolFlag returns new object that implements interface Flag and
// has state 'set' when var with the given address is true.
func BoolFlag(f *bool) Flag {
	return &boolFlag{f}
}

// StringFlag returns new object that implements interface Flag and
// has state 'set' when var with the given address equals given value of v.
func StringFlag(f *string, v string) Flag {
	return &stringFlag{f, v}
}

type boolFlag struct {
	b *bool
}

func (f *boolFlag) IsSet() bool {
	if f == nil {
		return false
	}
	return *f.b
}

type stringFlag struct {
	s *string
	v string
}

func (f *stringFlag) IsSet() bool {
	if f == nil {
		return false
	}
	return *f.s == f.v
}

var flags = make(map[Flag]os.Signal)

// Flags returns flags that was added by the function AddFlag.
func Flags() map[Flag]os.Signal {
	return flags
}

// AddFlag adds the flag and signal to the internal map.
func AddFlag(f Flag, sig os.Signal) {
	flags[f] = sig
}

// SendCommands sends active signals to the given process.
func SendCommands(p *os.Process) (err error) {
	for _, sig := range signals() {
		if err = p.Signal(sig); err != nil {
			return
		}
	}
	return
}

// ActiveFlags returns flags that has the state 'set'.
func ActiveFlags() (ret []Flag) {
	ret = make([]Flag, 0, 1)
	for f := range flags {
		if f.IsSet() {
			ret = append(ret, f)
		}
	}
	return
}

func signals() (ret []os.Signal) {
	ret = make([]os.Signal, 0, 1)
	for f, sig := range flags {
		if f.IsSet() {
			ret = append(ret, sig)
		}
	}
	return
}
<|endoftext|>


<commit_before>package hpcloud

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

/* Server flavours Smallest to Largest */
type Flavor int

const (
	XSmall = Flavor(100) + iota
	Small
	Medium
	Large
	XLarge
	DblXLarge
)

/* Available images */
type ServerImage int

const (
	UbuntuLucid10_04Kernel    = ServerImage(1235)
	UbuntuLucid10_04          = 1236
	UbuntuMaverick10_10Kernel = 1237
	UbuntuMaverick10_10       = 1238
	UbuntuNatty11_04Kernel    = 1239
	UbuntuNatty11_04          = 1240
	UbuntuOneiric11_10        = 5579
	UbuntuPrecise12_04        = 8419
	CentOS5_8Server64         = 54021
	CentOS6_2Server64Kernel   = 1356
	CentOS6_2Server64Ramdisk  = 1357
	CentOS6_2Server64         = 1358
	DebianSqueeze6_0_3Kernel  = 1359
	DebianSqueeze6_0_3Ramdisk = 1360
	DebianSqueeze6_0_3Server  = 1361
	Fedora16Server64          = 16291
	BitNamiDrupal7_14_0       = 22729
	BitNamiWebPack1_2_0       = 22731
	BitNamiDevPack1_0_0       = 4654
	ActiveStateStackatov1_2_6 = 14345
	ActiveStateStackatov2_2_2 = 59297
	ActiveStateStackatov2_2_3 = 60815
	EnterpriseDBPPAS9_1_2     = 9953
	EnterpriseDBPSQL9_1_3     = 9995
)

type Link struct {
	HREF string `json:"href"`
	Rel  string `json:"rel"`
}

/*
  Several embedded types are simply an ID string with a slice of Link
*/
type IDLink struct {
	Name  string `json:"name"`
	ID    string `json:"id"`
	Links []Link `json:"links"`
}

type Flavor_ struct {
	Name  string `json:"name"`
	ID    int64  `json:"id"`
	Links []Link `json:"links"`
}

type Flavors struct {
	F []Flavor_ `json:"flavors"`
}

type Image struct {
	Name     string            `json:"name"`
	ID       int64             `json:"id"`
	Links    []Link            `json:"links"`
	Progress int               `json:"progress"`
	Metadata map[string]string `json:"metadata"`
	Status   string            `json:"status"`
	Updated  string            `json:"updated"`
}

type Images struct {
	I []IDLink `json:"images"`
}

/*
  This type describes the JSON data which should be sent to the create
  server resource.
*/
type Server struct {
	ConfigDrive    bool              `json:"config_drive"`
	FlavorRef      Flavor            `json:"flavorRef"`
	ImageRef       ServerImage       `json:"imageRef"`
	MaxCount       int               `json:"max_count"`
	MinCount       int               `json:"min_count"`
	Name           string            `json:"name"`
	Key            string            `json:"key_name"`
	Personality    string            `json:"personality"`
	UserData       string            `json:"user_data"`
	SecurityGroups []IDLink          `json:"security_groups"`
	Metadata       map[string]string `json:"metadata"`
}

/*
  This type describes the JSON response from a successful CreateServer
  call.
*/
type ServerResponse struct {
	S struct {
		Status         string            `json:"status"`
		Updated        string            `json:"update"`
		HostID         string            `json:"hostId"`
		UserID         string            `json:"user_id"`
		Name           string            `json:"name"`
		Links          []Link            `json:"links"`
		Addresses      interface{}       `json:"addresses"`
		TenantID       string            `json:"tenant_id"`
		Image          IDLink            `json:"image"`
		Created        string            `json:"created"`
		UUID           string            `json:"uuid"`
		AccessIPv4     string            `json:"accessIPv4"`
		AccessIPv6     string            `json:"accessIPv6"`
		KeyName        string            `json:"key_name"`
		AdminPass      string            `json:"adminPass"`
		Flavor         IDLink            `json:"flavor"`
		ConfigDrive    string            `json:"config_drive"`
		ID             int64             `json:"id"`
		SecurityGroups []IDLink          `json:"security_groups"`
		Metadata       map[string]string `json:"metadata"`
	} `json:"server"`
}

func (a Access) CreateServer(s Server) (*ServerResponse, error) {
	b, err := s.MarshalJSON()
	if err != nil {
		return nil, err
	}
	path := fmt.Sprintf("%s%s/servers", COMPUTE_URL, a.TenantID)
	client := &http.Client{}
	req, err := http.NewRequest("POST", path, strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}
	req.Header.Add("X-Auth-Token", a.A.Token.ID)
	req.Header.Add("Content-type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	switch resp.StatusCode {
	case http.StatusAccepted:
		sr := &ServerResponse{}
		err = json.Unmarshal(body, sr)
		if err != nil {
			return nil, err
		}
		return sr, nil
	default:
		br := &BadRequest{}
		err = json.Unmarshal(body, br)
		if err != nil {
			return nil, err
		}
		return nil, errors.New(br.B.Message)
	}
	panic("Unreachable")
}

func (a Access) ListFlavors() (*Flavors, error) {
	body, err := a.baseComputeRequest("flavors")
	if err != nil {
		return nil, err
	}

	fl := &Flavors{}
	err = json.Unmarshal(body, fl)
	if err != nil {
		return nil, err
	}
	return fl, nil
}

func (a Access) ListImages() (*Images, error) {
	body, err := a.baseComputeRequest("images")
	if err != nil {
		return nil, err
	}

	im := &Images{}
	err = json.Unmarshal(body, im)
	if err != nil {
		return nil, err
	}
	return im, nil
}

func (a Access) ListImage(image_id string) (*Image, error) {
	body, err := a.baseComputeRequest(fmt.Sprintf("images/%s", image_id))
	if err != nil {
		return nil, err
	}
	fmt.Println(string(body))
	i := &Image{}
	err = json.Unmarshal(body, i)
	if err != nil {
		return nil, err
	}
	return i, nil

}

func (a Access) baseComputeRequest(url string) ([]byte, error) {
	path := fmt.Sprintf("%s%s/%s", COMPUTE_URL, a.TenantID, url)
	client := &http.Client{}
	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("X-Auth-Token", a.A.Token.ID)
	req.Header.Add("Content-type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	switch resp.StatusCode {
	case http.StatusOK, http.StatusNonAuthoritativeInfo:
		return body, nil
	default:
		br := &BadRequest{}
		err = json.Unmarshal(body, br)
		if err != nil {
			return nil, err
		}
		return nil, errors.New(br.B.Message)
	}
	panic("Unreachable")
}

func (s Server) MarshalJSON() ([]byte, error) {
	b := bytes.NewBufferString("")
	b.WriteString(`{"server":{`)
	/* The available images are 100-105, x-small to x-large. */
	if s.FlavorRef < 100 || s.FlavorRef > 105 {
		return []byte{},
			errors.New("Flavor Reference refers to a non-existant flavour.")
	} else {
		b.WriteString(fmt.Sprintf(`"flavorRef":%d`, s.FlavorRef))
	}
	if s.ImageRef == 0 {
		return []byte{},
			errors.New("An image name is required.")
	} else {
		b.WriteString(fmt.Sprintf(`,"imageRef":%d`, s.ImageRef))
	}
	if s.Name == "" {
		return []byte{},
			errors.New("A name is required")
	} else {
		b.WriteString(fmt.Sprintf(`,"name":"%s"`, s.Name))
	}

	/* Optional items */
	if s.Key != "" {
		b.WriteString(fmt.Sprintf(`,"key_name":"%s"`, s.Key))
	}
	if s.ConfigDrive {
		b.WriteString(`,"config_drive": true`)
	}
	if s.MinCount > 0 {
		b.WriteString(fmt.Sprintf(`,"min_count":%d`, s.MinCount))
	}
	if s.MaxCount > 0 {
		b.WriteString(fmt.Sprintf(`,"max_count":%d`, s.MaxCount))
	}
	if s.UserData != "" {
		/* user_data needs to be base64'd */
		newb := make([]byte, 0, len(s.UserData))
		base64.StdEncoding.Encode([]byte(s.UserData), newb)
		b.WriteString(fmt.Sprintf(`,"user_data": "%s",`, string(newb)))
	}
	if len(s.Personality) > 255 {
		return []byte{},
			errors.New("Server's personality cannot have >255 bytes.")
	} else if s.Personality != "" {
		b.WriteString(fmt.Sprintf(`,"personality":"%s",`, s.Personality))
	}
	if len(s.Metadata) > 0 {
		fmt.Println(len(s.Metadata))
		b.WriteString(`,"metadata":{`)
		cnt := 0
		for key, value := range s.Metadata {
			b.WriteString(fmt.Sprintf(`"%s": "%s"`, key, value))
			if cnt+1 != len(s.Metadata) {
				b.WriteString(",")
				cnt++
			} else {
				b.WriteString("}")
			}
		}
	}
	if len(s.SecurityGroups) > 0 {
		b.WriteString(`,"security_groups":[`)
		cnt := 0
		for _, sg := range s.SecurityGroups {
			b.WriteString(fmt.Sprintf(`{"name": "%s"}`, sg.Name))
			if cnt+1 != len(s.SecurityGroups) {
				b.WriteString(",")
				cnt++
			} else {
				b.WriteString("]")
			}
		}
	}
	b.WriteString("}}")
	return b.Bytes(), nil
}
<commit_msg>Make the baseComputeRequest take a method so we can use it for different verbs.<commit_after>package hpcloud

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

/* Server flavours Smallest to Largest */
type Flavor int

const (
	XSmall = Flavor(100) + iota
	Small
	Medium
	Large
	XLarge
	DblXLarge
)

/* Available images */
type ServerImage int

const (
	UbuntuLucid10_04Kernel    = ServerImage(1235)
	UbuntuLucid10_04          = 1236
	UbuntuMaverick10_10Kernel = 1237
	UbuntuMaverick10_10       = 1238
	UbuntuNatty11_04Kernel    = 1239
	UbuntuNatty11_04          = 1240
	UbuntuOneiric11_10        = 5579
	UbuntuPrecise12_04        = 8419
	CentOS5_8Server64         = 54021
	CentOS6_2Server64Kernel   = 1356
	CentOS6_2Server64Ramdisk  = 1357
	CentOS6_2Server64         = 1358
	DebianSqueeze6_0_3Kernel  = 1359
	DebianSqueeze6_0_3Ramdisk = 1360
	DebianSqueeze6_0_3Server  = 1361
	Fedora16Server64          = 16291
	BitNamiDrupal7_14_0       = 22729
	BitNamiWebPack1_2_0       = 22731
	BitNamiDevPack1_0_0       = 4654
	ActiveStateStackatov1_2_6 = 14345
	ActiveStateStackatov2_2_2 = 59297
	ActiveStateStackatov2_2_3 = 60815
	EnterpriseDBPPAS9_1_2     = 9953
	EnterpriseDBPSQL9_1_3     = 9995
)

type Link struct {
	HREF string `json:"href"`
	Rel  string `json:"rel"`
}

/*
  Several embedded types are simply an ID string with a slice of Link
*/
type IDLink struct {
	Name  string `json:"name"`
	ID    string `json:"id"`
	Links []Link `json:"links"`
}

type Flavor_ struct {
	Name  string `json:"name"`
	ID    int64  `json:"id"`
	Links []Link `json:"links"`
}

type Flavors struct {
	F []Flavor_ `json:"flavors"`
}

type Image struct {
	Name     string            `json:"name"`
	ID       int64             `json:"id"`
	Links    []Link            `json:"links"`
	Progress int               `json:"progress"`
	Metadata map[string]string `json:"metadata"`
	Status   string            `json:"status"`
	Updated  string            `json:"updated"`
}

type Images struct {
	I []IDLink `json:"images"`
}

/*
  This type describes the JSON data which should be sent to the create
  server resource.
*/
type Server struct {
	ConfigDrive    bool              `json:"config_drive"`
	FlavorRef      Flavor            `json:"flavorRef"`
	ImageRef       ServerImage       `json:"imageRef"`
	MaxCount       int               `json:"max_count"`
	MinCount       int               `json:"min_count"`
	Name           string            `json:"name"`
	Key            string            `json:"key_name"`
	Personality    string            `json:"personality"`
	UserData       string            `json:"user_data"`
	SecurityGroups []IDLink          `json:"security_groups"`
	Metadata       map[string]string `json:"metadata"`
}

/*
  This type describes the JSON response from a successful CreateServer
  call.
*/
type ServerResponse struct {
	S struct {
		Status         string            `json:"status"`
		Updated        string            `json:"update"`
		HostID         string            `json:"hostId"`
		UserID         string            `json:"user_id"`
		Name           string            `json:"name"`
		Links          []Link            `json:"links"`
		Addresses      interface{}       `json:"addresses"`
		TenantID       string            `json:"tenant_id"`
		Image          IDLink            `json:"image"`
		Created        string            `json:"created"`
		UUID           string            `json:"uuid"`
		AccessIPv4     string            `json:"accessIPv4"`
		AccessIPv6     string            `json:"accessIPv6"`
		KeyName        string            `json:"key_name"`
		AdminPass      string            `json:"adminPass"`
		Flavor         IDLink            `json:"flavor"`
		ConfigDrive    string            `json:"config_drive"`
		ID             int64             `json:"id"`
		SecurityGroups []IDLink          `json:"security_groups"`
		Metadata       map[string]string `json:"metadata"`
	} `json:"server"`
}

func (a Access) CreateServer(s Server) (*ServerResponse, error) {
	b, err := s.MarshalJSON()
	if err != nil {
		return nil, err
	}
	path := fmt.Sprintf("%s%s/servers", COMPUTE_URL, a.TenantID)
	client := &http.Client{}
	req, err := http.NewRequest("POST", path, strings.NewReader(string(b)))
	if err != nil {
		return nil, err
	}
	req.Header.Add("X-Auth-Token", a.A.Token.ID)
	req.Header.Add("Content-type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	switch resp.StatusCode {
	case http.StatusAccepted:
		sr := &ServerResponse{}
		err = json.Unmarshal(body, sr)
		if err != nil {
			return nil, err
		}
		return sr, nil
	default:
		br := &BadRequest{}
		err = json.Unmarshal(body, br)
		if err != nil {
			return nil, err
		}
		return nil, errors.New(br.B.Message)
	}
	panic("Unreachable")
}

func (a Access) ListFlavors() (*Flavors, error) {
	body, err := a.baseComputeRequest("flavors", "GET")
	if err != nil {
		return nil, err
	}

	fl := &Flavors{}
	err = json.Unmarshal(body, fl)
	if err != nil {
		return nil, err
	}
	return fl, nil
}

func (a Access) ListImages() (*Images, error) {
	body, err := a.baseComputeRequest("images", "GET")
	if err != nil {
		return nil, err
	}

	im := &Images{}
	err = json.Unmarshal(body, im)
	if err != nil {
		return nil, err
	}
	return im, nil
}

func (a Access) ListImage(image_id string) (*Image, error) {
	body, err := a.baseComputeRequest(fmt.Sprintf("images/%s", image_id), "GET")
	if err != nil {
		return nil, err
	}
	fmt.Println(string(body))
	i := &Image{}
	err = json.Unmarshal(body, i)
	if err != nil {
		return nil, err
	}
	return i, nil

}

func (a Access) baseComputeRequest(url, method string) ([]byte, error) {
	path := fmt.Sprintf("%s%s/%s", COMPUTE_URL, a.TenantID, url)
	client := &http.Client{}
	req, err := http.NewRequest(method, path, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("X-Auth-Token", a.A.Token.ID)
	req.Header.Add("Content-type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	switch resp.StatusCode {
	case http.StatusOK, http.StatusNonAuthoritativeInfo:
		return body, nil
	default:
		br := &BadRequest{}
		err = json.Unmarshal(body, br)
		if err != nil {
			return nil, err
		}
		return nil, errors.New(br.B.Message)
	}
	panic("Unreachable")
}

func (s Server) MarshalJSON() ([]byte, error) {
	b := bytes.NewBufferString("")
	b.WriteString(`{"server":{`)
	/* The available images are 100-105, x-small to x-large. */
	if s.FlavorRef < 100 || s.FlavorRef > 105 {
		return []byte{},
			errors.New("Flavor Reference refers to a non-existant flavour.")
	} else {
		b.WriteString(fmt.Sprintf(`"flavorRef":%d`, s.FlavorRef))
	}
	if s.ImageRef == 0 {
		return []byte{},
			errors.New("An image name is required.")
	} else {
		b.WriteString(fmt.Sprintf(`,"imageRef":%d`, s.ImageRef))
	}
	if s.Name == "" {
		return []byte{},
			errors.New("A name is required")
	} else {
		b.WriteString(fmt.Sprintf(`,"name":"%s"`, s.Name))
	}

	/* Optional items */
	if s.Key != "" {
		b.WriteString(fmt.Sprintf(`,"key_name":"%s"`, s.Key))
	}
	if s.ConfigDrive {
		b.WriteString(`,"config_drive": true`)
	}
	if s.MinCount > 0 {
		b.WriteString(fmt.Sprintf(`,"min_count":%d`, s.MinCount))
	}
	if s.MaxCount > 0 {
		b.WriteString(fmt.Sprintf(`,"max_count":%d`, s.MaxCount))
	}
	if s.UserData != "" {
		/* user_data needs to be base64'd */
		newb := make([]byte, 0, len(s.UserData))
		base64.StdEncoding.Encode([]byte(s.UserData), newb)
		b.WriteString(fmt.Sprintf(`,"user_data": "%s",`, string(newb)))
	}
	if len(s.Personality) > 255 {
		return []byte{},
			errors.New("Server's personality cannot have >255 bytes.")
	} else if s.Personality != "" {
		b.WriteString(fmt.Sprintf(`,"personality":"%s",`, s.Personality))
	}
	if len(s.Metadata) > 0 {
		fmt.Println(len(s.Metadata))
		b.WriteString(`,"metadata":{`)
		cnt := 0
		for key, value := range s.Metadata {
			b.WriteString(fmt.Sprintf(`"%s": "%s"`, key, value))
			if cnt+1 != len(s.Metadata) {
				b.WriteString(",")
				cnt++
			} else {
				b.WriteString("}")
			}
		}
	}
	if len(s.SecurityGroups) > 0 {
		b.WriteString(`,"security_groups":[`)
		cnt := 0
		for _, sg := range s.SecurityGroups {
			b.WriteString(fmt.Sprintf(`{"name": "%s"}`, sg.Name))
			if cnt+1 != len(s.SecurityGroups) {
				b.WriteString(",")
				cnt++
			} else {
				b.WriteString("]")
			}
		}
	}
	b.WriteString("}}")
	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"fmt"

	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/interfaces"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/factomd/database/databaseOverlay"
	"github.com/FactomProject/factomd/database/hybridDB"
)

// Database keys and key prefixes
var (
	fblockDBPrefix = []byte("FBlock")
)

type TXDatabaseOverlay struct {
	dbo databaseOverlay.Overlay
}

func NewTXOverlay(db interfaces.IDatabase) *TXDatabaseOverlay {
	answer := new(TXDatabaseOverlay)
	answer.dbo.DB = db
	return answer
}

func NewTXLevelDB(ldbpath string) (*TXDatabaseOverlay, error) {
	db, err := hybridDB.NewLevelMapHybridDB(ldbpath, false)
	if err != nil {
		fmt.Printf("err opening transaction db: %v\n", err)
	}

	if db == nil {
		fmt.Println("Creating new transaction db ...")
		db, err = hybridDB.NewLevelMapHybridDB(ldbpath, true)

		if err != nil {
			return nil, err
		}
	}
	fmt.Println("Transaction database started from: " + ldbpath)
	return NewTXOverlay(db), nil
}

func (db *TXDatabaseOverlay) Close() error {
	return db.dbo.Close()
}

// GetAllTXs returns a list of all transactions in the history of Factom. A
// local database is used to cache the factoid blocks.
func (db *TXDatabaseOverlay) GetAllTXs() ([]interfaces.ITransaction, error) {
	// update the database and get the newest fblock
	newest, err := db.update()
	if err != nil {
		return nil, err
	}
	fblock, err := db.GetFBlock(newest)
	if err != nil {
		return nil, err
	}
	txs := make([]interfaces.ITransaction, 0)

	for {
		// get all of the txs from the block
		height := fblock.GetDatabaseHeight()
		for _, tx := range fblock.GetTransactions() {
			ins, err := tx.TotalInputs()
			if err != nil {
				return nil, err
			}
			outs, err := tx.TotalOutputs()
			if err != nil {
				return nil, err
			}

			if ins != 0 || outs != 0 {
				tx.SetBlockHeight(height)
				txs = append(txs, tx)
			}
		}

		if pre := fblock.GetPrevKeyMR().String(); pre != factom.ZeroHash {
			// get the previous block
			fblock, err = db.GetFBlock(pre)
			if err != nil {
				return nil, err
			} else if fblock == nil {
				return nil, fmt.Errorf("Missing fblock in database: %s", pre)
			}
		} else {
			break
		}
	}

	return txs, nil
}

// GetTXAddress returns a list of all transactions in the history of Factom that
// include a specific address.
func (db *TXDatabaseOverlay) GetTXAddress(adr string) (
	[]interfaces.ITransaction, error) {
	filtered := make([]interfaces.ITransaction, 0)

	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		for _, in := range tx.GetInputs() {
			if primitives.ConvertFctAddressToUserStr(
				in.GetAddress()) == adr {
				txs = append(filtered, tx)
			}
		}
		for _, out := range tx.GetOutputs() {
			if primitives.ConvertFctAddressToUserStr(
				out.GetAddress()) == adr {
				txs = append(filtered, tx)
			}
		}
	}

	return filtered, nil
}

func (db *TXDatabaseOverlay) GetTXRange(start, end int) (
	[]interfaces.ITransaction, error) {
	if start < 0 || end < 0 {
		return nil, fmt.Errorf("Range cannot have negative numbers")
	}
	s, e := uint32(start), uint32(end)

	filtered := make([]interfaces.ITransaction, 0)

	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		if s <= tx.GetBlockHeight() && tx.GetBlockHeight() <= e {
			filtered = append(filtered, tx)
		}
	}

	return filtered, nil
}

func (db *TXDatabaseOverlay) GetTX(txid string) (
	interfaces.ITransaction, error) {
	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		if tx.GetSigHash().String() == txid {
			return tx, nil
		}
	}

	return nil, fmt.Errorf("Transaction not found")
}

// GetFBlock retrives a Factoid Block from Factom
func (db *TXDatabaseOverlay) GetFBlock(keymr string) (interfaces.IFBlock, error) {
	fblock := new(factoid.FBlock)
	data, err := db.dbo.Get(fblockDBPrefix, []byte(keymr), fblock)
	if err != nil {
		return nil, err
	}
	if data == nil {
		return nil, nil
	}
	return data.(interfaces.IFBlock), nil
}

func (db *TXDatabaseOverlay) InsertFBlock(fblock interfaces.IFBlock) error {
	fblockmr := []byte(fblock.GetKeyMR().String())

	batch := []interfaces.Record{}
	batch = append(batch, interfaces.Record{fblockDBPrefix, fblockmr, fblock})

	return db.dbo.PutInBatch(batch)
}

// update gets all fblocks written since the database was last updated, and
// returns the most recent fblock keymr.
func (db *TXDatabaseOverlay) update() (string, error) {
	fblock, err := fblockHead()
	if err != nil {
		return "", err
	}
	newest := fblock.GetKeyMR().String()

	prevmr := fblock.GetPrevKeyMR().String()
	for prevmr != factom.ZeroHash {
		//		// stop when we reach an fblock that is already in the db
		//		if f, err := db.GetFBlock(prevmr); err != nil {
		//			return "", err
		//		} else if f != nil {
		//			return newest, nil
		//		}

		// add the fblock to the db
		if err := db.InsertFBlock(fblock); err != nil {
			return "", err
		}

		fblock, err = getfblock(prevmr)
		if err != nil {
			return "", err
		}
		prevmr = fblock.GetPrevKeyMR().String()
	}

	// write the last fblock into the db
	if err := db.InsertFBlock(fblock); err != nil {
		return "", err
	}

	return newest, nil
}

// fblockHead gets the most recent fblock.
func fblockHead() (interfaces.IFBlock, error) {
	fblockID := "000000000000000000000000000000000000000000000000000000000000000f"

	dbhead, err := factom.GetDBlockHead()
	if err != nil {
		return nil, err
	}
	dblock, err := factom.GetDBlock(dbhead)
	if err != nil {
		return nil, err
	}

	var fblockmr string
	for _, eblock := range dblock.EntryBlockList {
		if eblock.ChainID == fblockID {
			fblockmr = eblock.KeyMR
		}
	}
	if fblockmr == "" {
		return nil, err
	}

	return getfblock(fblockmr)
}

func getfblock(keymr string) (interfaces.IFBlock, error) {
	p, err := factom.GetRaw(keymr)
	if err != nil {
		return nil, err
	}
	return factoid.UnmarshalFBlock(p)
}
<commit_msg>reorg<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package wallet

import (
	"fmt"

	"github.com/FactomProject/factom"
	"github.com/FactomProject/factomd/common/factoid"
	"github.com/FactomProject/factomd/common/interfaces"
	"github.com/FactomProject/factomd/common/primitives"
	"github.com/FactomProject/factomd/database/databaseOverlay"
	"github.com/FactomProject/factomd/database/hybridDB"
)

// Database keys and key prefixes
var (
	fblockDBPrefix = []byte("FBlock")
)

type TXDatabaseOverlay struct {
	dbo databaseOverlay.Overlay
}

func NewTXOverlay(db interfaces.IDatabase) *TXDatabaseOverlay {
	answer := new(TXDatabaseOverlay)
	answer.dbo.DB = db
	return answer
}

func NewTXLevelDB(ldbpath string) (*TXDatabaseOverlay, error) {
	db, err := hybridDB.NewLevelMapHybridDB(ldbpath, false)
	if err != nil {
		fmt.Printf("err opening transaction db: %v\n", err)
	}

	if db == nil {
		fmt.Println("Creating new transaction db ...")
		db, err = hybridDB.NewLevelMapHybridDB(ldbpath, true)

		if err != nil {
			return nil, err
		}
	}
	fmt.Println("Transaction database started from: " + ldbpath)
	return NewTXOverlay(db), nil
}

func (db *TXDatabaseOverlay) Close() error {
	return db.dbo.Close()
}

// GetAllTXs returns a list of all transactions in the history of Factom. A
// local database is used to cache the factoid blocks.
func (db *TXDatabaseOverlay) GetAllTXs() ([]interfaces.ITransaction, error) {
	// update the database and get the newest fblock
	newest, err := db.update()
	if err != nil {
		return nil, err
	}
	fblock, err := db.GetFBlock(newest)
	if err != nil {
		return nil, err
	}
	txs := make([]interfaces.ITransaction, 0)

	for {
		// get all of the txs from the block
		height := fblock.GetDatabaseHeight()
		for _, tx := range fblock.GetTransactions() {
			ins, err := tx.TotalInputs()
			if err != nil {
				return nil, err
			}
			outs, err := tx.TotalOutputs()
			if err != nil {
				return nil, err
			}

			if ins != 0 || outs != 0 {
				tx.SetBlockHeight(height)
				txs = append(txs, tx)
			}
		}

		if pre := fblock.GetPrevKeyMR().String(); pre != factom.ZeroHash {
			// get the previous block
			fblock, err = db.GetFBlock(pre)
			if err != nil {
				return nil, err
			} else if fblock == nil {
				return nil, fmt.Errorf("Missing fblock in database: %s", pre)
			}
		} else {
			break
		}
	}

	return txs, nil
}

// GetTX gets a transaction by the transaction id
func (db *TXDatabaseOverlay) GetTX(txid string) (
	interfaces.ITransaction, error) {
	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		if tx.GetSigHash().String() == txid {
			return tx, nil
		}
	}

	return nil, fmt.Errorf("Transaction not found")
}

// GetTXAddress returns a list of all transactions in the history of Factom that
// include a specific address.
func (db *TXDatabaseOverlay) GetTXAddress(adr string) (
	[]interfaces.ITransaction, error) {
	filtered := make([]interfaces.ITransaction, 0)

	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		for _, in := range tx.GetInputs() {
			if primitives.ConvertFctAddressToUserStr(
				in.GetAddress()) == adr {
				txs = append(filtered, tx)
			}
		}
		for _, out := range tx.GetOutputs() {
			if primitives.ConvertFctAddressToUserStr(
				out.GetAddress()) == adr {
				txs = append(filtered, tx)
			}
		}
	}

	return filtered, nil
}

func (db *TXDatabaseOverlay) GetTXRange(start, end int) (
	[]interfaces.ITransaction, error) {
	if start < 0 || end < 0 {
		return nil, fmt.Errorf("Range cannot have negative numbers")
	}
	s, e := uint32(start), uint32(end)

	filtered := make([]interfaces.ITransaction, 0)

	txs, err := db.GetAllTXs()
	if err != nil {
		return nil, err
	}

	for _, tx := range txs {
		if s <= tx.GetBlockHeight() && tx.GetBlockHeight() <= e {
			filtered = append(filtered, tx)
		}
	}

	return filtered, nil
}

// GetFBlock retrives a Factoid Block from Factom
func (db *TXDatabaseOverlay) GetFBlock(keymr string) (interfaces.IFBlock, error) {
	fblock := new(factoid.FBlock)
	data, err := db.dbo.Get(fblockDBPrefix, []byte(keymr), fblock)
	if err != nil {
		return nil, err
	}
	if data == nil {
		return nil, nil
	}
	return data.(interfaces.IFBlock), nil
}

func (db *TXDatabaseOverlay) InsertFBlock(fblock interfaces.IFBlock) error {
	fblockmr := []byte(fblock.GetKeyMR().String())

	batch := []interfaces.Record{}
	batch = append(batch, interfaces.Record{fblockDBPrefix, fblockmr, fblock})

	return db.dbo.PutInBatch(batch)
}

// update gets all fblocks written since the database was last updated, and
// returns the most recent fblock keymr.
func (db *TXDatabaseOverlay) update() (string, error) {
	fblock, err := fblockHead()
	if err != nil {
		return "", err
	}
	newest := fblock.GetKeyMR().String()

	prevmr := fblock.GetPrevKeyMR().String()
	for prevmr != factom.ZeroHash {
		//		// stop when we reach an fblock that is already in the db
		//		if f, err := db.GetFBlock(prevmr); err != nil {
		//			return "", err
		//		} else if f != nil {
		//			return newest, nil
		//		}

		// add the fblock to the db
		if err := db.InsertFBlock(fblock); err != nil {
			return "", err
		}

		fblock, err = getfblock(prevmr)
		if err != nil {
			return "", err
		}
		prevmr = fblock.GetPrevKeyMR().String()
	}

	// write the last fblock into the db
	if err := db.InsertFBlock(fblock); err != nil {
		return "", err
	}

	return newest, nil
}

// fblockHead gets the most recent fblock.
func fblockHead() (interfaces.IFBlock, error) {
	fblockID := "000000000000000000000000000000000000000000000000000000000000000f"

	dbhead, err := factom.GetDBlockHead()
	if err != nil {
		return nil, err
	}
	dblock, err := factom.GetDBlock(dbhead)
	if err != nil {
		return nil, err
	}

	var fblockmr string
	for _, eblock := range dblock.EntryBlockList {
		if eblock.ChainID == fblockID {
			fblockmr = eblock.KeyMR
		}
	}
	if fblockmr == "" {
		return nil, err
	}

	return getfblock(fblockmr)
}

func getfblock(keymr string) (interfaces.IFBlock, error) {
	p, err := factom.GetRaw(keymr)
	if err != nil {
		return nil, err
	}
	return factoid.UnmarshalFBlock(p)
}
<|endoftext|>