<commit_before>package stretcher

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
)

type Commands struct {
	Pre     CommandLines `yaml:"pre"`
	Post    CommandLines `yaml:"post"`
	Success CommandLines `yaml:"success"`
	Failure CommandLines `yaml:"failure"`
}

type CommandLines []CommandLine

func (cs CommandLines) Invoke() error {
	for _, c := range cs {
		err := c.Invoke()
		if err != nil {
			return err
		}
	}
	return nil
}

func (cs CommandLines) InvokePipe(src *bytes.Buffer) error {
	for _, c := range cs {
		buf := bytes.NewBuffer(src.Bytes())
		err := c.InvokePipe(buf)
		if err != nil {
			return err
		}
	}
	return nil
}

type CommandLine string

func (c CommandLine) String() string {
	return string(c)
}

func (c CommandLine) Invoke() error {
	log.Println("invoking command:", c.String())
	out, err := exec.Command("sh", "-c", c.String()).CombinedOutput()
	if len(out) > 0 {
		log.Println(string(out))
	}
	if err != nil {
		return fmt.Errorf("failed: %v %v", c, err)
	}
	return nil
}

func (c CommandLine) InvokePipe(src io.Reader) error {
	log.Println("invoking command:", c.String())
	cmd := exec.Command("sh", "-c", c.String())
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	err = cmd.Start()
	if err != nil {
		return err
	}
	cmdCh := make(chan error)
	// src => stdin
	go func() {
		_, err := io.Copy(stdin, src)
		if err != nil {
			cmdCh <- err
		}
		stdin.Close()
	}()
	// wait for command exit
	go func() {
		cmdCh <- cmd.Wait()
	}()
	go io.Copy(os.Stdout, stdout)
	go io.Copy(os.Stderr, stderr)

	cmdErr := <-cmdCh
	return cmdErr
}
<commit_msg>Wait completion for std(in|out|err) copied before cmd.Wait()<commit_after>package stretcher

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"sync"
)

type Commands struct {
	Pre     CommandLines `yaml:"pre"`
	Post    CommandLines `yaml:"post"`
	Success CommandLines `yaml:"success"`
	Failure CommandLines `yaml:"failure"`
}

type CommandLines []CommandLine

func (cs CommandLines) Invoke() error {
	for _, c := range cs {
		err := c.Invoke()
		if err != nil {
			return err
		}
	}
	return nil
}

func (cs CommandLines) InvokePipe(src *bytes.Buffer) error {
	for _, c := range cs {
		buf := bytes.NewBuffer(src.Bytes())
		err := c.InvokePipe(buf)
		if err != nil {
			return err
		}
	}
	return nil
}

type CommandLine string

func (c CommandLine) String() string {
	return string(c)
}

func (c CommandLine) Invoke() error {
	log.Println("invoking command:", c.String())
	out, err := exec.Command("sh", "-c", c.String()).CombinedOutput()
	if len(out) > 0 {
		log.Println(string(out))
	}
	if err != nil {
		return fmt.Errorf("failed: %v %v", c, err)
	}
	return nil
}

func (c CommandLine) InvokePipe(src io.Reader) error {
	log.Println("invoking command:", c.String())
	cmd := exec.Command("sh", "-c", c.String())
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		return err
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		return err
	}

	err = cmd.Start()
	if err != nil {
		return err
	}
	var wg sync.WaitGroup
	wg.Add(3)
	// src => cmd.stdin
	go func() {
		_, err := io.Copy(stdin, src)
		if err != nil {
			log.Println(err)
		}
		stdin.Close()
		wg.Done()
	}()
	// cmd.stdout => stretcher.stdout
	go func() {
		_, err := io.Copy(os.Stdout, stdout)
		if err != nil {
			log.Println(err)
		}
		stdout.Close()
		wg.Done()
	}()
	// cmd.stderr => stretcher.stderr
	go func() {
		_, err := io.Copy(os.Stderr, stderr)
		if err != nil {
			log.Println(err)
		}
		stderr.Close()
		wg.Done()
	}()
	wg.Wait()
	return cmd.Wait()
}
<|endoftext|>


<commit_before>// Package command implements helper functions for multi-command programs.
//
// This package includes types and functions for easily defining multiple
// subcommands with different options. A "help" subcommand is also automatically
// generated, which might be used to list all the available subcommands or
// to view all the help about a specific subcommand.
//
// Clients should just define a list of the command they implement and the call
// Run or RunArgs directly from main().
//
//  package main
//
//  import (
//	"gopkgs.com/command.v1"
//  )
//
//  var (
//	cmds = []*command.Cmd{
//	    {
//		Name: "awesome",
//		Help: "do something awesome"
//		Options: &awesomeOptions{Value:42},
//	    },
//	}
//  )
//
//  type awesomeOptions struct {
//	Value int `name:"v" help:"Some arbitrary value"`
//  }
//
//  func awesomeCommand(args []string, opts *AwesomeOptions) error {
//  ...
//  }
//
//  func main() {
//	commands.Run(cmds)
//  }
package command

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"text/tabwriter"
)

var (
	argsType = reflect.TypeOf([]string(nil))
	// ErrNoCommand is returned from Run when no command
	// has been specified (i.e. there are no arguments).
	ErrNoCommand = errors.New("no command provided")
	// ErrHelp is returned from Run when the help is shown,
	// either the brief help or the detailed help for a
	// command.
	ErrHelp = errors.New("help has been shown")
	// ErrUnusedArguments is returned form Run when the command
	// does not accept any arguments, but the user has provided
	// some.
	ErrUnusedArguments = errors.New("arguments provided but not used")
)

// UnknownCommandError is returned from Run when the specified
// command does not exist.
type UnknownCommandError string

func (e UnknownCommandError) Error() string {
	return fmt.Sprintf("unknown command %s", string(e))
}

// Cmd represents an available command.
type Cmd struct {
	// Name is the name of the command, case sensitive.
	Name string
	// Help is a short, one line help string displayed by
	// the help command when listing all the commands.
	Help string
	// LongHelp is a long, potentially multi-line, help message
	// displayed when using the help command for a specific
	// command (e.g. myprogram help somecommand)
	LongHelp string
	// Usage is displayed when showing the help for a specific
	// command. The program name (os.Args[0]) and the command
	// name are prepended to it when displaying it to the user.
	// (e.g. Usage = <some-argument> shows "usage: myprog subcmd <some-argument>")
	Usage string
	// Func is the handler function for the command. The function must take either
	// one or two arguments. The first one must be a []string, which will contain
	// any non-flag arguments. If the function accepts a second argument it must
	// be of the exact same type than the value provided in the Options field.
	// Handler functions might optionally return an error value.
	Func interface{}
	// Options might be either nil or a pointer to a struct type. Command flags
	// will be generated from this struct, in the same order as the fields are
	// defined. The current value of the field will be used as the default value
	// for the flag. Each field might also include two struct tags:
	//
	//  - name: The name of the flag. If not present, it will default to the field name in lowercase.
	//  - help: The short help shown the flag package for the given field.
	Options interface{}
}

// Run is a shorthand for RunArgs(os.Args[1:], commands).
func Run(commands []*Cmd) error {
	return RunArgs(os.Args[1:], commands)
}

// RunArgs tries to run a command from the specified list using the
// given arguments, interpreting the first argument as the command name.
// If the returned error is non-nil, it will be one of:
//
//  - ErrNoCommand when no arguments are provided
//  - ErrHelp when the user has requested any help to be shown
//  - ErrUnusedArguments when the command doesn't accept any arguments, but the user has provided some
//  - An UnknownCommandError when the command (the first argument) does not exist
//  - Any error returned by the command handler
//
// Any user error will be printed to Stderr by RunArgs, so callers don't need to print any
// error messages themselves.
//
// Note that RunArgs will panic in case of a programming error. This usually happens
// when Func or Options don't match the required constraints. See the documentation on
// those fields in the Cmd type for more information.
func RunArgs(args []string, commands []*Cmd) error {
	if len(args) == 0 || args[0] == "help" {
		return printHelp(os.Stderr, args, commands)
	}
	name := args[0]
	rem := args[1:]
	cmd := commandByName(commands, name)
	if cmd == nil {
		return printHelp(os.Stderr, args, commands)
	}
	fn := reflect.ValueOf(cmd.Func)
	if fn.Kind() != reflect.Func {
		panic(fmt.Errorf("command handler %s is not a function, it's %T", name, cmd.Func))
	}
	var optsVal reflect.Value
	var fnArgs []reflect.Value
	typ := fn.Type()
	numIn := typ.NumIn()
	if cmd.Options != nil {
		optsVal = reflect.ValueOf(cmd.Options)
		optsType := optsVal.Type()
		if numIn == 0 || (typ.In(0) != optsType && (numIn < 2 || typ.In(1) != optsType)) {
			panic(fmt.Errorf("command %s (%s) declares options of type %T but does not accept them", name, typ, cmd.Options))
		}
		flags, err := setupOptionsFlags(name, optsVal)
		if err != nil {
			panic(err)
		}
		if err := flags.Parse(rem); err != nil {
			return err
		}
		rem = flags.Args()
	}
	if numIn > 0 && typ.In(0) == argsType {
		fnArgs = append(fnArgs, reflect.ValueOf(rem))
	} else if len(rem) > 0 {
		fmt.Fprintf(os.Stderr, "command %s does not accept any arguments\n", name)
		return ErrUnusedArguments
	}
	if cmd.Options != nil {
		fnArgs = append(fnArgs, optsVal)
	}
	res := fn.Call(fnArgs)
	if len(res) > 0 {
		if err, ok := res[0].Interface().(error); ok {
			fmt.Fprintf(os.Stderr, "error running command %s: %s\n", name, err)
			return err
		}
	}
	return nil
}

func setupOptionsFlags(name string, val reflect.Value) (*flag.FlagSet, error) {
	if val.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("invalid options %s, must be a pointer", val.Type())
	}
	val = reflect.Indirect(val)
	typ := val.Type()
	if typ.Kind() != reflect.Struct {
		return nil, fmt.Errorf("invalid Options type %s, must be an struct", typ)
	}
	flagsName := fmt.Sprintf("%s %s subcommand", filepath.Base(os.Args[0]), name)
	flags := flag.NewFlagSet(flagsName, flag.ContinueOnError)
	for ii := 0; ii < typ.NumField(); ii++ {
		field := typ.Field(ii)
		fieldVal := val.Field(ii)
		ptr := fieldVal.Addr().Interface()
		name := strings.ToLower(field.Name)
		var help string
		if n := field.Tag.Get("name"); n != "" {
			name = n
		}
		if h := field.Tag.Get("help"); h != "" {
			help = h
		}
		if name == "" {
			return nil, fmt.Errorf("no name provided for field #%d in type %s", ii, typ)
		}
		if value, ok := ptr.(flag.Value); ok {
			flags.Var(value, name, help)
			continue
		}
		switch field.Type.Kind() {
		case reflect.Bool:
			flags.BoolVar(ptr.(*bool), name, fieldVal.Bool(), help)
		case reflect.Float64:
			flags.Float64Var(ptr.(*float64), name, fieldVal.Float(), help)
		case reflect.Int:
			flags.IntVar(ptr.(*int), name, int(fieldVal.Int()), help)
		case reflect.Uint:
			flags.UintVar(ptr.(*uint), name, uint(fieldVal.Uint()), help)
		case reflect.Int64:
			flags.Int64Var(ptr.(*int64), name, fieldVal.Int(), help)
		case reflect.Uint64:
			flags.Uint64Var(ptr.(*uint64), name, fieldVal.Uint(), help)
		case reflect.String:
			flags.StringVar(ptr.(*string), name, fieldVal.String(), help)
		default:
			return nil, fmt.Errorf("field %s has invalid option type %s", field.Name, field.Type)
		}
	}
	return flags, nil
}

