<commit_before>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"
	"text/tabwriter"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/rackerlabs/libcarina"
)

func writeCluster(w *tabwriter.Writer, cluster *libcarina.Cluster) (err error) {
	s := strings.Join([]string{cluster.ClusterName,
		cluster.Username,
		cluster.Flavor,
		cluster.Image,
		fmt.Sprintf("%v", cluster.Nodes),
		cluster.Status}, "\t")
	_, err = w.Write([]byte(s + "\n"))
	return
}

func writeCredentials(w *tabwriter.Writer, creds *libcarina.Credentials, pth string) (err error) {
	// TODO: Prompt when file already exists?
	for fname, b := range creds.Files {
		p := path.Join(pth, fname)
		err = ioutil.WriteFile(p, b, 0600)
		if err != nil {
			return err
		}
	}

	return nil
}

// Application is, our, well, application
type Application struct {
	*Context
	*kingpin.Application
}

// Command is a command needing a ClusterClient
type Command struct {
	*Context
	*kingpin.CmdClause
}

// Context context for the  App
type Context struct {
	ClusterClient *libcarina.ClusterClient
	TabWriter     *tabwriter.Writer
	Username      string
	APIKey        string
	Endpoint      string
}

// ClusterCommand is a Command with a ClusterName set
type ClusterCommand struct {
	*Command
	ClusterName string
}

// CredentialsCommand keeps context about the download command
type CredentialsCommand struct {
	*ClusterCommand
	Path string
}

// CreateCommand keeps context about the create command
type CreateCommand struct {
	*ClusterCommand

	// Options passed along to Carina's API
	Nodes     int
	AutoScale bool

	Wait bool

	// TODO: See if setting flavor or image makes sense, even if the API takes it
	// Flavor    string
	// Image     string
}

// GrowCommand keeps context about the number of nodes to scale by
type GrowCommand struct {
	*ClusterCommand
	Nodes int
}

// New creates a new Application
func New() *Application {

	app := kingpin.New("carina", "command line interface to launch and work with Docker Swarm clusters")

	cap := new(Application)
	ctx := new(Context)

	cap.Application = app
	cap.Context = ctx

	cap.PreAction(cap.Auth)

	cap.Flag("username", "Rackspace username - can also set env var RACKSPACE_USERNAME").OverrideDefaultFromEnvar("RACKSPACE_USERNAME").StringVar(&ctx.Username)
	cap.Flag("api-key", "Rackspace API Key - can also set env var RACKSPACE_APIKEY").OverrideDefaultFromEnvar("RACKSPACE_APIKEY").PlaceHolder("RACKSPACE_APIKEY").StringVar(&ctx.APIKey)
	cap.Flag("endpoint", "Carina API endpoint").Default(libcarina.BetaEndpoint).StringVar(&ctx.Endpoint)

	writer := new(tabwriter.Writer)
	writer.Init(os.Stdout, 0, 8, 1, '\t', 0)

	ctx.TabWriter = writer

	listCommand := cap.NewCommand(ctx, "list", "list swarm clusters")
	listCommand.Action(listCommand.List)

	getCommand := cap.NewClusterCommand(ctx, "get", "get information about a swarm cluster")
	getCommand.Action(getCommand.Get)

	deleteCommand := cap.NewClusterCommand(ctx, "delete", "delete a swarm cluster")
	deleteCommand.Action(deleteCommand.Delete)

	createCommand := new(CreateCommand)
	createCommand.ClusterCommand = cap.NewClusterCommand(ctx, "create", "create a swarm cluster")
	createCommand.Flag("wait", "wait for swarm cluster completion").BoolVar(&createCommand.Wait)
	createCommand.Flag("nodes", "number of nodes for the initial cluster").Default("1").IntVar(&createCommand.Nodes)
	createCommand.Flag("autoscale", "whether autoscale is on or off").BoolVar(&createCommand.AutoScale)
	createCommand.Action(createCommand.Create)

	credentialsCommand := new(CredentialsCommand)
	credentialsCommand.ClusterCommand = cap.NewClusterCommand(ctx, "credentials", "download credentials")
	credentialsCommand.Flag("path", "path to write credentials out to").StringVar(&credentialsCommand.Path)
	credentialsCommand.Action(credentialsCommand.Download)

	growCommand := new(GrowCommand)
	growCommand.ClusterCommand = cap.NewClusterCommand(ctx, "grow", "Grow a cluster by the requested number of nodes")
	growCommand.Flag("nodes", "number of nodes to increase the cluster by").Required().IntVar(&growCommand.Nodes)
	growCommand.Action(growCommand.Grow)

	return cap
}

// NewCommand creates a command that relies on Auth
func (app *Application) NewCommand(ctx *Context, name, help string) *Command {
	carina := new(Command)
	carina.Context = ctx
	carina.CmdClause = app.Command(name, help)
	return carina
}

// NewClusterCommand is a command that uses a cluster name
func (app *Application) NewClusterCommand(ctx *Context, name, help string) *ClusterCommand {
	cc := new(ClusterCommand)
	cc.Command = app.NewCommand(ctx, name, help)
	cc.Arg("cluster-name", "name of the cluster").Required().StringVar(&cc.ClusterName)
	return cc
}

// Auth does the authentication
func (app *Application) Auth(pc *kingpin.ParseContext) (err error) {
	carina := app.Context
	carina.ClusterClient, err = libcarina.NewClusterClient(carina.Endpoint, carina.Username, carina.APIKey)
	return err
}

// List the current swarm clusters
func (carina *Command) List(pc *kingpin.ParseContext) (err error) {
	clusterList, err := carina.ClusterClient.List()
	if err != nil {
		return err
	}

	headerFields := []string{
		"ClusterName",
		"Username",
		"Flavor",
		"Image",
		"Nodes",
		"Status",
	}
	s := strings.Join(headerFields, "\t")

	_, err = carina.TabWriter.Write([]byte(s + "\n"))
	if err != nil {
		return err
	}

	for _, cluster := range clusterList {
		err = writeCluster(carina.TabWriter, &cluster)
		if err != nil {
			return err
		}
	}
	err = carina.TabWriter.Flush()
	return err
}

type clusterFunc func(clusterName string) (*libcarina.Cluster, error)

// Does an func against a cluster then returns the new cluster representation
func (carina *ClusterCommand) clusterOp(clop clusterFunc) (err error) {
	cluster, err := clop(carina.ClusterName)
	if err != nil {
		return err
	}

	err = writeCluster(carina.TabWriter, cluster)
	if err != nil {
		return err
	}
	return carina.TabWriter.Flush()
}

// Get an individual cluster
func (carina *ClusterCommand) Get(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(carina.ClusterClient.Get)
}

// Delete a cluster
func (carina *ClusterCommand) Delete(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(carina.ClusterClient.Delete)
}

// Create a cluster
func (carina *CreateCommand) Create(pc *kingpin.ParseContext) (err error) {
	if carina.Nodes < 1 {
		return errors.New("nodes must be >= 1")
	}

	nodes := libcarina.Number(carina.Nodes)

	c := libcarina.Cluster{
		ClusterName: carina.ClusterName,
		Nodes:       nodes,
		AutoScale:   carina.AutoScale,
	}

	cluster, err := carina.ClusterClient.Create(c)

	// Transitions past point of "new" or "building" are assumed to be states we
	// can stop on.
	if carina.Wait {
		for cluster.Status == "new" || cluster.Status == "building" {
			time.Sleep(13 * time.Second)
			cluster, err = carina.ClusterClient.Get(carina.ClusterName)
			if err != nil {
				break
			}
		}
	}

	if err != nil {
		return err
	}

	err = writeCluster(carina.TabWriter, cluster)

	if err != nil {
		return err
	}
	return carina.TabWriter.Flush()
}

// Grow increase the size of the given cluster
func (carina *GrowCommand) Grow(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(func(clusterName string) (*libcarina.Cluster, error) {
		return carina.ClusterClient.Grow(clusterName, carina.Nodes)
	})
}

// Download credentials for a cluster
func (carina *CredentialsCommand) Download(pc *kingpin.ParseContext) (err error) {
	credentials, err := carina.ClusterClient.GetCredentials(carina.ClusterName)
	if err != nil {
		return err
	}

	p := path.Clean(carina.Path)

	if p != "." {
		err = os.MkdirAll(p, 0777)
	}

	if err != nil {
		return err
	}

	err = writeCredentials(carina.TabWriter, credentials, p)
	if err != nil {
		return err
	}

	if runtime.GOOS == "windows" {
		fmt.Fprintf(os.Stdout, "\"%v\"\n", path.Join(p, "docker.cmd"))
		fmt.Fprintf(os.Stdout, "# Run the above to set your docker environment\n")
	} else {
		fmt.Fprintf(os.Stdout, "source \"%v\"\n", path.Join(p, "docker.env"))
		fmt.Fprintf(os.Stdout, "# Run the above or eval a subshell with your arguments to %v\n", os.Args[0])
		fmt.Fprintf(os.Stdout, "# eval \"$( %v command... )\" \n", os.Args[0])
	}

	err = carina.TabWriter.Flush()
	return err
}

func main() {
	app := New()
	kingpin.MustParse(app.Parse(os.Args[1:]))
}
<commit_msg>Reorganize where functions are.<commit_after>package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"strings"
	"text/tabwriter"
	"time"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/rackerlabs/libcarina"
)

// Application is, our, well, application
type Application struct {
	*Context
	*kingpin.Application
}

// Command is a command needing a ClusterClient
type Command struct {
	*Context
	*kingpin.CmdClause
}

// Context context for the  App
type Context struct {
	ClusterClient *libcarina.ClusterClient
	TabWriter     *tabwriter.Writer
	Username      string
	APIKey        string
	Endpoint      string
}

// ClusterCommand is a Command with a ClusterName set
type ClusterCommand struct {
	*Command
	ClusterName string
}

// CredentialsCommand keeps context about the download command
type CredentialsCommand struct {
	*ClusterCommand
	Path string
}

// CreateCommand keeps context about the create command
type CreateCommand struct {
	*ClusterCommand

	// Options passed along to Carina's API
	Nodes     int
	AutoScale bool

	// Whether to wait until the cluster is created (or errored)
	Wait bool

	// TODO: See if setting flavor or image makes sense, even if the API takes it
	// Flavor    string
	// Image     string
}

// GrowCommand keeps context about the number of nodes to scale by
type GrowCommand struct {
	*ClusterCommand
	Nodes int
}

// New creates a new Application
func New() *Application {

	app := kingpin.New("carina", "command line interface to launch and work with Docker Swarm clusters")

	cap := new(Application)
	ctx := new(Context)

	cap.Application = app
	cap.Context = ctx

	cap.PreAction(cap.Auth)

	cap.Flag("username", "Rackspace username - can also set env var RACKSPACE_USERNAME").OverrideDefaultFromEnvar("RACKSPACE_USERNAME").StringVar(&ctx.Username)
	cap.Flag("api-key", "Rackspace API Key - can also set env var RACKSPACE_APIKEY").OverrideDefaultFromEnvar("RACKSPACE_APIKEY").PlaceHolder("RACKSPACE_APIKEY").StringVar(&ctx.APIKey)
	cap.Flag("endpoint", "Carina API endpoint").Default(libcarina.BetaEndpoint).StringVar(&ctx.Endpoint)

	writer := new(tabwriter.Writer)
	writer.Init(os.Stdout, 0, 8, 1, '\t', 0)

	ctx.TabWriter = writer

	listCommand := cap.NewCommand(ctx, "list", "list swarm clusters")
	listCommand.Action(listCommand.List)

	getCommand := cap.NewClusterCommand(ctx, "get", "get information about a swarm cluster")
	getCommand.Action(getCommand.Get)

	deleteCommand := cap.NewClusterCommand(ctx, "delete", "delete a swarm cluster")
	deleteCommand.Action(deleteCommand.Delete)

	createCommand := new(CreateCommand)
	createCommand.ClusterCommand = cap.NewClusterCommand(ctx, "create", "create a swarm cluster")
	createCommand.Flag("wait", "wait for swarm cluster completion").BoolVar(&createCommand.Wait)
	createCommand.Flag("nodes", "number of nodes for the initial cluster").Default("1").IntVar(&createCommand.Nodes)
	createCommand.Flag("autoscale", "whether autoscale is on or off").BoolVar(&createCommand.AutoScale)
	createCommand.Action(createCommand.Create)

	credentialsCommand := new(CredentialsCommand)
	credentialsCommand.ClusterCommand = cap.NewClusterCommand(ctx, "credentials", "download credentials")
	credentialsCommand.Flag("path", "path to write credentials out to").StringVar(&credentialsCommand.Path)
	credentialsCommand.Action(credentialsCommand.Download)

	growCommand := new(GrowCommand)
	growCommand.ClusterCommand = cap.NewClusterCommand(ctx, "grow", "Grow a cluster by the requested number of nodes")
	growCommand.Flag("nodes", "number of nodes to increase the cluster by").Required().IntVar(&growCommand.Nodes)
	growCommand.Action(growCommand.Grow)

	return cap
}

