<commit_before>package main

import (
	"os"

	"github.com/granateio/granate/generator"
	flags "github.com/jessevdk/go-flags"
)

// GenOpts Code generator options
type GenOpts struct {
	Config flags.Filename `short:"c" long:"config" description:"Path to graphql.yaml file"`

	Package string `short:"p" long:"package" description:"Name of the package to generate"`

	Tests bool `short:"t" long:"tests" description:"Generate tests"`
}

// BoilerOpts Boilerplate options
type BoilerOpts struct {
	Force bool `short:"f" long:"force" description:"Force overwrite of existing files"`
}

// TODO: Add '@deprecated( reason: "reason" )' anotation support

// func printSource(loc *ast.Location) {
// 	str := loc.Source.Body[loc.Start:loc.End]
// 	fmt.Println(string(str))
// }

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func main() {
	// genopts := GenOpts{
	// 	Config:  "graphql.yaml",
	// 	Package: "schema",
	// 	Tests:   false,
	// }
	// parser := flags.NewParser(&genopts, flags.Default)
	// boileropts := BoilerOpts{}
	// parser.AddCommand("boiler", "Creates boiler plate files",
	// 	"The boiler command creates boiler plate files, use -f to overwrite existing files",
	// 	&boileropts)
	// out, _ := parser.Parse()
	// fmt.Println(len(out), out)
	// if len(out) == 0 {
	// 	parser.WriteHelp(os.Stdout)
	// }

	// parser.WriteHelp(os.Stdout)
	// flags.Parse(&opt)
	// spew.Dump(opt)

	// TODO: Add program paramaters/flags and stuff
	file := "granate.yaml"

	if len(os.Args) > 1 {
		file = os.Args[1]
		// log.Fatal("Not enought arguments")
	}

	gen, _ := generator.New(file)
	gen.Generate()
}
<commit_msg>Add program paramters -c and -h, clean up main<commit_after>package main

import (
	"os"

	"github.com/granateio/granate/generator"
	flags "github.com/jessevdk/go-flags"
)

// Flags Code generator options
type Flags struct {
	Config string `short:"c" long:"config" description:"Path to <config>.yaml file"`
	Help   bool   `short:"h" long:"help" description:"Show available options"`
}

func check(e error) {
	if e != nil {
		panic(e)
	}
}

func main() {
	params := Flags{
		Config: "granate.yaml",
		Help:   false,
	}

	parser := flags.NewParser(&params, flags.Default^flags.HelpFlag)
	_, err := parser.Parse()
	check(err)

	if params.Help == true {
		parser.WriteHelp(os.Stdout)
		return
	}

	file := params.Config

	gen, _ := generator.New(file)
	gen.Generate()
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"strings"
	"xd/cmd/rpc"
	"xd/cmd/xd"
)

func main() {
	exename := strings.ToUpper(os.Args[0])
	docli := exename == "XD-CLI" || exename == "XD-CLI.EXE"
	if docli {
		rpc.Run()
	} else {
		xd.Run()
	}
}
<commit_msg>make it work<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"xd/cmd/rpc"
	"xd/cmd/xd"
)

func main() {
	exename := filepath.Base(strings.ToUpper(os.Args[0]))
	docli := exename == "XD-CLI" || exename == "XD-CLI.EXE"
	if docli {
		rpc.Run()
	} else {
		xd.Run()
	}
}
<|endoftext|>


<commit_before>package main

import "errors"
import "fmt"
import "io"
import "io/ioutil"
import "log"
import "net/url"
import "os"
import "os/exec"
import "path/filepath"
import "strings"

func cleanWcRoot(wcPath string) (err error) {
	infos, err := ioutil.ReadDir(wcPath)
	if nil != err {
		return
	}
	for _, inf := range infos {
		if ".svn" == inf.Name() {
			continue
		}
		fullPath := filepath.Join(wcPath, inf.Name())
		err = os.RemoveAll(fullPath)
		if nil != err {
			return
		}
	}
	return nil
}