func commandByName(commands []*Cmd, name string) *Cmd {
	for _, v := range commands {
		if v.Name == name {
			return v
		}
	}
	return nil
}

func printCommandHelp(w io.Writer, cmd *Cmd) {
	fmt.Fprintf(w, "%s: %s\n", cmd.Name, cmd.Help)
	if cmd.Usage != "" {
		fmt.Fprintf(w, "\nusage: %s %s %s\n", filepath.Base(os.Args[0]), cmd.Name, cmd.Usage)
	}
	if cmd.LongHelp != "" {
		fmt.Fprintf(w, "\n%s\n\n", cmd.LongHelp)
	}
	if cmd.Options != nil {
		opts := reflect.ValueOf(cmd.Options)
		if fs, err := setupOptionsFlags(cmd.Name, opts); err == nil {
			fs.PrintDefaults()
		}
	}
}

func printHelp(w io.Writer, args []string, commands []*Cmd) error {
	var err error
	if len(args) == 0 {
		fmt.Fprintln(w, "missing command, available ones are:\n")
		err = ErrNoCommand
	} else {
		var unknown string
		if args[0] != "help" && commandByName(commands, args[0]) == nil {
			unknown = args[0]
		}
		if len(args) > 1 && args[0] == "help" {
			if cmd := commandByName(commands, args[1]); cmd != nil {
				printCommandHelp(w, cmd)
				return ErrHelp
			}
			unknown = args[1]
		}
		if unknown != "" {
			fmt.Fprintf(w, "unknown command %s, available ones are:\n\n", unknown)
			err = UnknownCommandError(unknown)
		}
	}
	tw := tabwriter.NewWriter(w, 0, 8, 2, ' ', 0)
	for _, v := range commands {
		fmt.Fprintf(tw, "%s\t%s\n", v.Name, v.Help)
	}
	fmt.Fprint(tw, "help\tPrint this help\n")
	tw.Flush()
	fmt.Fprint(w, "\nTo view additional help for each command use help <command_name>\n")
	if err == nil {
		err = ErrHelp
	}
	return err
}
<commit_msg>Add support for main command options before running the subcommand<commit_after>// Package command implements helper functions for multi-command programs.
//
// This package includes types and functions for easily defining multiple
// subcommands with different options. A "help" subcommand is also automatically
// generated, which might be used to list all the available subcommands or
// to view all the help about a specific subcommand.
//
// Clients should just define a list of the command they implement and just call
// Run or RunOpts directly from main().
//
//  package main
//
//  import (
//	"gopkgs.com/command.v1"
//  )
//
//  var (
//	cmds = []*command.Cmd{
//	    {
//		Name: "awesome",
//		Help: "do something awesome"
//		Options: &awesomeOptions{Value:42},
//	    },
//	}
//  )
//
//  type awesomeOptions struct {
//	Value int `name:"v" help:"Some arbitrary value"`
//  }
//
//  func awesomeCommand(args []string, opts *AwesomeOptions) error {
//  ...
//  }
//
//  func main() {
//	commands.Run(cmds)
//  }
package command

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
	"text/tabwriter"
)

var (
	argsType = reflect.TypeOf([]string(nil))
	errType  = reflect.TypeOf((*error)(nil)).Elem()
	cmdType  = reflect.TypeOf((*Cmd)(nil))
	// ErrNoCommand is returned from Run when no command
	// has been specified (i.e. there are no arguments).
	ErrNoCommand = errors.New("no command provided")
	// ErrHelp is returned from Run when the help is shown,
	// either the brief help or the detailed help for a
	// command.
	ErrHelp = errors.New("help has been shown")
	// ErrUnusedArguments is returned form Run when the command
	// does not accept any arguments, but the user has provided
	// some.
	ErrUnusedArguments = errors.New("arguments provided but not used")
)

// UnknownCommandError is returned from Run when the specified
// command does not exist.
type UnknownCommandError string

func (e UnknownCommandError) Error() string {
	return fmt.Sprintf("unknown command %s", string(e))
}

// Cmd represents an available command.
type Cmd struct {
	// Name is the name of the command, case sensitive.
	Name string
	// Help is a short, one line help string displayed by
	// the help command when listing all the commands.
	Help string
	// LongHelp is a long, potentially multi-line, help message
	// displayed when using the help command for a specific
	// command (e.g. myprogram help somecommand)
	LongHelp string
	// Usage is displayed when showing the help for a specific
	// command. The program name (os.Args[0]) and the command
	// name are prepended to it when displaying it to the user.
	// (e.g. Usage = <some-argument> shows "usage: myprog subcmd <some-argument>")
	Usage string
	// Func is the handler function for the command. The function must take either
	// one or two arguments. The first one must be a []string, which will contain
	// any non-flag arguments. If the function accepts a second argument it must
	// be of the exact same type than the value provided in the Options field.
	// Handler functions might optionally return an error value.
	Func interface{}
	// Options might be either nil or a pointer to a struct type. Command flags
	// will be generated from this struct, in the same order as the fields are
	// defined. The current value of the field will be used as the default value
	// for the flag. Each field might also include two struct tags:
	//
	//  - name: The name of the flag. If not present, it will default to the field name in lowercase.
	//  - help: The short help shown the flag package for the given field.
	Options interface{}
}

// Run is a shorthand for RunOpts(nil, nil, commands).
func Run(commands []*Cmd) error {
	return RunOpts(nil, nil, commands)
}

// Options are used to specify additional options when calling RunOpts
type Options struct {
	// Options represents global options which the application
	// needs to handle before running any commands. If this field
	// is non-nil and Handler is also non-nil, its first argument
	// must match the type of this field.
	Options interface{}
	// Func must be a function which accepts a value of the same
	// type of Options as the first parameter and, optionally, a
	// *Cmd as the second argument, which will be the command which is
	// going the be run after calling Func.  Note that setting a non-nil
	// Func with nil Options is supported, but in that case Func must
	// take zero or one argument of type *Cmd. In any case, Func might return
	// either zero or one value of type error.
	Func interface{}
}

// RunOpts tries to run a command from the specified list using the
// given arguments, interpreting the first argument as the command name.
// If the returned error is non-nil, it will be one of:
//
//  - ErrNoCommand when no arguments are provided
//  - ErrHelp when the user has requested any help to be shown
//  - ErrUnusedArguments when the command doesn't accept any arguments, but the user has provided some
//  - An UnknownCommandError when the command (the first argument) does not exist
//  - Any error returned by the command handler
//
// If args is nil, it will be set to os.Args[1:].
//
// Any user error will be printed to os.Stderr by RunOpts, so callers don't need to print any
// error messages themselves.
//
// Note that RunOpts will panic in case of a programming error. This usually happens
// when Func or Options don't match the required constraints. See the documentation on
// those fields in the Cmd type for more information.
func RunOpts(args []string, opts *Options, commands []*Cmd) error {
	if args == nil {
		args = os.Args[1:]
	}
	optsFn, optsArgs, args, err := parseOptions(args, opts)
	if err != nil {
		return err
	}
	if len(args) == 0 || args[0] == "help" {
		return printHelp(os.Stderr, args, commands)
	}
	name := args[0]
	rem := args[1:]
	cmd := commandByName(commands, name)
	if optsFn.IsValid() {
		if optsFn.Type().NumIn() > 1 {
			optsArgs = append(optsArgs, reflect.ValueOf(cmd))
		}
		res := optsFn.Call(optsArgs)
		if len(res) > 0 {
			if e, ok := res[0].Interface().(error); ok {
				fmt.Fprintf(os.Stderr, "%s\n", e)
				return e
			}
		}
	}
	if cmd == nil {
		return printHelp(os.Stderr, args, commands)
	}
	fn := reflect.ValueOf(cmd.Func)
	if fn.Kind() != reflect.Func {
		panic(fmt.Errorf("command handler %s is not a function, it's %T", name, cmd.Func))
	}
	if err := validateFuncReturn(fn); err != nil {
		panic(fmt.Errorf("invalid handler for command %s: %s", name, err))
	}
	var optsVal reflect.Value
	var fnArgs []reflect.Value
	var mandatory []reflect.Type
	if cmd.Options != nil {
		optsVal = reflect.ValueOf(cmd.Options)
		mandatory = append(mandatory, optsVal.Type())
		flags, err := setupOptionsFlags(name, optsVal)
		if err != nil {
			panic(err)
		}
		if err := flags.Parse(rem); err != nil {
			return err
		}
		rem = flags.Args()
	}
	if err := validateFuncInput(fn, []reflect.Type{argsType}, mandatory, true); err != nil {
		panic(fmt.Errorf("invalid handler for command %s: %s", name, err))
	}
	typ := fn.Type()
	numIn := typ.NumIn()
	if numIn > 0 && typ.In(0) == argsType {
		fnArgs = append(fnArgs, reflect.ValueOf(rem))
	} else if len(rem) > 0 {
		fmt.Fprintf(os.Stderr, "command %s does not accept any arguments\n", name)
		return ErrUnusedArguments
	}
	if cmd.Options != nil {
		fnArgs = append(fnArgs, optsVal)
	}
	res := fn.Call(fnArgs)
	if len(res) > 0 {
		if err, ok := res[0].Interface().(error); ok {
			fmt.Fprintf(os.Stderr, "error running command %s: %s\n", name, err)
			return err
		}
	}
	return nil
}

func parseOptions(args []string, opts *Options) (reflect.Value, []reflect.Value, []string, error) {
	var optsFn reflect.Value
	var optsArgs []reflect.Value
	if opts != nil {
		var globalOptsVal reflect.Value
		var mandatory []reflect.Type
		if opts.Options != nil {
			globalOptsVal = reflect.ValueOf(opts.Options)
			mandatory = append(mandatory, globalOptsVal.Type())
			flags, err := setupOptionsFlags("", globalOptsVal)
			if err != nil {
				panic(err)
			}
			if err := flags.Parse(args); err != nil {
				return optsFn, optsArgs, args, err
			}
			args = flags.Args()
		}
		if opts.Func != nil {
			optsFn = reflect.ValueOf(opts.Func)
			if optsFn.Kind() != reflect.Func {
				panic(fmt.Errorf("options handler is not a function, it's %T", opts.Func))
			}
			if err := validateFuncReturn(optsFn); err != nil {
				panic(fmt.Errorf("invalid options handler: %s", err))
			}
			if err := validateFuncInput(optsFn, []reflect.Type{cmdType}, mandatory, false); err != nil {
				panic(fmt.Errorf("invalid options handler: %s", err))
			}
			if opts.Options != nil {
				optsArgs = append(optsArgs, globalOptsVal)
			}
		}
	}
	return optsFn, optsArgs, args, nil
}