// NewCommand creates a command that relies on Auth
func (app *Application) NewCommand(ctx *Context, name, help string) *Command {
	carina := new(Command)
	carina.Context = ctx
	carina.CmdClause = app.Command(name, help)
	return carina
}

// NewClusterCommand is a command that uses a cluster name
func (app *Application) NewClusterCommand(ctx *Context, name, help string) *ClusterCommand {
	cc := new(ClusterCommand)
	cc.Command = app.NewCommand(ctx, name, help)
	cc.Arg("cluster-name", "name of the cluster").Required().StringVar(&cc.ClusterName)
	return cc
}

// Auth does the authentication
func (app *Application) Auth(pc *kingpin.ParseContext) (err error) {
	carina := app.Context
	carina.ClusterClient, err = libcarina.NewClusterClient(carina.Endpoint, carina.Username, carina.APIKey)
	return err
}

// List the current swarm clusters
func (carina *Command) List(pc *kingpin.ParseContext) (err error) {
	clusterList, err := carina.ClusterClient.List()
	if err != nil {
		return err
	}

	headerFields := []string{
		"ClusterName",
		"Username",
		"Flavor",
		"Image",
		"Nodes",
		"Status",
	}
	s := strings.Join(headerFields, "\t")

	_, err = carina.TabWriter.Write([]byte(s + "\n"))
	if err != nil {
		return err
	}

	for _, cluster := range clusterList {
		err = writeCluster(carina.TabWriter, &cluster)
		if err != nil {
			return err
		}
	}
	err = carina.TabWriter.Flush()
	return err
}

type clusterFunc func(clusterName string) (*libcarina.Cluster, error)

// Does an func against a cluster then returns the new cluster representation
func (carina *ClusterCommand) clusterOp(clop clusterFunc) (err error) {
	cluster, err := clop(carina.ClusterName)
	if err != nil {
		return err
	}

	err = writeCluster(carina.TabWriter, cluster)
	if err != nil {
		return err
	}
	return carina.TabWriter.Flush()
}

// Get an individual cluster
func (carina *ClusterCommand) Get(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(carina.ClusterClient.Get)
}

// Delete a cluster
func (carina *ClusterCommand) Delete(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(carina.ClusterClient.Delete)
}

// Grow increases the size of the given cluster
func (carina *GrowCommand) Grow(pc *kingpin.ParseContext) (err error) {
	return carina.clusterOp(func(clusterName string) (*libcarina.Cluster, error) {
		return carina.ClusterClient.Grow(clusterName, carina.Nodes)
	})
}

// Create a cluster
func (carina *CreateCommand) Create(pc *kingpin.ParseContext) (err error) {
	if carina.Nodes < 1 {
		return errors.New("nodes must be >= 1")
	}

	nodes := libcarina.Number(carina.Nodes)

	c := libcarina.Cluster{
		ClusterName: carina.ClusterName,
		Nodes:       nodes,
		AutoScale:   carina.AutoScale,
	}

	cluster, err := carina.ClusterClient.Create(c)

	// Transitions past point of "new" or "building" are assumed to be states we
	// can stop on.
	if carina.Wait {
		for cluster.Status == "new" || cluster.Status == "building" {
			time.Sleep(13 * time.Second)
			cluster, err = carina.ClusterClient.Get(carina.ClusterName)
			if err != nil {
				break
			}
		}
	}

	if err != nil {
		return err
	}

	err = writeCluster(carina.TabWriter, cluster)

	if err != nil {
		return err
	}
	return carina.TabWriter.Flush()
}

// Download credentials for a cluster
func (carina *CredentialsCommand) Download(pc *kingpin.ParseContext) (err error) {
	credentials, err := carina.ClusterClient.GetCredentials(carina.ClusterName)
	if err != nil {
		return err
	}

	p := path.Clean(carina.Path)

	if p != "." {
		err = os.MkdirAll(p, 0777)
	}

	if err != nil {
		return err
	}

	err = writeCredentials(carina.TabWriter, credentials, p)
	if err != nil {
		return err
	}

	if runtime.GOOS == "windows" {
		fmt.Fprintf(os.Stdout, "\"%v\"\n", path.Join(p, "docker.cmd"))
		fmt.Fprintf(os.Stdout, "# Run the above to set your docker environment\n")
	} else {
		fmt.Fprintf(os.Stdout, "source \"%v\"\n", path.Join(p, "docker.env"))
		fmt.Fprintf(os.Stdout, "# Run the above or eval a subshell with your arguments to %v\n", os.Args[0])
		fmt.Fprintf(os.Stdout, "# eval \"$( %v command... )\" \n", os.Args[0])
	}

	err = carina.TabWriter.Flush()
	return err
}

func writeCredentials(w *tabwriter.Writer, creds *libcarina.Credentials, pth string) (err error) {
	// TODO: Prompt when file already exists?
	for fname, b := range creds.Files {
		p := path.Join(pth, fname)
		err = ioutil.WriteFile(p, b, 0600)
		if err != nil {
			return err
		}
	}

	return nil
}

func writeCluster(w *tabwriter.Writer, cluster *libcarina.Cluster) (err error) {
	s := strings.Join([]string{cluster.ClusterName,
		cluster.Username,
		cluster.Flavor,
		cluster.Image,
		fmt.Sprintf("%v", cluster.Nodes),
		cluster.Status}, "\t")
	_, err = w.Write([]byte(s + "\n"))
	return
}

func main() {
	app := New()
	kingpin.MustParse(app.Parse(os.Args[1:]))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintln(os.Stderr, "Usage: gh-ssh-pubkey [username, ...]")
		os.Exit(1)
	}

	for _, name := range os.Args[1:] {
		keys, err := GetSSHKey(name)
		if err != nil {
			panic(err)
		}
		fmt.Printf("# from https://github.com/%s\n", name)
		fmt.Println(keys)
	}
}

func GetSSHKey(name string) (string, error) {
	resp, err := http.Get(fmt.Sprintf("https://github.com/%s.keys", name))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	return string(b), err
}
<commit_msg>Write to authorized_keys<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/mitchellh/go-homedir"
	"github.com/ogier/pflag"
)

func main() {
	var write bool
	pflag.BoolVarP(&write, "write", "w", false, "write to ~/.ssh/authorized_keys")
	pflag.Parse()

	if len(pflag.Args()) == 0 {
		fmt.Fprintln(os.Stderr, "Usage: gh-ssh-pubkey [-w] username [, username2...]")
		os.Exit(1)
	}

	out, err := Out(write)
	if err != nil {
		panic(err)
	}
	defer out.Close()

	for _, name := range pflag.Args() {
		keys, err := GetSSHKey(name)
		if err != nil {
			panic(err)
		}
		fmt.Fprintf(out, "\n# from https://github.com/%s\n", name)
		fmt.Fprint(out, keys)
	}
}

func GetSSHKey(name string) (string, error) {
	resp, err := http.Get(fmt.Sprintf("https://github.com/%s.keys", name))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	return string(b), err
}

func Out(write bool) (io.WriteCloser, error) {
	if !write {
		return os.Stdout, nil
	}

	path, err := homedir.Expand("~/.ssh/authorized_keys")
	if err != nil {
		return nil, err
	}
	return os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"text/template"
)

const (
	rootPath     = "."
	assetsPath   = rootPath + "/assets"
	appServer    = "localhost:8080"
	goemonServer = "localhost:35730"
)

type Template struct {
	Path string
	Name string
	Body string
}

type Scaffold struct {
	Assets     string
	Server     string
	Livereload string
}

var templateFiles = []Template{
	Template{
		Path: rootPath,
		Name: "main.go",
		Body: `package main

import (
	"net/http"
)

func cacheHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "no-store")
		h.ServeHTTP(w, r)
	})
}

func main() {
	h := http.FileServer(http.Dir("{{.Assets}}"))
	h = cacheHandler(h)
	http.Handle("/", h)
	http.ListenAndServe("{{.Server}}", nil)
}
`,
	},
	Template{
		Path: rootPath,
		Name: "goemon.yml",
		Body: `livereload: {{.Livereload}}
tasks:
- match: '{{.Assets}}/*.gcss'
  commands:
  - cat ${GOEMON_TARGET_FILE} | gcss > ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - :livereload /
- match: '{{.Assets}}/*.ace'
  commands:
  - cat ${GOEMON_TARGET_FILE} | ace > ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - echo "<script src=\"http://{{.Livereload}}/livereload.js\"></script>" >> ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - :livereload /
- match: '*.go'
  commands:
  - go build
  - :restart
  - :livereload /
`,
	},
	Template{
		Path: assetsPath,
		Name: "sample.html.ace",
		Body: `= doctype html
html lang=en
  head
    title Hello Ace
    link rel="stylesheet" type="text/css" href="sample.css"
  body
    h1 goemon + ace + gcss
    #container.wrapper
      p..
        Ace is an HTML template engine for Go.
        This engine simplifies HTML coding in Go web application development.
      p GCSS is a pure Go CSS preprocessor.
      p goemon is Go Extensible Monitoring
    = javascript
      console.log('Welcome to Ace');
`,
	},
	Template{
		Path: assetsPath,
		Name: "sample.css.gcss",
		Body: `$main-color: blue

h1
  color: $main-color
`,
	},
}

func makeFile(file string, body string, s *Scaffold) {
	tmpl, err := template.New(file).Parse(body)
	if err != nil {
		panic(err)
	}

	var doc bytes.Buffer
	err = tmpl.Execute(&doc, s)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(file, doc.Bytes(), 0644)
	if err != nil {
		panic(err)
	}
}

func generateFile() {
	scaffold := Scaffold{
		Assets:     assetsPath,
		Server:     appServer,
		Livereload: goemonServer,
	}

	os.Mkdir(assetsPath, 0755)
	for _, tpl := range templateFiles {
		file := tpl.Path + "/" + tpl.Name
		makeFile(file, tpl.Body, &scaffold)
		fmt.Fprintf(os.Stderr, "generated %s\n", file)
	}
}

func isEmptyDir(path string) bool {
	if fis, _ := ioutil.ReadDir(path); len(fis) > 0 {
		return false
	}
	return true
}

func checkEmpty() bool {
	pwd, _ := os.Getwd()
	return isEmptyDir(pwd)
}

func main() {
	if !checkEmpty() {
		fmt.Fprintln(os.Stderr, "file exists")
		os.Exit(1)
	}
	generateFile()

	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "install goemon , Ace and GCSS")
	fmt.Fprintln(os.Stderr, "  go get github.com/mattn/goemon/cmd/goemon")
	fmt.Fprintln(os.Stderr, "  go get github.com/yosssi/ace/cmd/ace")
	fmt.Fprintln(os.Stderr, "  go get github.com/yosssi/gcss/cmd/gcss")
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "run command")
	fmt.Fprintln(os.Stderr, "  touch assets/*")
	fmt.Fprintln(os.Stderr, "  goemon go run main.go")
	fmt.Fprintln(os.Stderr, "")
}
<commit_msg>typo help message<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"text/template"
)

const (
	rootPath     = "."
	assetsPath   = rootPath + "/assets"
	appServer    = "localhost:8080"
	goemonServer = "localhost:35730"
)

type Template struct {
	Path string
	Name string
	Body string
}

type Scaffold struct {
	Assets     string
	Server     string
	Livereload string
}

var templateFiles = []Template{
	Template{
		Path: rootPath,
		Name: "main.go",
		Body: `package main

import (
	"net/http"
)

func cacheHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "no-store")
		h.ServeHTTP(w, r)
	})
}

func main() {
	h := http.FileServer(http.Dir("{{.Assets}}"))
	h = cacheHandler(h)
	http.Handle("/", h)
	http.ListenAndServe("{{.Server}}", nil)
}
`,
	},
	Template{
		Path: rootPath,
		Name: "goemon.yml",
		Body: `livereload: {{.Livereload}}
tasks:
- match: '{{.Assets}}/*.gcss'
  commands:
  - cat ${GOEMON_TARGET_FILE} | gcss > ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - :livereload /
- match: '{{.Assets}}/*.ace'
  commands:
  - cat ${GOEMON_TARGET_FILE} | ace > ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - echo "<script src=\"http://{{.Livereload}}/livereload.js\"></script>" >> ${GOEMON_TARGET_DIR}/${GOEMON_TARGET_NAME}
  - :livereload /
- match: '*.go'
  commands:
  - go build
  - :restart
  - :livereload /
`,
	},
	Template{
		Path: assetsPath,
		Name: "sample.html.ace",
		Body: `= doctype html
html lang=en
  head
    title Hello Ace
    link rel="stylesheet" type="text/css" href="sample.css"
  body
    h1 goemon + ace + gcss
    #container.wrapper
      p..
        Ace is an HTML template engine for Go.
        This engine simplifies HTML coding in Go web application development.
      p GCSS is a pure Go CSS preprocessor.
      p goemon is Go Extensible Monitoring
    = javascript
      console.log('Welcome to Ace');
`,
	},
	Template{
		Path: assetsPath,
		Name: "sample.css.gcss",
		Body: `$main-color: blue

h1
  color: $main-color
`,
	},
}