func execPiped(name string, arg ...string) error {
	fmt.Println(name + " " + strings.Join(arg, " "))
	cmd := exec.Command(name, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	return cmd.Run()
}

func copyFile(src, dst string) (err error) {
	s, err := os.Open(src)
	if err != nil {
		return
	}
	defer func() {
		closeErr := s.Close()
		if nil == err {
			err = closeErr
		}
	}()
	d, err := os.Create(dst)
	if err != nil {
		return
	}
	_, err = io.Copy(d, s)
	if nil != err {
		d.Close()
		return
	}
	return d.Close()
}

func copyRecursive(srcDir, dstDir string) (err error) {
	err = os.MkdirAll(dstDir, perm)
	if nil != err {
		return
	}
	infs, err := ioutil.ReadDir(srcDir)
	if nil != err {
		return
	}
	for _, inf := range infs {
		src := filepath.Join(srcDir, inf.Name())
		dst := filepath.Join(dstDir, inf.Name())
		if inf.IsDir() {
			err = copyRecursive(src, dst)
			if nil != err {
				return
			}
			continue
		}
		err = copyFile(src, dst)
		if nil != err {
			return
		}
	}
	return nil
}

func execPrint(name string, arg ...string) ([]byte, error) {
	fmt.Println(name + " " + strings.Join(arg, " "))
	return exec.Command(name, arg...).Output()
}

// TODO: append global svn options if provided
func svnCheckout(repos *url.URL, wcPath string, ga globalArgs) error {
	args := []string{"checkout", repos.String(), wcPath}
	return execPiped("svn", args...)
}

// TODO: append global svn options if provided
func svnCommit(wcPath, message string, ga globalArgs) error {
	args := []string{"commit", wcPath, "--message", message}
	return execPiped("svn", args...)
}

func svnGetMissing(wcPath string) (missing []string, err error) {
	out, err := execPrint("svn", "status", wcPath)
	if nil != err {
		return
	}
	lines := strings.Split(string(out), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if len(line) < 3 {
			continue
		}
		if line[0] != '!' {
			continue
		}
		if ' ' != line[1] && '\t' != line[1] {
			err = errors.New("Unkown status line: " + line)
			return
		}
		p := strings.TrimSpace(line[1:])
		missing = append(missing, p)
	}
	return
}

func svnDeleteMissing(wcPath string) (err error) {
	missing, err := svnGetMissing(wcPath)
	if nil != err {
		return
	}
	if len(missing) == 0 {
		return
	}
	args := append([]string{"rm"}, missing...)
	err = execPiped("svn", args...)
	if nil != err {
		return
	}
	return
}

func svnDiffCommit(ca commitArgs, ga globalArgs) (err error) {
	err = svnCheckout(ca.Repos, ca.WcPath, ga)
	if nil != err {
		return
	}
	err = cleanWcRoot(ca.WcPath)
	if nil != err {
		return
	}
	err = copyRecursive(ca.SrcPath, ca.WcPath)
	if nil != err {
		return
	}
	err = execPiped("svn", "add", ca.WcPath, "--force")
	if nil != err {
		return
	}
	err = svnDeleteMissing(ca.WcPath)
	if nil != err {
		return
	}
	return svnCommit(ca.WcPath, ca.Message, ga)
}

func createRepos(reposPath string) (repos *url.URL, err error) {
	err = execPiped("svnadmin", "create", reposPath)
	if nil != err {
		return
	}
	absReposPath, err := filepath.Abs(reposPath)
	if nil != err {
		return
	}
	absReposPath = "file://" + absReposPath
	repos, err = url.Parse(absReposPath)
	return
}

type testData struct {
	Path    string
	IsDir   bool
	Content string
}

func makeTestData() []testData {
	result := []testData{
		{"1.txt", false, "data1"},
		{"2.txt", false, "data2"},
		{"subdir_a", true, ""},
		{filepath.Join("subdir_a", "3.txt"), false, "data3"},
		{"subdir_b", true, ""},
		{filepath.Join("subdir_b", "4.txt"), false, "data4"},
		{"subdir_c", true, ""}}
	return result
}

func removeSomeTestFiles(srcPath string) (err error) {
	err = os.Remove(filepath.Join(srcPath, "1.txt"))
	if nil != err {
		return
	}
	err = os.Remove(filepath.Join(srcPath, "subdir_a", "3.txt"))
	if nil != err {
		return
	}
	return os.RemoveAll(filepath.Join(srcPath, "subdir_b"))
}

const perm = 0755

func crateTestFiles(basePath string, tds []testData) (err error) {
	err = os.Mkdir(basePath, perm)
	if nil != err {
		return
	}
	for _, td := range tds {
		path := filepath.Join(basePath, td.Path)
		if td.IsDir {
			err = os.Mkdir(path, perm)
			if nil != err {
				return
			}
			continue
		}
		err = ioutil.WriteFile(path, []byte(td.Content), perm)
		if nil != err {
			return
		}
	}
	return nil
}

func setupTest(testPath string) (repos *url.URL, srcPath string, err error) {
	err = os.Mkdir(testPath, perm)
	if nil != err {
		return
	}
	srcPath = filepath.Join(testPath, "src")
	tds := makeTestData()
	err = crateTestFiles(srcPath, tds)
	if nil != err {
		return
	}
	reposPath := filepath.Join(testPath, "repos")
	repos, err = createRepos(reposPath)
	return
}

func teardownTest(testPath string) {
	err := os.RemoveAll(testPath)
	if nil != err {
		log.Println("ERROR: ", err)
	}
}

func runSelfTest() (err error) {
	fmt.Print("\n\nSelf test --> Start...\n\n\n")
	testPath := filepath.Join(".", "self_test")
	ca := commitArgs{}
	ca.Message = "Hellooo :D"
	ca.WcPath = filepath.Join(testPath, "wc")
	ca.Repos, ca.SrcPath, err = setupTest(testPath)
	if nil != err {
		return
	}
	defer teardownTest(testPath)
	ga := globalArgs{}
	err = svnDiffCommit(ca, ga)
	if nil != err {
		return
	}
	err = removeSomeTestFiles(ca.SrcPath)
	if nil != err {
		return
	}
	err = svnDiffCommit(ca, ga)
	if nil != err {
		return
	}
	fmt.Print("\n\nSelf test --> Success.\n\n\n")
	return nil
}

func parseArgs() (args cmdArgs, err error) {
	for i, arg := range os.Args {
		fmt.Println(i, ": ", arg)
	}
	args.RunSelfTest = true
	return
}

type globalArgs struct {
	ConfigDir               *string // --config-dir ARG
	ConfigOption            *string // --config-options ARG
	NoAuthCache             bool    // --no-auth-cache
	NonInteractive          bool    // --non-ineractive
	Password                *string // --password ARG
	TrustServerCertFailures *string // --trust-server-cert-failures ARG 'unknown-ca' 'cn-mismatch' 'expired' 'not-yet-valid' 'other'
	Username                *string // --username ARG
}

type commitArgs struct {
	Message  string   // --message ARG
	SrcPath  string   // --src-path ARG
	Repos    *url.URL // --dst-url ARG
	WcPath   string   // --wc-path ARG
	WcDelete bool     // --wc-delete
}

type cmdArgs struct {
	Help        bool // --help
	RunSelfTest bool // --run-self-test
	CommitArgs  commitArgs
	GlobalArgs  globalArgs
}

func main() {
	args, err := parseArgs()
	if nil != err {
		log.Fatal(err)
	}
	if args.RunSelfTest {
		err = runSelfTest()
	} else if args.Help {
		// print usage
	}
	if nil != err {
		log.Fatal(err)
	}
}
<commit_msg>Refactored.<commit_after>package main

import "errors"
import "fmt"
import "io"
import "io/ioutil"
import "log"
import "net/url"
import "os"
import "os/exec"
import "path/filepath"
import "strings"

func cleanWcRoot(wcPath string) (err error) {
	infos, err := ioutil.ReadDir(wcPath)
	if nil != err {
		return
	}
	for _, inf := range infos {
		if ".svn" == inf.Name() {
			continue
		}
		fullPath := filepath.Join(wcPath, inf.Name())
		err = os.RemoveAll(fullPath)
		if nil != err {
			return
		}
	}
	return nil
}

func execPiped(name string, arg ...string) error {
	fmt.Println(name + " " + strings.Join(arg, " "))
	cmd := exec.Command(name, arg...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin
	return cmd.Run()
}

func copyFile(src, dst string) (err error) {
	s, err := os.Open(src)
	if err != nil {
		return
	}
	defer func() {
		closeErr := s.Close()
		if nil == err {
			err = closeErr
		}
	}()
	d, err := os.Create(dst)
	if err != nil {
		return
	}
	_, err = io.Copy(d, s)
	if nil != err {
		d.Close()
		return
	}
	return d.Close()
}

func copyRecursive(srcDir, dstDir string) (err error) {
	err = os.MkdirAll(dstDir, perm)
	if nil != err {
		return
	}
	infs, err := ioutil.ReadDir(srcDir)
	if nil != err {
		return
	}
	for _, inf := range infs {
		src := filepath.Join(srcDir, inf.Name())
		dst := filepath.Join(dstDir, inf.Name())
		if inf.IsDir() {
			err = copyRecursive(src, dst)
			if nil != err {
				return
			}
			continue
		}
		err = copyFile(src, dst)
		if nil != err {
			return
		}
	}
	return nil
}

func execPrint(name string, arg ...string) ([]byte, error) {
	fmt.Println(name + " " + strings.Join(arg, " "))
	return exec.Command(name, arg...).Output()
}

// TODO: append global svn options if provided
func svnCheckout(repos *url.URL, wcPath string, ga globalArgs) error {
	args := []string{"checkout", repos.String(), wcPath}
	return execPiped("svn", args...)
}

// TODO: append global svn options if provided
func svnCommit(wcPath, message string, ga globalArgs) error {
	args := []string{"commit", wcPath, "--message", message}
	return execPiped("svn", args...)
}

func svnGetMissing(wcPath string) (missing []string, err error) {
	out, err := execPrint("svn", "status", wcPath)
	if nil != err {
		return
	}
	lines := strings.Split(string(out), "\n")
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if len(line) < 3 {
			continue
		}
		if line[0] != '!' {
			continue
		}
		if ' ' != line[1] && '\t' != line[1] {
			err = errors.New("Unkown status line: " + line)
			return
		}
		p := strings.TrimSpace(line[1:])
		missing = append(missing, p)
	}
	return
}

func svnDeleteMissing(wcPath string) (err error) {
	missing, err := svnGetMissing(wcPath)
	if nil != err {
		return
	}
	if len(missing) == 0 {
		return
	}
	args := append([]string{"rm"}, missing...)
	err = execPiped("svn", args...)
	if nil != err {
		return
	}
	return
}

func svnDiffCommit(ca commitArgs, ga globalArgs) (err error) {
	err = svnCheckout(ca.Repos, ca.WcPath, ga)
	if nil != err {
		return
	}
	err = cleanWcRoot(ca.WcPath)
	if nil != err {
		return
	}
	err = copyRecursive(ca.SrcPath, ca.WcPath)
	if nil != err {
		return
	}
	err = execPiped("svn", "add", ca.WcPath, "--force")
	if nil != err {
		return
	}
	err = svnDeleteMissing(ca.WcPath)
	if nil != err {
		return
	}
	return svnCommit(ca.WcPath, ca.Message, ga)
}

func createRepos(reposPath string) (repos *url.URL, err error) {
	err = execPiped("svnadmin", "create", reposPath)
	if nil != err {
		return
	}
	absReposPath, err := filepath.Abs(reposPath)
	if nil != err {
		return
	}
	absReposPath = "file://" + absReposPath
	repos, err = url.Parse(absReposPath)
	return
}

type testData struct {
	Path    string
	IsDir   bool
	Content string
}

func makeTestData() []testData {
	result := []testData{
		{"1.txt", false, "data1"},
		{"2.txt", false, "data2"},
		{"subdir_a", true, ""},
		{filepath.Join("subdir_a", "3.txt"), false, "data3"},
		{"subdir_b", true, ""},
		{filepath.Join("subdir_b", "4.txt"), false, "data4"},
		{"subdir_c", true, ""}}
	return result
}

func removeSomeTestFiles(srcPath string) (err error) {
	err = os.Remove(filepath.Join(srcPath, "1.txt"))
	if nil != err {
		return
	}
	err = os.Remove(filepath.Join(srcPath, "subdir_a", "3.txt"))
	if nil != err {
		return
	}
	return os.RemoveAll(filepath.Join(srcPath, "subdir_b"))
}

const perm = 0755

func crateTestFiles(basePath string, tds []testData) (err error) {
	err = os.Mkdir(basePath, perm)
	if nil != err {
		return
	}
	for _, td := range tds {
		err = createTestFile(td, basePath)
		if nil != err {
			return
		}
	}
	return nil
}

func createTestFile(td testData, basePath string) error {
	path := filepath.Join(basePath, td.Path)
	if td.IsDir {
		return os.Mkdir(path, perm)
	}
	return ioutil.WriteFile(path, []byte(td.Content), perm)
}

func setupTest(testPath string) (repos *url.URL, srcPath string, err error) {
	err = os.Mkdir(testPath, perm)
	if nil != err {
		return
	}
	srcPath = filepath.Join(testPath, "src")
	tds := makeTestData()
	err = crateTestFiles(srcPath, tds)
	if nil != err {
		return
	}
	reposPath := filepath.Join(testPath, "repos")
	repos, err = createRepos(reposPath)
	return
}

func teardownTest(testPath string) {
	err := os.RemoveAll(testPath)
	if nil != err {
		log.Println("ERROR: ", err)
	}
}

func runSelfTest() (err error) {
	fmt.Print("\n\nSelf test --> Start...\n\n\n")
	testPath := filepath.Join(".", "self_test")
	ca := commitArgs{}
	ca.Message = "Hellooo :D"
	ca.WcPath = filepath.Join(testPath, "wc")
	ca.Repos, ca.SrcPath, err = setupTest(testPath)
	if nil != err {
		return
	}
	defer teardownTest(testPath)
	ga := globalArgs{}
	err = svnDiffCommit(ca, ga)
	if nil != err {
		return
	}
	err = removeSomeTestFiles(ca.SrcPath)
	if nil != err {
		return
	}
	err = svnDiffCommit(ca, ga)
	if nil != err {
		return
	}
	fmt.Print("\n\nSelf test --> Success.\n\n\n")
	return nil
}

func parseArgs() (args cmdArgs, err error) {
	for i, arg := range os.Args {
		fmt.Println(i, ": ", arg)
	}
	args.RunSelfTest = true
	return
}

type globalArgs struct {
	ConfigDir               *string // --config-dir ARG
	ConfigOption            *string // --config-options ARG
	NoAuthCache             bool    // --no-auth-cache
	NonInteractive          bool    // --non-ineractive
	Password                *string // --password ARG
	TrustServerCertFailures *string // --trust-server-cert-failures ARG 'unknown-ca' 'cn-mismatch' 'expired' 'not-yet-valid' 'other'
	Username                *string // --username ARG
}

type commitArgs struct {
	Message  string   // --message ARG
	SrcPath  string   // --src-path ARG
	Repos    *url.URL // --dst-url ARG
	WcPath   string   // --wc-path ARG
	WcDelete bool     // --wc-delete
}

type cmdArgs struct {
	Help        bool // --help
	RunSelfTest bool // --run-self-test
	CommitArgs  commitArgs
	GlobalArgs  globalArgs
}

func main() {
	args, err := parseArgs()
	if nil != err {
		log.Fatal(err)
	}
	if args.RunSelfTest {
		err = runSelfTest()
	} else if args.Help {
		// print usage
	}
	if nil != err {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
)

const (
	cormFilename = "Cormfile"
	cormDir      = "_corm"
)

var (
	currentDir     string
	dirtyVendorDir string
)

var errCannotParseLine = errors.New("cannot parse line")

var vcsMetaDir = []string{".svn", ".git", ".hg"}

type repository struct {
	Path   string
	Commit string
}

func parse(s string) (*repository, error) {
	// TODO: Consider the format
	fields := strings.Fields(s)
	switch len(fields) {
	case 1:
		return &repository{Path: fields[0]}, nil
	case 2:
		return &repository{Path: fields[0], Commit: fields[1]}, nil
	default:
		return nil, errCannotParseLine
	}
}

func exists(filepath string) bool {
	_, err := os.Stat(filepath)
	return err == nil
}

func readCorm(filepath string) ([]*repository, error) {
	f, err := os.Open(filepath)
	if err != nil {
		return nil, fmt.Errorf("cannot open Cormfile: %s", err)
	}
	defer f.Close()

	repos := make([]*repository, 0, 30)

	s := bufio.NewScanner(f)
	for s.Scan() {
		line := s.Text()
		if line == "" {
			continue
		}

		repo, err := parse(line)
		if err != nil {
			fmt.Fprintf(os.Stderr, "SKIPPED: %s: %s\n", err, line)
			continue
		}
		repos = append(repos, repo)
	}

	return repos, nil
}

func goGet(repo *repository) error {
	// TODO: can handle options for `go get`
	fmt.Printf("go get %s\n", repo.Path)
	cmd := exec.Command("go", "get", repo.Path)
	cmd.Stdout = os.Stdout
	err := cmd.Run()
	// Commit が指定されている場合の処理は後で実装する
	return err
}

func newCopyFileFun(srcBase string, destBase string) filepath.WalkFunc {

	return func(srcPath string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		relPath, err := filepath.Rel(srcBase, srcPath)
		if err != nil {
			return err
		}

		destPath := filepath.Join(destBase, relPath)

		if info.IsDir() {
			index := sort.SearchStrings(vcsMetaDir, info.Name())
			if index < len(vcsMetaDir) {
				return filepath.SkipDir
			}

			return os.MkdirAll(destPath, info.Mode())
		}

		if exists(destPath) {
			return nil
		}

		return os.Link(srcPath, destPath)
	}

}

func export(src string, dest string) error {
	copyFile := newCopyFileFun(src, dest)
	err := filepath.Walk(src, copyFile)
	return err
}

func init() {
	var err error
	currentDir, err = os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, "cannot get current directory")
		os.Exit(1)
	}

	dirtyVendorDir = filepath.Join(currentDir, cormDir)
}