func validateArguments(val reflect.Value, n int, args []reflect.Type, mandatory bool) (int, error) {
	typ := val.Type()
	numIn := typ.NumIn()
	for _, v := range args {
		if n >= numIn {
			if !mandatory {
				break
			}
			return 0, fmt.Errorf("function %s must accept an argument of type %s as the #%d parameter, but in only has %d arguments", funcName(val), v, n+1, numIn)
		}
		in := typ.In(n)
		if in != v {
			if !mandatory {
				continue
			}
			return 0, fmt.Errorf("function %s must accept an argument of type %s as the #%d parameter, not %s", funcName(val), v, n+1, in)
		}
		n++
	}
	return n, nil
}

func validateFuncInput(val reflect.Value, optional []reflect.Type, mandatory []reflect.Type, optionalFirst bool) error {
	n := 0
	var toCheck [][]reflect.Type
	var mandatories []bool
	if optionalFirst {
		toCheck = [][]reflect.Type{optional, mandatory}
		mandatories = []bool{false, true}
	} else {
		toCheck = [][]reflect.Type{mandatory, optional}
		mandatories = []bool{true, false}
	}
	var err error
	for ii, v := range toCheck {
		n, err = validateArguments(val, n, v, mandatories[ii])
		if err != nil {
			return err
		}
	}
	typ := val.Type()
	numIn := typ.NumIn()
	if n != numIn {
		var remaining []string
		for ii := n; ii < numIn; ii++ {
			remaining = append(remaining, typ.In(ii).String())
		}
		return fmt.Errorf("function %s has %d unused arguments of types %s", funcName(val), numIn-n, strings.Join(remaining, ", "))
	}
	return nil
}

func validateFuncReturn(val reflect.Value) error {
	typ := val.Type()
	numOut := typ.NumOut()
	if numOut == 0 {
		return nil
	}
	if numOut > 1 {
		return fmt.Errorf("function %s must return 0 or 1 arguments, not %d", funcName(val), numOut)
	}
	if typ.Out(0) != errType {
		return fmt.Errorf("function %s must return a value of type %s, not %s", funcName(val), errType, typ.Out(0))
	}
	return nil
}

func funcName(val reflect.Value) string {
	ptr := val.Pointer()
	fn := runtime.FuncForPC(ptr)
	if fn == nil {
		return fmt.Sprintf("unknown function at %p", ptr)
	}
	return fn.Name()
}

func setupOptionsFlags(name string, val reflect.Value) (*flag.FlagSet, error) {
	if val.Kind() != reflect.Ptr {
		return nil, fmt.Errorf("invalid options %s, must be a pointer", val.Type())
	}
	val = reflect.Indirect(val)
	typ := val.Type()
	if typ.Kind() != reflect.Struct {
		return nil, fmt.Errorf("invalid Options type %s, must be an struct", typ)
	}
	arg0 := filepath.Base(os.Args[0])
	var flagsName string
	if name != "" {
		flagsName = fmt.Sprintf("%s %s subcommand", arg0, name)
	} else {
		flagsName = arg0
	}
	flags := flag.NewFlagSet(flagsName, flag.ContinueOnError)
	for ii := 0; ii < typ.NumField(); ii++ {
		field := typ.Field(ii)
		fieldVal := val.Field(ii)
		ptr := fieldVal.Addr().Interface()
		name := strings.ToLower(field.Name)
		var help string
		if n := field.Tag.Get("name"); n != "" {
			name = n
		}
		if h := field.Tag.Get("help"); h != "" {
			help = h
		}
		if name == "" {
			return nil, fmt.Errorf("no name provided for field #%d in type %s", ii, typ)
		}
		if value, ok := ptr.(flag.Value); ok {
			flags.Var(value, name, help)
			continue
		}
		switch field.Type.Kind() {
		case reflect.Bool:
			flags.BoolVar(ptr.(*bool), name, fieldVal.Bool(), help)
		case reflect.Float64:
			flags.Float64Var(ptr.(*float64), name, fieldVal.Float(), help)
		case reflect.Int:
			flags.IntVar(ptr.(*int), name, int(fieldVal.Int()), help)
		case reflect.Uint:
			flags.UintVar(ptr.(*uint), name, uint(fieldVal.Uint()), help)
		case reflect.Int64:
			flags.Int64Var(ptr.(*int64), name, fieldVal.Int(), help)
		case reflect.Uint64:
			flags.Uint64Var(ptr.(*uint64), name, fieldVal.Uint(), help)
		case reflect.String:
			flags.StringVar(ptr.(*string), name, fieldVal.String(), help)
		default:
			return nil, fmt.Errorf("field %s has invalid option type %s", field.Name, field.Type)
		}
	}
	return flags, nil
}

func commandByName(commands []*Cmd, name string) *Cmd {
	for _, v := range commands {
		if v.Name == name {
			return v
		}
	}
	return nil
}

func printCommandHelp(w io.Writer, cmd *Cmd) {
	fmt.Fprintf(w, "%s: %s\n", cmd.Name, cmd.Help)
	if cmd.Usage != "" {
		fmt.Fprintf(w, "\nusage: %s %s %s\n", filepath.Base(os.Args[0]), cmd.Name, cmd.Usage)
	}
	if cmd.LongHelp != "" {
		fmt.Fprintf(w, "\n%s\n\n", cmd.LongHelp)
	}
	if cmd.Options != nil {
		opts := reflect.ValueOf(cmd.Options)
		if fs, err := setupOptionsFlags(cmd.Name, opts); err == nil {
			fs.PrintDefaults()
		}
	}
}

func printHelp(w io.Writer, args []string, commands []*Cmd) error {
	var err error
	if len(args) == 0 {
		fmt.Fprintln(w, "missing command, available ones are:\n")
		err = ErrNoCommand
	} else {
		var unknown string
		if args[0] != "help" && commandByName(commands, args[0]) == nil {
			unknown = args[0]
		}
		if len(args) > 1 && args[0] == "help" {
			if cmd := commandByName(commands, args[1]); cmd != nil {
				printCommandHelp(w, cmd)
				return ErrHelp
			}
			unknown = args[1]
		}
		if unknown != "" {
			fmt.Fprintf(w, "unknown command %s, available ones are:\n\n", unknown)
			err = UnknownCommandError(unknown)
		}
	}
	tw := tabwriter.NewWriter(w, 0, 8, 2, ' ', 0)
	for _, v := range commands {
		fmt.Fprintf(tw, "%s\t%s\n", v.Name, v.Help)
	}
	fmt.Fprint(tw, "help\tPrint this help\n")
	tw.Flush()
	fmt.Fprint(w, "\nTo view additional help for each command use help <command_name>\n")
	if err == nil {
		err = ErrHelp
	}
	return err
}
<|endoftext|>


<commit_before>package main

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

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

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

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

func deliverCrashReport(job *runnerCommand, getter func(name string) (string, int), logger func(text string)) {
	ip, port := getter("githubcard")
	if port > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		conn, err := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		if err == nil {
			defer conn.Close()
			client := pbgh.NewGithubClient(conn)
			elems := strings.Split(job.details.Spec.GetName(), "/")
			if len(job.output) > 0 {
				client.AddIssue(ctx, &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output}, grpc.FailFast(false))
			}
		}
	}
}

func (s *Server) addMessage(details *pb.JobDetails, message string) {
	for _, t := range s.runner.backgroundTasks {
		if t.details.GetSpec().Name == details.Spec.Name {
			t.output += message
		}
	}
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.StartTime = 0
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().Name)
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job)
			for job.StartTime == 0 {
				time.Sleep(waitTime)
			}
			job.State = pb.JobDetails_PENDING
		case pb.JobDetails_KILLING:
			s.runner.kill(job)
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job)
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_PENDING:
			time.Sleep(time.Minute)
			if isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_RUNNING
			} else {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				job.TestCount++
			} else {
				job.TestCount = 0
			}
			if job.TestCount > 3 {
				s.Log(fmt.Sprintf("Killing beacuse we couldn't reach 3 times: %v", job))
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_DEAD:
			job.State = pb.JobDetails_ACKNOWLEDGED
		}
	}
}

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

	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) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, err := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	if err == nil {
		defer conn.Close()

		registry := pbd.NewDiscoveryServiceClient(conn)
		entry := pbd.RegistryEntry{Name: name, Identifier: server}
		r, err2 := registry.Discover(ctx, &entry, grpc.FailFast(false))

		if err2 == nil {
			return r.Ip, int(r.Port)
		}
	}
	return "", -1
}

// 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)

	if dPort > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		resp, err := c.IsAlive(ctx, &pbs.Alive{}, grpc.FailFast(false))

		if err != nil || resp.Name != elems[len(elems)-1] {
			e, ok := status.FromError(err)
			if ok && e.Code() != codes.Unavailable {
				return false
			}
		}

		return true
	}

	//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
}

// GetState gets the state of the server
func (s Server) GetState() []*pbs.State {
	return []*pbs.State{}
}

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

func runCommand(c *runnerCommand) {
	if c == nil || c.command == nil {
		return
	}

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

	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
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	c.command.Env = envl

	out, err := c.command.StderrPipe()
	if err != nil {
		log.Fatalf("Problem getting stderr: %v", err)
	}

	if out != nil {
		scanner := bufio.NewScanner(out)
		go func() {
			for scanner != nil && scanner.Scan() {
				c.output += scanner.Text()
			}
		}()
	}

	c.command.Start()

	if !c.background {
		c.command.Wait()
		c.complete = true
	} else {
		c.details.StartTime = time.Now().Unix()
	}
}

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

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

		var rebuildList []*pb.JobDetails
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			if time.Since(job.started) > time.Hour {
				rebuildList = append(rebuildList, job.details)
				hashList = append(hashList, job.hash)
			}
		}

		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.runner.getip = s.GetIP
	s.runner.logger = s.Log
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<commit_msg>Added fail to serve output<commit_after>package main

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

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

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

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

func deliverCrashReport(job *runnerCommand, getter func(name string) (string, int), logger func(text string)) {
	ip, port := getter("githubcard")
	if port > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		conn, err := grpc.Dial(ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		if err == nil {
			defer conn.Close()
			client := pbgh.NewGithubClient(conn)
			elems := strings.Split(job.details.Spec.GetName(), "/")
			if len(job.output) > 0 {
				client.AddIssue(ctx, &pbgh.Issue{Service: elems[len(elems)-1], Title: "CRASH REPORT", Body: job.output}, grpc.FailFast(false))
			}
		}
	}
}

func (s *Server) addMessage(details *pb.JobDetails, message string) {
	for _, t := range s.runner.backgroundTasks {
		if t.details.GetSpec().Name == details.Spec.Name {
			t.output += message
		}
	}
}