func makeFile(file string, body string, s *Scaffold) {
	tmpl, err := template.New(file).Parse(body)
	if err != nil {
		panic(err)
	}

	var doc bytes.Buffer
	err = tmpl.Execute(&doc, s)
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile(file, doc.Bytes(), 0644)
	if err != nil {
		panic(err)
	}
}

func generateFile() {
	scaffold := Scaffold{
		Assets:     assetsPath,
		Server:     appServer,
		Livereload: goemonServer,
	}

	os.Mkdir(assetsPath, 0755)
	for _, tpl := range templateFiles {
		file := tpl.Path + "/" + tpl.Name
		makeFile(file, tpl.Body, &scaffold)
		fmt.Fprintf(os.Stderr, "generated %s\n", file)
	}
}

func isEmptyDir(path string) bool {
	if fis, _ := ioutil.ReadDir(path); len(fis) > 0 {
		return false
	}
	return true
}

func checkEmpty() bool {
	pwd, _ := os.Getwd()
	return isEmptyDir(pwd)
}

func main() {
	if !checkEmpty() {
		fmt.Fprintln(os.Stderr, "file exists")
		os.Exit(1)
	}
	generateFile()

	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "install goemon , Ace and GCSS")
	fmt.Fprintln(os.Stderr, "  go get github.com/mattn/goemon/cmd/goemon")
	fmt.Fprintln(os.Stderr, "  go get github.com/yosssi/ace/cmd/ace")
	fmt.Fprintln(os.Stderr, "  go get github.com/yosssi/gcss/cmd/gcss")
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "run command")
	fmt.Fprintln(os.Stderr, "  goemon go run main.go")
	fmt.Fprintln(os.Stderr, "  touch assets/*")
	fmt.Fprintln(os.Stderr, "  open http://localhost:8080/sample.html")
	fmt.Fprintln(os.Stderr, "")
}
<|endoftext|>


<commit_before><commit_msg>concurrency<commit_after>package main

import (
	"fmt"
	"sync"
)

func ingest() <-chan []string {
	out := make(chan []string)
	go func() {
		out <- []string{"aaaa", "bbb"}
		out <- []string{"cccccc", "dddddd"}
		out <- []string{"e", "fffff", "g"}
		close(out)
	}()
	return out
}

func process(concurrency int, in <-chan []string) <-chan int {
	var wg sync.WaitGroup
	wg.Add(concurrency)

	out := make(chan int)

	work := func() {
		for data := range in {
			for _, word := range data {
				out <- len(word)
			}
		}
		wg.Done()

	}

	go func() {
		for i := 0; i < concurrency; i++ {
			go work()
		}

	}()

	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

func store(in <-chan int) <-chan struct{} {
	done := make(chan struct{})
	go func() {
		defer close(done)
		for data := range in {
			fmt.Println(data)
		}
	}()
	return done
}

func main() {
	// stage 1 ingest data from source
	in := ingest()

	// stage 2 - process data
	reduced := process(4, in)

	// stage 3 - store
	<-store(reduced)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync/atomic"
	"time"

	tuf "github.com/flynn/go-tuf/client"
	tufdata "github.com/flynn/go-tuf/data"
	"github.com/jackc/pgx"
)

func main() {
	var keys []*tufdata.Key
	if err := json.Unmarshal([]byte(os.Getenv("ROOT_KEYS")), &keys); err != nil {
		log.Fatal("missing or invalid ROOT_KEYS:", err)
	}
	opts := &tuf.HTTPRemoteOptions{
		UserAgent: "cli-redirect/v1",
	}
	remote, err := tuf.HTTPRemoteStore(os.Getenv("REPO_URL"), opts)
	if err != nil {
		log.Fatal("error initializing remote store:", err)
	}
	r := &redirector{
		RepoURL: os.Getenv("REPO_URL"),
		Client:  tuf.NewClient(tuf.MemoryLocalStore(), remote),
		refresh: make(chan struct{}, 1),
		notify:  make(chan struct{}, 1),
	}
	if err := r.Client.Init(keys, len(keys)); err != nil {
		log.Fatal("error initializing client:", err)
	}
	if _, err := r.Client.Update(); err != nil {
		log.Fatal("error running first update:", err)
	}
	targets, err := r.Client.Targets()
	if err != nil {
		log.Fatal("error getting targets:", err)
	}
	r.Targets.Store(targets)

	pgConf, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal("error parsing DATABASE_URL:", err)
	}
	r.DB, err = pgx.NewConnPool(pgx.ConnPoolConfig{ConnConfig: pgConf})
	if err != nil {
		log.Fatal("error creating pgx pool:", err)
	}

	go r.pgListener()
	go r.pgNotifier()
	go r.tufLoader()

	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), r))
}

type redirector struct {
	RepoURL         string
	Client          *tuf.Client
	Targets         atomic.Value // map[string]tufdata.Files
	DB              *pgx.ConnPool
	refresh, notify chan struct{}
}

func (r *redirector) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/refresh" {
		r.maybeNotify()
		return
	}
	w.Header().Set("Cache-Control", "no-cache")

	if req.URL.Path == "/cli.ps1" {
		r.powershell(w, req)
		return
	}

	var plat string
	if p := strings.TrimPrefix(strings.TrimPrefix(req.URL.Path, "/cli"), "/"); p == "" {
		plat = guessPlat(req.UserAgent())
	} else if strings.Count(p, "-") == 1 {
		plat = p
	} else {
		http.Error(w, "unknown platform", 404)
		return
	}

	name := fmt.Sprintf("/flynn-%s.gz", plat)
	f, ok := r.targets()[name]
	if !ok {
		http.Error(w, "unknown target", 404)
		return
	}

	http.Redirect(w, req, r.url(name, f), 302)
}

func (r *redirector) targets() tufdata.Files {
	return r.Targets.Load().(tufdata.Files)
}

func (r *redirector) url(name string, file tufdata.FileMeta) string {
	return fmt.Sprintf("%s/targets/%x.%s", r.RepoURL, []byte(file.Hashes["sha512"]), name[1:])
}

func (r *redirector) pgListener() {
	var conn *pgx.Conn
	listen := func() (err error) {
		conn, err = r.DB.Acquire()
		if err != nil {
			return
		}
		if err = conn.Listen("refresh"); err != nil {
			return
		}
		for {
			_, err = conn.WaitForNotification(time.Second)
			if err == pgx.ErrNotificationTimeout {
				continue
			}
			if err != nil {
				return
			}
			r.maybeLoad()
		}
	}
	for {
		err := listen()
		log.Println("listen error:", err)
		if conn != nil {
			conn.Exec("UNLISTEN refresh")
			r.DB.Release(conn)
			conn = nil
		}
		time.Sleep(time.Second)
	}
}

func (r *redirector) pgNotify() {
	if _, err := r.DB.Exec("NOTIFY refresh"); err != nil {
		log.Print("error notifying", err)
	}
}

func (r *redirector) pgNotifier() {
	for range r.notify {
		r.pgNotify()
		// maximum of one notify per minute
		time.Sleep(time.Minute)
	}
}

func (r *redirector) tufLoader() {
	go func() {
		// reload every 15 minutes
		for range time.Tick(15 * time.Minute) {
			r.maybeLoad()
		}
	}()

	for range r.refresh {
		r.loadTUF()
		// maximum of one fetch per minute
		time.Sleep(time.Minute)
	}
}

func (r *redirector) maybeLoad() {
	select {
	case r.refresh <- struct{}{}:
	default:
	}
}

func (r *redirector) maybeNotify() {
	select {
	case r.notify <- struct{}{}:
	default:
	}
}

func (r *redirector) loadTUF() {
	retryLater := func() { time.AfterFunc(time.Minute, r.maybeLoad) }
	if _, err := r.Client.Update(); err != nil {
		if tuf.IsLatestSnapshot(err) {
			return
		}
		log.Print("error running TUF update:", err)
		retryLater()
		return
	}
	targets, err := r.Client.Targets()
	if err != nil {
		log.Print("error getting targets:", err)
		retryLater()
		return
	}
	r.Targets.Store(targets)
}

func guessArch(ua string) string {
	if strings.Contains(ua, "x86_64") || strings.Contains(ua, "amd64") || isDarwin(ua) {
		return "amd64"
	}
	return "386"
}

func isDarwin(ua string) bool {
	return strings.Contains(ua, "mac os x") || strings.Contains(ua, "darwin")
}

func guessOS(ua string) string {
	if isDarwin(ua) {
		return "darwin"
	}
	if strings.Contains(ua, "windows") {
		return "windows"
	}
	return "linux"
}

func guessPlat(ua string) string {
	ua = strings.ToLower(ua)
	return guessOS(ua) + "-" + guessArch(ua)
}
<commit_msg>Default architecture to amd64 instead of 386<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"sync/atomic"
	"time"

	tuf "github.com/flynn/go-tuf/client"
	tufdata "github.com/flynn/go-tuf/data"
	"github.com/jackc/pgx"
)

func main() {
	var keys []*tufdata.Key
	if err := json.Unmarshal([]byte(os.Getenv("ROOT_KEYS")), &keys); err != nil {
		log.Fatal("missing or invalid ROOT_KEYS:", err)
	}
	opts := &tuf.HTTPRemoteOptions{
		UserAgent: "cli-redirect/v1",
	}
	remote, err := tuf.HTTPRemoteStore(os.Getenv("REPO_URL"), opts)
	if err != nil {
		log.Fatal("error initializing remote store:", err)
	}
	r := &redirector{
		RepoURL: os.Getenv("REPO_URL"),
		Client:  tuf.NewClient(tuf.MemoryLocalStore(), remote),
		refresh: make(chan struct{}, 1),
		notify:  make(chan struct{}, 1),
	}
	if err := r.Client.Init(keys, len(keys)); err != nil {
		log.Fatal("error initializing client:", err)
	}
	if _, err := r.Client.Update(); err != nil {
		log.Fatal("error running first update:", err)
	}
	targets, err := r.Client.Targets()
	if err != nil {
		log.Fatal("error getting targets:", err)
	}
	r.Targets.Store(targets)

	pgConf, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal("error parsing DATABASE_URL:", err)
	}
	r.DB, err = pgx.NewConnPool(pgx.ConnPoolConfig{ConnConfig: pgConf})
	if err != nil {
		log.Fatal("error creating pgx pool:", err)
	}

	go r.pgListener()
	go r.pgNotifier()
	go r.tufLoader()

	log.Fatal(http.ListenAndServe(":"+os.Getenv("PORT"), r))
}

type redirector struct {
	RepoURL         string
	Client          *tuf.Client
	Targets         atomic.Value // map[string]tufdata.Files
	DB              *pgx.ConnPool
	refresh, notify chan struct{}
}

func (r *redirector) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	if req.URL.Path == "/refresh" {
		r.maybeNotify()
		return
	}
	w.Header().Set("Cache-Control", "no-cache")

	if req.URL.Path == "/cli.ps1" {
		r.powershell(w, req)
		return
	}

	var plat string
	if p := strings.TrimPrefix(strings.TrimPrefix(req.URL.Path, "/cli"), "/"); p == "" {
		plat = guessPlat(req.UserAgent())
	} else if strings.Count(p, "-") == 1 {
		plat = p
	} else {
		http.Error(w, "unknown platform", 404)
		return
	}

	name := fmt.Sprintf("/flynn-%s.gz", plat)
	f, ok := r.targets()[name]
	if !ok {
		http.Error(w, "unknown target", 404)
		return
	}

	http.Redirect(w, req, r.url(name, f), 302)
}

func (r *redirector) targets() tufdata.Files {
	return r.Targets.Load().(tufdata.Files)
}

func (r *redirector) url(name string, file tufdata.FileMeta) string {
	return fmt.Sprintf("%s/targets/%x.%s", r.RepoURL, []byte(file.Hashes["sha512"]), name[1:])
}

func (r *redirector) pgListener() {
	var conn *pgx.Conn
	listen := func() (err error) {
		conn, err = r.DB.Acquire()
		if err != nil {
			return
		}
		if err = conn.Listen("refresh"); err != nil {
			return
		}
		for {
			_, err = conn.WaitForNotification(time.Second)
			if err == pgx.ErrNotificationTimeout {
				continue
			}
			if err != nil {
				return
			}
			r.maybeLoad()
		}
	}
	for {
		err := listen()
		log.Println("listen error:", err)
		if conn != nil {
			conn.Exec("UNLISTEN refresh")
			r.DB.Release(conn)
			conn = nil
		}
		time.Sleep(time.Second)
	}
}