func fakeGopath() {

	// if target package exists default GOPATH, then go get does nothing.
	// So, set GOPATH dirtyVendorDir only

	os.Setenv("GOPATH", dirtyVendorDir)

}

func mainCmd() int {
	cormfile := filepath.Join(currentDir, cormFilename)
	if !exists(cormfile) {
		fmt.Fprintf(os.Stderr, "%s does not exists\n", cormfile)
		return 1
	}

	repos, err := readCorm(cormfile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if len(repos) == 0 {
		fmt.Fprintln(os.Stderr, "no repositories in Cormfile")
		return 1
	}

	fakeGopath()
	for _, repo := range repos {
		err := goGet(repo)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot exec go get: %s, %s\n", repo.Path, err)
		}
	}

	return 0
}

func exportCmd() int {
	dirtyVendorSrcDir := filepath.Join(dirtyVendorDir, "src")

	if !exists(dirtyVendorDir) {
		fmt.Fprintf(os.Stderr, "%s does not exists\n", dirtyVendorSrcDir)
		return 1
	}

	cleanVendorDir := filepath.Join(currentDir, "vendor")
	err := export(dirtyVendorSrcDir, cleanVendorDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, "export error:", err)
		return 1
	}

	return 0
}

func execCmd() int {
	fakeGopath()
	return 0
}

func usage() int {
	fmt.Println(`Usage: corm command
	install	:	install packages from Cormfile.
	export	:	export packages to vendor directory.`)

	return 1
}

func main() {
	sort.Strings(vcsMetaDir)

	if len(os.Args) == 1 {
		os.Exit(usage())
	}

	command := os.Args[1]

	switch command {
	case "install":
		os.Exit(mainCmd())
	case "export":
		os.Exit(exportCmd())
	case "exec":
		os.Exit(execCmd())
	default:
		os.Exit(usage())
	}
}
<commit_msg>ひとまず受け取ったパラメータをexecすることができた<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
)

const (
	cormFilename = "Cormfile"
	cormDir      = "_corm"
)

var (
	currentDir     string
	dirtyVendorDir string
)

var errCannotParseLine = errors.New("cannot parse line")

var vcsMetaDir = []string{".svn", ".git", ".hg"}

type repository struct {
	Path   string
	Commit string
}

func parse(s string) (*repository, error) {
	// TODO: Consider the format
	fields := strings.Fields(s)
	switch len(fields) {
	case 1:
		return &repository{Path: fields[0]}, nil
	case 2:
		return &repository{Path: fields[0], Commit: fields[1]}, nil
	default:
		return nil, errCannotParseLine
	}
}

func exists(filepath string) bool {
	_, err := os.Stat(filepath)
	return err == nil
}

func readCorm(filepath string) ([]*repository, error) {
	f, err := os.Open(filepath)
	if err != nil {
		return nil, fmt.Errorf("cannot open Cormfile: %s", err)
	}
	defer f.Close()

	repos := make([]*repository, 0, 30)

	s := bufio.NewScanner(f)
	for s.Scan() {
		line := s.Text()
		if line == "" {
			continue
		}

		repo, err := parse(line)
		if err != nil {
			fmt.Fprintf(os.Stderr, "SKIPPED: %s: %s\n", err, line)
			continue
		}
		repos = append(repos, repo)
	}

	return repos, nil
}

func goGet(repo *repository) error {
	// TODO: can handle options for `go get`
	fmt.Printf("go get %s\n", repo.Path)
	cmd := exec.Command("go", "get", repo.Path)
	cmd.Stdout = os.Stdout
	err := cmd.Run()
	// Commit が指定されている場合の処理は後で実装する
	return err
}

func newCopyFileFun(srcBase string, destBase string) filepath.WalkFunc {

	return func(srcPath string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		relPath, err := filepath.Rel(srcBase, srcPath)
		if err != nil {
			return err
		}

		destPath := filepath.Join(destBase, relPath)

		if info.IsDir() {
			index := sort.SearchStrings(vcsMetaDir, info.Name())
			if index < len(vcsMetaDir) {
				return filepath.SkipDir
			}

			return os.MkdirAll(destPath, info.Mode())
		}

		if exists(destPath) {
			return nil
		}

		return os.Link(srcPath, destPath)
	}

}

func export(src string, dest string) error {
	copyFile := newCopyFileFun(src, dest)
	err := filepath.Walk(src, copyFile)
	return err
}

func init() {
	var err error
	currentDir, err = os.Getwd()
	if err != nil {
		fmt.Fprintln(os.Stderr, "cannot get current directory")
		os.Exit(1)
	}

	dirtyVendorDir = filepath.Join(currentDir, cormDir)
}

func fakeGopath() {

	// if target package exists default GOPATH, then go get does nothing.
	// So, set GOPATH dirtyVendorDir only

	os.Setenv("GOPATH", dirtyVendorDir)

}

func mainCmd() int {
	cormfile := filepath.Join(currentDir, cormFilename)
	if !exists(cormfile) {
		fmt.Fprintf(os.Stderr, "%s does not exists\n", cormfile)
		return 1
	}

	repos, err := readCorm(cormfile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	if len(repos) == 0 {
		fmt.Fprintln(os.Stderr, "no repositories in Cormfile")
		return 1
	}

	fakeGopath()
	for _, repo := range repos {
		err := goGet(repo)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot exec go get: %s, %s\n", repo.Path, err)
		}
	}

	return 0
}

func exportCmd() int {
	dirtyVendorSrcDir := filepath.Join(dirtyVendorDir, "src")

	if !exists(dirtyVendorDir) {
		fmt.Fprintf(os.Stderr, "%s does not exists\n", dirtyVendorSrcDir)
		return 1
	}

	cleanVendorDir := filepath.Join(currentDir, "vendor")
	err := export(dirtyVendorSrcDir, cleanVendorDir)
	if err != nil {
		fmt.Fprintln(os.Stderr, "export error:", err)
		return 1
	}

	return 0
}

func execCmd(args []string) int {
	if len(args) == 0 {
		fmt.Fprintln(os.Stderr, "no exec target command")
		return 1
	}

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

	// TODO: cant exec vim main.go
	err := cmd.Run()
	if err != nil {
		fmt.Fprintln(os.Stderr, "exec error:", err)
		return 1
	}
	return 0
}

func usage() int {
	fmt.Println(`Usage: corm command
	install	:	install packages from Cormfile.
	export	:	export packages to vendor directory.`)

	return 1
}

func main() {
	sort.Strings(vcsMetaDir)

	if len(os.Args) == 1 {
		os.Exit(usage())
	}

	command := os.Args[1]

	switch command {
	case "install":
		os.Exit(mainCmd())
	case "export":
		os.Exit(exportCmd())
	case "exec":
		os.Exit(execCmd(os.Args[2:]))
	default:
		os.Exit(usage())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"flag"
	"fmt"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/ec2"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	FILE_NAME = "/tmp/gopher_instances"
)

// Command Line Variables
var command string

// Flags Variables
var flagSet *flag.FlagSet

// Creation options
var instanceCount int
var instanceImage, instanceType, instanceRegionName, instanceLogin, instanceKey string

// Attack options
var numberOfRequests, concurrentRequests int
var options, url string

// EC2 Variables
var instanceRegion aws.Region

func init() {
	if len(os.Args) == 1 {
		command = "help"
	} else {
		command = os.Args[1]
	}

	flagSet = flag.NewFlagSet(command, flag.ExitOnError)

	// Creation options
	flagSet.IntVar(&instanceCount, "count", 5, "The number of gophers to call into action")
	flagSet.StringVar(&instanceRegionName, "region", "us-east-1", "The availability zone to start each gopher in (default: us-east-1d)")
	flagSet.StringVar(&instanceImage, "image", "ami-2bc99d42", "The image id to use for each gopher (default: ami-2bc99d42)")
	flagSet.StringVar(&instanceType, "type", "t1.micro", "The instance type to use for each gopher (default: t1.micro)")
	flagSet.StringVar(&instanceLogin, "login", "ubuntu", "The ssh username name to use to connect to the new servers (default: ubuntu).")
	flagSet.StringVar(&instanceKey, "key", "gophers", "The ssh key pair name to use to connect to the new gophers (default: gophers)")

	// Attack options
	flagSet.IntVar(&numberOfRequests, "requests", 5, "The number of requests to perform per gopher")
	flagSet.IntVar(&concurrentRequests, "concurrent", 1, "The number of concurrent requests to make per gopher")
	flagSet.StringVar(&url, "url", "", "The url to point the gophers towards when attacking")
	flagSet.StringVar(&options, "options", "", "Additional attack options (Not supported yet)")

	setupRegion()
}

func main() {
	if len(os.Args) <= 1 {
		flagSet.PrintDefaults()
	} else {
		flagSet.Parse(os.Args[2:])

	}

	switch command {
	case "help":
		printInstructions()
	case "up":
		up()
	case "down":
		down()
	case "attack":
		attack()
	case "report":
		report()
	default:
		flagSet.PrintDefaults()
	}
}

func up() {
	fmt.Printf("Adding %v gopher(s) to your army.\n", instanceCount)

	if instanceCount <= 0 {
		fmt.Printf("You must declare a number of gophers greater than 0.")
		return
	}
	createInstances := ec2.RunInstances{
		MinCount:     instanceCount,
		MaxCount:     instanceCount,
		ImageId:      instanceImage,
		InstanceType: instanceType,
		KeyName:      instanceKey,
	}

	ec2Connection, err := ec2Connect()
	runInstancesResponse, err := ec2Connection.RunInstances(&createInstances)
	handleError(err)

	_, err = tagInstances(runInstancesResponse.Instances)
	handleError(err)

	instances, err := findInstances(0)
	handleError(err)

	notReadyInstancesCount := len(instances)
	for notReadyInstancesCount != 0 {
		time.Sleep(3 * time.Second)
		instances, err := findInstances(0)
		handleError(err)

		readyInstancesCount := notReadyInstancesCount - len(instances)

		for i := 0; i < readyInstancesCount; i++ {
			fmt.Printf(".")
		}

		notReadyInstancesCount = len(instances)
	}

	instances, err = findInstances(16)
	handleError(err)

	fmt.Println("\nArming your gophers with grenades, stand back!")

	setupResponseChannel := make(chan setupResponse)
	for _, instance := range instances {
		setupInstance(setupResponseChannel, instance.DNSName)
	}

	for i := 0; i < len(instances); i++ {
		resp := <-setupResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers were inbred, check your AWS account to make sure things haven't gone awry.")
			fmt.Printf("Message: (%v) %v\n", resp.host, resp.message)
			fmt.Printf("Error: (%v) %v\n", resp.host, resp.err)
		}
	}

	fmt.Printf("\n%v gophers are ready to invade!\n", len(instances))
}