func (s *Server) monitor(job *pb.JobDetails) {
	for true {
		switch job.State {
		case pb.JobDetails_ACKNOWLEDGED:
			job.StartTime = 0
			job.State = pb.JobDetails_BUILDING
			s.runner.Checkout(job.GetSpec().Name)
			job.State = pb.JobDetails_BUILT
		case pb.JobDetails_BUILT:
			s.runner.Run(job)
			for job.StartTime == 0 {
				time.Sleep(waitTime)
			}
			job.State = pb.JobDetails_PENDING
		case pb.JobDetails_KILLING:
			s.runner.kill(job)
			if !isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_UPDATE_STARTING:
			s.runner.Update(job)
			job.State = pb.JobDetails_RUNNING
		case pb.JobDetails_PENDING:
			time.Sleep(time.Minute)
			if isAlive(job.GetSpec()) {
				job.State = pb.JobDetails_RUNNING
			} else {
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_RUNNING:
			time.Sleep(waitTime)
			if !isAlive(job.GetSpec()) {
				job.TestCount++
			} else {
				job.TestCount = 0
			}
			if job.TestCount > 3 {
				s.Log(fmt.Sprintf("Killing beacuse we couldn't reach 3 times: %v", job))
				job.State = pb.JobDetails_DEAD
			}
		case pb.JobDetails_DEAD:
			job.State = pb.JobDetails_ACKNOWLEDGED
		}
	}
}

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

	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) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, err := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	if err == nil {
		defer conn.Close()

		registry := pbd.NewDiscoveryServiceClient(conn)
		entry := pbd.RegistryEntry{Name: name, Identifier: server}
		r, err2 := registry.Discover(ctx, &entry, grpc.FailFast(false))

		if err2 == nil {
			return r.Ip, int(r.Port)
		}
	}
	return "", -1
}

// 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)

	if dPort > 0 {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			return false
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		resp, err := c.IsAlive(ctx, &pbs.Alive{}, grpc.FailFast(false))

		if err != nil || resp.Name != elems[len(elems)-1] {
			e, ok := status.FromError(err)
			if ok && e.Code() != codes.Unavailable {
				return false
			}
		}

		return true
	}

	//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
}

// GetState gets the state of the server
func (s Server) GetState() []*pbs.State {
	return []*pbs.State{}
}

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

func runCommand(c *runnerCommand) {
	if c == nil || c.command == nil {
		return
	}

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

	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
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	c.command.Env = envl

	out, err := c.command.StderrPipe()
	if err != nil {
		log.Fatalf("Problem getting stderr: %v", err)
	}

	if out != nil {
		scanner := bufio.NewScanner(out)
		go func() {
			for scanner != nil && scanner.Scan() {
				c.output += scanner.Text()
			}
		}()
	}

	c.command.Start()

	if !c.background {
		c.command.Wait()
		c.complete = true
	} else {
		c.details.StartTime = time.Now().Unix()
	}
}

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

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

		var rebuildList []*pb.JobDetails
		var hashList []string
		for _, job := range s.runner.backgroundTasks {
			if time.Since(job.started) > time.Hour {
				rebuildList = append(rebuildList, job.details)
				hashList = append(hashList, job.hash)
			}
		}

		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.runner.getip = s.GetIP
	s.runner.logger = s.Log
	s.Register = s
	s.PrepServer()
	s.GoServer.Killme = false
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	err := s.Serve()
	log.Fatalf("Unable to serve: %v", err)
}
<|endoftext|>


<commit_before>package cli

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

// Command is a subcommand for a cli.App.
type Command struct {
	// The name of the command
	Name string
	// short name of the command. Typically one character (deprecated, use `Aliases`)
	ShortName string
	// A list of aliases for the command
	Aliases []string
	// A short description of the usage of this command
	Usage string
	// A longer explanation of how the command works
	Description string
	// The function to call when checking for bash command completions
	BashComplete func(context *Context)
	// An action to execute before any sub-subcommands are run, but after the context is ready
	// If a non-nil error is returned, no sub-subcommands are run
	Before func(context *Context) error
	// An action to execute after any subcommands are run, but after the subcommand has finished
	// It is run even if Action() panics
	After func(context *Context) error
	// The function to call when this command is invoked
	Action func(context *Context)
	// List of child commands
	Subcommands []Command
	// List of flags to parse
	Flags []Flag
	// Treat all flags as normal arguments if true
	SkipFlagParsing bool
	// Boolean to hide built-in help command
	HideHelp bool

	commandNamePath []string
}

// Returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string {
	if c.commandNamePath == nil {
		return c.Name
	}
	return strings.Join(c.commandNamePath, " ")
}

// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
	if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
		return c.startApp(ctx)
	}

	if !c.HideHelp && (HelpFlag != BoolFlag{}) {
		// append help to flags
		c.Flags = append(
			c.Flags,
			HelpFlag,
		)
	}

	if ctx.App.EnableBashCompletion {
		c.Flags = append(c.Flags, BashCompletionFlag)
	}

	set := flagSet(c.Name, c.Flags)
	set.SetOutput(ioutil.Discard)

	firstFlagIndex := -1
	terminatorIndex := -1
	for index, arg := range ctx.Args() {
		if arg == "--" {
			terminatorIndex = index
			break
		} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
			firstFlagIndex = index
		}
	}

	var err error
	if firstFlagIndex > -1 && !c.SkipFlagParsing {
		args := ctx.Args()
		regularArgs := make([]string, len(args[1:firstFlagIndex]))
		copy(regularArgs, args[1:firstFlagIndex])

		var flagArgs []string
		if terminatorIndex > -1 {
			flagArgs = args[firstFlagIndex:terminatorIndex]
			regularArgs = append(regularArgs, args[terminatorIndex:]...)
		} else {
			flagArgs = args[firstFlagIndex:]
		}

		err = set.Parse(append(flagArgs, regularArgs...))
	} else {
		err = set.Parse(ctx.Args().Tail())
	}

	if err != nil {
		fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
		fmt.Fprintln(ctx.App.Writer)
		ShowCommandHelp(ctx, c.Name)
		return err
	}

	nerr := normalizeFlags(c.Flags, set)
	if nerr != nil {
		fmt.Fprintln(ctx.App.Writer, nerr)
		fmt.Fprintln(ctx.App.Writer)
		ShowCommandHelp(ctx, c.Name)
		return nerr
	}
	context := NewContext(ctx.App, set, ctx)

	if checkCommandCompletions(context, c.Name) {
		return nil
	}

	if checkCommandHelp(context, c.Name) {
		return nil
	}
	context.Command = c
	c.Action(context)
	return nil
}

func (c Command) Names() []string {
	names := []string{c.Name}

	if c.ShortName != "" {
		names = append(names, c.ShortName)
	}

	return append(names, c.Aliases...)
}

// Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
	for _, n := range c.Names() {
		if n == name {
			return true
		}
	}
	return false
}

func (c Command) startApp(ctx *Context) error {
	app := NewApp()

	// set the name and usage
	app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
	if c.Description != "" {
		app.Usage = c.Description
	} else {
		app.Usage = c.Usage
	}

	// set CommandNotFound
	app.CommandNotFound = ctx.App.CommandNotFound

	// set the flags and commands
	app.Commands = c.Subcommands
	app.Flags = c.Flags
	app.HideHelp = c.HideHelp

	app.Version = ctx.App.Version
	app.HideVersion = ctx.App.HideVersion
	app.Compiled = ctx.App.Compiled
	app.Author = ctx.App.Author
	app.Email = ctx.App.Email
	app.Writer = ctx.App.Writer

	// bash completion
	app.EnableBashCompletion = ctx.App.EnableBashCompletion
	if c.BashComplete != nil {
		app.BashComplete = c.BashComplete
	}

	// set the actions
	app.Before = c.Before
	app.After = c.After
	if c.Action != nil {
		app.Action = c.Action
	} else {
		app.Action = helpSubcommand.Action
	}

	var newCmds []Command
	for _, cc := range app.Commands {
		cc.commandNamePath = []string{c.Name, cc.Name}
		newCmds = append(newCmds, cc)
	}
	app.Commands = newCmds

	return app.RunAsSubcommand(ctx)
}
<commit_msg>added ArgumentHelp to Command struct<commit_after>package cli

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

// Command is a subcommand for a cli.App.
type Command struct {
	// The name of the command
	Name string
	// short name of the command. Typically one character (deprecated, use `Aliases`)
	ShortName string
	// A list of aliases for the command
	Aliases []string
	// A short description of the usage of this command
	Usage string
	// A longer explanation of how the command works
	Description string
	// The function to call when checking for bash command completions
	BashComplete func(context *Context)
	// An action to execute before any sub-subcommands are run, but after the context is ready
	// If a non-nil error is returned, no sub-subcommands are run
	Before func(context *Context) error
	// An action to execute after any subcommands are run, but after the subcommand has finished
	// It is run even if Action() panics
	After func(context *Context) error
	// The function to call when this command is invoked
	Action func(context *Context)
	// List of child commands
	Subcommands []Command
	// List of flags to parse
	Flags []Flag
	// Treat all flags as normal arguments if true
	SkipFlagParsing bool
	// Boolean to hide built-in help command
	HideHelp bool
	// for non-flag argument help in USAGE section
	// For `app command <path1> <path2>`, ArgumentHelp would be "<path1> <path2>"
	ArgumentHelp string

	commandNamePath []string
}

// Returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string {
	if c.commandNamePath == nil {
		return c.Name
	}
	return strings.Join(c.commandNamePath, " ")
}

// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error {
	if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
		return c.startApp(ctx)
	}

	if !c.HideHelp && (HelpFlag != BoolFlag{}) {
		// append help to flags
		c.Flags = append(
			c.Flags,
			HelpFlag,
		)
	}

	if ctx.App.EnableBashCompletion {
		c.Flags = append(c.Flags, BashCompletionFlag)
	}

	set := flagSet(c.Name, c.Flags)
	set.SetOutput(ioutil.Discard)

	firstFlagIndex := -1
	terminatorIndex := -1
	for index, arg := range ctx.Args() {
		if arg == "--" {
			terminatorIndex = index
			break
		} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
			firstFlagIndex = index
		}
	}

	var err error
	if firstFlagIndex > -1 && !c.SkipFlagParsing {
		args := ctx.Args()
		regularArgs := make([]string, len(args[1:firstFlagIndex]))
		copy(regularArgs, args[1:firstFlagIndex])

		var flagArgs []string
		if terminatorIndex > -1 {
			flagArgs = args[firstFlagIndex:terminatorIndex]
			regularArgs = append(regularArgs, args[terminatorIndex:]...)
		} else {
			flagArgs = args[firstFlagIndex:]
		}

		err = set.Parse(append(flagArgs, regularArgs...))
	} else {
		err = set.Parse(ctx.Args().Tail())
	}

	if err != nil {
		fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
		fmt.Fprintln(ctx.App.Writer)
		ShowCommandHelp(ctx, c.Name)
		return err
	}

	nerr := normalizeFlags(c.Flags, set)
	if nerr != nil {
		fmt.Fprintln(ctx.App.Writer, nerr)
		fmt.Fprintln(ctx.App.Writer)
		ShowCommandHelp(ctx, c.Name)
		return nerr
	}
	context := NewContext(ctx.App, set, ctx)

	if checkCommandCompletions(context, c.Name) {
		return nil
	}

	if checkCommandHelp(context, c.Name) {
		return nil
	}
	context.Command = c
	c.Action(context)
	return nil
}