func (r *redirector) pgNotify() {
	if _, err := r.DB.Exec("NOTIFY refresh"); err != nil {
		log.Print("error notifying", err)
	}
}

func (r *redirector) pgNotifier() {
	for range r.notify {
		r.pgNotify()
		// maximum of one notify per minute
		time.Sleep(time.Minute)
	}
}

func (r *redirector) tufLoader() {
	go func() {
		// reload every 15 minutes
		for range time.Tick(15 * time.Minute) {
			r.maybeLoad()
		}
	}()

	for range r.refresh {
		r.loadTUF()
		// maximum of one fetch per minute
		time.Sleep(time.Minute)
	}
}

func (r *redirector) maybeLoad() {
	select {
	case r.refresh <- struct{}{}:
	default:
	}
}

func (r *redirector) maybeNotify() {
	select {
	case r.notify <- struct{}{}:
	default:
	}
}

func (r *redirector) loadTUF() {
	retryLater := func() { time.AfterFunc(time.Minute, r.maybeLoad) }
	if _, err := r.Client.Update(); err != nil {
		if tuf.IsLatestSnapshot(err) {
			return
		}
		log.Print("error running TUF update:", err)
		retryLater()
		return
	}
	targets, err := r.Client.Targets()
	if err != nil {
		log.Print("error getting targets:", err)
		retryLater()
		return
	}
	r.Targets.Store(targets)
}

func guessArch(ua string) string {
	if strings.Contains(ua, "i386") || strings.Contains(ua, "i686") {
		return "386"
	}
	return "amd64"
}

func isDarwin(ua string) bool {
	return strings.Contains(ua, "mac os x") || strings.Contains(ua, "darwin")
}

func guessOS(ua string) string {
	if isDarwin(ua) {
		return "darwin"
	}
	if strings.Contains(ua, "windows") {
		return "windows"
	}
	return "linux"
}

func guessPlat(ua string) string {
	ua = strings.ToLower(ua)
	return guessOS(ua) + "-" + guessArch(ua)
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"runtime"
	"time"

	"github.com/ernestio/definition-mapper/libmapper"
	"github.com/ernestio/definition-mapper/libmapper/providers"
	ecc "github.com/ernestio/ernest-config-client"
	"github.com/nats-io/nats"
	"gopkg.in/r3labs/graph.v2"
)

var n *nats.Conn

func getInputDetails(body []byte) (string, string, string, string, string) {
	var service struct {
		ID         string `json:"id"`
		Name       string `json:"name"`
		Previous   string `json:"previous_id"`
		Datacenter struct {
			Type string `json:"type"`
		} `json:"datacenter"`
		Definition struct {
			Name string `json:"name"`
		} `json:"service"`
	}

	if err := json.Unmarshal(body, &service); err != nil {
		log.Panic(err)
	}

	return service.ID, service.Name, service.Datacenter.Type, service.Previous, service.Definition.Name
}

func definitionToGraph(m libmapper.Mapper, body []byte) (*graph.Graph, error) {
	var gd map[string]interface{}
	err := json.Unmarshal(body, &gd)
	if err != nil {
		return nil, err
	}

	definition, ok := gd["service"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not convert definition")
	}

	credentials, ok := gd["datacenter"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not find datacenter credentials")
	}

	sid, ok := gd["id"].(string)
	if ok != true {
		return nil, errors.New("could not find service id")
	}

	d, err := m.LoadDefinition(definition)
	if err != nil {
		return nil, err
	}

	g, err := m.ConvertDefinition(d)
	if err != nil {
		return nil, err
	}

	// set graph ID and credentials
	g.ID = sid
	err = g.AddComponent(m.ProviderCredentials(credentials))
	if err != nil {
		return nil, err
	}

	return g, nil
}

func mappingToGraph(m libmapper.Mapper, body []byte) (*graph.Graph, error) {
	var gm map[string]interface{}
	err := json.Unmarshal(body, &gm)
	if err != nil {
		return nil, err
	}

	return m.LoadGraph(gm)
}

// SubscribeCreateService : definition.map.creation subscriber
// For a given definition, it will generate the valid service
// and necessary workflow to create the environment on the
// provider
func SubscribeCreateService(body []byte) ([]byte, error) {
	id, _, t, p, _ := getInputDetails(body)

	m := providers.NewMapper(t)
	if m == nil {
		return body, fmt.Errorf("Unconfigured provider type : '%s'", t)
	}

	g, err := definitionToGraph(m, body)
	if err != nil {
		return body, err
	}

	// If there is a previous service
	if p != "" {
		oMsg, rerr := n.Request("service.get.mapping", []byte(`{"id":"`+p+`"}`), time.Second)
		if rerr != nil {
			return body, rerr
		}
		og, merr := mappingToGraph(m, oMsg.Data)
		if merr != nil {
			return body, merr
		}

		for _, c := range g.Components {
			oc := og.Component(c.GetID())
			if oc != nil {
				c.Update(oc)
			}
		}

		g, err = g.Diff(og)
		if err != nil {
			return body, err
		}
	} else {
		g, err = g.Diff(graph.New())
		if err != nil {
			return body, err
		}
	}

	g.ID = id

	return g.ToJSON()
}

// SubscribeImportService : definition.map.import subscriber
// For a given filters it will generate a workflow to fully
// import a provider service.
func SubscribeImportService(body []byte) ([]byte, error) {
	var err error
	var filters []string

	var gd map[string]interface{}
	err = json.Unmarshal(body, &gd)
	if err != nil {
		return nil, err
	}

	credentials, ok := gd["datacenter"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not find datacenter credentials")
	}

	id, _, t, _, n := getInputDetails(body)

	filters = append(filters, n)

	m := providers.NewMapper(t)

	g := m.CreateImportGraph(filters)
	if g, err = g.Diff(graph.New()); err != nil {
		return body, err
	}

	g.ID = id
	err = g.AddComponent(m.ProviderCredentials(credentials))
	if err != nil {
		return nil, err
	}

	return g.ToJSON()
}

// SubscribeDeleteService : definition.map.deletion subscriber
// For a given existing service will generate a valid internal
// service with a workflow to delete all its components
func SubscribeDeleteService(body []byte) ([]byte, error) {
	_, _, t, p, _ := getInputDetails(body)
	m := providers.NewMapper(t)

	oMsg, rerr := n.Request("service.get.mapping", []byte(`{"id":"`+p+`"}`), time.Second)
	if rerr != nil {
		return body, rerr
	}

	original, merr := mappingToGraph(m, oMsg.Data)
	if merr != nil {
		return body, merr
	}

	empty := graph.New()

	g, err := empty.Diff(original)
	if err != nil {
		return body, err
	}

	g.ID = p

	return json.Marshal(g)
}

// SubscribeMapService : definition.map.service subscriber
// For a given full service will generate the relative
// definition
func SubscribeMapService(body []byte) ([]byte, error) {
	var gd map[string]interface{}

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

	_, _, t, _, _ := getInputDetails(body)
	m := providers.NewMapper(t)

	original, err := m.LoadGraph(gd)
	if err != nil {
		return body, err
	}
	definition, err := m.ConvertGraph(original)
	if err != nil {
		return body, err
	}

	return json.Marshal(definition)
}

// ManageDefinitions : Manages all subscriptions
func ManageDefinitions() {
	if _, err := n.Subscribe("definition.map.creation", func(m *nats.Msg) {
		if body, err := SubscribeCreateService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.import", func(m *nats.Msg) {
		if body, err := SubscribeImportService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.deletion", func(m *nats.Msg) {
		if body, err := SubscribeDeleteService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.service", func(m *nats.Msg) {
		if body, err := SubscribeMapService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}
}

func setup() {
	n = ecc.NewConfig(os.Getenv("NATS_URI")).Nats()
}

func main() {
	setup()
	ManageDefinitions()
	runtime.Goexit()
}
<commit_msg>converting import graph on completed import<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"os"
	"runtime"
	"time"

	"github.com/ernestio/definition-mapper/libmapper"
	"github.com/ernestio/definition-mapper/libmapper/providers"
	ecc "github.com/ernestio/ernest-config-client"
	"github.com/nats-io/nats"
	"gopkg.in/r3labs/graph.v2"
)

var n *nats.Conn

func getInputDetails(body []byte) (string, string, string, string, string) {
	var service struct {
		ID         string `json:"id"`
		Name       string `json:"name"`
		Previous   string `json:"previous_id"`
		Datacenter struct {
			Type string `json:"type"`
		} `json:"datacenter"`
		Definition struct {
			Name string `json:"name"`
		} `json:"service"`
	}

	if err := json.Unmarshal(body, &service); err != nil {
		log.Panic(err)
	}

	return service.ID, service.Name, service.Datacenter.Type, service.Previous, service.Definition.Name
}

func getGraphDetails(g *graph.Graph) (string, string) {
	credentials := g.GetComponents().ByType("credentials")

	return g.ID, credentials[0].GetProvider()
}

func definitionToGraph(m libmapper.Mapper, body []byte) (*graph.Graph, error) {
	var gd map[string]interface{}
	err := json.Unmarshal(body, &gd)
	if err != nil {
		return nil, err
	}

	definition, ok := gd["service"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not convert definition")
	}

	credentials, ok := gd["datacenter"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not find datacenter credentials")
	}

	sid, ok := gd["id"].(string)
	if ok != true {
		return nil, errors.New("could not find service id")
	}

	d, err := m.LoadDefinition(definition)
	if err != nil {
		return nil, err
	}

	g, err := m.ConvertDefinition(d)
	if err != nil {
		return nil, err
	}

	// set graph ID and credentials
	g.ID = sid
	err = g.AddComponent(m.ProviderCredentials(credentials))
	if err != nil {
		return nil, err
	}

	return g, nil
}

func mappingToGraph(m libmapper.Mapper, body []byte) (*graph.Graph, error) {
	var gm map[string]interface{}
	err := json.Unmarshal(body, &gm)
	if err != nil {
		return nil, err
	}

	return m.LoadGraph(gm)
}

// SubscribeCreateService : definition.map.creation subscriber
// For a given definition, it will generate the valid service
// and necessary workflow to create the environment on the
// provider
func SubscribeCreateService(body []byte) ([]byte, error) {
	id, _, t, p, _ := getInputDetails(body)

	m := providers.NewMapper(t)
	if m == nil {
		return body, fmt.Errorf("Unconfigured provider type : '%s'", t)
	}

	g, err := definitionToGraph(m, body)
	if err != nil {
		return body, err
	}

	// If there is a previous service
	if p != "" {
		oMsg, rerr := n.Request("service.get.mapping", []byte(`{"id":"`+p+`"}`), time.Second)
		if rerr != nil {
			return body, rerr
		}
		og, merr := mappingToGraph(m, oMsg.Data)
		if merr != nil {
			return body, merr
		}

		for _, c := range g.Components {
			oc := og.Component(c.GetID())
			if oc != nil {
				c.Update(oc)
			}
		}

		g, err = g.Diff(og)
		if err != nil {
			return body, err
		}
	} else {
		g, err = g.Diff(graph.New())
		if err != nil {
			return body, err
		}
	}

	g.ID = id

	return g.ToJSON()
}

// SubscribeImportService : definition.map.import subscriber
// For a given filters it will generate a workflow to fully
// import a provider service.
func SubscribeImportService(body []byte) ([]byte, error) {
	var err error
	var filters []string

	var gd map[string]interface{}
	err = json.Unmarshal(body, &gd)
	if err != nil {
		return nil, err
	}

	credentials, ok := gd["datacenter"].(map[string]interface{})
	if ok != true {
		return nil, errors.New("could not find datacenter credentials")
	}

	id, _, t, _, n := getInputDetails(body)

	filters = append(filters, n)

	m := providers.NewMapper(t)

	g := m.CreateImportGraph(filters)
	if g, err = g.Diff(graph.New()); err != nil {
		return body, err
	}

	g.ID = id
	err = g.AddComponent(m.ProviderCredentials(credentials))
	if err != nil {
		return nil, err
	}

	return g.ToJSON()
}

// SubscribeImportComplete : service.create.done subscriber
// Converts a completed import graph to an inpurt definition
func SubscribeImportComplete(body []byte) error {
	var service struct {
		ID         string `json:"id"`
		Definition string `json:"definition"`
	}

	var gg map[string]interface{}
	err := json.Unmarshal(body, &gg)
	if err != nil {
		return err
	}

	g := graph.New()
	err = g.Load(gg)
	if err != nil {
		return err
	}

	id, provider := getGraphDetails(g)
	m := providers.NewMapper(provider)

	d, err := m.ConvertGraph(g)
	if err != nil {
		return err
	}

	ddata, err := json.Marshal(d)
	if err != nil {
		return err
	}

	service.ID = id
	service.Definition = string(ddata)

	sdata, err := json.Marshal(service)
	if err != nil {
		return err
	}

	n.Publish("service.set.definition", sdata)

	return nil
}