func down() {
	fmt.Println("Your gopher army has been nuked from orbit.")

	instances, err := findInstances(-1)
	handleError(err)

	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	ec2Connection.TerminateInstances(instanceIds)
}

func attack() {
	fmt.Println("your gophers are on the move!")

	if url == "" {
		fmt.Println("You must provide a url to start the attack.")
		return
	}

	instances, err := findInstances(16)
	handleError(err)

	attackResponseChannel := make(chan benchmarkResponse)
	for _, instance := range instances {
		startAttack(attackResponseChannel, instance.DNSName)
	}

	var complete, failed int
	var totalTime, requestsPerSecond float32
	for i := 0; i < len(instances); i++ {
		resp := <-attackResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers started a civil war.")
		}

		complete += resp.Complete
		failed += resp.Failed
		requestsPerSecond += resp.RequestsPerSecond
		totalTime += resp.TimePerRequest * float32(resp.Complete+resp.Failed)
	}

	fmt.Println("Completed requests:", complete)
	fmt.Println("Failed requests:", failed)
	fmt.Println("Requests per second:", requestsPerSecond, "[#/sec] (mean)")
	fmt.Println("Time per request:", totalTime/float32(complete+failed), "[ms] (mean)")
}

func report() {
	fmt.Println("Who know where the gophers are?")

	instances, err := findInstances(-1)
	handleError(err)

	if len(instances) > 0 {
		fmt.Println("Name (DNS Name) - State")
		for _, instance := range instances {
			var instanceName string

			for _, tag := range instance.Tags {
				if tag.Key == "Name" {
					instanceName = tag.Value
				}
			}

			fmt.Printf("%s (%s) - %s\n", instanceName, instance.DNSName, instance.State.Name)
		}
	} else {
		fmt.Println("Your army has gone AWOL.  Better recruit some more!")
	}
}

func setupInstance(response chan setupResponse, host string) {
	go func() {
		setupResponse := setupResponse{host: host}

		var client *ssh.ClientConn
		for i := 0; client == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("Attempting to create and ssh connection to %s.\n", host)
			client, _ = sshClient(fmt.Sprintf("%s:22", host))
		}

		var session *ssh.Session
		for i := 0; session == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("creating the session: %v\n", client)
			session, _ = client.NewSession()
		}

		// fmt.Println("defering the session")
		defer session.Close()

		// fmt.Println("setting up the buffer")
		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer
		// fmt.Println("making the call")
		err := session.Run("sudo apt-get -o Debug::pkgProblemResolver=true install apache2-utils -y")
		if err != nil {
			setupResponse.err = append(setupResponse.err, err)
		}

		setupResponse.message = outputBuffer.String()
		// fmt.Println("returning the response")
		response <- setupResponse
	}()
}

func startAttack(response chan benchmarkResponse, host string) {
	go func() {
		benchmarkResponse := benchmarkResponse{}

		client, err := sshClient(fmt.Sprintf("%s:22", host))
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		session, err := client.NewSession()
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		defer session.Close()

		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer

		benchmarkCommand := fmt.Sprintf("ab -r -n %v -c %v %v \"%v\"", numberOfRequests, concurrentRequests, options, url)
		err = session.Run(benchmarkCommand)
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		// fmt.Println(&outputBuffer)
		outputString := outputBuffer.String()

		for _, line := range strings.Split(outputString, "\n") {
			if strings.Contains(line, "Complete requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Complete, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Failed requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Failed, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Requests per second:") {
				re := regexp.MustCompile("Requests per second:\\s*(\\d+.\\d+)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.RequestsPerSecond = float32(valueFloat)
			}
			if strings.Contains(line, "Time per request:") && !strings.Contains(line, "across all concurrent requests") {
				re := regexp.MustCompile("Time per request:\\s*(\\d+.\\d+)\\s*\\[ms\\]\\s*\\(mean\\)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.TimePerRequest = float32(valueFloat)
			}
		}

		response <- benchmarkResponse
	}()
}

func printInstructions() {
	fmt.Println(`gophers COMMAND [options]

gophers with grenades

A utility for arming (creating) many gophers (small EC2 instances) to attack
(load test) targets (web applications).

commands:
  up      Start a batch of load testing servers.
  attack  Begin the attack on a specific url.
  down    Shutdown and deactivate the load testing servers.
  report  Report the status of the load testing servers.
    `)
}

func ec2Connect() (*ec2.EC2, error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return nil, err
	}

	ec2Connection := ec2.New(auth, aws.USEast)

	return ec2Connection, nil
}

func setupRegion() {
	instanceRegion = aws.Regions[instanceRegionName]
}

func getInstanceIds(instances []ec2.Instance) (instanceIds []string) {
	for _, instance := range instances {
		instanceIds = append(instanceIds, instance.InstanceId)
	}

	return instanceIds
}

func tagInstances(instances []ec2.Instance) (responses []*ec2.SimpleResp, err error) {
	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	if err != nil {
		return nil, err
	}

	for _, instance := range instances {
		nameTag := ec2.Tag{"Name", instance.InstanceId}
		gopherTag := ec2.Tag{"gopher", "true"}
		tags := []ec2.Tag{nameTag, gopherTag}

		response, err := ec2Connection.CreateTags(instanceIds, tags)
		if err != nil {
			return nil, err
		}

		responses = append(responses, response)
	}

	return responses, nil
}

func findInstances(statusCode int) (instances []ec2.Instance, err error) {
	filter := ec2.NewFilter()
	filter.Add("tag:gopher", "true")

	if statusCode != -1 {
		filter.Add("instance-state-code", strconv.Itoa(statusCode))
	}

	ec2Connection, err := ec2Connect()
	resp, err := ec2Connection.Instances(nil, filter)
	if err != nil {
		return nil, err
	}

	for _, reservation := range resp.Reservations {
		for _, instance := range reservation.Instances {
			instances = append(instances, instance)
		}
	}

	return instances, nil
}

func sshClient(host string) (*ssh.ClientConn, error) {
	var auths []ssh.ClientAuth

	keypath := getKeyPath()
	k := &keyring{}
	err := k.loadPEM(keypath)
	if err != nil {
		return nil, err
	}

	auths = append(auths, ssh.ClientAuthKeyring(k))

	config := &ssh.ClientConfig{
		User: "ubuntu",
		Auth: auths,
	}

	client, err := ssh.Dial("tcp", host, config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func getKeyPath() string {
	user, _ := user.Current()
	homeDirectory := user.HomeDir

	return filepath.Join(homeDirectory, ".ssh", fmt.Sprintf("%s.pem", instanceKey))
}

func handleError(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>removed debug line for apt-get install<commit_after>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"flag"
	"fmt"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/ec2"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	FILE_NAME = "/tmp/gopher_instances"
)

// Command Line Variables
var command string

// Flags Variables
var flagSet *flag.FlagSet

// Creation options
var instanceCount int
var instanceImage, instanceType, instanceRegionName, instanceLogin, instanceKey string

// Attack options
var numberOfRequests, concurrentRequests int
var options, url string

// EC2 Variables
var instanceRegion aws.Region

func init() {
	if len(os.Args) == 1 {
		command = "help"
	} else {
		command = os.Args[1]
	}

	flagSet = flag.NewFlagSet(command, flag.ExitOnError)

	// Creation options
	flagSet.IntVar(&instanceCount, "count", 5, "The number of gophers to call into action")
	flagSet.StringVar(&instanceRegionName, "region", "us-east-1", "The availability zone to start each gopher in (default: us-east-1d)")
	flagSet.StringVar(&instanceImage, "image", "ami-2bc99d42", "The image id to use for each gopher (default: ami-2bc99d42)")
	flagSet.StringVar(&instanceType, "type", "t1.micro", "The instance type to use for each gopher (default: t1.micro)")
	flagSet.StringVar(&instanceLogin, "login", "ubuntu", "The ssh username name to use to connect to the new servers (default: ubuntu).")
	flagSet.StringVar(&instanceKey, "key", "gophers", "The ssh key pair name to use to connect to the new gophers (default: gophers)")

	// Attack options
	flagSet.IntVar(&numberOfRequests, "requests", 5, "The number of requests to perform per gopher")
	flagSet.IntVar(&concurrentRequests, "concurrent", 1, "The number of concurrent requests to make per gopher")
	flagSet.StringVar(&url, "url", "", "The url to point the gophers towards when attacking")
	flagSet.StringVar(&options, "options", "", "Additional attack options (Not supported yet)")

	setupRegion()
}

func main() {
	if len(os.Args) <= 1 {
		flagSet.PrintDefaults()
	} else {
		flagSet.Parse(os.Args[2:])

	}

	switch command {
	case "help":
		printInstructions()
	case "up":
		up()
	case "down":
		down()
	case "attack":
		attack()
	case "report":
		report()
	default:
		flagSet.PrintDefaults()
	}
}

func up() {
	fmt.Printf("Adding %v gopher(s) to your army.\n", instanceCount)

	if instanceCount <= 0 {
		fmt.Printf("You must declare a number of gophers greater than 0.")
		return
	}
	createInstances := ec2.RunInstances{
		MinCount:     instanceCount,
		MaxCount:     instanceCount,
		ImageId:      instanceImage,
		InstanceType: instanceType,
		KeyName:      instanceKey,
	}

	ec2Connection, err := ec2Connect()
	runInstancesResponse, err := ec2Connection.RunInstances(&createInstances)
	handleError(err)

	_, err = tagInstances(runInstancesResponse.Instances)
	handleError(err)

	instances, err := findInstances(0)
	handleError(err)

	notReadyInstancesCount := len(instances)
	for notReadyInstancesCount != 0 {
		time.Sleep(3 * time.Second)
		instances, err := findInstances(0)
		handleError(err)

		readyInstancesCount := notReadyInstancesCount - len(instances)

		for i := 0; i < readyInstancesCount; i++ {
			fmt.Printf(".")
		}

		notReadyInstancesCount = len(instances)
	}

	instances, err = findInstances(16)
	handleError(err)

	fmt.Println("\nArming your gophers with grenades, stand back!")

	setupResponseChannel := make(chan setupResponse)
	for _, instance := range instances {
		setupInstance(setupResponseChannel, instance.DNSName)
	}

	for i := 0; i < len(instances); i++ {
		resp := <-setupResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers were inbred, check your AWS account to make sure things haven't gone awry.")
			fmt.Printf("Message: (%v) %v\n", resp.host, resp.message)
			fmt.Printf("Error: (%v) %v\n", resp.host, resp.err)
		}
	}

	fmt.Printf("\n%v gophers are ready to invade!\n", len(instances))
}

func down() {
	fmt.Println("Your gopher army has been nuked from orbit.")

	instances, err := findInstances(-1)
	handleError(err)

	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	ec2Connection.TerminateInstances(instanceIds)
}

func attack() {
	fmt.Println("your gophers are on the move!")

	if url == "" {
		fmt.Println("You must provide a url to start the attack.")
		return
	}

	instances, err := findInstances(16)
	handleError(err)

	attackResponseChannel := make(chan benchmarkResponse)
	for _, instance := range instances {
		startAttack(attackResponseChannel, instance.DNSName)
	}

	var complete, failed int
	var totalTime, requestsPerSecond float32
	for i := 0; i < len(instances); i++ {
		resp := <-attackResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers started a civil war.")
		}

		complete += resp.Complete
		failed += resp.Failed
		requestsPerSecond += resp.RequestsPerSecond
		totalTime += resp.TimePerRequest * float32(resp.Complete+resp.Failed)
	}

	fmt.Println("Completed requests:", complete)
	fmt.Println("Failed requests:", failed)
	fmt.Println("Requests per second:", requestsPerSecond, "[#/sec] (mean)")
	fmt.Println("Time per request:", totalTime/float32(complete+failed), "[ms] (mean)")
}

func report() {
	fmt.Println("Who know where the gophers are?")

	instances, err := findInstances(-1)
	handleError(err)

	if len(instances) > 0 {
		fmt.Println("Name (DNS Name) - State")
		for _, instance := range instances {
			var instanceName string

			for _, tag := range instance.Tags {
				if tag.Key == "Name" {
					instanceName = tag.Value
				}
			}

			fmt.Printf("%s (%s) - %s\n", instanceName, instance.DNSName, instance.State.Name)
		}
	} else {
		fmt.Println("Your army has gone AWOL.  Better recruit some more!")
	}
}

func setupInstance(response chan setupResponse, host string) {
	go func() {
		setupResponse := setupResponse{host: host}

		var client *ssh.ClientConn
		for i := 0; client == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("Attempting to create and ssh connection to %s.\n", host)
			client, _ = sshClient(fmt.Sprintf("%s:22", host))
		}

		var session *ssh.Session
		for i := 0; session == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("creating the session: %v\n", client)
			session, _ = client.NewSession()
		}

		// fmt.Println("defering the session")
		defer session.Close()

		// fmt.Println("setting up the buffer")
		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer
		// fmt.Println("making the call")
		err := session.Run("sudo apt-get install apache2-utils -y")
		if err != nil {
			setupResponse.err = append(setupResponse.err, err)
		}

		setupResponse.message = outputBuffer.String()
		// fmt.Println("returning the response")
		response <- setupResponse
	}()
}