func (c Command) Names() []string {
	names := []string{c.Name}

	if c.ShortName != "" {
		names = append(names, c.ShortName)
	}

	return append(names, c.Aliases...)
}

// Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool {
	for _, n := range c.Names() {
		if n == name {
			return true
		}
	}
	return false
}

func (c Command) startApp(ctx *Context) error {
	app := NewApp()

	// set the name and usage
	app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
	if c.Description != "" {
		app.Usage = c.Description
	} else {
		app.Usage = c.Usage
	}

	// set CommandNotFound
	app.CommandNotFound = ctx.App.CommandNotFound

	// set the flags and commands
	app.Commands = c.Subcommands
	app.Flags = c.Flags
	app.HideHelp = c.HideHelp

	app.Version = ctx.App.Version
	app.HideVersion = ctx.App.HideVersion
	app.Compiled = ctx.App.Compiled
	app.Author = ctx.App.Author
	app.Email = ctx.App.Email
	app.Writer = ctx.App.Writer

	// bash completion
	app.EnableBashCompletion = ctx.App.EnableBashCompletion
	if c.BashComplete != nil {
		app.BashComplete = c.BashComplete
	}

	// set the actions
	app.Before = c.Before
	app.After = c.After
	if c.Action != nil {
		app.Action = c.Action
	} else {
		app.Action = helpSubcommand.Action
	}

	var newCmds []Command
	for _, cc := range app.Commands {
		cc.commandNamePath = []string{c.Name, cc.Name}
		newCmds = append(newCmds, cc)
	}
	app.Commands = newCmds

	return app.RunAsSubcommand(ctx)
}
<|endoftext|>


<commit_before>package hexa

import (
	"bufio"
	"context"
	"io"
	"log"
	"os/exec"
)

type StdPlumber interface {
	StderrPipe() (io.ReadCloser, error)
	StdinPipe() (io.WriteCloser, error)
	StdoutPipe() (io.ReadCloser, error)
}

func CopyPipe(ctx context.Context, w io.Writer, r io.Reader) {
	go func() {
		line_reader := bufio.NewScanner(r)

		select {
		case <-ctx.Done():
			return
		default:
		}

		for line_reader.Scan() {
			select {
			case <-ctx.Done():
				return
			default:
			}

			l := line_reader.Text()
			w.Write([]byte(l))

			select {
			case <-ctx.Done():
				return
			default:
			}
		}
	}()
}

func NewCommand(parent context.Context, pipeHandler func(plumber StdPlumber), name string, args ...string) StoppableOne {
	own_ctx := NewDContextToStoppable(parent)
	cmd := exec.CommandContext(own_ctx, name, args...)

	switch pipeHandler {
	case nil:
	default:
		pipeHandler(cmd)
	}

	go func() {
		defer own_ctx.InClose()
		err := cmd.Run()
		if err != nil {
			log.Printf("%+v", err)
		}
	}()
	return own_ctx
}
<commit_msg>line end is added in copy-pipe<commit_after>package hexa

import (
	"bufio"
	"context"
	"io"
	"log"
	"os/exec"
)

type StdPlumber interface {
	StderrPipe() (io.ReadCloser, error)
	StdinPipe() (io.WriteCloser, error)
	StdoutPipe() (io.ReadCloser, error)
}

func CopyPipe(ctx context.Context, w io.Writer, r io.Reader) {
	go func() {
		line_reader := bufio.NewScanner(r)

		select {
		case <-ctx.Done():
			return
		default:
		}

		for line_reader.Scan() {
			select {
			case <-ctx.Done():
				return
			default:
			}

			l := line_reader.Text() + "\n"
			w.Write([]byte(l))

			select {
			case <-ctx.Done():
				return
			default:
			}
		}
	}()
}

func NewCommand(parent context.Context, pipeHandler func(plumber StdPlumber), name string, args ...string) StoppableOne {
	own_ctx := NewDContextToStoppable(parent)
	cmd := exec.CommandContext(own_ctx, name, args...)

	switch pipeHandler {
	case nil:
	default:
		pipeHandler(cmd)
	}

	go func() {
		defer own_ctx.InClose()
		err := cmd.Run()
		if err != nil {
			log.Printf("%+v", err)
		}
	}()
	return own_ctx
}
<|endoftext|>


<commit_before>package fakku

import (
	"fmt"
	"log"
	"net/url"
	"time"
)

type contentCommentApiFunction struct {
	contentApiFunction
	supportsPagination
	TopComments bool
}

func (a contentCommentApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", a.contentApiFunction.Construct())
	log.Printf("url: %s", base)
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		return paginateString(base, a.Page)
	}
}

func getContentCommentsGeneric(url apiFunction) (*Comments, error) {
	var c Comments
	if err := apiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func ContentComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
	}
	return getContentCommentsGeneric(url)
}

func ContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		supportsPagination: supportsPagination{Page: page},
	}
	return getContentCommentsGeneric(url)
}

func ContentTopComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

func (this *Content) TopComments() (*Comments, error) {
	return ContentTopComments(this.Category, this.rawName)
}
func (this *Content) CommentsPage(page uint) (*Comments, error) {
	return ContentCommentsPage(this.Category, this.rawName, page)
}
func (this *Content) Comments() (*Comments, error) {
	return ContentComments(this.Category, this.rawName)
}

type Comment struct {
	Id           int64   `json:"comment_id"`
	Parent       int64   `json:"comment_attached_id"`
	Poster       string  `json:"comment_poster"`
	RawPosterUrl string  `json:"comment_poster_url"`
	Reputation   float64 `json:"comment_reputation"`
	Text         string  `json:"comment_text"`
	RawDate      int64   `json:"comment_date"`
}

func (this *Comment) PosterUrl() (*url.URL, error) {
	return url.Parse(this.RawPosterUrl)
}
func (this *Comment) Date() time.Time {
	return time.Unix(this.RawDate, 0)
}

/*
func (this *Comment) PosterInformation() (*UserProfile, error) {
	return
}
*/

type CommentList []Comment
type Comments struct {
	Comments   CommentList `json:"comments"`
	PageNumber int         `json:"page"`
	Total      int         `json:"total"`
	Pages      int         `json:"pages"`
}

type UserComment struct {
	Id          uint   `json:"comment_id"`
	AttachedId  uint   `json:"comment_attached_id"`
	Reputation  int    `json:"comment_reputation"`
	Text        string `json:"comment_string"`
	RawDate     int64  `json:"comment_date"`
	ContentName string `json:"comment_content_name"`
	ContentUrl  string `json:"comment_content_url"`
}
type UserCommentList []UserComment

func (this *UserComment) Url() (*url.URL, error) {
	return url.Parse(this.ContentUrl)
}
func (this *UserComment) Date() time.Time {
	return time.Unix(this.RawDate, 0)
}

type UserComments struct {
	CommentsList UserCommentList `json:"comments"`
	Total        uint            `json:"total"`
	Pages        uint            `json:"pages"`
}

type userCommentsApiFunction struct {
	userApiFunction
	supportsPagination
}

func (c userCommentsApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", c.userApiFunction.Construct())
	return paginateString(base, c.Page)
}

func GetUserCommentsPage(user string, page uint) (*UserComments, error) {
	var c UserComments
	url := userCommentsApiFunction{
		userApiFunction:    userApiFunction{Name: user},
		supportsPagination: supportsPagination{Page: page},
	}
	if err := apiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}

}

func GetUserComments(user string) (*UserComments, error) {
	return GetUserCommentsPage(user, 0)
}

func (this *UserProfile) Comments() (*UserComments, error) {
	return GetUserComments(this.Username)
}
func (this *UserProfile) CommentsPage(page uint) (*UserComments, error) {
	return GetUserCommentsPage(this.Username, page)
}
<commit_msg>Fixed some 503 errors for user posts and topics :D<commit_after>package fakku

import (
	"fmt"
	"log"
	"net/url"
	"time"
)

type contentCommentApiFunction struct {
	contentApiFunction
	supportsPagination
	TopComments bool
}

func (a contentCommentApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", a.contentApiFunction.Construct())
	log.Printf("url: %s", base)
	if a.TopComments {
		return fmt.Sprintf("%s/top", base)
	} else {
		return paginateString(base, a.Page)
	}
}

func getContentCommentsGeneric(url apiFunction) (*Comments, error) {
	var c Comments
	if err := apiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}
}
func ContentComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		supportsPagination: supportsPagination{Page: 0},
		TopComments:        false,
	}
	return getContentCommentsGeneric(url)
}

func ContentCommentsPage(category, name string, page uint) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		supportsPagination: supportsPagination{Page: page},
		TopComments:        false,
	}
	return getContentCommentsGeneric(url)
}

func ContentTopComments(category, name string) (*Comments, error) {
	url := contentCommentApiFunction{
		contentApiFunction: contentApiFunction{
			Category: category,
			Name:     name,
		},
		TopComments: true,
	}
	return getContentCommentsGeneric(url)
}

func (this *Content) TopComments() (*Comments, error) {
	return ContentTopComments(this.Category, this.rawName)
}
func (this *Content) CommentsPage(page uint) (*Comments, error) {
	return ContentCommentsPage(this.Category, this.rawName, page)
}
func (this *Content) Comments() (*Comments, error) {
	return ContentComments(this.Category, this.rawName)
}

type Comment struct {
	Id         int64   `json:"comment_id"`
	Parent     int64   `json:"comment_attached_id"`
	Reputation float64 `json:"comment_reputation"`
	Text       string  `json:"comment_text"`
	RawDate    int64   `json:"comment_date"`
	Name       string  `json:"comment_poster" json:"comment_content_name"`
	RawUrl     string  `json:"comment_poster_url" json:"comment_content_url"`
}

func (this *Comment) Url() (*url.URL, error) {
	return url.Parse(this.Name)
}
func (this *Comment) Date() time.Time {
	return time.Unix(this.RawDate, 0)
}

/*
func (this *Comment) PosterInformation() (*UserProfile, error) {
	return
}
*/

type CommentList []Comment
type Comments struct {
	Comments   CommentList `json:"comments"`
	PageNumber int         `json:"page"`
	Total      int         `json:"total"`
	Pages      int         `json:"pages"`
}

/*
type UserComment struct {
	Id          uint   `json:"comment_id"`
	AttachedId  uint   `json:"comment_attached_id"`
	Reputation  int    `json:"comment_reputation"`
	Text        string `json:"comment_string"`
	RawDate     int64  `json:"comment_date"`
	ContentName string `json:"comment_content_name"`
	ContentUrl  string `json:"comment_content_url"`
}
*/
//type UserCommentList []UserComment
/*
func (this *UserComment) Url() (*url.URL, error) {
	return url.Parse(this.ContentUrl)
}
func (this *UserComment) Date() time.Time {
	return time.Unix(this.RawDate, 0)
}
*/

type UserComments struct {
	CommentsList CommentList `json:"comments"`
	Total        uint        `json:"total"`
	Pages        uint        `json:"pages"`
}

type userCommentsApiFunction struct {
	userApiFunction
	supportsPagination
}

func (c userCommentsApiFunction) Construct() string {
	base := fmt.Sprintf("%s/comments", c.userApiFunction.Construct())
	return paginateString(base, c.Page)
}