// SubscribeDeleteService : definition.map.deletion subscriber
// For a given existing service will generate a valid internal
// service with a workflow to delete all its components
func SubscribeDeleteService(body []byte) ([]byte, error) {
	_, _, t, p, _ := getInputDetails(body)
	m := providers.NewMapper(t)

	oMsg, rerr := n.Request("service.get.mapping", []byte(`{"id":"`+p+`"}`), time.Second)
	if rerr != nil {
		return body, rerr
	}

	original, merr := mappingToGraph(m, oMsg.Data)
	if merr != nil {
		return body, merr
	}

	empty := graph.New()

	g, err := empty.Diff(original)
	if err != nil {
		return body, err
	}

	g.ID = p

	return json.Marshal(g)
}

// SubscribeMapService : definition.map.service subscriber
// For a given full service will generate the relative
// definition
func SubscribeMapService(body []byte) ([]byte, error) {
	var gd map[string]interface{}

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

	_, _, t, _, _ := getInputDetails(body)
	m := providers.NewMapper(t)

	original, err := m.LoadGraph(gd)
	if err != nil {
		return body, err
	}
	definition, err := m.ConvertGraph(original)
	if err != nil {
		return body, err
	}

	return json.Marshal(definition)
}

// ManageDefinitions : Manages all subscriptions
func ManageDefinitions() {
	if _, err := n.Subscribe("definition.map.creation", func(m *nats.Msg) {
		if body, err := SubscribeCreateService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.import", func(m *nats.Msg) {
		if body, err := SubscribeImportService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.deletion", func(m *nats.Msg) {
		if body, err := SubscribeDeleteService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("definition.map.service", func(m *nats.Msg) {
		if body, err := SubscribeMapService(m.Data); err == nil {
			if err = n.Publish(m.Reply, body); err != nil {
				log.Println(err.Error())
			}
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}

	if _, err := n.Subscribe("service.import.done", func(m *nats.Msg) {
		if err := SubscribeImportComplete(m.Data); err == nil {
			log.Println(err.Error())
		} else {
			log.Println(err.Error())
			if err = n.Publish(m.Reply, []byte(`{"error":"`+err.Error()+`"}`)); err != nil {
				log.Println("Error trying to respond through nats : " + err.Error())
			}
		}
	}); err != nil {
		log.Panic(err)
	}
}

func setup() {
	n = ecc.NewConfig(os.Getenv("NATS_URI")).Nats()
}

func main() {
	setup()
	ManageDefinitions()
	runtime.Goexit()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/dustin/go-humanize"
	"gopkg.in/alecthomas/kingpin.v1"
	"os"
	"time"
)

const (
	ENV_ENANOS_PORT string = "ENANOS_PORT"
)

var (
	verbose     = kingpin.Flag("verbose", "Enable verbose mode.").Bool()
	port        = kingpin.Flag("port", "the port to host the server on").Default("8000").Short('p').OverrideDefaultFromEnvar(ENV_ENANOS_PORT).Int()
	host        = kingpin.Flag("host", "this host for enanos to bind to").Default("0.0.0.0").String()
	minSleep    = kingpin.Flag("min-sleep", "the minimum sleep time for the wait endpoint e.g. 5ms, 5s, 5m etc...").Default("1s").String()
	maxSleep    = kingpin.Flag("max-sleep", "the maximum sleep time for the wait endpoint e.g. 5ms, 5s, 5m etc...").Default("60s").String()
	randomSleep = kingpin.Flag("random-sleep", "whether to sleep a random time between min and max or just the max").Default("false").Bool()
	minSize     = kingpin.Flag("min-size", "the minimum size of response body for the content_size endpoint e.g. 5B, 5KB, 5MB etc...").Default("10KB").String()
	maxSize     = kingpin.Flag("max-size", "the maximum size of response body for the content_size endpoint e.g. 5B, 5KB, 5MB etc...").Default("100KB").String()
	randomSize  = kingpin.Flag("random-size", "whether to return a random sized payload between min and max or just max").Default("false").Bool()
	content     = kingpin.Flag("content", "the content to return for OK responses").Default("hello world").String()
	headers     = kingpin.Flag("header", "response headers to be returned. Key:Value").Short('H').Strings()
)

func main() {
	kingpin.Version("1.1.0")
	kingpin.CommandLine.Help = `Enanos is an investigation tool in the form of a HTTP server with several endpoints that can be used to substitute the actual http service dependencies of a system.  This tool allows you to see how a system will perform against varying un-stable http services, each which exhibit different effects.

	/success		- will return a 200 response code
	/server_error		- will return a random 5XX response code
	/content_size		- will return a 200 response code but a response body with a size between <minSize> and <maxSize>.  The content returned will be random or a mangled version of the content which has been configured to return i.e. it cannot guarantee to meet any content-types configured in that it will be malformed.
	/wait			- will return a 200 response code but only after a random sleep between <minSleep> and <maxSleep>
	/redirect		- will return a random 3XX response code.  If the response code is one which redirects then Bashful will return its own location to invite an infinite redirect loop
	/client_error		- will return a random 4XX response code
	/dead_or_alive	- will kill the server and only bring it back online after configured amount of time (ms) has passed

	/defined?code=<code>	- will return the specified http status code
	`
	kingpin.Parse()
	var snoozer Snoozer
	var responseBodyGenerator ResponseBodyGenerator
	var responseCodeGenerator ResponseCodeGenerator = NewRandomResponseCodeGenerator(responseCodes_300, responseCodes_400, responseCodes_500)

	minSizeValue, minSizeErr := humanize.ParseBytes(*minSize)
	maxSizeValue, maxSizeErr := humanize.ParseBytes(*maxSize)

	if minSizeErr != nil || maxSizeErr != nil {
		fmt.Errorf("Invalid size specified for min or max size")
		os.Exit(1)
	}

	if *randomSize {
		responseBodyGenerator = NewRandomResponseBodyGenerator(int(minSizeValue), int(maxSizeValue))
	} else {
		responseBodyGenerator = NewMaxResponseBodyGenerator(int(maxSizeValue))
	}

	minSleepValue, minSleepErr := time.ParseDuration(*minSleep)
	maxSleepValue, maxSleepErr := time.ParseDuration(*maxSleep)

	if minSleepErr != nil || maxSleepErr != nil {
		fmt.Errorf("Invalid duration specified for min or max sleep")
		os.Exit(1)
	}

	if *randomSleep {
		snoozer = NewRandomSnoozer(minSleepValue, maxSleepValue)
	} else {
		snoozer = NewMaxSnoozer(maxSleepValue)
	}

	config := Config{*port, *host, *verbose, *content, *headers}
	fmt.Println(fmt.Sprintf("Enanos Server listening on port %d", *port))
	StartEnanos(config, responseBodyGenerator, responseCodeGenerator, snoozer)
}
<commit_msg>Added a short flag for vebose<commit_after>package main

import (
	"fmt"
	"github.com/dustin/go-humanize"
	"gopkg.in/alecthomas/kingpin.v1"
	"os"
	"time"
)

const (
	ENV_ENANOS_PORT string = "ENANOS_PORT"
)

var (
	verbose     = kingpin.Flag("verbose", "Enable verbose mode.").Short('v').Bool()
	port        = kingpin.Flag("port", "the port to host the server on").Default("8000").Short('p').OverrideDefaultFromEnvar(ENV_ENANOS_PORT).Int()
	host        = kingpin.Flag("host", "this host for enanos to bind to").Default("0.0.0.0").String()
	minSleep    = kingpin.Flag("min-sleep", "the minimum sleep time for the wait endpoint e.g. 5ms, 5s, 5m etc...").Default("1s").String()
	maxSleep    = kingpin.Flag("max-sleep", "the maximum sleep time for the wait endpoint e.g. 5ms, 5s, 5m etc...").Default("60s").String()
	randomSleep = kingpin.Flag("random-sleep", "whether to sleep a random time between min and max or just the max").Default("false").Bool()
	minSize     = kingpin.Flag("min-size", "the minimum size of response body for the content_size endpoint e.g. 5B, 5KB, 5MB etc...").Default("10KB").String()
	maxSize     = kingpin.Flag("max-size", "the maximum size of response body for the content_size endpoint e.g. 5B, 5KB, 5MB etc...").Default("100KB").String()
	randomSize  = kingpin.Flag("random-size", "whether to return a random sized payload between min and max or just max").Default("false").Bool()
	content     = kingpin.Flag("content", "the content to return for OK responses").Default("hello world").String()
	headers     = kingpin.Flag("header", "response headers to be returned. Key:Value").Short('H').Strings()
)

func main() {
	kingpin.Version("1.1.0")
	kingpin.CommandLine.Help = `Enanos is an investigation tool in the form of a HTTP server with several endpoints that can be used to substitute the actual http service dependencies of a system.  This tool allows you to see how a system will perform against varying un-stable http services, each which exhibit different effects.

	/success		- will return a 200 response code
	/server_error		- will return a random 5XX response code
	/content_size		- will return a 200 response code but a response body with a size between <minSize> and <maxSize>.  The content returned will be random or a mangled version of the content which has been configured to return i.e. it cannot guarantee to meet any content-types configured in that it will be malformed.
	/wait			- will return a 200 response code but only after a random sleep between <minSleep> and <maxSleep>
	/redirect		- will return a random 3XX response code.  If the response code is one which redirects then Bashful will return its own location to invite an infinite redirect loop
	/client_error		- will return a random 4XX response code
	/dead_or_alive	- will kill the server and only bring it back online after configured amount of time (ms) has passed

	/defined?code=<code>	- will return the specified http status code
	`
	kingpin.Parse()
	var snoozer Snoozer
	var responseBodyGenerator ResponseBodyGenerator
	var responseCodeGenerator ResponseCodeGenerator = NewRandomResponseCodeGenerator(responseCodes_300, responseCodes_400, responseCodes_500)

	minSizeValue, minSizeErr := humanize.ParseBytes(*minSize)
	maxSizeValue, maxSizeErr := humanize.ParseBytes(*maxSize)

	if minSizeErr != nil || maxSizeErr != nil {
		fmt.Errorf("Invalid size specified for min or max size")
		os.Exit(1)
	}

	if *randomSize {
		responseBodyGenerator = NewRandomResponseBodyGenerator(int(minSizeValue), int(maxSizeValue))
	} else {
		responseBodyGenerator = NewMaxResponseBodyGenerator(int(maxSizeValue))
	}

	minSleepValue, minSleepErr := time.ParseDuration(*minSleep)
	maxSleepValue, maxSleepErr := time.ParseDuration(*maxSleep)

	if minSleepErr != nil || maxSleepErr != nil {
		fmt.Errorf("Invalid duration specified for min or max sleep")
		os.Exit(1)
	}

	if *randomSleep {
		snoozer = NewRandomSnoozer(minSleepValue, maxSleepValue)
	} else {
		snoozer = NewMaxSnoozer(maxSleepValue)
	}

	config := Config{*port, *host, *verbose, *content, *headers}
	fmt.Println(fmt.Sprintf("Enanos Server listening on port %d", *port))
	StartEnanos(config, responseBodyGenerator, responseCodeGenerator, snoozer)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"

	"github.com/boltdb/bolt"
	"github.com/chzyer/readline"
)

var db *bolt.DB

func main() {
	// Setup flags
	// statsPtr := flag.Bool("stats", false, "show stats and usage of `r`")
	// completePtr := flag.String("complete", "", "show all results for `r`")
	commandPtr := flag.Bool("command", false, "show last command selected from `r`")
	addPtr := flag.String("add", "", "show stats and usage of `r`")
	flag.Parse()

	// Setup bolt db
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	boltPath := filepath.Join(usr.HomeDir, ".r.db")
	// It will be created if it doesn't exist.
	db, err = bolt.Open(boltPath, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// reset last command to blank
	// set line as stored command
	err = db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("command"))
		if err != nil {
			return err
		}

		err = b.Put([]byte("command"), []byte(""))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		log.Fatal(err)
	}

	// Check if `results` flag is passed
	// if *completePtr != "" {
	// 	results := showResults(*completePtr)
	// 	for _, result := range results {
	// 		fmt.Println(result)
	// 	}
	// 	os.Exit(0)
	// }

	if *commandPtr {
		printLastCommand()
		os.Exit(0)
	}

	// Check if `add` flag is passed
	if *addPtr != "" {
		args := strings.Split(*addPtr, ":")
		err := add(args[0], args[1])
		if err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
	}

	readLine()
}

func readLine() {
	// create completer from results
	results, err := showResults()
	if err != nil {
		log.Panic(err)
	}

	var pcItems []*readline.PrefixCompleter
	for _, result := range results {
		pcItems = append(pcItems, readline.PcItem(result))
	}
	var completer = readline.NewPrefixCompleter(pcItems...)

	rl, err := readline.NewEx(&readline.Config{
		Prompt:       "> ",
		AutoComplete: completer,
	})
	if err != nil {
		log.Panic(err)
	}
	defer rl.Close()

	for {
		line, err := rl.Readline()
		if err != nil { // io.EOF
			break
		}

		// set line as stored command
		err = db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("command"))
			if err != nil {
				return err
			}

			err = b.Put([]byte("command"), []byte(line))
			if err != nil {
				return err
			}
			return nil
		})

		if err != nil {
			log.Fatal(err)
		}
		// fmt.Println(line)
		os.Exit(0)
	}
}