func startAttack(response chan benchmarkResponse, host string) {
	go func() {
		benchmarkResponse := benchmarkResponse{}

		client, err := sshClient(fmt.Sprintf("%s:22", host))
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		session, err := client.NewSession()
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		defer session.Close()

		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer

		benchmarkCommand := fmt.Sprintf("ab -r -n %v -c %v %v \"%v\"", numberOfRequests, concurrentRequests, options, url)
		err = session.Run(benchmarkCommand)
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		// fmt.Println(&outputBuffer)
		outputString := outputBuffer.String()

		for _, line := range strings.Split(outputString, "\n") {
			if strings.Contains(line, "Complete requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Complete, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Failed requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Failed, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Requests per second:") {
				re := regexp.MustCompile("Requests per second:\\s*(\\d+.\\d+)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.RequestsPerSecond = float32(valueFloat)
			}
			if strings.Contains(line, "Time per request:") && !strings.Contains(line, "across all concurrent requests") {
				re := regexp.MustCompile("Time per request:\\s*(\\d+.\\d+)\\s*\\[ms\\]\\s*\\(mean\\)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.TimePerRequest = float32(valueFloat)
			}
		}

		response <- benchmarkResponse
	}()
}

func printInstructions() {
	fmt.Println(`gophers COMMAND [options]

gophers with grenades

A utility for arming (creating) many gophers (small EC2 instances) to attack
(load test) targets (web applications).

commands:
  up      Start a batch of load testing servers.
  attack  Begin the attack on a specific url.
  down    Shutdown and deactivate the load testing servers.
  report  Report the status of the load testing servers.
    `)
}

func ec2Connect() (*ec2.EC2, error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return nil, err
	}

	ec2Connection := ec2.New(auth, aws.USEast)

	return ec2Connection, nil
}

func setupRegion() {
	instanceRegion = aws.Regions[instanceRegionName]
}

func getInstanceIds(instances []ec2.Instance) (instanceIds []string) {
	for _, instance := range instances {
		instanceIds = append(instanceIds, instance.InstanceId)
	}

	return instanceIds
}

func tagInstances(instances []ec2.Instance) (responses []*ec2.SimpleResp, err error) {
	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	if err != nil {
		return nil, err
	}

	for _, instance := range instances {
		nameTag := ec2.Tag{"Name", instance.InstanceId}
		gopherTag := ec2.Tag{"gopher", "true"}
		tags := []ec2.Tag{nameTag, gopherTag}

		response, err := ec2Connection.CreateTags(instanceIds, tags)
		if err != nil {
			return nil, err
		}

		responses = append(responses, response)
	}

	return responses, nil
}

func findInstances(statusCode int) (instances []ec2.Instance, err error) {
	filter := ec2.NewFilter()
	filter.Add("tag:gopher", "true")

	if statusCode != -1 {
		filter.Add("instance-state-code", strconv.Itoa(statusCode))
	}

	ec2Connection, err := ec2Connect()
	resp, err := ec2Connection.Instances(nil, filter)
	if err != nil {
		return nil, err
	}

	for _, reservation := range resp.Reservations {
		for _, instance := range reservation.Instances {
			instances = append(instances, instance)
		}
	}

	return instances, nil
}

func sshClient(host string) (*ssh.ClientConn, error) {
	var auths []ssh.ClientAuth

	keypath := getKeyPath()
	k := &keyring{}
	err := k.loadPEM(keypath)
	if err != nil {
		return nil, err
	}

	auths = append(auths, ssh.ClientAuthKeyring(k))

	config := &ssh.ClientConfig{
		User: "ubuntu",
		Auth: auths,
	}

	client, err := ssh.Dial("tcp", host, config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func getKeyPath() string {
	user, _ := user.Current()
	homeDirectory := user.HomeDir

	return filepath.Join(homeDirectory, ".ssh", fmt.Sprintf("%s.pem", instanceKey))
}

func handleError(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/openfaas-incubator/of-watchdog/config"
	"github.com/openfaas-incubator/of-watchdog/executor"
	"github.com/openfaas-incubator/of-watchdog/metrics"
	limiter "github.com/openfaas/faas-middleware/concurrency-limiter"
)

var (
	acceptingConnections int32
)

func main() {
	flag.Parse()

	switch flag.Arg(0) {
	case "healthcheck":
		if lockFilePresent() {
			os.Exit(0)
		}

		os.Exit(1)
	}

	atomic.StoreInt32(&acceptingConnections, 0)

	watchdogConfig := config.New(os.Environ())

	if len(watchdogConfig.FunctionProcess) == 0 && watchdogConfig.OperationalMode != config.ModeStatic {
		fmt.Fprintf(os.Stderr, "Provide a \"function_process\" or \"fprocess\" environmental variable for your function.\n")
		os.Exit(1)
	}

	requestHandler := buildRequestHandler(watchdogConfig)

	log.Printf("OperationalMode: %s\n", config.WatchdogMode(watchdogConfig.OperationalMode))

	httpMetrics := metrics.NewHttp()
	http.HandleFunc("/", metrics.InstrumentHandler(requestHandler, httpMetrics))
	http.HandleFunc("/_/health", makeHealthHandler())

	metricsServer := metrics.MetricsServer{}
	metricsServer.Register(watchdogConfig.MetricsPort)

	cancel := make(chan bool)

	go metricsServer.Serve(cancel)

	shutdownTimeout := watchdogConfig.HTTPWriteTimeout
	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", watchdogConfig.TCPPort),
		ReadTimeout:    watchdogConfig.HTTPReadTimeout,
		WriteTimeout:   watchdogConfig.HTTPWriteTimeout,
		MaxHeaderBytes: 1 << 20, // Max header of 1MB
	}

	log.Printf("Timeouts: read: %s, write: %s hard: %s.\n",
		watchdogConfig.HTTPReadTimeout,
		watchdogConfig.HTTPWriteTimeout,
		watchdogConfig.ExecTimeout)
	log.Printf("Listening on port: %d\n", watchdogConfig.TCPPort)

	listenUntilShutdown(shutdownTimeout, s, watchdogConfig.SuppressLock)
}

func markUnhealthy() error {
	atomic.StoreInt32(&acceptingConnections, 0)

	path := filepath.Join(os.TempDir(), ".lock")
	log.Printf("Removing lock-file : %s\n", path)
	removeErr := os.Remove(path)
	return removeErr
}

func listenUntilShutdown(shutdownTimeout time.Duration, s *http.Server, suppressLock bool) {

	idleConnsClosed := make(chan struct{})
	go func() {
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, syscall.SIGTERM)

		<-sig

		log.Printf("SIGTERM received.. shutting down server in %s\n", shutdownTimeout.String())

		healthErr := markUnhealthy()

		if healthErr != nil {
			log.Printf("Unable to mark unhealthy during shutdown: %s\n", healthErr.Error())
		}

		<-time.Tick(shutdownTimeout)

		if err := s.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			log.Printf("Error in Shutdown: %v", err)
		}

		log.Printf("No new connections allowed. Exiting in: %s\n", shutdownTimeout.String())

		<-time.Tick(shutdownTimeout)

		close(idleConnsClosed)
	}()

	// Run the HTTP server in a separate go-routine.
	go func() {
		if err := s.ListenAndServe(); err != http.ErrServerClosed {
			log.Printf("Error ListenAndServe: %v", err)
			close(idleConnsClosed)
		}
	}()

	if suppressLock == false {
		path, writeErr := createLockFile()

		if writeErr != nil {
			log.Panicf("Cannot write %s. To disable lock-file set env suppress_lock=true.\n Error: %s.\n", path, writeErr.Error())
		}
	} else {
		log.Println("Warning: \"suppress_lock\" is enabled. No automated health-checks will be in place for your function.")

		atomic.StoreInt32(&acceptingConnections, 1)
	}

	<-idleConnsClosed
}