func GetUserCommentsPage(user string, page uint) (*UserComments, error) {
	var c UserComments
	url := userCommentsApiFunction{
		userApiFunction:    userApiFunction{Name: user},
		supportsPagination: supportsPagination{Page: page},
	}
	if err := apiCall(url, &c); err != nil {
		return nil, err
	} else {
		return &c, nil
	}

}

func GetUserComments(user string) (*UserComments, error) {
	return GetUserCommentsPage(user, 0)
}

func (this *UserProfile) Comments() (*UserComments, error) {
	return GetUserComments(this.Username)
}
func (this *UserProfile) CommentsPage(page uint) (*UserComments, error) {
	return GetUserCommentsPage(this.Username, page)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Steven Labrum

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 CheckIt

import (
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var tempDirectory = ""

func writefile(filename string, body []byte, ext string) {

	err := ioutil.WriteFile(filename+ext, body, 0777)
	if err != nil {
		return
	}
}

func randFolder() string {
	b := make([]byte, 2)
	binary.LittleEndian.PutUint16(b, uint16(rand.Intn(1000)))
	hash := md5.Sum(b)

	return fmt.Sprintf("%x", hash)
}

func textAreas() []string {
	var texts []string

	for key := range boxes {
		texts = append(texts, boxes[key].Body)
	}
	return texts
}

/*
	Runs commands specified in args using input as Stdin
*/
func InterfaceRun(box Box, body []byte, args ...string) (out []byte, err error) {

	tempDirectory = randFolder()

	os.Mkdir("./"+tempDirectory, 0777)

	writefile("./"+tempDirectory+"/"+args[0], body, "")
	args = args[1:]
	textareas := textAreas()

	killer := time.NewTimer(10000000)
	var timer bool

	go func() {
		killer = time.AfterFunc(configuration.Timeout, TimeOut)
	}()

	go func() {
		out, err = box.Run(textareas, tempDirectory, args...)
		timer = killer.Stop()
	}()

	if timer {
		out = []byte("TIME OUT")
	}
	if err != nil {
		fmt.Println(string(out))
		return
	}

	defer os.RemoveAll("./" + tempDirectory + "/")

	return out, err
}

func TimeOut() {
	fmt.Print("TIME OUT")
}
<commit_msg>TimeOut with channels<commit_after>/*
Copyright 2015 Steven Labrum

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 CheckIt

import (
	"crypto/md5"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var tempDirectory = ""

func writefile(filename string, body []byte, ext string) {

	err := ioutil.WriteFile(filename+ext, body, 0777)
	if err != nil {
		return
	}
}

func randFolder() string {
	b := make([]byte, 2)
	binary.LittleEndian.PutUint16(b, uint16(rand.Intn(1000)))
	hash := md5.Sum(b)

	return fmt.Sprintf("%x", hash)
}

func textAreas() []string {
	var texts []string

	for key := range boxes {
		texts = append(texts, boxes[key].Body)
	}
	return texts
}

/*
	Runs commands specified in args using input as Stdin
*/
func InterfaceRun(box Box, body []byte, args ...string) (out []byte, err error) {

	tempDirectory = randFolder()

	os.Mkdir("./"+tempDirectory, 0777)

	writefile("./"+tempDirectory+"/"+args[0], body, "")
	args = args[1:]
	textareas := textAreas()

	timeout := make(chan bool, 1)
	inTime := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	go func() {
		out, err = box.Run(textareas, tempDirectory, args...)
		inTime <- true
	}()

	select{
	case<-timeout:
		out = []byte("ERROR: Execution of code took too long.")
	case<-inTime:
	}

	if err != nil {
		fmt.Println(string(out))
		return
	}

	defer os.RemoveAll("./" + tempDirectory + "/")

	return out, err
}

func TimeOut() {
	fmt.Print("TIME OUT")
}
<|endoftext|>


<commit_before>package main

import (
	"compress/flate"
	"compress/gzip"
	"compress/zlib"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	client := new(http.Client)

	//request, _ := http.NewRequest("GET", "http://www.bbc.co.uk/", nil)
	request, _ := http.NewRequest("GET", "http://www.sueddeutsche.de/", nil)
	request.Header.Add("Accept-Encoding", "deflate")

	response, _ := client.Do(request)

	defer response.Body.Close()

	// Check that the server actually sent compressed data
	var reader io.ReadCloser
	var err error
	switch response.Header.Get("Content-Encoding") {
	case "flate":
		fmt.Println("FLATE")
		reader = flate.NewReader(response.Body)
		//defer reader.Close()
	case "deflate":
		fmt.Println("DEFLATE")
		reader, err = zlib.NewReader(response.Body)
		if err != nil {
			fmt.Println(err)
		}
		//defer reader.Close()
	case "gzip":
		fmt.Println("GZIP")
		reader, err = gzip.NewReader(response.Body)
		if err != nil {
			fmt.Println(err)
		}
		//defer reader.Close()
	default:
		fmt.Println("OTHER")
		reader = response.Body
	}

	io.Copy(os.Stdout, reader) // print html to standard out
}
<commit_msg>Progress on deflate support.<commit_after>package main

import (
	"compress/flate"
	"compress/gzip"
	"compress/zlib"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
)

var site = flag.String("site", "http://www.sueddeutsche.de/", "Site to fetch.")
var encoding = flag.String("encoding", "deflate", "Encodings to accept.")

func main() {
	flag.Parse()
	client := new(http.Client)

	//request, _ := http.NewRequest("GET", "http://www.bbc.co.uk/", nil)
	request, _ := http.NewRequest("GET", *site, nil)
	request.Header.Add("Accept-Encoding", *encoding)

	response, _ := client.Do(request)
	//body, _ := ioutil.ReadAll(response.Body)
	defer response.Body.Close()

	// Check that the server actually sent compressed data
	var reader io.ReadCloser
	//var reader io.Reader
	var err error

	ce := response.Header.Get("Content-Encoding")
	fmt.Println("TEST:", ce, *encoding)

	switch ce {
	case "deflate":
		fmt.Println("DEFLATE")
		reader, err = zlib.NewReader(response.Body)
		if err == nil {
			break
		} else {
			fmt.Println(err)
		}
		reader = flate.NewReader(response.Body)
		//defer reader.Close()
	case "gzip":
		fmt.Println("GZIP")
		reader, err = gzip.NewReader(response.Body)
		if err != nil {
			fmt.Println(err)
		}
		//defer reader.Close()
	case "compress", "br":
		fmt.Println("UNSUPPORTED: %s", ce)
		fallthrough
	default:
		fmt.Println("IDENTITIY")
		//reader = bytes.Reader(body)
	}

	io.Copy(os.Stdout, reader) // print html to standard out
}
<|endoftext|>


<commit_before>//  Copyright 2017 Walter Schulze
//
//  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 derive

import (
	"go/ast"
	"go/types"
	"path/filepath"

	"golang.org/x/tools/go/loader"
)

const derivedFilename = "derived.gen.go"

type fileInfo struct {
	astFile   *ast.File
	fullpath  string
	undefined []*call
	derived   []*call
	funcNames map[string]struct{}
}

func newFileInfos(program *loader.Program, pkgInfo *loader.PackageInfo) []*fileInfo {
	files := []*fileInfo{}
	for i := range pkgInfo.Files {
		astFile := pkgInfo.Files[i]
		file := program.Fset.File(astFile.Pos())
		if file == nil {
			// probably derived.gen.go has non parsable code.
			continue
		}
		fullpath := file.Name()

		_, fname := filepath.Split(fullpath)
		if fname == derivedFilename {
			continue
		}

		f := &finder{program, pkgInfo, nil, nil, make(map[string]struct{})}
		for _, d := range astFile.Decls {
			ast.Walk(f, d)
		}
		undefined := make([]*call, len(f.undefined))
		for i := range f.undefined {
			undefined[i] = newCall(pkgInfo, f.undefined[i])
		}
		derived := make([]*call, len(f.derived))
		for i := range f.derived {
			derived[i] = newCall(pkgInfo, f.derived[i])
		}

		files = append(files, &fileInfo{
			astFile:   pkgInfo.Files[i],
			fullpath:  fullpath,
			undefined: undefined,
			derived:   derived,
			funcNames: f.funcNames,
		})
	}
	return files
}

type finder struct {
	program   *loader.Program
	pkgInfo   *loader.PackageInfo
	undefined []*ast.CallExpr
	derived   []*ast.CallExpr
	funcNames map[string]struct{}
}

func (this *finder) Visit(node ast.Node) (w ast.Visitor) {
	call, ok := node.(*ast.CallExpr)
	if !ok {
		return this
	}
	fn, ok := call.Fun.(*ast.Ident)
	if !ok {
		return this
	}
	def, ok := this.pkgInfo.Uses[fn]
	if !ok {
		this.undefined = append(this.undefined, call)
		return this
	}
	if _, ok := def.(*types.Builtin); ok {
		return this
	}
	file := this.program.Fset.File(def.Pos())
	if file == nil {
		// probably a cast, for example float64()
		return this
	}
	_, filename := filepath.Split(file.Name())
	if filename == derivedFilename {
		this.derived = append(this.derived, call)
		return this
	}
	this.funcNames[fn.Name] = struct{}{}
	return this
}

type call struct {
	Expr *ast.CallExpr
	Name string
	Args []types.Type
}

func newCall(pkgInfo *loader.PackageInfo, expr *ast.CallExpr) *call {
	fn, ok := expr.Fun.(*ast.Ident)
	if !ok {
		panic("unreachable, finder has already eliminated this option")
	}
	name := fn.Name
	typs := getInputTypes(pkgInfo, expr)
	return &call{expr, name, typs}
}

// argTypes returns the argument types of a function call.
func getInputTypes(pkgInfo *loader.PackageInfo, call *ast.CallExpr) []types.Type {
	typs := make([]types.Type, len(call.Args))
	for i, a := range call.Args {
		typs[i] = pkgInfo.TypeOf(a)
	}
	return typs
}

// HasUndefined returns whether the call has undefined arguments
func (this *call) HasUndefined() bool {
	for i := range this.Args {
		if this.Args[i] == nil {
			return true
		}
		if basic, ok := this.Args[i].(*types.Basic); ok {
			if basic.Kind() == types.Invalid {
				return true
			}
		}
	}
	return false
}
<commit_msg>more lint<commit_after>//  Copyright 2017 Walter Schulze
//
//  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 derive

import (
	"go/ast"
	"go/types"
	"path/filepath"

	"golang.org/x/tools/go/loader"
)

const derivedFilename = "derived.gen.go"

type fileInfo struct {
	astFile   *ast.File
	fullpath  string
	undefined []*call
	derived   []*call
	funcNames map[string]struct{}
}

func newFileInfos(program *loader.Program, pkgInfo *loader.PackageInfo) []*fileInfo {
	files := []*fileInfo{}
	for i := range pkgInfo.Files {
		astFile := pkgInfo.Files[i]
		file := program.Fset.File(astFile.Pos())
		if file == nil {
			// probably derived.gen.go has non parsable code.
			continue
		}
		fullpath := file.Name()

		_, fname := filepath.Split(fullpath)
		if fname == derivedFilename {
			continue
		}

		f := &finder{program, pkgInfo, nil, nil, make(map[string]struct{})}
		for _, d := range astFile.Decls {
			ast.Walk(f, d)
		}
		undefined := make([]*call, len(f.undefined))
		for i := range f.undefined {
			undefined[i] = newCall(pkgInfo, f.undefined[i])
		}
		derived := make([]*call, len(f.derived))
		for i := range f.derived {
			derived[i] = newCall(pkgInfo, f.derived[i])
		}

		files = append(files, &fileInfo{
			astFile:   pkgInfo.Files[i],
			fullpath:  fullpath,
			undefined: undefined,
			derived:   derived,
			funcNames: f.funcNames,
		})
	}
	return files
}

type finder struct {
	program   *loader.Program
	pkgInfo   *loader.PackageInfo
	undefined []*ast.CallExpr
	derived   []*ast.CallExpr
	funcNames map[string]struct{}
}

func (f *finder) Visit(node ast.Node) (w ast.Visitor) {
	call, ok := node.(*ast.CallExpr)
	if !ok {
		return f
	}
	fn, ok := call.Fun.(*ast.Ident)
	if !ok {
		return f
	}
	def, ok := f.pkgInfo.Uses[fn]
	if !ok {
		f.undefined = append(f.undefined, call)
		return f
	}
	if _, ok := def.(*types.Builtin); ok {
		return f
	}
	file := f.program.Fset.File(def.Pos())
	if file == nil {
		// probably a cast, for example float64()
		return f
	}
	_, filename := filepath.Split(file.Name())
	if filename == derivedFilename {
		f.derived = append(f.derived, call)
		return f
	}
	f.funcNames[fn.Name] = struct{}{}
	return f
}

type call struct {
	Expr *ast.CallExpr
	Name string
	Args []types.Type
}

func newCall(pkgInfo *loader.PackageInfo, expr *ast.CallExpr) *call {
	fn, ok := expr.Fun.(*ast.Ident)
	if !ok {
		panic("unreachable, finder has already eliminated this option")
	}
	name := fn.Name
	typs := getInputTypes(pkgInfo, expr)
	return &call{expr, name, typs}
}

// argTypes returns the argument types of a function call.
func getInputTypes(pkgInfo *loader.PackageInfo, call *ast.CallExpr) []types.Type {
	typs := make([]types.Type, len(call.Args))
	for i, a := range call.Args {
		typs[i] = pkgInfo.TypeOf(a)
	}
	return typs
}

// HasUndefined returns whether the call has undefined arguments
func (c *call) HasUndefined() bool {
	for i := range c.Args {
		if c.Args[i] == nil {
			return true
		}
		if basic, ok := c.Args[i].(*types.Basic); ok {
			if basic.Kind() == types.Invalid {
				return true
			}
		}
	}
	return false
}
<|endoftext|>


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

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
)

// Build at the supplied commit (or branch or tag), embedding the given version
// name and returning a path to a directory containing exactly the
// root-relative file system structure we desire.
func build(
	commit string,
	version string,
	osys string) (dir string, err error) {
	log.Printf("Building version %s from %s.", version, commit)

	// Create a directory to hold our outputs. Kill it if we later return in
	// error.
	dir, err = ioutil.TempDir("", "package_gcsfuse_build")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Set up the destination for a call to build_gcsfuse, which writes files
	// like
	//
	//     bin/gcsfuse
	//     sbin/mount.gcsfuse
	//
	// On Linux and OS X we want these to go into different places.
	var buildDir string
	switch osys {
	case "linux":
		buildDir = path.Join(dir, "usr")

	case "darwin":
		buildDir = path.Join(dir, "usr/local")

	default:
		err = fmt.Errorf("Unhandled OS: %q", osys)
		return
	}

	err = os.MkdirAll(buildDir, 0755)
	if err != nil {
		err = fmt.Errorf("MkdirAll: %v", err)
		return
	}

	// Create another directory into which we will clone the git repo bloe.
	gitDir, err := ioutil.TempDir("", "package_gcsfuse_git")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer os.RemoveAll(gitDir)

	// Clone the git repo, checking out the correct tag.
	{
		log.Printf("Cloning into %s", gitDir)

		cmd := exec.Command(
			"git",
			"clone",
			"-b", commit,
			"https://github.com/GoogleCloudPlatform/gcsfuse.git",
			gitDir)

		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("Cloning: %v\nOutput:\n%s", err, output)
			return
		}
	}

	// Run build_gcsfuse.
	{
		log.Printf("Running build_gcsfuse...")

		cmd := exec.Command(
			"go",
			"run",
			path.Join(gitDir, "tools/build_gcsfuse/*.go"),
			gitDir,
			buildDir,
			version)

		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("go run build_gcsfuse: %v\nOutput:\n%s", err, output)
			return
		}
	}

	// Add symlink(s) from /sbin to /usr/sbin or /usr/local/sbin, as the case may
	// be.
	{
		symlinks := map[string]string{}
		switch osys {
		case "linux":
			symlinks["sbin/mount.fuse.gcsfuse"] = "usr/sbin/mount.fuse.gcsfuse"
			symlinks["sbin/mount.gcsfuse"] = "usr/sbin/mount.gcsfuse"

		case "darwin":
			symlinks["sbin/mount_gcsfuse"] = "usr/sbin/mount_gcsfuse"

		default:
			err = fmt.Errorf("Unhandled OS: %q", osys)
			return
		}

		for src, target := range symlinks {
			err = os.Symlink(target, path.Join(dir, src))
			if err != nil {
				err = fmt.Errorf("Symlink: %v", err)
				return
			}
		}
	}

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

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
)