func printLastCommand() {
	var val string
	db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("command"))
		if err != nil {
			return err
		}

		val = string(b.Get([]byte("command")))
		return nil
	})

	fmt.Println(val)
}

func showResults() ([]string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	// results := []string{"git status", "git clone", "go install", "cd /Users/jesse/", "cd /Users/jesse/gocode/src/github.com/jesselucas", "ls -Glah"}
	var results []string
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("DirectoryBucket"))
		pathBucket := b.Bucket([]byte(wd))
		return pathBucket.ForEach(func(k, v []byte) error {
			fmt.Printf("key=%s, value=%s\n", k, v)
			results = append(results, string(k))
			return nil
		})
	})

	if err != nil {
		return nil, err
	}

	return results, nil

	// filter
	// var filtered []string
	// for _, result := range results {
	// 	if strings.HasPrefix(result, input) {
	// 		filtered = append(filtered, result)
	// 	}
	// }
	//
	// return filtered

}

// add checks if command being passed is in the listCommands
// then stores the command and workding directory
func add(path string, promptCmd string) error {
	// get the first command in the promptCmd string
	cmd := strings.Split(promptCmd, " ")[0]

	commands, err := listCommands()
	if err != nil {
		return err
	}

	// check if the command is valid
	if !containsCmd(cmd, commands) {
		return nil
	}

	// Add command to db
	// fmt.Printf("adding. cmd: %s, path: %s \n", promptCmd, path)
	return db.Update(func(tx *bolt.Tx) error {
		directoryBucket, err := tx.CreateBucketIfNotExists([]byte("DirectoryBucket"))
		if err != nil {
			return err
		}

		pathBucket, err := directoryBucket.CreateBucketIfNotExists([]byte(path))
		if err != nil {
			return err
		}

		// Store path and command for contextual path sorting
		cmdBucket, err := tx.CreateBucketIfNotExists([]byte("CommandBucket"))
		if err != nil {
			return err
		}

		// Don't store if the command is r
		if cmd == "r" {
			return nil
		}

		// TODO first look up command and then increment it's count

		// Store just command and usage for overall most used sorting
		err = cmdBucket.Put([]byte(promptCmd), []byte("1"))
		if err != nil {
			return err
		}

		return pathBucket.Put([]byte(promptCmd), []byte("1"))
	})
}

func containsCmd(cmd string, commands []string) bool {
	for _, c := range commands {
		// check first command against list of commands
		if c == cmd {
			return true
		}
	}
	return false
}

// listCommands use $PATH to find directories
// Then reads each directory and looks for executables
func listCommands() ([]string, error) {
	// Split $PATH directories into slice
	paths := strings.Split(os.Getenv("PATH"), ":")
	var commands []string

	// created buffered error chan
	errc := make(chan error, 1)

	// sync go routines
	var wg sync.WaitGroup

	// find commands appends results to commands slice
	findCommands := func(p string) {
		defer wg.Done()

		files, err := ioutil.ReadDir(p)
		if err != nil {
			errc <- err // write err into error chan
			return
		}

		for _, f := range files {
			m := f.Mode()

			// Check if file is executable
			if m&0111 != 0 {
				commands = append(commands, f.Name())
			}
		}

		errc <- nil // write nil into error chan
	}

	// Check each path for commands
	for _, p := range paths {
		wg.Add(1)
		go findCommands(p)

		// read any error that is in error chan
		if err := <-errc; err != nil {
			return nil, err
		}
	}

	wg.Wait() // Wait for the paths to be checked

	return commands, nil
}

// stats TODO print stats and usage of r
func stats() {
	fmt.Println("stats")
}
<commit_msg>Moving where last command is reset<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"sync"

	"github.com/boltdb/bolt"
	"github.com/chzyer/readline"
)

var db *bolt.DB

func main() {
	// Setup flags
	// statsPtr := flag.Bool("stats", false, "show stats and usage of `r`")
	// completePtr := flag.String("complete", "", "show all results for `r`")
	commandPtr := flag.Bool("command", false, "show last command selected from `r`")
	addPtr := flag.String("add", "", "show stats and usage of `r`")
	flag.Parse()

	// Setup bolt db
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	boltPath := filepath.Join(usr.HomeDir, ".r.db")
	// It will be created if it doesn't exist.
	db, err = bolt.Open(boltPath, 0600, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// Check if `results` flag is passed
	// if *completePtr != "" {
	// 	results := showResults(*completePtr)
	// 	for _, result := range results {
	// 		fmt.Println(result)
	// 	}
	// 	os.Exit(0)
	// }

	if *commandPtr {
		printLastCommand()
		os.Exit(0)
	}

	// Check if `add` flag is passed
	if *addPtr != "" {
		args := strings.Split(*addPtr, ":")
		err := add(args[0], args[1])
		if err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
	}

	// reset last command to blank
	// set line as stored command
	err = db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("command"))
		if err != nil {
			return err
		}

		err = b.Put([]byte("command"), []byte(""))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		log.Fatal(err)
	}

	readLine()
}

func readLine() {
	// create completer from results
	results, err := showResults()
	if err != nil {
		log.Panic(err)
	}

	var pcItems []*readline.PrefixCompleter
	for _, result := range results {
		pcItems = append(pcItems, readline.PcItem(result))
	}
	var completer = readline.NewPrefixCompleter(pcItems...)

	rl, err := readline.NewEx(&readline.Config{
		Prompt:       "> ",
		AutoComplete: completer,
	})
	if err != nil {
		log.Panic(err)
	}
	defer rl.Close()

	for {
		line, err := rl.Readline()
		if err != nil { // io.EOF
			break
		}

		// set line as stored command
		err = db.Update(func(tx *bolt.Tx) error {
			b, err := tx.CreateBucketIfNotExists([]byte("command"))
			if err != nil {
				return err
			}

			err = b.Put([]byte("command"), []byte(line))
			if err != nil {
				return err
			}
			return nil
		})

		if err != nil {
			log.Fatal(err)
		}
		// fmt.Println(line)
		os.Exit(0)
	}
}

func printLastCommand() {
	var val string
	db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("command"))
		if err != nil {
			return err
		}

		val = string(b.Get([]byte("command")))
		return nil
	})

	fmt.Println(val)
}

func showResults() ([]string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return nil, err
	}

	// results := []string{"git status", "git clone", "go install", "cd /Users/jesse/", "cd /Users/jesse/gocode/src/github.com/jesselucas", "ls -Glah"}
	var results []string
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("DirectoryBucket"))
		pathBucket := b.Bucket([]byte(wd))
		return pathBucket.ForEach(func(k, v []byte) error {
			results = append(results, string(k))
			return nil
		})
	})

	if err != nil {
		return nil, err
	}

	return results, nil

	// filter
	// var filtered []string
	// for _, result := range results {
	// 	if strings.HasPrefix(result, input) {
	// 		filtered = append(filtered, result)
	// 	}
	// }
	//
	// return filtered

}

// add checks if command being passed is in the listCommands
// then stores the command and workding directory
func add(path string, promptCmd string) error {
	// get the first command in the promptCmd string
	cmd := strings.Split(promptCmd, " ")[0]

	commands, err := listCommands()
	if err != nil {
		return err
	}

	// check if the command is valid
	if !containsCmd(cmd, commands) {
		return nil
	}

	// Add command to db
	// fmt.Printf("adding. cmd: %s, path: %s \n", promptCmd, path)
	return db.Update(func(tx *bolt.Tx) error {
		directoryBucket, err := tx.CreateBucketIfNotExists([]byte("DirectoryBucket"))
		if err != nil {
			return err
		}

		pathBucket, err := directoryBucket.CreateBucketIfNotExists([]byte(path))
		if err != nil {
			return err
		}

		// Store path and command for contextual path sorting
		cmdBucket, err := tx.CreateBucketIfNotExists([]byte("CommandBucket"))
		if err != nil {
			return err
		}

		// Don't store if the command is r
		if cmd == "r" {
			return nil
		}

		// TODO first look up command and then increment it's count

		// Store just command and usage for overall most used sorting
		err = cmdBucket.Put([]byte(promptCmd), []byte("1"))
		if err != nil {
			return err
		}

		return pathBucket.Put([]byte(promptCmd), []byte("1"))
	})
}

func containsCmd(cmd string, commands []string) bool {
	for _, c := range commands {
		// check first command against list of commands
		if c == cmd {
			return true
		}
	}
	return false
}

// listCommands use $PATH to find directories
// Then reads each directory and looks for executables
func listCommands() ([]string, error) {
	// Split $PATH directories into slice
	paths := strings.Split(os.Getenv("PATH"), ":")
	var commands []string

	// created buffered error chan
	errc := make(chan error, 1)

	// sync go routines
	var wg sync.WaitGroup

	// find commands appends results to commands slice
	findCommands := func(p string) {
		defer wg.Done()

		files, err := ioutil.ReadDir(p)
		if err != nil {
			errc <- err // write err into error chan
			return
		}

		for _, f := range files {
			m := f.Mode()

			// Check if file is executable
			if m&0111 != 0 {
				commands = append(commands, f.Name())
			}
		}

		errc <- nil // write nil into error chan
	}

	// Check each path for commands
	for _, p := range paths {
		wg.Add(1)
		go findCommands(p)

		// read any error that is in error chan
		if err := <-errc; err != nil {
			return nil, err
		}
	}

	wg.Wait() // Wait for the paths to be checked

	return commands, nil
}

// stats TODO print stats and usage of r
func stats() {
	fmt.Println("stats")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/go-martini/martini"
	"github.com/wmbest2/rats_server/rats"
	"github.com/wmbest2/rats_server/test"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strconv"
	"time"
)

func uuid() (string, error) {
	uuid := make([]byte, 16)
	n, err := rand.Read(uuid)
	if n != len(uuid) || err != nil {
		return "", err
	}
	// TODO: verify the two lines implement RFC 4122 correctly
	uuid[8] = 0x80 // variant bits see page 5
	uuid[4] = 0x40 // version 4 Pseudo Random, see page 7

	return hex.EncodeToString(uuid), nil
}

func Mongo(db string) martini.Handler {
	session, err := mgo.Dial(db)
	if err != nil {
		panic(err)
	}

	return func(c martini.Context) {
		reqSession := session.Clone()
		c.Map(reqSession.DB("rats"))
		defer reqSession.Close()

		c.Next()
	}
}

func makeTestFolder() (string, string) {
	uuid, err := uuid()
	if err != nil {
		panic(err)
	}

	dir := fmt.Sprintf("test_runs/%s", uuid)
	os.MkdirAll(dir, os.ModeDir|os.ModePerm|os.ModeTemporary)
	return uuid, dir
}

func save(key string, filename string, r *http.Request) (bool, error) {
	apk, _, _ := r.FormFile(key)
	if apk != nil {
		apk_file, err := os.Create(filename)

		if err != nil {
			return false, err
		}

		_, err = io.Copy(apk_file, apk)
		apk.Close()
		apk_file.Close()

		if err != nil {
			return false, err
		}

		return true, nil
	}
	return false, nil
}

func RunTests(w http.ResponseWriter, r *http.Request, db *mgo.Database) (int, []byte) {
	uuid, dir := makeTestFolder()

    count,_ := strconv.Atoi(r.FormValue("count"))

    filter := &rats.DeviceFilter{Count: count}

	f := fmt.Sprintf("%s/main.apk", dir)
	install, err := save("apk", f, r)

	if err != nil {
		panic(err)
	}

    devices := <-rats.GetDevices(filter)
    rats.Reserve(devices)

	if install {
		rats.Install(f, devices)
	}

	f = fmt.Sprintf("%s/test.apk", dir)
	_, err = save("test-apk", f, r)

	if err != nil {
		panic("A Test Apk must be supplied")
	}

	rats.Install(f, devices)
	manifest := rats.GetManifest(f)

	rats.Unlock(devices)

	s := test.RunTests(manifest, devices)
	s.Name = uuid
	s.Timestamp = time.Now()
	s.Project = manifest.Instrument.Target

	if dbErr := db.C("runs").Insert(&s); dbErr != nil {
		return http.StatusConflict, []byte(dbErr.Error())
	}

	rats.Uninstall(manifest.Package, devices)
	rats.Uninstall(manifest.Instrument.Target, devices)
    rats.Release(devices)

	os.RemoveAll(dir)

	str, err := json.Marshal(s)
	if err != nil {
		panic(err)
	}

	//pprof.WriteHeapProfile(file)
	//file.Close()
	return http.StatusOK, str
}