func buildRequestHandler(watchdogConfig config.WatchdogConfig) http.Handler {
	var requestHandler http.HandlerFunc

	switch watchdogConfig.OperationalMode {
	case config.ModeStreaming:
		requestHandler = makeForkRequestHandler(watchdogConfig)
		break
	case config.ModeSerializing:
		requestHandler = makeSerializingForkRequestHandler(watchdogConfig)
		break
	case config.ModeAfterBurn:
		requestHandler = makeAfterBurnRequestHandler(watchdogConfig)
		break
	case config.ModeHTTP:
		requestHandler = makeHTTPRequestHandler(watchdogConfig)
		break
	case config.ModeStatic:
		requestHandler = makeStaticRequestHandler(watchdogConfig)
	default:
		log.Panicf("unknown watchdog mode: %d", watchdogConfig.OperationalMode)
		break
	}

	if watchdogConfig.MaxInflight > 0 {
		return limiter.NewConcurrencyLimiter(requestHandler, watchdogConfig.MaxInflight)
	}

	return requestHandler
}

// createLockFile returns a path to a lock file and/or an error
// if the file could not be created.
func createLockFile() (string, error) {
	path := filepath.Join(os.TempDir(), ".lock")
	log.Printf("Writing lock-file to: %s\n", path)
	writeErr := ioutil.WriteFile(path, []byte{}, 0660)

	atomic.StoreInt32(&acceptingConnections, 1)

	return path, writeErr
}

func makeAfterBurnRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {

	commandName, arguments := watchdogConfig.Process()
	functionInvoker := executor.AfterBurnFunctionRunner{
		Process:     commandName,
		ProcessArgs: arguments,
	}

	log.Printf("Forking %s %s\n", commandName, arguments)
	functionInvoker.Start()

	return func(w http.ResponseWriter, r *http.Request) {

		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
		}

		functionInvoker.Mutex.Lock()

		err := functionInvoker.Run(req, r.ContentLength, r, w)

		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		}

		functionInvoker.Mutex.Unlock()
	}
}

func makeSerializingForkRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	functionInvoker := executor.SerializingForkFunctionRunner{
		ExecTimeout: watchdogConfig.ExecTimeout,
	}

	return func(w http.ResponseWriter, r *http.Request) {

		var environment []string

		if watchdogConfig.InjectCGIHeaders {
			environment = getEnvironment(r)
		}

		commandName, arguments := watchdogConfig.Process()
		req := executor.FunctionRequest{
			Process:       commandName,
			ProcessArgs:   arguments,
			InputReader:   r.Body,
			ContentLength: &r.ContentLength,
			OutputWriter:  w,
			Environment:   environment,
		}

		w.Header().Set("Content-Type", watchdogConfig.ContentType)
		err := functionInvoker.Run(req, w)
		if err != nil {
			log.Println(err)
		}
	}
}

func makeForkRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	functionInvoker := executor.ForkFunctionRunner{
		ExecTimeout: watchdogConfig.ExecTimeout,
	}

	return func(w http.ResponseWriter, r *http.Request) {

		var environment []string

		if watchdogConfig.InjectCGIHeaders {
			environment = getEnvironment(r)
		}

		commandName, arguments := watchdogConfig.Process()
		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
			Environment:  environment,
		}

		w.Header().Set("Content-Type", watchdogConfig.ContentType)
		err := functionInvoker.Run(req)
		if err != nil {
			log.Println(err.Error())

			// Probably cannot write to client if we already have written a header
			// w.WriteHeader(500)
			// w.Write([]byte(err.Error()))
		}
	}
}

func getEnvironment(r *http.Request) []string {
	var envs []string

	envs = os.Environ()
	for k, v := range r.Header {
		kv := fmt.Sprintf("Http_%s=%s", strings.Replace(k, "-", "_", -1), v[0])
		envs = append(envs, kv)
	}
	envs = append(envs, fmt.Sprintf("Http_Method=%s", r.Method))

	if len(r.URL.RawQuery) > 0 {
		envs = append(envs, fmt.Sprintf("Http_Query=%s", r.URL.RawQuery))
	}

	if len(r.URL.Path) > 0 {
		envs = append(envs, fmt.Sprintf("Http_Path=%s", r.URL.Path))
	}

	return envs
}

func makeHTTPRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	commandName, arguments := watchdogConfig.Process()
	functionInvoker := executor.HTTPFunctionRunner{
		ExecTimeout:    watchdogConfig.ExecTimeout,
		Process:        commandName,
		ProcessArgs:    arguments,
		BufferHTTPBody: watchdogConfig.BufferHTTPBody,
	}

	if len(watchdogConfig.UpstreamURL) == 0 {
		log.Fatal(`For "mode=http" you must specify a valid URL for "http_upstream_url"`)
	}

	urlValue, upstreamURLErr := url.Parse(watchdogConfig.UpstreamURL)
	if upstreamURLErr != nil {
		log.Fatal(upstreamURLErr)
	}
	functionInvoker.UpstreamURL = urlValue

	fmt.Printf("Forking - %s %s\n", commandName, arguments)
	functionInvoker.Start()

	return func(w http.ResponseWriter, r *http.Request) {

		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
		}

		if r.Body != nil {
			defer r.Body.Close()
		}

		err := functionInvoker.Run(req, r.ContentLength, r, w)

		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		}

	}
}

func makeStaticRequestHandler(watchdogConfig config.WatchdogConfig) http.HandlerFunc {
	if watchdogConfig.StaticPath == "" {
		log.Fatal(`For mode=static you must specify the "static_path" to serve`)
	}

	log.Printf("Serving files at %s", watchdogConfig.StaticPath)
	return http.FileServer(http.Dir(watchdogConfig.StaticPath)).ServeHTTP
}

func lockFilePresent() bool {
	path := filepath.Join(os.TempDir(), ".lock")
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return false
	}
	return true
}

func makeHealthHandler() func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			if atomic.LoadInt32(&acceptingConnections) == 0 || lockFilePresent() == false {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			w.WriteHeader(http.StatusOK)
			w.Write([]byte("OK"))

			break
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	}
}
<commit_msg>Automatically create lock file directory.<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"sync/atomic"
	"syscall"
	"time"

	"github.com/openfaas-incubator/of-watchdog/config"
	"github.com/openfaas-incubator/of-watchdog/executor"
	"github.com/openfaas-incubator/of-watchdog/metrics"
	limiter "github.com/openfaas/faas-middleware/concurrency-limiter"
)

var (
	acceptingConnections int32
)

func main() {
	flag.Parse()

	switch flag.Arg(0) {
	case "healthcheck":
		if lockFilePresent() {
			os.Exit(0)
		}

		os.Exit(1)
	}

	atomic.StoreInt32(&acceptingConnections, 0)

	watchdogConfig := config.New(os.Environ())

	if len(watchdogConfig.FunctionProcess) == 0 && watchdogConfig.OperationalMode != config.ModeStatic {
		fmt.Fprintf(os.Stderr, "Provide a \"function_process\" or \"fprocess\" environmental variable for your function.\n")
		os.Exit(1)
	}

	requestHandler := buildRequestHandler(watchdogConfig)

	log.Printf("OperationalMode: %s\n", config.WatchdogMode(watchdogConfig.OperationalMode))

	httpMetrics := metrics.NewHttp()
	http.HandleFunc("/", metrics.InstrumentHandler(requestHandler, httpMetrics))
	http.HandleFunc("/_/health", makeHealthHandler())

	metricsServer := metrics.MetricsServer{}
	metricsServer.Register(watchdogConfig.MetricsPort)

	cancel := make(chan bool)

	go metricsServer.Serve(cancel)

	shutdownTimeout := watchdogConfig.HTTPWriteTimeout
	s := &http.Server{
		Addr:           fmt.Sprintf(":%d", watchdogConfig.TCPPort),
		ReadTimeout:    watchdogConfig.HTTPReadTimeout,
		WriteTimeout:   watchdogConfig.HTTPWriteTimeout,
		MaxHeaderBytes: 1 << 20, // Max header of 1MB
	}

	log.Printf("Timeouts: read: %s, write: %s hard: %s.\n",
		watchdogConfig.HTTPReadTimeout,
		watchdogConfig.HTTPWriteTimeout,
		watchdogConfig.ExecTimeout)
	log.Printf("Listening on port: %d\n", watchdogConfig.TCPPort)

	listenUntilShutdown(shutdownTimeout, s, watchdogConfig.SuppressLock)
}

func markUnhealthy() error {
	atomic.StoreInt32(&acceptingConnections, 0)

	path := filepath.Join(os.TempDir(), ".lock")
	log.Printf("Removing lock-file : %s\n", path)
	removeErr := os.Remove(path)
	return removeErr
}

func listenUntilShutdown(shutdownTimeout time.Duration, s *http.Server, suppressLock bool) {

	idleConnsClosed := make(chan struct{})
	go func() {
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, syscall.SIGTERM)

		<-sig

		log.Printf("SIGTERM received.. shutting down server in %s\n", shutdownTimeout.String())

		healthErr := markUnhealthy()

		if healthErr != nil {
			log.Printf("Unable to mark unhealthy during shutdown: %s\n", healthErr.Error())
		}

		<-time.Tick(shutdownTimeout)

		if err := s.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			log.Printf("Error in Shutdown: %v", err)
		}

		log.Printf("No new connections allowed. Exiting in: %s\n", shutdownTimeout.String())

		<-time.Tick(shutdownTimeout)

		close(idleConnsClosed)
	}()

	// Run the HTTP server in a separate go-routine.
	go func() {
		if err := s.ListenAndServe(); err != http.ErrServerClosed {
			log.Printf("Error ListenAndServe: %v", err)
			close(idleConnsClosed)
		}
	}()

	if suppressLock == false {
		path, writeErr := createLockFile()

		if writeErr != nil {
			log.Panicf("Cannot write %s. To disable lock-file set env suppress_lock=true.\n Error: %s.\n", path, writeErr.Error())
		}
	} else {
		log.Println("Warning: \"suppress_lock\" is enabled. No automated health-checks will be in place for your function.")

		atomic.StoreInt32(&acceptingConnections, 1)
	}

	<-idleConnsClosed
}

func buildRequestHandler(watchdogConfig config.WatchdogConfig) http.Handler {
	var requestHandler http.HandlerFunc

	switch watchdogConfig.OperationalMode {
	case config.ModeStreaming:
		requestHandler = makeForkRequestHandler(watchdogConfig)
		break
	case config.ModeSerializing:
		requestHandler = makeSerializingForkRequestHandler(watchdogConfig)
		break
	case config.ModeAfterBurn:
		requestHandler = makeAfterBurnRequestHandler(watchdogConfig)
		break
	case config.ModeHTTP:
		requestHandler = makeHTTPRequestHandler(watchdogConfig)
		break
	case config.ModeStatic:
		requestHandler = makeStaticRequestHandler(watchdogConfig)
	default:
		log.Panicf("unknown watchdog mode: %d", watchdogConfig.OperationalMode)
		break
	}

	if watchdogConfig.MaxInflight > 0 {
		return limiter.NewConcurrencyLimiter(requestHandler, watchdogConfig.MaxInflight)
	}

	return requestHandler
}