// Build at the supplied commit (or branch or tag), embedding the given version
// name and returning a path to a directory containing exactly the
// root-relative file system structure we desire.
func build(
	commit string,
	version string,
	osys string) (dir string, err error) {
	log.Printf("Building version %s from %s.", version, commit)

	// Create a directory to hold our outputs. Kill it if we later return in
	// error.
	dir, err = ioutil.TempDir("", "package_gcsfuse_build")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer func() {
		if err != nil {
			os.RemoveAll(dir)
		}
	}()

	// Set up the destination for a call to build_gcsfuse, which writes files
	// like
	//
	//     bin/gcsfuse
	//     sbin/mount.gcsfuse
	//
	// On Linux and OS X we want these to go into different places.
	var buildDir string
	switch osys {
	case "linux":
		buildDir = path.Join(dir, "usr")

	case "darwin":
		buildDir = path.Join(dir, "usr/local")

	default:
		err = fmt.Errorf("Unhandled OS: %q", osys)
		return
	}

	err = os.MkdirAll(buildDir, 0755)
	if err != nil {
		err = fmt.Errorf("MkdirAll: %v", err)
		return
	}

	// Create another directory into which we will clone the git repo bloe.
	gitDir, err := ioutil.TempDir("", "package_gcsfuse_git")
	if err != nil {
		err = fmt.Errorf("TempDir: %v", err)
		return
	}

	defer os.RemoveAll(gitDir)

	// Clone the git repo, checking out the correct tag.
	{
		log.Printf("Cloning into %s", gitDir)

		cmd := exec.Command(
			"git",
			"clone",
			"-b", commit,
			"https://github.com/GoogleCloudPlatform/gcsfuse.git",
			gitDir)

		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("Cloning: %v\nOutput:\n%s", err, output)
			return
		}
	}

	// Build build_gcsfuse.
	buildTool := path.Join(gitDir, "build_gcsfuse")
	{
		log.Printf("Building build_gcsfuse...")

		cmd := exec.Command(
			"go",
			"build",
			"-o", buildTool,
		)

		cmd.Dir = path.Join(gitDir, "tools/build_gcsfuse")
		cmd.Env = []string{
			"GO15VENDOREXPERIMENT=1",
			"GOPATH=/does/not/exist",
		}

		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("Building build_gcsfuse: %v\nOutput:\n%s", err, output)
			return
		}
	}

	// Run build_gcsfuse.
	{
		log.Printf("Running build_gcsfuse...")

		cmd := exec.Command(
			buildTool,
			gitDir,
			buildDir,
			version)

		var output []byte
		output, err = cmd.CombinedOutput()
		if err != nil {
			err = fmt.Errorf("go run build_gcsfuse: %v\nOutput:\n%s", err, output)
			return
		}
	}

	// Add symlink(s) from /sbin to /usr/sbin or /usr/local/sbin, as the case may
	// be.
	{
		symlinks := map[string]string{}
		switch osys {
		case "linux":
			symlinks["sbin/mount.fuse.gcsfuse"] = "usr/sbin/mount.fuse.gcsfuse"
			symlinks["sbin/mount.gcsfuse"] = "usr/sbin/mount.gcsfuse"

		case "darwin":
			symlinks["sbin/mount_gcsfuse"] = "usr/sbin/mount_gcsfuse"

		default:
			err = fmt.Errorf("Unhandled OS: %q", osys)
			return
		}

		for src, target := range symlinks {
			err = os.Symlink(target, path.Join(dir, src))
			if err != nil {
				err = fmt.Errorf("Symlink: %v", err)
				return
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>package main

import "github.com/n0rad/go-erlog/errs"

func (p *Pod) CleanAndTry() error {
	return errs.With("Not implemented")
}
<commit_msg>[#209] support dgr try on pod<commit_after>package main

import "github.com/n0rad/go-erlog/logs"

func (p *Pod) CleanAndTry() error {
	logs.WithF(p.fields).Info("Try")

	for _, e := range p.manifest.Pod.Apps {
		aci, err := p.toPodAci(e)
		if err != nil {
			return err
		}

		if err := aci.CleanAndTry(); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package obj

import (
	"fmt"
	"io"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/aws/aws-sdk-go/service/storagegateway"
)

type amazonClient struct {
	bucket   string
	s3       *s3.S3
	uploader *s3manager.Uploader
}

func newAmazonClient(bucket string, id string, secret string, token string, region string) (*amazonClient, error) {
	session := session.New(&aws.Config{
		Credentials: credentials.NewStaticCredentials(id, secret, token),
		Region:      aws.String(region),
	})
	return &amazonClient{
		bucket:   bucket,
		s3:       s3.New(session),
		uploader: s3manager.NewUploader(session),
	}, nil
}

func (c *amazonClient) Writer(name string) (io.WriteCloser, error) {
	return newBackoffWriteCloser(c, newWriter(c, name)), nil
}

func (c *amazonClient) Walk(name string, fn func(name string) error) error {
	var fnErr error
	fmt.Printf("checking bucket %v and prefix %v\n", c.bucket, name)
	if err := c.s3.ListObjectsPages(
		&s3.ListObjectsInput{
			Bucket: aws.String(c.bucket),
			Prefix: aws.String(name),
		},
		func(listObjectsOutput *s3.ListObjectsOutput, lastPage bool) bool {
			fmt.Printf("got %v results in s3 ListObjectsOutput: %v\n", len(listObjectsOutput.Contents), listObjectsOutput)
			for _, object := range listObjectsOutput.Contents {
				if err := fn(*object.Key); err != nil {
					fnErr = err
					return false
				}
			}
			return true
		},
	); err != nil {
		return err
	}
	return fnErr
}

func (c *amazonClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	byteRange := ""
	if size == 0 {
		byteRange = fmt.Sprintf("bytes=%d-", offset)
	} else {
		// we substract 1 one from the right bound because http byte ranges are
		// inclusive rather than clopen
		byteRange = fmt.Sprintf("bytes=%d-%d", offset, offset+size-1)
	}

	getObjectOutput, err := c.s3.GetObject(&s3.GetObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
		Range:  aws.String(byteRange),
	})
	if err != nil {
		return nil, err
	}
	return newBackoffReadCloser(c, getObjectOutput.Body), nil
}

func (c *amazonClient) Delete(name string) error {
	_, err := c.s3.DeleteObject(&s3.DeleteObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
	})
	return err
}

func (c *amazonClient) Exists(name string) bool {
	_, err := c.s3.HeadObject(&s3.HeadObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
	})
	return err == nil
}

func (c *amazonClient) IsRetryable(err error) bool {
	awsErr, ok := err.(awserr.Error)
	if !ok {
		return false
	}
	for _, c := range []string{
		storagegateway.ErrorCodeServiceUnavailable,
		storagegateway.ErrorCodeInternalError,
		storagegateway.ErrorCodeGatewayInternalError,
	} {
		if c == awsErr.Code() {
			return true
		}
	}
	return false
}

func (c *amazonClient) IsIgnorable(err error) bool {
	return false
}

func (c *amazonClient) IsNotExist(err error) bool {
	awsErr, ok := err.(awserr.Error)
	if !ok {
		return false
	}
	if awsErr.Code() == "NoSuchKey" {
		return true
	}
	return false
}

type amazonWriter struct {
	errChan chan error
	pipe    *io.PipeWriter
}

func newWriter(client *amazonClient, name string) *amazonWriter {
	reader, writer := io.Pipe()
	w := &amazonWriter{
		errChan: make(chan error),
		pipe:    writer,
	}
	go func() {
		_, err := client.uploader.Upload(&s3manager.UploadInput{
			Body:            reader,
			Bucket:          aws.String(client.bucket),
			Key:             aws.String(name),
			ContentEncoding: aws.String("application/octet-stream"),
		})
		w.errChan <- err
	}()
	return w
}

func (w *amazonWriter) Write(p []byte) (int, error) {
	return w.pipe.Write(p)
}

func (w *amazonWriter) Close() error {
	if err := w.pipe.Close(); err != nil {
		return err
	}
	return <-w.errChan
}
<commit_msg>moar debug<commit_after>package obj

import (
	"fmt"
	"io"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
	"github.com/aws/aws-sdk-go/service/storagegateway"
)

type amazonClient struct {
	bucket   string
	s3       *s3.S3
	uploader *s3manager.Uploader
}

func newAmazonClient(bucket string, id string, secret string, token string, region string) (*amazonClient, error) {
	session := session.New(&aws.Config{
		Credentials: credentials.NewStaticCredentials(id, secret, token),
		Region:      aws.String(region),
	})
	return &amazonClient{
		bucket:   bucket,
		s3:       s3.New(session),
		uploader: s3manager.NewUploader(session),
	}, nil
}

func (c *amazonClient) Writer(name string) (io.WriteCloser, error) {
	return newBackoffWriteCloser(c, newWriter(c, name)), nil
}

func (c *amazonClient) Walk(name string, fn func(name string) error) error {
	var fnErr error
	fmt.Printf("checking bucket %v and prefix %v\n", c.bucket, name)
	if err := c.s3.ListObjectsPages(
		&s3.ListObjectsInput{
			Bucket: aws.String(c.bucket),
			Prefix: aws.String(name),
		},
		func(listObjectsOutput *s3.ListObjectsOutput, lastPage bool) bool {
			fmt.Printf("got %v results in s3 ListObjectsOutput: %v\n", len(listObjectsOutput.Contents), listObjectsOutput)
			for _, object := range listObjectsOutput.Contents {
				if err := fn(*object.Key); err != nil {
					fnErr = err
					return false
				}
			}
			return true
		},
	); err != nil {
		return err
	}
	fmt.Printf("finished checking bucket\n")
	return fnErr
}

func (c *amazonClient) Reader(name string, offset uint64, size uint64) (io.ReadCloser, error) {
	byteRange := ""
	if size == 0 {
		byteRange = fmt.Sprintf("bytes=%d-", offset)
	} else {
		// we substract 1 one from the right bound because http byte ranges are
		// inclusive rather than clopen
		byteRange = fmt.Sprintf("bytes=%d-%d", offset, offset+size-1)
	}

	getObjectOutput, err := c.s3.GetObject(&s3.GetObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
		Range:  aws.String(byteRange),
	})
	if err != nil {
		return nil, err
	}
	return newBackoffReadCloser(c, getObjectOutput.Body), nil
}

func (c *amazonClient) Delete(name string) error {
	_, err := c.s3.DeleteObject(&s3.DeleteObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
	})
	return err
}

func (c *amazonClient) Exists(name string) bool {
	_, err := c.s3.HeadObject(&s3.HeadObjectInput{
		Bucket: aws.String(c.bucket),
		Key:    aws.String(name),
	})
	return err == nil
}

func (c *amazonClient) IsRetryable(err error) bool {
	awsErr, ok := err.(awserr.Error)
	if !ok {
		return false
	}
	for _, c := range []string{
		storagegateway.ErrorCodeServiceUnavailable,
		storagegateway.ErrorCodeInternalError,
		storagegateway.ErrorCodeGatewayInternalError,
	} {
		if c == awsErr.Code() {
			return true
		}
	}
	return false
}

func (c *amazonClient) IsIgnorable(err error) bool {
	return false
}

func (c *amazonClient) IsNotExist(err error) bool {
	awsErr, ok := err.(awserr.Error)
	if !ok {
		return false
	}
	if awsErr.Code() == "NoSuchKey" {
		return true
	}
	return false
}

type amazonWriter struct {
	errChan chan error
	pipe    *io.PipeWriter
}

func newWriter(client *amazonClient, name string) *amazonWriter {
	reader, writer := io.Pipe()
	w := &amazonWriter{
		errChan: make(chan error),
		pipe:    writer,
	}
	go func() {
		_, err := client.uploader.Upload(&s3manager.UploadInput{
			Body:            reader,
			Bucket:          aws.String(client.bucket),
			Key:             aws.String(name),
			ContentEncoding: aws.String("application/octet-stream"),
		})
		w.errChan <- err
	}()
	return w
}

func (w *amazonWriter) Write(p []byte) (int, error) {
	return w.pipe.Write(p)
}

func (w *amazonWriter) Close() error {
	if err := w.pipe.Close(); err != nil {
		return err
	}
	return <-w.errChan
}
<|endoftext|>


<commit_before>package dialog

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

func generateView(g *gocui.Gui, desc string, fill string, coords []int, editable bool) error {
	if StringInSlice(desc, views) {
		return nil
	}
	if v, err := g.SetView(desc, coords[0], coords[1], coords[2], coords[3]); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		fmt.Fprint(v, fill)
	}
	view, _ := g.View(desc)
	view.Title = desc
	view.Wrap = true
	view.Autoscroll = true
	view.Editable = editable

	views = append(views, desc)
	curView = len(views) - 1
	idxView++

	return nil
}