func GetRunDevice(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	var runs test.TestSuites
	q := bson.M{"name": parms["id"]}
	fmt.Printf("%#v\n", q)
	query := db.C("runs").Find(q).Limit(1)
	query.One(&runs)
	for _, run := range runs.TestSuites {
		if run.Hostname == parms["device"] {
			b, _ := json.Marshal(run)
			return http.StatusOK, string(b)
		}
	}
	file, err := os.Create("memprof")
	if err != nil {
		log.Fatal(err)
	}

	pprof.StartCPUProfile(file)
	defer pprof.StopCPUProfile()

	return http.StatusNotFound, fmt.Sprintf("Run on Device %s Not Found", parms["device"])
}

func GetRun(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	var runs test.TestSuites
	query := db.C("runs").Find(bson.M{"name": parms["id"]}).Limit(1)
	query.One(&runs)
	b, _ := json.Marshal(runs)
	return http.StatusOK, string(b)
}

func GetRuns(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	page := 0
	p := r.URL.Query().Get("page")
	if p != "" {
		page, _ = strconv.Atoi(p)
	}

	size := 25
	s := r.URL.Query().Get("count")
	if s != "" {
		size, _ = strconv.Atoi(s)
	}

	var runs []*test.TestSuites
	query := db.C("runs").Find(bson.M{}).Limit(size).Skip(page * size)
	//query.Select(bson.M{"name": 1, "project": 1, "timestamp": 1, "time": 1, "success": 1})
	query.Sort("-timestamp")
	query.All(&runs)
	b, _ := json.Marshal(runs)
	return http.StatusOK, string(b)
}

func GetDevices(parms martini.Params) (int, string) {
	b, _ := json.Marshal(<-rats.GetAllDevices())
	return http.StatusOK, string(b)
}

func serveStatic(m *martini.Martini) {
	_, file, _, _ := runtime.Caller(0)
	here := filepath.Dir(file)
	static := filepath.Join(here, "/public")
	m.Use(martini.Static(string(static)))
}

func main() {

	go rats.UpdateAdb(5)

	m := martini.New()
	m.Use(martini.Recovery())
	m.Use(martini.Logger())
	m.Use(Mongo("localhost/rats"))
	serveStatic(m)
	r := martini.NewRouter()
	r.Get(`/api/devices`, GetDevices)
	r.Post("/api/run", RunTests)
	r.Get("/api/runs", GetRuns)
	r.Get("/api/runs/:id", GetRun)
	r.Get("/api/runs/:id/:device", GetRunDevice)

	m.Action(r.Handle)
	m.Run()
}
<commit_msg>Fixed query<commit_after>package main

import (
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/go-martini/martini"
	"github.com/wmbest2/rats_server/rats"
	"github.com/wmbest2/rats_server/test"
	"io"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"time"
)

func uuid() (string, error) {
	uuid := make([]byte, 16)
	n, err := rand.Read(uuid)
	if n != len(uuid) || err != nil {
		return "", err
	}
	// TODO: verify the two lines implement RFC 4122 correctly
	uuid[8] = 0x80 // variant bits see page 5
	uuid[4] = 0x40 // version 4 Pseudo Random, see page 7

	return hex.EncodeToString(uuid), nil
}

func Mongo(db string) martini.Handler {
	session, err := mgo.Dial(db)
	if err != nil {
		panic(err)
	}

	return func(c martini.Context) {
		reqSession := session.Clone()
		c.Map(reqSession.DB("rats"))
		defer reqSession.Close()

		c.Next()
	}
}

func makeTestFolder() (string, string) {
	uuid, err := uuid()
	if err != nil {
		panic(err)
	}

	dir := fmt.Sprintf("test_runs/%s", uuid)
	os.MkdirAll(dir, os.ModeDir|os.ModePerm|os.ModeTemporary)
	return uuid, dir
}

func save(key string, filename string, r *http.Request) (bool, error) {
	apk, _, _ := r.FormFile(key)
	if apk != nil {
		apk_file, err := os.Create(filename)

		if err != nil {
			return false, err
		}

		_, err = io.Copy(apk_file, apk)
		apk.Close()
		apk_file.Close()

		if err != nil {
			return false, err
		}

		return true, nil
	}
	return false, nil
}

func RunTests(w http.ResponseWriter, r *http.Request, db *mgo.Database) (int, []byte) {
	uuid, dir := makeTestFolder()

    count,_ := strconv.Atoi(r.FormValue("count"))

    filter := &rats.DeviceFilter{Count: count}

	f := fmt.Sprintf("%s/main.apk", dir)
	install, err := save("apk", f, r)

	if err != nil {
		panic(err)
	}

    devices := <-rats.GetDevices(filter)
    rats.Reserve(devices)

	if install {
		rats.Install(f, devices)
	}

	f = fmt.Sprintf("%s/test.apk", dir)
	_, err = save("test-apk", f, r)

	if err != nil {
		panic("A Test Apk must be supplied")
	}

	rats.Install(f, devices)
	manifest := rats.GetManifest(f)

	rats.Unlock(devices)

	s := test.RunTests(manifest, devices)
	s.Name = uuid
	s.Timestamp = time.Now()
	s.Project = manifest.Instrument.Target

	if dbErr := db.C("runs").Insert(&s); dbErr != nil {
		return http.StatusConflict, []byte(dbErr.Error())
	}

	rats.Uninstall(manifest.Package, devices)
	rats.Uninstall(manifest.Instrument.Target, devices)
    rats.Release(devices)

	os.RemoveAll(dir)

	str, err := json.Marshal(s)
	if err != nil {
		panic(err)
	}

	return http.StatusOK, str
}

func GetRunDevice(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	var runs test.TestSuites
	q := bson.M{"name": parms["id"]}
	fmt.Printf("%#v\n", q)
	query := db.C("runs").Find(q).Limit(1)
	query.One(&runs)
	for _, run := range runs.TestSuites {
		if run.Hostname == parms["device"] {
			b, _ := json.Marshal(run)
			return http.StatusOK, string(b)
		}
	}

	return http.StatusNotFound, fmt.Sprintf("Run on Device %s Not Found", parms["device"])
}

func GetRun(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	var runs test.TestSuites
	query := db.C("runs").Find(bson.M{"name": parms["id"]}).Limit(1)
	query.One(&runs)
	b, _ := json.Marshal(runs)
	return http.StatusOK, string(b)
}

func GetRuns(r *http.Request, parms martini.Params, db *mgo.Database) (int, string) {
	page := 0
	p := r.URL.Query().Get("page")
	if p != "" {
		page, _ = strconv.Atoi(p)
	}

	size := 25
	s := r.URL.Query().Get("count")
	if s != "" {
		size, _ = strconv.Atoi(s)
	}

	var runs []*test.TestSuites
    query := db.C("runs").Find(bson.M{}).Limit(size).Skip(page * size)
    query.Select(bson.M{"name": 1, "project": 1, "timestamp": 1, "time": 1, "success": 1, "testsuites.host": 1})
	query.Sort("-timestamp")
	query.All(&runs)
	b, _ := json.Marshal(runs)
	return http.StatusOK, string(b)
}

func GetDevices(parms martini.Params) (int, string) {
	b, _ := json.Marshal(<-rats.GetAllDevices())
	return http.StatusOK, string(b)
}

func serveStatic(m *martini.Martini) {
	_, file, _, _ := runtime.Caller(0)
	here := filepath.Dir(file)
	static := filepath.Join(here, "/public")
	m.Use(martini.Static(string(static)))
}

func main() {
	go rats.UpdateAdb(5)

	m := martini.New()
	m.Use(martini.Recovery())
	m.Use(martini.Logger())
	m.Use(Mongo("localhost/rats"))
	serveStatic(m)
	r := martini.NewRouter()
	r.Get(`/api/devices`, GetDevices)
	r.Post("/api/run", RunTests)
	r.Get("/api/runs", GetRuns)
	r.Get("/api/runs/:id", GetRun)
	r.Get("/api/runs/:id/:device", GetRunDevice)

	m.Action(r.Handle)
	m.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/negroni"
	"github.com/xyproto/onthefly"
)

const (
	bannerW = 20
	bannerH = 40

	zoomFactor = 8 // 8x zoom

	fullW  = bannerW
	fullH  = bannerH
	halfW  = bannerW / 2
	halfH  = bannerH / 2
	thirdW = bannerW / 3
	thirdH = bannerH / 3

	maxX = fullW - 1
	maxY = fullH - 1

	maxPatterns = 99 // 6

	patternUpperHalf = iota
	patternLowerHalf
	patternUpperThird
	patternLowerThird
	patternUpperTriangle
	patternLowerTriangle
	patternCircle
	patternHorizontalLine
	patternVerticalLine
)

type Pattern struct {
	color string
	ptype int
}

type Banner struct {
	patterns []*Pattern
	curpat   int
}

func (b *Banner) Draw(svg *onthefly.Tag) {
	// generate the picture, then draw
	for _, pattern := range b.patterns {
		switch pattern.ptype {
		case patternUpperHalf:
			svg.Box(0, 0, fullW, halfH, pattern.color)
		case patternLowerHalf:
			svg.Box(0, halfH, fullW, halfH, pattern.color)
		case patternUpperThird:
			svg.Box(0, 0, fullW, thirdH, pattern.color)
		case patternLowerThird:
			svg.Box(0, fullH-thirdH, fullW, fullH-thirdH, pattern.color)
		case patternUpperTriangle:
			svg.Triangle(0, 0, fullW, 0, halfW, halfH, pattern.color)
		case patternLowerTriangle:
			svg.Triangle(0, fullH, fullW, fullH, halfW, halfH, pattern.color)
		case patternCircle:
			svg.Circle(halfW, halfH, thirdW, pattern.color)
		case patternHorizontalLine:
			svg.Box(0, halfH-1, fullW, 2, pattern.color)
		case patternVerticalLine:
			svg.Box(halfW-1, 0, 2, fullH, pattern.color)
		}
	}
	// For debugging
	//svg.Pixel(0, 0, 0, 255, 0)
	//svg.Pixel(maxX, 0, 0, 0, 255)
	//svg.Pixel(0, maxY, 255, 255, 0)
	//svg.Pixel(maxX, maxY, 0, 255, 255)
}

// Generate a new SVG Page for a banner
func (b *Banner) SVGpage() *onthefly.Page {
	page, svg := onthefly.NewTinySVG(0, 0, bannerW, bannerH)
	desc := svg.AddNewTag("desc")
	desc.AddContent("A banner")
	b.Draw(svg)
	return page
}

func NewBanner() *Banner {
	return &Banner{}
}

func NewPattern(color string, pattern int) *Pattern {
	return &Pattern{color, pattern}
}

func (b *Banner) AddPattern(p *Pattern) {
	if len(b.patterns) > maxPatterns {
		log.Fatalln("Too many patters for banner, max", maxPatterns)
	}
	b.patterns = append(b.patterns, p)
}

// Generate a new onthefly Page (HTML5 and CSS combined)
func mainPage(svgurl string) *onthefly.Page {

	// Create a new HTML5 page, with CSS included
	page := onthefly.NewHTML5Page("Banner")

	page.AddContent("Banner")

	// Change the margin (em is default)
	page.SetMargin(4)

	// Change the font family
	page.SetFontFamily("serif") // or: sans-serif

	// Change the color scheme
	page.SetColor("black", "#d0d0d0")

	// Include the generated SVG image on the page
	body, _ := page.GetTag("body")

	// CSS attributes for the body tag
	body.AddStyle("font-size", "2em")

	// Paragraph
	p := body.AddNewTag("p")

	// CSS style
	p.AddStyle("margin-top", "2em")

	var (
		tag          *onthefly.Tag
		useObjectTag = false
	)
	if useObjectTag {
		// object tag
		tag = p.AddNewTag("object")
		// HTML attributes
		tag.AddAttrib("data", svgurl)
		tag.AddAttrib("type", "image/svg+xml")
	} else {
		// img tag
		tag = p.AddNewTag("img")
		// HTML attributes
		tag.AddAttrib("src", svgurl)
		tag.AddAttrib("alt", "Banner")
	}

	// CSS style
	w := strconv.Itoa(bannerW * zoomFactor)
	h := strconv.Itoa(bannerH * zoomFactor)
	tag.AddStyle("width", w+"px")
	tag.AddStyle("height", h+"px")
	tag.AddStyle("border", "8px solid black")

	return page
}