// createLockFile returns a path to a lock file and/or an error
// if the file could not be created.
func createLockFile() (string, error) {
	path := filepath.Join(os.TempDir(), ".lock")
	log.Printf("Writing lock-file to: %s\n", path)

	mkdirErr := os.MkdirAll(os.TempDir(), os.ModePerm)
	if mkdirErr != nil {
		return path, mkdirErr
	}

	writeErr := ioutil.WriteFile(path, []byte{}, 0660)
	if writeErr != nil {
		return path, writeErr
	}

	atomic.StoreInt32(&acceptingConnections, 1)
	return path, nil
}

func makeAfterBurnRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {

	commandName, arguments := watchdogConfig.Process()
	functionInvoker := executor.AfterBurnFunctionRunner{
		Process:     commandName,
		ProcessArgs: arguments,
	}

	log.Printf("Forking %s %s\n", commandName, arguments)
	functionInvoker.Start()

	return func(w http.ResponseWriter, r *http.Request) {

		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
		}

		functionInvoker.Mutex.Lock()

		err := functionInvoker.Run(req, r.ContentLength, r, w)

		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		}

		functionInvoker.Mutex.Unlock()
	}
}

func makeSerializingForkRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	functionInvoker := executor.SerializingForkFunctionRunner{
		ExecTimeout: watchdogConfig.ExecTimeout,
	}

	return func(w http.ResponseWriter, r *http.Request) {

		var environment []string

		if watchdogConfig.InjectCGIHeaders {
			environment = getEnvironment(r)
		}

		commandName, arguments := watchdogConfig.Process()
		req := executor.FunctionRequest{
			Process:       commandName,
			ProcessArgs:   arguments,
			InputReader:   r.Body,
			ContentLength: &r.ContentLength,
			OutputWriter:  w,
			Environment:   environment,
		}

		w.Header().Set("Content-Type", watchdogConfig.ContentType)
		err := functionInvoker.Run(req, w)
		if err != nil {
			log.Println(err)
		}
	}
}

func makeForkRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	functionInvoker := executor.ForkFunctionRunner{
		ExecTimeout: watchdogConfig.ExecTimeout,
	}

	return func(w http.ResponseWriter, r *http.Request) {

		var environment []string

		if watchdogConfig.InjectCGIHeaders {
			environment = getEnvironment(r)
		}

		commandName, arguments := watchdogConfig.Process()
		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
			Environment:  environment,
		}

		w.Header().Set("Content-Type", watchdogConfig.ContentType)
		err := functionInvoker.Run(req)
		if err != nil {
			log.Println(err.Error())

			// Probably cannot write to client if we already have written a header
			// w.WriteHeader(500)
			// w.Write([]byte(err.Error()))
		}
	}
}

func getEnvironment(r *http.Request) []string {
	var envs []string

	envs = os.Environ()
	for k, v := range r.Header {
		kv := fmt.Sprintf("Http_%s=%s", strings.Replace(k, "-", "_", -1), v[0])
		envs = append(envs, kv)
	}
	envs = append(envs, fmt.Sprintf("Http_Method=%s", r.Method))

	if len(r.URL.RawQuery) > 0 {
		envs = append(envs, fmt.Sprintf("Http_Query=%s", r.URL.RawQuery))
	}

	if len(r.URL.Path) > 0 {
		envs = append(envs, fmt.Sprintf("Http_Path=%s", r.URL.Path))
	}

	return envs
}

func makeHTTPRequestHandler(watchdogConfig config.WatchdogConfig) func(http.ResponseWriter, *http.Request) {
	commandName, arguments := watchdogConfig.Process()
	functionInvoker := executor.HTTPFunctionRunner{
		ExecTimeout:    watchdogConfig.ExecTimeout,
		Process:        commandName,
		ProcessArgs:    arguments,
		BufferHTTPBody: watchdogConfig.BufferHTTPBody,
	}

	if len(watchdogConfig.UpstreamURL) == 0 {
		log.Fatal(`For "mode=http" you must specify a valid URL for "http_upstream_url"`)
	}

	urlValue, upstreamURLErr := url.Parse(watchdogConfig.UpstreamURL)
	if upstreamURLErr != nil {
		log.Fatal(upstreamURLErr)
	}
	functionInvoker.UpstreamURL = urlValue

	fmt.Printf("Forking - %s %s\n", commandName, arguments)
	functionInvoker.Start()

	return func(w http.ResponseWriter, r *http.Request) {

		req := executor.FunctionRequest{
			Process:      commandName,
			ProcessArgs:  arguments,
			InputReader:  r.Body,
			OutputWriter: w,
		}

		if r.Body != nil {
			defer r.Body.Close()
		}

		err := functionInvoker.Run(req, r.ContentLength, r, w)

		if err != nil {
			w.WriteHeader(500)
			w.Write([]byte(err.Error()))
		}

	}
}

func makeStaticRequestHandler(watchdogConfig config.WatchdogConfig) http.HandlerFunc {
	if watchdogConfig.StaticPath == "" {
		log.Fatal(`For mode=static you must specify the "static_path" to serve`)
	}

	log.Printf("Serving files at %s", watchdogConfig.StaticPath)
	return http.FileServer(http.Dir(watchdogConfig.StaticPath)).ServeHTTP
}

func lockFilePresent() bool {
	path := filepath.Join(os.TempDir(), ".lock")
	if _, err := os.Stat(path); os.IsNotExist(err) {
		return false
	}
	return true
}

func makeHealthHandler() func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodGet:
			if atomic.LoadInt32(&acceptingConnections) == 0 || lockFilePresent() == false {
				w.WriteHeader(http.StatusServiceUnavailable)
				return
			}

			w.WriteHeader(http.StatusOK)
			w.Write([]byte("OK"))

			break
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

type disallowDirectoryListing http.Dir

func (fs disallowDirectoryListing) Open(name string) (http.File, error) {
	f, err := http.Dir(fs).Open(name)
	if err != nil {
		return nil, err
	}
	if stat, _ := f.Stat(); stat.IsDir() {
		return nil, os.ErrNotExist
	}
	return f, nil
}

type UnsafeHandlerIface interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request) error
}

type UnsafeHandler struct {
	UnsafeHandlerIface
}

func (ctx UnsafeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method == "HEAD" {
		r.Method = "GET"
	}
	if err := ctx.UnsafeHandlerIface.ServeHTTP(w, r); err != nil {
		log.Println("error rendering template", r.URL.Path, err.Error())
		if err = RenderError(w, http.StatusInternalServerError, ""); err != nil {
			log.Println("error rendering error", err.Error())
			http.Error(w, "Error while rendering error message.", http.StatusInternalServerError)
		}
	}
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	bind := flag.String("bind", ":8000", "The network ([ip]:port) to bind on.")
	addr := flag.String("addr", "", "The public address (host[:port]) of this node.")
	ephemeral := flag.Bool("ephemeral", false, "Use a process-local in-memory userless database. Can only be enabled in joint mode.")
	flag.Parse()

	if *ephemeral && *addr != "" {
		log.Fatal("-ephemeral cannot be used with -addr. Running as a part of a cluster requires coordination through a database.")
	}

	ctx := Context{
		Database:        NewAnonDatabase(),
		SecureKey:       []byte("12345678901234567890123456789012"),
		StreamKeepAlive: 10 * time.Second,
	}
	if !*ephemeral {
		var err error
		if ctx.Database, err = NewSQLDatabase(*addr, "sqlite3", "development.db"); err != nil {
			log.Fatal("Could not connect to database: ", err)
		}
	}

	mux := http.NewServeMux()
	mux.Handle("/static/", http.FileServer(disallowDirectoryListing(".")))
	mux.Handle("/stream/", UnsafeHandler{NewRetransmissionHandler(&ctx)})
	mux.Handle("/", UnsafeHandler{NewUIHandler(&ctx)})
	log.Fatal(http.ListenAndServe(*bind, mux))
}
<commit_msg>Double the stream timeout.<commit_after>package main

import (
	"flag"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"math/rand"
	"net/http"
	"os"
	"time"
)

type disallowDirectoryListing http.Dir

func (fs disallowDirectoryListing) Open(name string) (http.File, error) {
	f, err := http.Dir(fs).Open(name)
	if err != nil {
		return nil, err
	}
	if stat, _ := f.Stat(); stat.IsDir() {
		return nil, os.ErrNotExist
	}
	return f, nil
}

type UnsafeHandlerIface interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request) error
}

type UnsafeHandler struct {
	UnsafeHandlerIface
}

func (ctx UnsafeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method == "HEAD" {
		r.Method = "GET"
	}
	if err := ctx.UnsafeHandlerIface.ServeHTTP(w, r); err != nil {
		log.Println("error rendering template", r.URL.Path, err.Error())
		if err = RenderError(w, http.StatusInternalServerError, ""); err != nil {
			log.Println("error rendering error", err.Error())
			http.Error(w, "Error while rendering error message.", http.StatusInternalServerError)
		}
	}
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	bind := flag.String("bind", ":8000", "The network ([ip]:port) to bind on.")
	addr := flag.String("addr", "", "The public address (host[:port]) of this node.")
	ephemeral := flag.Bool("ephemeral", false, "Use a process-local in-memory userless database. Can only be enabled in joint mode.")
	flag.Parse()

	if *ephemeral && *addr != "" {
		log.Fatal("-ephemeral cannot be used with -addr. Running as a part of a cluster requires coordination through a database.")
	}

	ctx := Context{
		Database:        NewAnonDatabase(),
		SecureKey:       []byte("12345678901234567890123456789012"),
		StreamKeepAlive: 20 * time.Second,
	}
	if !*ephemeral {
		var err error
		if ctx.Database, err = NewSQLDatabase(*addr, "sqlite3", "development.db"); err != nil {
			log.Fatal("Could not connect to database: ", err)
		}
	}

	mux := http.NewServeMux()
	mux.Handle("/static/", http.FileServer(disallowDirectoryListing(".")))
	mux.Handle("/stream/", UnsafeHandler{NewRetransmissionHandler(&ctx)})
	mux.Handle("/", UnsafeHandler{NewUIHandler(&ctx)})
	log.Fatal(http.ListenAndServe(*bind, mux))
}
<|endoftext|>


<commit_before>package wire

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"

	"golang.org/x/crypto/ripemd160"

	. "github.com/tendermint/go-common"
)