// GenerateParamsLayout generates CUI to receive params
func GenerateParamsLayout(params map[string]string, command string) {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Highlight = true
	g.Cursor = true
	g.SelFgColor = gocui.ColorGreen

	g.SetManagerFunc(layout)

	maxX, maxY := g.Size()
	generateView(g, "Command(TAB => Select next, ENTER => Execute command):",
		command, []int{maxX / 10, maxY / 10, (maxX / 2) + (maxX / 3), maxY/10 + 5}, false)
	idx := 0
	for k, v := range params {
		generateView(g, k, v, []int{maxX / 10, (maxY / 4) + (idx+1)*layoutStep,
			maxX/10 + 20, (maxY / 4) + 2 + (idx+1)*layoutStep}, true)
		idx++
	}

	initKeybindings(g)

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func nextView(g *gocui.Gui) error {
	next := curView + 1
	if next > len(views)-1 {
		next = 0
	}

	if _, err := g.SetCurrentView(views[next]); err != nil {
		return err
	}

	curView = next
	return nil
}

func initKeybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyEnter, gocui.ModNone, evaluateParams); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone,
		func(g *gocui.Gui, v *gocui.View) error {
			return nextView(g)
		}); err != nil {
		return err
	}
	return nil
}

func layout(g *gocui.Gui) error {
	return nil
}

func quit(_ *gocui.Gui, _ *gocui.View) error {
	return gocui.ErrQuit
}
<commit_msg>Focus on the first view<commit_after>package dialog

import (
	"fmt"
	"log"

	"github.com/jroimartin/gocui"
)

func generateView(g *gocui.Gui, desc string, fill string, coords []int, editable bool) error {
	if StringInSlice(desc, views) {
		return nil
	}
	if v, err := g.SetView(desc, coords[0], coords[1], coords[2], coords[3]); err != nil {
		if err != gocui.ErrUnknownView {
			return err
		}
		fmt.Fprint(v, fill)
	}
	view, _ := g.View(desc)
	view.Title = desc
	view.Wrap = true
	view.Autoscroll = true
	view.Editable = editable

	views = append(views, desc)
	idxView++

	return nil
}

// GenerateParamsLayout generates CUI to receive params
func GenerateParamsLayout(params map[string]string, command string) {
	g, err := gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}
	defer g.Close()

	g.Highlight = true
	g.Cursor = true
	g.SelFgColor = gocui.ColorGreen

	g.SetManagerFunc(layout)

	maxX, maxY := g.Size()
	generateView(g, "Command(TAB => Select next, ENTER => Execute command):",
		command, []int{maxX / 10, maxY / 10, (maxX / 2) + (maxX / 3), maxY/10 + 5}, false)
	idx := 0
	for k, v := range params {
		generateView(g, k, v, []int{maxX / 10, (maxY / 4) + (idx+1)*layoutStep,
			maxX/10 + 20, (maxY / 4) + 2 + (idx+1)*layoutStep}, true)
		idx++
	}

	initKeybindings(g)

	curView = 0
	g.SetCurrentView(views[0])

	if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func nextView(g *gocui.Gui) error {
	next := curView + 1
	if next > len(views)-1 {
		next = 0
	}

	if _, err := g.SetCurrentView(views[next]); err != nil {
		return err
	}

	curView = next
	return nil
}

func initKeybindings(g *gocui.Gui) error {
	if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
		return err
	}

	if err := g.SetKeybinding("", gocui.KeyEnter, gocui.ModNone, evaluateParams); err != nil {
		return err
	}
	if err := g.SetKeybinding("", gocui.KeyTab, gocui.ModNone,
		func(g *gocui.Gui, v *gocui.View) error {
			return nextView(g)
		}); err != nil {
		return err
	}
	return nil
}

func layout(g *gocui.Gui) error {
	return nil
}

func quit(_ *gocui.Gui, _ *gocui.View) error {
	return gocui.ErrQuit
}
<|endoftext|>