// Set up the paths and handlers then start serving.
func main() {
	b := NewBanner()

	// TODO: Add a list of patterns to a banner
	b.AddPattern(NewPattern("red", patternUpperHalf))
	b.AddPattern(NewPattern("purple", patternLowerHalf))
	b.AddPattern(NewPattern("blue", patternUpperTriangle))
	b.AddPattern(NewPattern("blue", patternLowerTriangle))
	b.AddPattern(NewPattern("blue", patternCircle))
	b.AddPattern(NewPattern("blue", patternUpperThird))
	b.AddPattern(NewPattern("blue", patternLowerThird))
	b.AddPattern(NewPattern("blue", patternHorizontalLine))
	b.AddPattern(NewPattern("orange", patternVerticalLine))

	// Create a Negroni instance and a ServeMux instance
	n := negroni.Classic()
	mux := http.NewServeMux()

	// Publish the generated SVG as "/banner.svg"
	svgurl := "/img/banner.svg"
	mux.HandleFunc(svgurl, func(w http.ResponseWriter, req *http.Request) {
		w.Header().Add("Content-Type", "image/svg+xml")
		fmt.Fprint(w, b.SVGpage().String())
	})

	// Generate a Page that includes the svg image
	page := mainPage(svgurl)
	// Publish the generated Page in a way that connects the HTML and CSS
	page.Publish(mux, "/", "/css/banner.css", false)

	// Share the files in public (already included in Classic)
	//n.Use(negroni.NewStatic(http.Dir("public")))

	// Handler goes last
	n.UseHandler(mux)

	// Listen for requests at port 3000
	n.Run(":3000")
}
<commit_msg>Started implementing all patterns. All colors ok.<commit_after>package main

import (
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"strconv"
	"time"

	"github.com/codegangsta/negroni"
	"github.com/xyproto/onthefly"
)

const (
	bannerW = 20
	bannerH = 40

	zoomFactor = 8 // 8x zoom

	fullW  = bannerW
	fullH  = bannerH
	halfW  = bannerW / 2
	halfH  = bannerH / 2
	thirdW = bannerW / 3
	thirdH = bannerH / 3

	maxX = fullW - 1
	maxY = fullH - 1

	maxPatterns = 99 // 6

	// Same order as minecraft.gamepedia.com/Banner
	patternLowerThird         = iota // Base Fess Banner
	patternUpperThird                // Chief Fess Banner
	patternLeftThird                 // Pale Dexter Banner
	patternRightThird                // Pale Sinister Banner
	patternCenterThird               // Pale Banner
	patternHorizontalLine            // Fess Banner
	patternDiagonal1                 // Bend Banner
	patternDiagonal2                 // Bend Sinister Banner
	patterStripes                    // Paly Banner
	patternDiaCross                  // Saltire Banner
	patternCross                     // Cross Banner
	patternUpperLeftTriangle         // Per Bend Sinister Banner
	patternUpperRightTriangle        // Per Bend Banner
	patternLowerLeftTriangle         // Per Bend Inverted Banner
	patternLowerRightTriangle        // Per Bend Sinister Inverted Banner
	patternLeftHalf                  // Per Pale Banner
	patternRightHalf                 // Per Pale Inverted Banner
	patternUpperHalf                 // Per Fess Banner
	patternLowerHalf                 // Per Fess Inverted Banner
	patternLowerLeftSquare           // Base Dexter Canton Banner
	patternLowerRightSquare          // Base Sinister Canton Banner
	patternUpperLeftSquare           // Chief Dexter Canton Banner
	patternUpperRightSqaure          // Chief Sinister Canton Banner
	patternLowerTriangle             // Chevron Banner
	patternUpperTriangle             // Inverted Chevron Banner
	patternLowerWaves                // Base Indented Banner
	patternUpperWaves                // Chief Indented Banner
	patternCircle                    // Roundel Banner
	patternDiamond                   // Lozenge Banner
	patternBorder                    // Bordure Banner
	patternWaveBorder                // Black/Dyed Borduer Indented Banner
	patternBricks                    // Black/Dyed Field Masoned Banner
	patternGradientDown              // Gradient Banner
	patternGradientUp                // Base Gradient Banner
	patternCreeper                   // Black/Dyed Creeper Charge Banner
	patternSkull                     // Black/Dyed Skull Charge Banner
	patternFlower                    // Black/Dyed Flower Charge Banner
	patternLogo                      // Black/Dyed Mojang Charge Banner

	// Custom patterns
	patternFull // Background

	colorWhite = iota
	colorOrange
	colorMagenta
	colorLightBlue
	colorYellow
	colorLime
	colorPink
	colorGray
	colorLightGray
	colorCyan
	colorPurple
	colorBlue
	colorBrown
	colorGreen
	colorRed
	colorBlack

	// Custom colors
	colorBrightWhite
)

var (
	colors = map[int]string{
		colorWhite:       "#989898",
		colorOrange:      "#804d23",
		colorMagenta:     "#6b3181",
		colorLightBlue:   "#3e5b7f",
		colorYellow:      "#898923",
		colorLime:        "#4c7815",
		colorPink:        "#8f4c62",
		colorGray:        "#313131",
		colorLightGray:   "#5b5b5b",
		colorCyan:        "#314c5b",
		colorPurple:      "#4d2b6a",
		colorBlue:        "#23316b",
		colorBrown:       "#3e3123",
		colorGreen:       "#3e4c23",
		colorRed:         "#5c2323",
		colorBlack:       "#151515",
		colorBrightWhite: "#ffffff",
	}
)

type Pattern struct {
	pattern int
	color   int
}

type Banner struct {
	patterns []*Pattern
	curpat   int
}

func (b *Banner) Draw(svg *onthefly.Tag) {
	// generate the picture, then draw
	for _, p := range b.patterns {
		color, ok := colors[p.color]
		if !ok {
			log.Fatalln("Invalid color ID: ", p.color)
		}
		//log.Println("color:", color)
		switch p.pattern {
		case patternLowerThird: // Base Fess Banner
			svg.Box(0, fullH-thirdH, fullW, fullH-thirdH, color)
		case patternUpperThird: // Chief Fess Banner
			svg.Box(0, 0, fullW, thirdH, color)
		case patternLeftThird: // Pale Dexter Banner
		case patternRightThird: // Pale Sinister Banner
		case patternCenterThird: // Pale Banner
			svg.Box(halfW-(thirdW/2), 0, thirdW, fullH, color)
		case patternHorizontalLine: // Fess Banner
			svg.Box(0, halfH-1, fullW, 2, color)
		case patternDiagonal1: // Bend Banner
		case patternDiagonal2: // Bend Sinister Banner
		case patterStripes: // Paly Banner
		case patternDiaCross: // Saltire Banner
		case patternCross: // Cross Banner
		case patternUpperLeftTriangle: // Per Bend Sinister Banner
		case patternUpperRightTriangle: // Per Bend Banner
		case patternLowerLeftTriangle: // Per Bend Inverted Banner
		case patternLowerRightTriangle: // Per Bend Sinister Inverted Banner
		case patternLeftHalf: // Per Pale Banner
		case patternRightHalf: // Per Pale Inverted Banner
		case patternUpperHalf: // Per Fess Banner
			svg.Box(0, 0, fullW, halfH, color)
		case patternLowerHalf: // Per Fess Inverted Banner
			svg.Box(0, halfH, fullW, halfH, color)
		case patternLowerLeftSquare: // Base Dexter Canton Banner
		case patternLowerRightSquare: // Base Sinister Canton Banner
		case patternUpperLeftSquare: // Chief Dexter Canton Banner
		case patternUpperRightSqaure: // Chief Sinister Canton Banner
		case patternLowerTriangle: // Chevron Banner
			svg.Triangle(0, fullH, fullW, fullH, halfW, halfH, color)
		case patternUpperTriangle: // Inverted Chevron Banner
			svg.Triangle(0, 0, fullW, 0, halfW, halfH, color)
		case patternLowerWaves: // Base Indented Banner
		case patternUpperWaves: // Chief Indented Banner
		case patternCircle: // Roundel Banner
			svg.Circle(halfW, halfH, thirdW, color)
		case patternDiamond: // Lozenge Banner
		case patternBorder: // Bordure Banner
		case patternWaveBorder: // Black/Dyed Borduer Indented Banner
		case patternBricks: // Black/Dyed Field Masoned Banner
		case patternGradientDown: // Gradient Banner
		case patternGradientUp: // Base Gradient Banner
		case patternCreeper: // Black/Dyed Creeper Charge Banner
		case patternSkull: // Black/Dyed Skull Charge Banner
		case patternFlower: // Black/Dyed Flower Charge Banner
		case patternLogo: // Black/Dyed Mojang Charge Banner
		case patternFull:
			svg.Box(0, 0, fullW, fullH, color)
		}
	}
	// For debugging
	//svg.Pixel(0, 0, 0, 255, 0)
	//svg.Pixel(maxX, 0, 0, 0, 255)
	//svg.Pixel(0, maxY, 255, 255, 0)
	//svg.Pixel(maxX, maxY, 0, 255, 255)
}

// Generate a new SVG Page for a banner
func (b *Banner) SVGpage() *onthefly.Page {
	page, svg := onthefly.NewTinySVG(0, 0, bannerW, bannerH)
	desc := svg.AddNewTag("desc")
	desc.AddContent("A banner")
	b.Draw(svg)
	return page
}

func NewBanner() *Banner {
	return &Banner{}
}

func NewPattern(pattern, color int) *Pattern {
	if (pattern < patternLowerThird) || (pattern > patternFull) {
		log.Fatalln("Invalid pattern ID: ", pattern)
	}
	return &Pattern{pattern, color}
}

func (b *Banner) AddPattern(p *Pattern) {
	if len(b.patterns) > maxPatterns {
		log.Fatalln("Too many patters for banner, max", maxPatterns)
	}
	b.patterns = append(b.patterns, p)
}

// Generate a new onthefly Page (HTML5 and CSS combined)
func mainPage(svgurls []string) *onthefly.Page {

	title := "Banners"

	// Create a new HTML5 page, with CSS included
	page := onthefly.NewHTML5Page(title)
	page.AddContent(title)

	// Change the margin (em is default)
	page.SetMargin(4)

	// Change the font family
	page.SetFontFamily("sans-serif")

	// Change the color scheme
	page.SetColor("black", "#a0a0a0")

	// Include the generated SVG image on the page
	body, _ := page.GetTag("body")

	// CSS attributes for the body tag
	body.AddStyle("font-size", "2em")

	// Paragraph
	p := body.AddNewTag("p")

	// CSS style
	p.AddStyle("margin-top", "2em")

	// Add images
	var (
		tag          *onthefly.Tag
		useObjectTag = false
	)
	for _, svgurl := range svgurls {
		if useObjectTag {
			// object tag
			tag = p.AddNewTag("object")
			// HTML attributes
			tag.AddAttrib("data", svgurl)
			tag.AddAttrib("type", "image/svg+xml")
		} else {
			// img tag
			tag = p.AddNewTag("img")
			// HTML attributes
			tag.AddAttrib("src", svgurl)
			tag.AddAttrib("alt", "Banner")
		}
	}

	// CSS style
	w := strconv.Itoa(bannerW * zoomFactor)
	h := strconv.Itoa(bannerH * zoomFactor)
	tag.AddStyle("width", w+"px")
	tag.AddStyle("height", h+"px")
	tag.AddStyle("border", "8px solid black")

	return page
}

func randomColor() int {
	return colorWhite + rand.Intn((colorBlack-colorWhite)+1)
}

func seed() {
	rand.Seed(time.Now().UnixNano())
}

// Set up the paths and handlers then start serving.
func main() {
	seed()

	// Create a Negroni instance and a ServeMux instance
	n := negroni.Classic()
	mux := http.NewServeMux()

	var (
		svgurls []string
		b       *Banner
	)
	for i := patternLowerThird; i < patternLogo; i++ {

		b = NewBanner()
		b.AddPattern(NewPattern(patternFull, colorBrightWhite))
		b.AddPattern(NewPattern(i, colorRed))

		svgString := b.SVGpage().String()

		// Publish the generated SVG as "/img/banner_NNN.svg"
		svgurl := fmt.Sprintf("/img/banner_%d.svg", i)
		mux.HandleFunc(svgurl, func(w http.ResponseWriter, req *http.Request) {
			w.Header().Add("Content-Type", "image/svg+xml")
			fmt.Fprint(w, svgString)
		})

		svgurls = append(svgurls, svgurl)
	}

	// Generate a Page that includes the svg images
	page := mainPage(svgurls)
	// Publish the generated Page in a way that connects the HTML and CSS
	page.Publish(mux, "/", "/css/banner.css", false)

	// Handler goes last
	n.UseHandler(mux)

	// Listen for requests at port 3000
	n.Run(":3000")
}
<|endoftext|>