func BinaryBytes(o interface{}) []byte {
	w, n, err := new(bytes.Buffer), new(int), new(error)
	WriteBinary(o, w, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return w.Bytes()
}

// o: a pointer to the object to be filled
func ReadBinaryBytes(d []byte, o interface{}) error {
	r, n, err := bytes.NewBuffer(d), new(int), new(error)
	ReadBinaryPtr(o, r, 0, n, err)
	return *err
}

func JSONBytes(o interface{}) []byte {
	w, n, err := new(bytes.Buffer), new(int), new(error)
	WriteJSON(o, w, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return w.Bytes()
}

// NOTE: inefficient
func JSONBytesPretty(o interface{}) []byte {
	jsonBytes := JSONBytes(o)
	var object interface{}
	err := json.Unmarshal(jsonBytes, &object)
	if err != nil {
		PanicSanity(err)
	}
	jsonBytes, err = json.MarshalIndent(object, "", "\t")
	if err != nil {
		PanicSanity(err)
	}
	return jsonBytes
}

// NOTE: does not care about the type, only the binary representation.
func BinaryEqual(a, b interface{}) bool {
	aBytes := BinaryBytes(a)
	bBytes := BinaryBytes(b)
	return bytes.Equal(aBytes, bBytes)
}

// NOTE: does not care about the type, only the binary representation.
func BinaryCompare(a, b interface{}) int {
	aBytes := BinaryBytes(a)
	bBytes := BinaryBytes(b)
	return bytes.Compare(aBytes, bBytes)
}

// NOTE: only use this if you need 32 bytes.
func BinarySha256(o interface{}) []byte {
	hasher, n, err := sha256.New(), new(int), new(error)
	WriteBinary(o, hasher, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return hasher.Sum(nil)
}

// NOTE: The default hash function is Ripemd160.
func BinaryRipemd160(o interface{}) []byte {
	hasher, n, err := ripemd160.New(), new(int), new(error)
	WriteBinary(o, hasher, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return hasher.Sum(nil)
}
<commit_msg>Add ReadJSONBytes<commit_after>package wire

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"

	"golang.org/x/crypto/ripemd160"

	. "github.com/tendermint/go-common"
)

func BinaryBytes(o interface{}) []byte {
	w, n, err := new(bytes.Buffer), new(int), new(error)
	WriteBinary(o, w, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return w.Bytes()
}

// o: a pointer to the object to be filled
func ReadBinaryBytes(d []byte, o interface{}) error {
	r, n, err := bytes.NewBuffer(d), new(int), new(error)
	ReadBinaryPtr(o, r, 0, n, err)
	return *err
}

func JSONBytes(o interface{}) []byte {
	w, n, err := new(bytes.Buffer), new(int), new(error)
	WriteJSON(o, w, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return w.Bytes()
}

// NOTE: inefficient
func JSONBytesPretty(o interface{}) []byte {
	jsonBytes := JSONBytes(o)
	var object interface{}
	err := json.Unmarshal(jsonBytes, &object)
	if err != nil {
		PanicSanity(err)
	}
	jsonBytes, err = json.MarshalIndent(object, "", "\t")
	if err != nil {
		PanicSanity(err)
	}
	return jsonBytes
}

// o: a pointer to the object to be filled
func ReadJSONBytes(d []byte, o interface{}) (err error) {
	ReadJSONPtr(o, d, &err)
	return
}

// NOTE: does not care about the type, only the binary representation.
func BinaryEqual(a, b interface{}) bool {
	aBytes := BinaryBytes(a)
	bBytes := BinaryBytes(b)
	return bytes.Equal(aBytes, bBytes)
}

// NOTE: does not care about the type, only the binary representation.
func BinaryCompare(a, b interface{}) int {
	aBytes := BinaryBytes(a)
	bBytes := BinaryBytes(b)
	return bytes.Compare(aBytes, bBytes)
}

// NOTE: only use this if you need 32 bytes.
func BinarySha256(o interface{}) []byte {
	hasher, n, err := sha256.New(), new(int), new(error)
	WriteBinary(o, hasher, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return hasher.Sum(nil)
}

// NOTE: The default hash function is Ripemd160.
func BinaryRipemd160(o interface{}) []byte {
	hasher, n, err := ripemd160.New(), new(int), new(error)
	WriteBinary(o, hasher, n, err)
	if *err != nil {
		PanicSanity(*err)
	}
	return hasher.Sum(nil)
}
<|endoftext|>


<commit_before>package chi

import (
	"net/http"
	"strings"
)

// chain builds a http.Handler composed of middlewares and endpoint handler in the
// order they are passed.
func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
	// Return ahead of time if there aren't any middlewares for the chain
	if middlewares == nil || len(middlewares) == 0 {
		return endpoint
	}

	// Wrap the end handler with the middleware chain
	h := middlewares[len(middlewares)-1](endpoint)
	for i := len(middlewares) - 2; i >= 0; i-- {
		h = middlewares[i](h)
	}

	return h
}

// Respond with just the allowed methods, as required by RFC2616 for
// 405 Method not allowed.
func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
	methods := make([]string, len(methodMap))
	i := 0
	for m := range methodMap {
		methods[i] = m // still faster than append to array with capacity
		i++
	}

	w.Header().Add("Allow", strings.Join(methods, ","))
	w.WriteHeader(405)
	w.Write([]byte(http.StatusText(405)))
}
<commit_msg>Invalid header, since its not actually a list of allowed methods for the route<commit_after>package chi

import "net/http"

// chain builds a http.Handler composed of middlewares and endpoint handler in the
// order they are passed.
func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
	// Return ahead of time if there aren't any middlewares for the chain
	if middlewares == nil || len(middlewares) == 0 {
		return endpoint
	}

	// Wrap the end handler with the middleware chain
	h := middlewares[len(middlewares)-1](endpoint)
	for i := len(middlewares) - 2; i >= 0; i-- {
		h = middlewares[i](h)
	}

	return h
}

// Respond with just the allowed methods, as required by RFC2616 for
// 405 Method not allowed.
func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(405)
	w.Write([]byte(http.StatusText(405)))
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"unicode"
)

func TrimGLCmdPrefix(str string) string {
	if strings.HasPrefix(str, "gl") {
		return strings.TrimPrefix(str, "gl")
	}
	if strings.HasPrefix(str, "glx") {
		return strings.TrimPrefix(str, "glx")
	}
	if strings.HasPrefix(str, "wgl") {
		return strings.TrimPrefix(str, "wgl")
	}
	return str
}

func TrimGLEnumPrefix(str string) string {
	t := str
	p := ""
	if strings.HasPrefix(str, "GL_") {
		t = strings.TrimPrefix(t, "GL_")
		p = "GL_"
	} else if strings.HasPrefix(str, "GLX_") {
		t = strings.TrimPrefix(str, "GLX_")
		p = "GLX_"
	} else if strings.HasPrefix(str, "WGL_") {
		t = strings.TrimPrefix(str, "WGL_")
		p = "WGL_"
	}
	if strings.IndexAny(t, "0123456789") == 0 {
		return p + t
	}
	return t
}

func RenameIfReservedCWord(word string) string {
	switch word {
	case "near", "far":
		return fmt.Sprintf("%s", word)
	}
	return word
}

func RenameIfReservedGoWord(word string) string {
	switch word {
	case "func", "type", "struct", "range", "map", "string":
		return fmt.Sprintf("gl%s", word)
	}
	return word
}

// Writer that removes whitespace- or comment-only lines delimited by \n
// A necessary evil to work around how text/template handles whitespace
type BlankLineStrippingWriter struct {
	output io.Writer
	buf    *bytes.Buffer
}

func NewBlankLineStrippingWriter(wrapped io.Writer) *BlankLineStrippingWriter {
	return &BlankLineStrippingWriter{wrapped, new(bytes.Buffer)}
}

func isBlank(line string) bool {
	blank := true
	for _, ch := range line {
		if !unicode.IsSpace(ch) && ch != '/' {
			blank = false
			break
		}
	}
	return blank
}

func (w BlankLineStrippingWriter) Write(p []byte) (n int, err error) {
	// Buffer the current write
	nn, err := w.buf.Write(p)
	if nn != len(p) || err != nil {
		return 0, err
	}
	// Write non-empty lines from the buffer
	for {
		line, err := w.buf.ReadString('\n')
		switch err {
		case nil:
			if !isBlank(line) {
				nn, e := w.output.Write([]byte(line))
				if nn != len(line) || e != nil {
					return n, err
				}
			}
			n += len(line)
		case io.EOF:
			// Did not have a whole line to read, rebuffer the unconsumed data
			w.buf.Write([]byte(line))
			return 0, nil
		default:
			return 0, err
		}
	}
	return n, err
}
<commit_msg>Minor renaming in util.<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"strings"
	"unicode"
)

func TrimGLCmdPrefix(cmdName string) string {
	if strings.HasPrefix(cmdName, "gl") {
		return strings.TrimPrefix(cmdName, "gl")
	}
	if strings.HasPrefix(cmdName, "glx") {
		return strings.TrimPrefix(cmdName, "glx")
	}
	if strings.HasPrefix(cmdName, "wgl") {
		return strings.TrimPrefix(cmdName, "wgl")
	}
	return cmdName
}

func TrimGLEnumPrefix(enumName string) string {
	trimmed := enumName
	prefix := ""
	if strings.HasPrefix(enumName, "GL_") {
		trimmed = strings.TrimPrefix(enumName, "GL_")
		prefix = "GL_"
	} else if strings.HasPrefix(enumName, "GLX_") {
		trimmed = strings.TrimPrefix(enumName, "GLX_")
		prefix = "GLX_"
	} else if strings.HasPrefix(enumName, "WGL_") {
		trimmed = strings.TrimPrefix(enumName, "WGL_")
		prefix = "WGL_"
	}
	if strings.IndexAny(t, "0123456789") == 0 {
		return prefix + trimmed
	}
	return trimmed
}

func RenameIfReservedCWord(word string) string {
	switch word {
	case "near", "far":
		return fmt.Sprintf("%s", word)
	}
	return word
}

func RenameIfReservedGoWord(word string) string {
	switch word {
	case "func", "type", "struct", "range", "map", "string":
		return fmt.Sprintf("gl%s", word)
	}
	return word
}

// Writer that removes whitespace- or comment-only lines delimited by \n
// A necessary evil to work around how text/template handles whitespace
type BlankLineStrippingWriter struct {
	output io.Writer
	buf    *bytes.Buffer
}

func NewBlankLineStrippingWriter(wrapped io.Writer) *BlankLineStrippingWriter {
	return &BlankLineStrippingWriter{wrapped, new(bytes.Buffer)}
}

func isBlank(line string) bool {
	blank := true
	for _, ch := range line {
		if !unicode.IsSpace(ch) && ch != '/' {
			blank = false
			break
		}
	}
	return blank
}

func (w BlankLineStrippingWriter) Write(p []byte) (n int, err error) {
	// Buffer the current write
	nn, err := w.buf.Write(p)
	if nn != len(p) || err != nil {
		return 0, err
	}
	// Write non-empty lines from the buffer
	for {
		line, err := w.buf.ReadString('\n')
		switch err {
		case nil:
			if !isBlank(line) {
				nn, e := w.output.Write([]byte(line))
				if nn != len(line) || e != nil {
					return n, err
				}
			}
			n += len(line)
		case io.EOF:
			// Did not have a whole line to read, rebuffer the unconsumed data
			w.buf.Write([]byte(line))
			return 0, nil
		default:
			return 0, err
		}
	}
	return n, err
}
<|endoftext|>