<commit_before>package app

import (
	"github.com/jessevdk/go-flags"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type option_set struct {
	DisableS3 bool   `short:"d" long:"no-s3" description:"Disable publishing to S3"`
	OnlyRun   string `short:"o" long:"only" description:"Only run specific confiugration"`
}

var opts option_set

func Run(args []string) {
	args, mode := checkArgs(args)

	args, err := flags.ParseArgs(&opts, args)

	if strings.HasSuffix(args[0], ".enc") || len(args) >= 2 && mode != "compile" {
		performExtraction(args)
		return
	}

	abs, err := filepath.Abs(args[0])
	if err != nil {
		panicQuitf("Unable to expand %v\r\n", args[1])
	}

	performCompilation(abs, opts)
}

func checkArgs(args []string) ([]string, string) {
	if len(args) == 1 {
		printArgMessage(args[0])
		return []string{}, ""
	}

	appname := args[0]
	args = args[1:len(args)]

	var mode string
	if args[0] == "compile" || args[0] == "extract" {
		if len(args) == 1 {
			printArgMessage(appname)
			return []string{}, ""
		} else {
			mode = args[0]
			args = args[1:len(args)]
		}
	}

	return args, mode
}

func printArgMessage(appname string) {
	log.Printf("Usage: %v CONFIG_FILE\r\n", appname)
	panicQuitf("Usage: %v ENCRYPTED_FILE KEY_FILE [OUT_FILE]\r\n", appname)
}

func panicQuit() {
	os.Exit(1)
}

func panicQuitf(format string, v ...interface{}) {
	log.Printf(format, v...)
	os.Exit(1)
}
<commit_msg>Ambiguous<commit_after>package app

import (
	"github.com/jessevdk/go-flags"
	"log"
	"os"
	"path/filepath"
	"strings"
)

type option_set struct {
	DisableS3 bool   `short:"n" long:"no-s3" description:"Disable publishing to S3"`
	OnlyRun   string `short:"o" long:"only" description:"Only run specific confiugration"`
}

var opts option_set

func Run(args []string) {
	args, mode := checkArgs(args)

	args, err := flags.ParseArgs(&opts, args)

	if strings.HasSuffix(args[0], ".enc") || len(args) >= 2 && mode != "compile" {
		performExtraction(args)
		return
	}

	abs, err := filepath.Abs(args[0])
	if err != nil {
		panicQuitf("Unable to expand %v\r\n", args[1])
	}

	performCompilation(abs, opts)
}

func checkArgs(args []string) ([]string, string) {
	if len(args) == 1 {
		printArgMessage(args[0])
		return []string{}, ""
	}

	appname := args[0]
	args = args[1:len(args)]

	var mode string
	if args[0] == "compile" || args[0] == "extract" {
		if len(args) == 1 {
			printArgMessage(appname)
			return []string{}, ""
		} else {
			mode = args[0]
			args = args[1:len(args)]
		}
	}

	return args, mode
}

func printArgMessage(appname string) {
	log.Printf("Usage: %v CONFIG_FILE\r\n", appname)
	panicQuitf("Usage: %v ENCRYPTED_FILE KEY_FILE [OUT_FILE]\r\n", appname)
}

func panicQuit() {
	os.Exit(1)
}

func panicQuitf(format string, v ...interface{}) {
	log.Printf(format, v...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package gamq

import (
	"bufio"
	"bytes"
	"fmt"
	"net"
	"testing"
)

func TestConnectionManager_parseClientCommand_helpMessageReturns(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("HELP", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_parseClientCommand_isCaseInsensitive(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("help", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_whenInitialized_acceptsConnectionsCorrectly(t *testing.T) {
	// Choose a high port, so we don't need sudo to run tests
	config := Config{}
	config.Port = 55555
	SetConfig(&config)

	underTest := ConnectionManager{}
	go underTest.Initialize()

	testConn, err := net.Dial("tcp", "localhost:55555")
	if err != nil {
		t.Fail()
	}

	fmt.Fprintf(testConn, "PINGREQ\n")
	response, err := bufio.NewReader(testConn).ReadString('\n')

	if err != nil || response != "PINGRESP\n" {
		t.Fail()
	}
}
<commit_msg>Some more tests.<commit_after>package gamq

import (
	"bufio"
	"bytes"
	"fmt"
	"net"
	"testing"
)

func TestConnectionManager_parseClientCommand_helpMessageReturns(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("HELP", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_parseClientCommand_isCaseInsensitive(t *testing.T) {
	underTest := ConnectionManager{}

	buf := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(buf)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("help", &mockClient)

	if buf.String() == UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_parseClientCommand_invalidCommandProcessedCorrectly(t *testing.T) {
	underTest := ConnectionManager{}

	dummyWriterBuffer := new(bytes.Buffer)
	bufWriter := bufio.NewWriter(dummyWriterBuffer)
	mockClient := Client{Name: "Mock", Writer: bufWriter}

	underTest.parseClientCommand("fdkfjadkfh", &mockClient)

	if dummyWriterBuffer.String() != UNRECOGNISEDCOMMANDTEXT {
		t.Fail()
	}
}

func TestConnectionManager_emptyClientCommand_handledGracefully(t *testing.T) {
	underTest := ConnectionManager{}

	mockClient := Client{}

	underTest.parseClientCommand("", &mockClient)
}

func TestConnectionManager_whenInitialized_acceptsConnectionsCorrectly(t *testing.T) {
	// Choose a high port, so we don't need sudo to run tests
	config := Config{}
	config.Port = 55555
	SetConfig(&config)

	underTest := ConnectionManager{}
	go underTest.Initialize()

	testConn, err := net.Dial("tcp", "localhost:55555")
	if err != nil || testConn == nil {
		t.Fail()
	}

	fmt.Fprintf(testConn, "PINGREQ\n")
	response, err := bufio.NewReader(testConn).ReadString('\n')

	if err != nil || response != "PINGRESP\n" {
		t.Fail()
	}

	testConn.Close()
}
<|endoftext|>


<commit_before>package api

import (
	"errors"
	"fmt"
	"net/url"

	"github.com/levigross/grequests"
)

type EngineInfo struct {
	AppID string `json:"appId"`
}

type VersionInfo struct {
	VersionTag string `json:"versionTag"`
}

type GroupDeployInfo struct {
	Deployable bool        `json:"deployable"`
	Version    VersionInfo `json:"version"`
}

type InstanceInfo struct {
	Name string `json:"name"`
	Prod int    `json:"prod"`
}

type GetGroupsResult struct {
	GroupName    string            `json:"groupName"`
	Repository   string            `json:"repository"`
	Domain       string            `json:"domain"`
	Instances    []InstanceInfo    `json:"instances"`
	Staging      GroupDeployInfo   `json:"staging"`
	Production   GroupDeployInfo   `json:"production"`
	Environments map[string]string `json:"environments"`
}

type DeployOptions struct {
	DirectUpload   bool
	Message        string
	NoDepsCache    bool
	OverwriteFuncs bool
	Options        string // Additional options in urlencode format
}

func deploy(appID string, group string, prod int, params map[string]interface{}) (*grequests.Response, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	var url string
	switch prod {
	case 0:
		url = "/1.1/engine/groups/" + group + "/staging/version"
	case 1:
		url = "/1.1/engine/groups/" + group + "/production/version"
	default:
		return nil, fmt.Errorf("invalid prod value %d", prod)
	}

	directUpload, _ := params["direct"].(bool)

	if directUpload {
		opts.Data = func() map[string]string {
			data := make(map[string]string)
			for k, v := range params {
				data[k] = fmt.Sprint(v)
			}
			return data
		}()
		archiveFilePath, ok := params["zipUrl"].(string)
		if !ok {
			return nil, fmt.Errorf("bad archive file path")
		}
		archiveFile, err := grequests.FileUploadFromDisk(archiveFilePath)
		if err != nil {
			return nil, err
		}
		opts.Files = archiveFile
		return client.post(url, nil, opts)
	}

	delete(params, "direct")
	return client.post(url, params, opts)
}

// DeployImage will deploy the engine group with specify image tag
func DeployImage(appID string, group string, prod int, imageTag string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["versionTag"] = imageTag

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}
	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// DeployAppFromGit will deploy applications with user's git repo
// returns the event token for polling deploy log
func DeployAppFromGit(appID string, group string, prod int, revision string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["gitTag"] = revision

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}
	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// DeployAppFromFile will deploy applications with specific file
// returns the event token for polling deploy log
func DeployAppFromFile(appID string, group string, prod int, fileURL string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["direct"] = opts.DirectUpload
	params["zipUrl"] = fileURL

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}

	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// GetGroups returns the application's engine groups
func GetGroups(appID string) ([]*GetGroupsResult, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	resp, err := client.get("/1.1/engine/groups?all=true", opts)
	if err != nil {
		return nil, err
	}

	var result []*GetGroupsResult
	err = resp.JSON(&result)
	if err != nil {
		return nil, err
	}

	// filter the staging group, since it's not used anymore
	var filtered []*GetGroupsResult
	for _, group := range result {
		if group.GroupName == "staging" {
			continue
		}
		filtered = append(filtered, group)
	}

	return filtered, nil
}

// GetGroup will fetch all groups from API and return the current group info
func GetGroup(appID string, groupName string) (*GetGroupsResult, error) {
	groups, err := GetGroups(appID)
	if err != nil {
		return nil, err
	}
	for _, group := range groups {
		if group.GroupName == groupName {
			return group, nil
		}
	}
	return nil, errors.New("Failed to find group: " + groupName)
}

func GetEngineInfo(appID string) (*EngineInfo, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	response, err := client.get("/1.1/engine", opts)
	if err != nil {
		return nil, err
	}
	var result = new(EngineInfo)
	err = response.JSON(result)
	return result, err
}

func PutEnvironments(appID string, group string, envs map[string]string) error {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return err
	}
	opts.Headers["X-LC-Id"] = appID

	params := make(map[string]interface{})
	environments := make(map[string]interface{})
	for k, v := range envs {
		environments[k] = v
	}
	params["environments"] = environments

	url := "/1.1/engine/groups/" + group
	response, err := client.patch(url, params, opts)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		return fmt.Errorf("Error updating environment variable, code: %d", response.StatusCode)
	}
	return nil
}

func prepareDeployParams(options *DeployOptions) (map[string]interface{}, error) {
	params := map[string]interface{}{
		"noDependenciesCache": options.NoDepsCache,
		"overwriteFunctions":  options.OverwriteFuncs,
		"async":               true,
	}

	if options.Message != "" {
		params["comment"] = options.Message
	}

	if options.Options != "" {
		queryString, err := url.ParseQuery(options.Options)

		if err != nil {
			return nil, err
		}

		for k, v := range queryString {
			params[k] = v[0]
		}
	}

	return params, nil
}
<commit_msg>feat: add multipart's fieldname<commit_after>package api

import (
	"errors"
	"fmt"
	"net/url"
	"os"

	"github.com/aisk/logp"
	"github.com/levigross/grequests"
)

type EngineInfo struct {
	AppID string `json:"appId"`
}

type VersionInfo struct {
	VersionTag string `json:"versionTag"`
}

type GroupDeployInfo struct {
	Deployable bool        `json:"deployable"`
	Version    VersionInfo `json:"version"`
}

type InstanceInfo struct {
	Name string `json:"name"`
	Prod int    `json:"prod"`
}

type GetGroupsResult struct {
	GroupName    string            `json:"groupName"`
	Repository   string            `json:"repository"`
	Domain       string            `json:"domain"`
	Instances    []InstanceInfo    `json:"instances"`
	Staging      GroupDeployInfo   `json:"staging"`
	Production   GroupDeployInfo   `json:"production"`
	Environments map[string]string `json:"environments"`
}

type DeployOptions struct {
	DirectUpload   bool
	Message        string
	NoDepsCache    bool
	OverwriteFuncs bool
	Options        string // Additional options in urlencode format
}

func deploy(appID string, group string, prod int, params map[string]interface{}) (*grequests.Response, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	var url string
	switch prod {
	case 0:
		url = "/1.1/engine/groups/" + group + "/staging/version"
	case 1:
		url = "/1.1/engine/groups/" + group + "/production/version"
	default:
		return nil, fmt.Errorf("invalid prod value %d", prod)
	}

	directUpload, _ := params["direct"].(bool)
	delete(params, "direct")
	if directUpload {
		opts.Data = func() map[string]string {
			data := make(map[string]string)
			for k, v := range params {
				data[k] = fmt.Sprint(v)
			}
			return data
		}()
		archiveFilePath, ok := params["zipUrl"].(string)
		if !ok {
			return nil, fmt.Errorf("bad archive file path")
		}
		fd, err := os.Open(archiveFilePath)
		if err != nil {
			return nil, err
		}
		defer func() {
			if err := fd.Close(); err != nil {
				logp.Error(err)
			}
		}()
		opts.Files = []grequests.FileUpload{
			{
				FileName:     "leanengine.zip",
				FileContents: fd,
				FieldName:    "tarball",
			},
		}

		return client.post(url, nil, opts)
	}
	return client.post(url, params, opts)
}

// DeployImage will deploy the engine group with specify image tag
func DeployImage(appID string, group string, prod int, imageTag string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["versionTag"] = imageTag

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}
	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// DeployAppFromGit will deploy applications with user's git repo
// returns the event token for polling deploy log
func DeployAppFromGit(appID string, group string, prod int, revision string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["gitTag"] = revision

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}
	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// DeployAppFromFile will deploy applications with specific file
// returns the event token for polling deploy log
func DeployAppFromFile(appID string, group string, prod int, fileURL string, opts *DeployOptions) (string, error) {
	params, err := prepareDeployParams(opts)

	if err != nil {
		return "", err
	}

	params["direct"] = opts.DirectUpload
	params["zipUrl"] = fileURL

	resp, err := deploy(appID, group, prod, params)
	if err != nil {
		return "", err
	}

	result := new(struct {
		EventToken string `json:"eventToken"`
	})
	err = resp.JSON(result)
	return result.EventToken, err
}

// GetGroups returns the application's engine groups
func GetGroups(appID string) ([]*GetGroupsResult, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	resp, err := client.get("/1.1/engine/groups?all=true", opts)
	if err != nil {
		return nil, err
	}

	var result []*GetGroupsResult
	err = resp.JSON(&result)
	if err != nil {
		return nil, err
	}

	// filter the staging group, since it's not used anymore
	var filtered []*GetGroupsResult
	for _, group := range result {
		if group.GroupName == "staging" {
			continue
		}
		filtered = append(filtered, group)
	}

	return filtered, nil
}

// GetGroup will fetch all groups from API and return the current group info
func GetGroup(appID string, groupName string) (*GetGroupsResult, error) {
	groups, err := GetGroups(appID)
	if err != nil {
		return nil, err
	}
	for _, group := range groups {
		if group.GroupName == groupName {
			return group, nil
		}
	}
	return nil, errors.New("Failed to find group: " + groupName)
}

func GetEngineInfo(appID string) (*EngineInfo, error) {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return nil, err
	}
	opts.Headers["X-LC-Id"] = appID

	response, err := client.get("/1.1/engine", opts)
	if err != nil {
		return nil, err
	}
	var result = new(EngineInfo)
	err = response.JSON(result)
	return result, err
}

func PutEnvironments(appID string, group string, envs map[string]string) error {
	client := NewClientByApp(appID)

	opts, err := client.options()
	if err != nil {
		return err
	}
	opts.Headers["X-LC-Id"] = appID

	params := make(map[string]interface{})
	environments := make(map[string]interface{})
	for k, v := range envs {
		environments[k] = v
	}
	params["environments"] = environments

	url := "/1.1/engine/groups/" + group
	response, err := client.patch(url, params, opts)
	if err != nil {
		return err
	}
	if response.StatusCode != 200 {
		return fmt.Errorf("Error updating environment variable, code: %d", response.StatusCode)
	}
	return nil
}

func prepareDeployParams(options *DeployOptions) (map[string]interface{}, error) {
	params := map[string]interface{}{
		"noDependenciesCache": options.NoDepsCache,
		"overwriteFunctions":  options.OverwriteFuncs,
		"async":               true,
	}

	if options.Message != "" {
		params["comment"] = options.Message
	}

	if options.Options != "" {
		queryString, err := url.ParseQuery(options.Options)

		if err != nil {
			return nil, err
		}

		for k, v := range queryString {
			params[k] = v[0]
		}
	}

	return params, nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/kr/pty"
	"github.com/mattn/go-shellwords"
	"github.com/pivotal-golang/archiver/compressor"
	"github.com/pkg/term"

	"github.com/cloudfoundry-incubator/garden"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

func handleComplete(c *cli.Context) {
	// This will complete if no args are passed
	if c.Args().Present() {
		return
	}

	containers, err := client(c).Containers(nil)
	failIf(err)

	for _, container := range containers {
		fmt.Println(container.Handle())
	}
}

func fail(err error) {
	fmt.Fprintln(os.Stderr, "failed:", err)
	os.Exit(1)
}

func failIf(err error) {
	if err != nil {
		fail(err)
	}
}

func client(c *cli.Context) garden.Client {
	target := c.GlobalString("target")
	return gclient.New(gconn.New("tcp", target))
}

func handle(c *cli.Context) string {
	if len(c.Args()) == 0 {
		fail(errors.New("must provide container handle"))
	}
	return c.Args().First()
}

func main() {
	app := cli.NewApp()
	app.Name = "gaol"
	app.Usage = "a cli for garden"
	app.Version = "0.0.1"
	app.Author = "Chris Brown"
	app.Email = "cbrown@pivotal.io"
	app.EnableBashCompletion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "target, t",
			Value:  "localhost:7777",
			Usage:  "server to which commands are sent",
			EnvVar: "GAOL_TARGET",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:  "ping",
			Usage: "check if the server is running",
			Action: func(c *cli.Context) {
				err := client(c).Ping()
				failIf(err)
			},
		},
		{
			Name:  "create",
			Usage: "create a container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "handle, n",
					Usage: "name to give container",
				},
				cli.StringFlag{
					Name:  "rootfs, r",
					Usage: "rootfs image with which to create the container",
				},
				cli.DurationFlag{
					Name:  "grace, g",
					Usage: "grace time (resetting ttl) of container",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "privileged user in container is privileged in host",
				},
			},
			Action: func(c *cli.Context) {
				handle := c.String("handle")
				grace := c.Duration("grace")
				rootfs := c.String("rootfs")
				privileged := c.Bool("privileged")

				container, err := client(c).Create(garden.ContainerSpec{
					Handle:     handle,
					GraceTime:  grace,
					RootFSPath: rootfs,
					Privileged: privileged,
				})
				failIf(err)

				fmt.Println(container.Handle())
			},
		},
		{
			Name:         "destroy",
			Usage:        "destroy a container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				client := client(c)
				handles := c.Args()

				for _, handle := range handles {
					err := client.Destroy(handle)
					failIf(err)
				}
			},
		},
		{
			Name:  "list",
			Usage: "get a list of running containers",
			Action: func(c *cli.Context) {
				containers, err := client(c).Containers(nil)
				failIf(err)

				for _, container := range containers {
					fmt.Println(container.Handle())
				}
			},
		},
		{
			Name:  "run",
			Usage: "run a command in a container",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "attach, a",
					Usage: "attach to the process after it is started",
				},
				cli.StringFlag{
					Name:  "dir, d",
					Usage: "current working directory of process",
				},
				cli.StringFlag{
					Name:  "user, u",
					Usage: "user to run the process as",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "use privileged user in container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				attach := c.Bool("attach")
				dir := c.String("dir")
				user := c.String("user")
				privileged := c.Bool("privileged")

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				var processIo garden.ProcessIO
				if attach {
					processIo = garden.ProcessIO{
						Stdin:  os.Stdin,
						Stdout: os.Stdout,
						Stderr: os.Stderr,
					}
				} else {
					processIo = garden.ProcessIO{}
				}

				command := c.Args()[1]
				args, err := shellwords.Parse(command)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path:       args[0],
					Args:       args[1:],
					Dir:        dir,
					Privileged: privileged,
					User:       user,
				}, processIo)
				failIf(err)

				if attach {
					_, err = process.Wait()
					failIf(err)
				} else {
					fmt.Println(process.ID())
				}
			},
		},
		{
			Name:  "attach",
			Usage: "attach to command running in the container",
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "pid, p",
					Usage: "process id to connect to",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				pid := uint32(c.Int("pid"))

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				process, err := container.Attach(pid, garden.ProcessIO{
					Stdin:  os.Stdin,
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				})
				failIf(err)

				_, err = process.Wait()
				failIf(err)
			},
		},
		{
			Name:         "shell",
			Usage:        "open a shell inside the running container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				container, err := client(c).Lookup(handle(c))
				failIf(err)

				term, err := term.Open(os.Stdin.Name())
				failIf(err)

				err = term.SetRaw()
				failIf(err)

				rows, cols, err := pty.Getsize(os.Stdin)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path: "/bin/sh",
					Args: []string{"-l"},
					Env:  []string{"TERM=" + os.Getenv("TERM")},
					TTY: &garden.TTYSpec{
						WindowSize: &garden.WindowSize{
							Rows:    rows,
							Columns: cols,
						},
					},
					Privileged: true,
				}, garden.ProcessIO{
					Stdin:  term,
					Stdout: term,
					Stderr: term,
				})
				if err != nil {
					term.Restore()
					failIf(err)
				}

				resized := make(chan os.Signal, 10)
				signal.Notify(resized, syscall.SIGWINCH)

				go func() {
					for {
						<-resized

						rows, cols, err := pty.Getsize(os.Stdin)
						if err == nil {
							process.SetTTY(garden.TTYSpec{
								WindowSize: &garden.WindowSize{
									Rows:    rows,
									Columns: cols,
								},
							})
						}
					}
				}()

				process.Wait()
				term.Restore()
			},
		},
		{
			Name:  "stream-in",
			Usage: "stream data into the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "to-file, t",
					Usage: "destination path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				dst := c.String("to-file")
				if dst == "" {
					fail(errors.New("missing --to-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				// perform dance to get correct file names
				tmpDir, err := ioutil.TempDir("", "gaol")
				failIf(err)
				defer os.RemoveAll(tmpDir)

				tmp, err := os.Create(filepath.Join(tmpDir, filepath.Base(dst)))
				failIf(err)

				_, err = io.Copy(tmp, os.Stdin)
				failIf(err)

				err = tmp.Close()
				failIf(err)

				reader, writer := io.Pipe()
				go func(w io.WriteCloser) {
					err := compressor.WriteTar(tmp.Name(), w)
					failIf(err)
					w.Close()
				}(writer)

				err = container.StreamIn(filepath.Dir(dst), reader)
				failIf(err)
			},
		},
		{
			Name:  "stream-out",
			Usage: "stream data out of the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from-file, f",
					Usage: "source path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				src := c.String("from-file")
				if src == "" {
					fail(errors.New("missing --from-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				output, err := container.StreamOut(src)
				failIf(err)

				tr := tar.NewReader(output)
				_, err = tr.Next()
				failIf(err)

				_, err = io.Copy(os.Stdout, tr)
				failIf(err)
			},
		},
	}

	app.Run(os.Args)
}
<commit_msg>add net in support<commit_after>package main

import (
	"archive/tar"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/kr/pty"
	"github.com/mattn/go-shellwords"
	"github.com/pivotal-golang/archiver/compressor"
	"github.com/pkg/term"

	"github.com/cloudfoundry-incubator/garden"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

func handleComplete(c *cli.Context) {
	// This will complete if no args are passed
	if c.Args().Present() {
		return
	}

	containers, err := client(c).Containers(nil)
	failIf(err)

	for _, container := range containers {
		fmt.Println(container.Handle())
	}
}

func fail(err error) {
	fmt.Fprintln(os.Stderr, "failed:", err)
	os.Exit(1)
}

func failIf(err error) {
	if err != nil {
		fail(err)
	}
}

func client(c *cli.Context) garden.Client {
	target := c.GlobalString("target")
	return gclient.New(gconn.New("tcp", target))
}

func handle(c *cli.Context) string {
	if len(c.Args()) == 0 {
		fail(errors.New("must provide container handle"))
	}
	return c.Args().First()
}

func main() {
	app := cli.NewApp()
	app.Name = "gaol"
	app.Usage = "a cli for garden"
	app.Version = "0.0.1"
	app.Author = "Chris Brown"
	app.Email = "cbrown@pivotal.io"
	app.EnableBashCompletion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "target, t",
			Value:  "localhost:7777",
			Usage:  "server to which commands are sent",
			EnvVar: "GAOL_TARGET",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:  "ping",
			Usage: "check if the server is running",
			Action: func(c *cli.Context) {
				err := client(c).Ping()
				failIf(err)
			},
		},
		{
			Name:  "create",
			Usage: "create a container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "handle, n",
					Usage: "name to give container",
				},
				cli.StringFlag{
					Name:  "rootfs, r",
					Usage: "rootfs image with which to create the container",
				},
				cli.DurationFlag{
					Name:  "grace, g",
					Usage: "grace time (resetting ttl) of container",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "privileged user in container is privileged in host",
				},
			},
			Action: func(c *cli.Context) {
				handle := c.String("handle")
				grace := c.Duration("grace")
				rootfs := c.String("rootfs")
				privileged := c.Bool("privileged")

				container, err := client(c).Create(garden.ContainerSpec{
					Handle:     handle,
					GraceTime:  grace,
					RootFSPath: rootfs,
					Privileged: privileged,
				})
				failIf(err)

				fmt.Println(container.Handle())
			},
		},
		{
			Name:         "destroy",
			Usage:        "destroy a container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				client := client(c)
				handles := c.Args()

				for _, handle := range handles {
					err := client.Destroy(handle)
					failIf(err)
				}
			},
		},
		{
			Name:  "list",
			Usage: "get a list of running containers",
			Action: func(c *cli.Context) {
				containers, err := client(c).Containers(nil)
				failIf(err)

				for _, container := range containers {
					fmt.Println(container.Handle())
				}
			},
		},
		{
			Name:  "run",
			Usage: "run a command in a container",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "attach, a",
					Usage: "attach to the process after it is started",
				},
				cli.StringFlag{
					Name:  "dir, d",
					Usage: "current working directory of process",
				},
				cli.StringFlag{
					Name:  "user, u",
					Usage: "user to run the process as",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "use privileged user in container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				attach := c.Bool("attach")
				dir := c.String("dir")
				user := c.String("user")
				privileged := c.Bool("privileged")

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				var processIo garden.ProcessIO
				if attach {
					processIo = garden.ProcessIO{
						Stdin:  os.Stdin,
						Stdout: os.Stdout,
						Stderr: os.Stderr,
					}
				} else {
					processIo = garden.ProcessIO{}
				}

				command := c.Args()[1]
				args, err := shellwords.Parse(command)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path:       args[0],
					Args:       args[1:],
					Dir:        dir,
					Privileged: privileged,
					User:       user,
				}, processIo)
				failIf(err)

				if attach {
					_, err = process.Wait()
					failIf(err)
				} else {
					fmt.Println(process.ID())
				}
			},
		},
		{
			Name:  "attach",
			Usage: "attach to command running in the container",
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "pid, p",
					Usage: "process id to connect to",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				pid := uint32(c.Int("pid"))

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				process, err := container.Attach(pid, garden.ProcessIO{
					Stdin:  os.Stdin,
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				})
				failIf(err)

				_, err = process.Wait()
				failIf(err)
			},
		},
		{
			Name:         "shell",
			Usage:        "open a shell inside the running container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				container, err := client(c).Lookup(handle(c))
				failIf(err)

				term, err := term.Open(os.Stdin.Name())
				failIf(err)

				err = term.SetRaw()
				failIf(err)

				rows, cols, err := pty.Getsize(os.Stdin)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path: "/bin/sh",
					Args: []string{"-l"},
					Env:  []string{"TERM=" + os.Getenv("TERM")},
					TTY: &garden.TTYSpec{
						WindowSize: &garden.WindowSize{
							Rows:    rows,
							Columns: cols,
						},
					},
					Privileged: true,
				}, garden.ProcessIO{
					Stdin:  term,
					Stdout: term,
					Stderr: term,
				})
				if err != nil {
					term.Restore()
					failIf(err)
				}

				resized := make(chan os.Signal, 10)
				signal.Notify(resized, syscall.SIGWINCH)

				go func() {
					for {
						<-resized

						rows, cols, err := pty.Getsize(os.Stdin)
						if err == nil {
							process.SetTTY(garden.TTYSpec{
								WindowSize: &garden.WindowSize{
									Rows:    rows,
									Columns: cols,
								},
							})
						}
					}
				}()

				process.Wait()
				term.Restore()
			},
		},
		{
			Name:  "stream-in",
			Usage: "stream data into the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "to-file, t",
					Usage: "destination path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				dst := c.String("to-file")
				if dst == "" {
					fail(errors.New("missing --to-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				// perform dance to get correct file names
				tmpDir, err := ioutil.TempDir("", "gaol")
				failIf(err)
				defer os.RemoveAll(tmpDir)

				tmp, err := os.Create(filepath.Join(tmpDir, filepath.Base(dst)))
				failIf(err)

				_, err = io.Copy(tmp, os.Stdin)
				failIf(err)

				err = tmp.Close()
				failIf(err)

				reader, writer := io.Pipe()
				go func(w io.WriteCloser) {
					err := compressor.WriteTar(tmp.Name(), w)
					failIf(err)
					w.Close()
				}(writer)

				err = container.StreamIn(filepath.Dir(dst), reader)
				failIf(err)
			},
		},
		{
			Name:  "stream-out",
			Usage: "stream data out of the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from-file, f",
					Usage: "source path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				src := c.String("from-file")
				if src == "" {
					fail(errors.New("missing --from-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				output, err := container.StreamOut(src)
				failIf(err)

				tr := tar.NewReader(output)
				_, err = tr.Next()
				failIf(err)

				_, err = io.Copy(os.Stdout, tr)
				failIf(err)
			},
		},
		{
			Name:  "net-in",
			Usage: "map a port on the host to a port in the container",
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "port, p",
					Usage: "container port",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				target := c.GlobalString("target")
				requestedContainerPort := uint32(c.Int("port"))

				if target == "" {
					fail(errors.New("target must be set"))
				}

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				hostPort, _, err := container.NetIn(0, requestedContainerPort)
				failIf(err)

				host, _, err := net.SplitHostPort(target)
				failIf(err)

				fmt.Println(net.JoinHostPort(host, fmt.Sprintf("%d", hostPort)))
			},
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package ls

import (
	flag "../../appletflag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"os"
	"text/tabwriter"
)

var (
	longFlag      = flag.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flag.Bool("r", false, "Recurse into directories")
	humanFlag     = flag.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flag.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Main() {
	flag.Parse()

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flag.PrintDefaults()
		return
	}

	dirs, e := getDirList()
	if e != nil {
		log.Fatalf("Could not get cwd: %s\n", e)
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			log.Printf("Error while listing directory: %s\n", e)
		}
	}
	out.Flush()
	return
}

func getDirList() ([]string, error) {
	if flag.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flag.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				return e
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	fmt.Fprintf(out, "%s%s\t", e.Name(), getEntryTypeString(e))
	if *longFlag {
		fmt.Fprintf(out, "%s\t", getModeString(e.Mode().Perm()))
		fmt.Fprintf(out, "%s\t", getSizeString(e.Size()))
		// fmt.Fprintf(out, "%s\t", getUserString(e.Uid))
	}
	fmt.Fprintln(out, "")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if uint32(mode)&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%9dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("%7.3f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} /*else if e.IsBlock() {
		return "<>"
	} else if e.IsFifo() {
		return ">>"
	} else if e.IsSymlink() {
		return "@"
	} else if e.IsSocket() {
		return "&"
	} else if e.IsRegular() && (e.Mode&0001 == 0001) {
		return "*"
	}*/
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<commit_msg>ls: Don't stop recursing on error<commit_after>package ls

import (
	flag "../../appletflag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"os"
	"text/tabwriter"
)

var (
	longFlag      = flag.Bool("l", false, "Long, detailed listing")
	recursiveFlag = flag.Bool("r", false, "Recurse into directories")
	humanFlag     = flag.Bool("h", false, "Output sizes in a human readable format")
	helpFlag      = flag.Bool("help", false, "Show this help")
	out           = tabwriter.NewWriter(os.Stdout, 4, 4, 1, ' ', 0)
)

func Main() {
	flag.Parse()

	if *helpFlag {
		println("`ls` [options] [dirs...]")
		flag.PrintDefaults()
		return
	}

	dirs, e := getDirList()
	if e != nil {
		log.Fatalf("Could not get cwd: %s\n", e)
	}

	for _, dir := range dirs {
		e := list(dir, "")
		if e != nil {
			log.Printf("Error while listing directory: %s\n", e)
		}
	}
	out.Flush()
	return
}

func getDirList() ([]string, error) {
	if flag.NArg() <= 0 {
		cwd, e := os.Getwd()
		return []string{cwd}, e
	}
	return flag.Args(), nil
}

func list(dir, prefix string) error {
	entries, e := ioutil.ReadDir(dir)
	if e != nil {
		return e
	}

	for _, entry := range entries {
		printEntry(entry)
		if entry.IsDir() && *recursiveFlag {
			folder := prefix + "/" + entry.Name()
			fmt.Fprintf(out, "%s:\n", folder)
			e := list(dir+"/"+entry.Name(), folder)
			if e != nil {
				log.Printf("Failed listing %s: %s", entry.Name(), e)
				continue
			}
		}
	}
	return nil
}

func printEntry(e os.FileInfo) {
	fmt.Fprintf(out, "%s%s\t", e.Name(), getEntryTypeString(e))
	if *longFlag {
		fmt.Fprintf(out, "%s\t", getModeString(e.Mode().Perm()))
		fmt.Fprintf(out, "%s\t", getSizeString(e.Size()))
		// fmt.Fprintf(out, "%s\t", getUserString(e.Uid))
	}
	fmt.Fprintln(out, "")
}

var accessSymbols = "xwr"

func getModeString(mode os.FileMode) (s string) {
	for i := 8; i >= 0; i-- {
		if uint32(mode)&(1<<uint(i)) == 0 {
			s += "-"
		} else {
			char := i % 3
			s += accessSymbols[char : char+1]
		}
	}
	return
}

var sizeSymbols = "BkMGT"

func getSizeString(size int64) (s string) {
	if !*humanFlag {
		return fmt.Sprintf("%9dB", size)
	}
	var power int
	if size == 0 {
		power = 0
	} else {
		power = int(math.Log(float64(size)) / math.Log(1024.0))
	}
	if power > len(sizeSymbols)-1 {
		power = len(sizeSymbols) - 1
	}
	rSize := float64(size) / math.Pow(1024, float64(power))
	return fmt.Sprintf("%7.3f%s", rSize, sizeSymbols[power:power+1])
}

func getEntryTypeString(e os.FileInfo) string {
	if e.IsDir() {
		return "/"
	} /*else if e.IsBlock() {
		return "<>"
	} else if e.IsFifo() {
		return ">>"
	} else if e.IsSymlink() {
		return "@"
	} else if e.IsSocket() {
		return "&"
	} else if e.IsRegular() && (e.Mode&0001 == 0001) {
		return "*"
	}*/
	return ""
}

func getUserString(id int) string {
	return fmt.Sprintf("%03d", id)
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Vitess Authors.

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

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

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

package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/log"
	vttestpb "vitess.io/vitess/go/vt/proto/vttest"
	"vitess.io/vitess/go/vt/vttest"
)

var cluster *vttest.LocalCluster

func main() {
	flag.Parse()

	var err error
	cluster, err = runCluster()
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		cluster.TearDown()
		os.Exit(1)
	}
	defer cluster.TearDown()

	mux := http.NewServeMux()
	mux.Handle("/", http.FileServer(http.Dir("./")))
	mux.HandleFunc("/exec", exec)
	go http.ListenAndServe(":8000", mux)
	wait()
}

func runCluster() (*vttest.LocalCluster, error) {
	localCluster := &vttest.LocalCluster{
		Config: vttest.Config{
			Topology: &vttestpb.VTTestTopology{
				Keyspaces: []*vttestpb.Keyspace{{
					Name: "user",
					Shards: []*vttestpb.Shard{{
						Name: "-80",
					}, {
						Name: "80-",
					}},
				}, {
					Name: "lookup",
					Shards: []*vttestpb.Shard{{
						Name: "0",
					}},
				}},
			},
			SchemaDir:     path.Join(os.Getenv("VTROOT"), "examples/demo/schema"),
			MySQLBindHost: "0.0.0.0",
		},
	}
	env, err := vttest.NewLocalTestEnv("", 12345)
	if err != nil {
		return localCluster, err
	}
	localCluster.Env = env
	err = localCluster.Setup()
	return localCluster, err
}

func wait() {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	<-c
}

func exec(w http.ResponseWriter, req *http.Request) {
	enc := json.NewEncoder(w)
	enc.SetEscapeHTML(true)

	cp := &mysql.ConnParams{
		Host: "127.0.0.1",
		Port: cluster.Env.PortForProtocol("vtcombo_mysql_port", ""),
	}
	conn, err := mysql.Connect(context.Background(), cp)
	if err != nil {
		response := map[string]string{
			"error": err.Error(),
		}
		enc.Encode(response)
		return
	}
	defer conn.Close()
	query := req.FormValue("query")
	response := make(map[string]interface{})
	response["queries"] = []string{}
	execQuery(conn, "result", query, "", "", response)
	execQuery(conn, "user0", "select * from user", "user", "-80", response)
	execQuery(conn, "user1", "select * from user", "user", "80-", response)
	execQuery(conn, "user_extra0", "select * from user_extra", "user", "-80", response)
	execQuery(conn, "user_extra1", "select * from user_extra", "user", "80-", response)
	execQuery(conn, "music0", "select * from music", "user", "-80", response)
	execQuery(conn, "music1", "select * from music", "user", "80-", response)
	execQuery(conn, "music_extra0", "select * from music_extra", "user", "-80", response)
	execQuery(conn, "music_extra1", "select * from music_extra", "user", "80-", response)
	execQuery(conn, "name_info0", "select * from name_info", "user", "-80", response)
	execQuery(conn, "name_info1", "select * from name_info", "user", "80-", response)
	execQuery(conn, "music_keyspace_idx0", "select music_id, hex(keyspace_id) from music_keyspace_idx", "user", "-80", response)
	execQuery(conn, "music_keyspace_idx1", "select music_id, hex(keyspace_id) from music_keyspace_idx", "user", "80-", response)
	execQuery(conn, "user_seq", "select * from user_seq", "lookup", "0", response)
	execQuery(conn, "music_seq", "select * from music_seq", "lookup", "0", response)
	execQuery(conn, "name_keyspace_idx", "select name, hex(keyspace_id) from name_keyspace_idx", "lookup", "0", response)
	enc.Encode(response)
}

func execQuery(conn *mysql.Conn, key, query, keyspace, shard string, response map[string]interface{}) {
	if query == "" || query == "undefined" {
		return
	}
	if keyspace != "" {
		_, err := conn.ExecuteFetch(fmt.Sprintf("use `%v:%v`", keyspace, shard), 10000, true)
		if err != nil {
			response[key] = map[string]interface{}{
				"title": key,
				"error": err.Error(),
			}
			return
		}
	}
	title := key
	switch {
	case strings.HasSuffix(key, "0"):
		title = key[:len(key)-1] + ":-80"
	case strings.HasSuffix(key, "1"):
		title = key[:len(key)-1] + ":80-"
	}
	qr, err := conn.ExecuteFetch(query, 10000, true)
	if err != nil {
		response[key] = map[string]interface{}{
			"title": title,
			"error": err.Error(),
		}
		log.Errorf("error: %v", err)
		return
	}
	response[key] = resultToMap(title, qr)
}

func resultToMap(title string, qr *sqltypes.Result) map[string]interface{} {
	fields := make([]string, 0, len(qr.Fields))
	for _, field := range qr.Fields {
		fields = append(fields, field.Name)
	}
	rows := make([][]string, 0, len(qr.Rows))
	for _, row := range qr.Rows {
		srow := make([]string, 0, len(row))
		for _, value := range row {
			srow = append(srow, value.ToString())
		}
		rows = append(rows, srow)
	}
	return map[string]interface{}{
		"title":        title,
		"fields":       fields,
		"rows":         rows,
		"rowsaffected": int64(qr.RowsAffected),
		"insertid":     int64(qr.InsertID),
	}
}
<commit_msg>demo: add querylog<commit_after>/*
Copyright 2020 The Vitess Authors.

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

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

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

package main

import (
	"bufio"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"time"

	"vitess.io/vitess/go/mysql"
	"vitess.io/vitess/go/sqltypes"
	"vitess.io/vitess/go/vt/log"
	vttestpb "vitess.io/vitess/go/vt/proto/vttest"
	"vitess.io/vitess/go/vt/vttest"
)

var cluster *vttest.LocalCluster
var querylog <-chan string

func main() {
	flag.Parse()

	runCluster()
	querylog, _ = streamQuerylog(cluster.Env.PortForProtocol("vtcombo", ""))

	mux := http.NewServeMux()
	mux.Handle("/", http.FileServer(http.Dir("./")))
	mux.HandleFunc("/exec", exec)
	go http.ListenAndServe(":8000", mux)

	wait()
	cluster.TearDown()
}

func runCluster() {
	cluster = &vttest.LocalCluster{
		Config: vttest.Config{
			Topology: &vttestpb.VTTestTopology{
				Keyspaces: []*vttestpb.Keyspace{{
					Name: "user",
					Shards: []*vttestpb.Shard{{
						Name: "-80",
					}, {
						Name: "80-",
					}},
				}, {
					Name: "lookup",
					Shards: []*vttestpb.Shard{{
						Name: "0",
					}},
				}},
			},
			SchemaDir:     path.Join(os.Getenv("VTROOT"), "examples/demo/schema"),
			MySQLBindHost: "0.0.0.0",
		},
	}
	env, err := vttest.NewLocalTestEnv("", 12345)
	if err != nil {
		log.Exitf("Error: %v", err)
	}
	cluster.Env = env
	err = cluster.Setup()
	if err != nil {
		cluster.TearDown()
		log.Exitf("Error: %v", err)
	}
}

func wait() {
	c := make(chan os.Signal, 2)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	<-c
}

func exec(w http.ResponseWriter, req *http.Request) {
	enc := json.NewEncoder(w)
	enc.SetEscapeHTML(true)

	cp := &mysql.ConnParams{
		Host: "127.0.0.1",
		Port: cluster.Env.PortForProtocol("vtcombo_mysql_port", ""),
	}
	conn, err := mysql.Connect(context.Background(), cp)
	if err != nil {
		response := map[string]string{
			"error": err.Error(),
		}
		enc.Encode(response)
		return
	}
	defer conn.Close()
	query := req.FormValue("query")
	response := make(map[string]interface{})

	var queries []string
	// Clear existing log.
	for {
		select {
		case <-querylog:
			continue
		default:
		}
		break
	}
	execQuery(conn, "result", query, "", "", response)
	// Collect
	time.Sleep(250 * time.Millisecond)
	for {
		select {
		case val := <-querylog:
			queries = append(queries, val)
			continue
		default:
		}
		break
	}
	response["queries"] = queries

	execQuery(conn, "user0", "select * from user", "user", "-80", response)
	execQuery(conn, "user1", "select * from user", "user", "80-", response)
	execQuery(conn, "user_extra0", "select * from user_extra", "user", "-80", response)
	execQuery(conn, "user_extra1", "select * from user_extra", "user", "80-", response)
	execQuery(conn, "music0", "select * from music", "user", "-80", response)
	execQuery(conn, "music1", "select * from music", "user", "80-", response)
	execQuery(conn, "music_extra0", "select * from music_extra", "user", "-80", response)
	execQuery(conn, "music_extra1", "select * from music_extra", "user", "80-", response)
	execQuery(conn, "name_info0", "select * from name_info", "user", "-80", response)
	execQuery(conn, "name_info1", "select * from name_info", "user", "80-", response)
	execQuery(conn, "music_keyspace_idx0", "select music_id, hex(keyspace_id) from music_keyspace_idx", "user", "-80", response)
	execQuery(conn, "music_keyspace_idx1", "select music_id, hex(keyspace_id) from music_keyspace_idx", "user", "80-", response)
	execQuery(conn, "user_seq", "select * from user_seq", "lookup", "0", response)
	execQuery(conn, "music_seq", "select * from music_seq", "lookup", "0", response)
	execQuery(conn, "name_keyspace_idx", "select name, hex(keyspace_id) from name_keyspace_idx", "lookup", "0", response)
	enc.Encode(response)
}

func execQuery(conn *mysql.Conn, key, query, keyspace, shard string, response map[string]interface{}) {
	if query == "" || query == "undefined" {
		return
	}
	if keyspace != "" {
		_, err := conn.ExecuteFetch(fmt.Sprintf("use `%v:%v`", keyspace, shard), 10000, true)
		if err != nil {
			response[key] = map[string]interface{}{
				"title": key,
				"error": err.Error(),
			}
			return
		}
	}
	title := key
	switch {
	case strings.HasSuffix(key, "0"):
		title = key[:len(key)-1] + ":-80"
	case strings.HasSuffix(key, "1"):
		title = key[:len(key)-1] + ":80-"
	}
	qr, err := conn.ExecuteFetch(query, 10000, true)
	if err != nil {
		response[key] = map[string]interface{}{
			"title": title,
			"error": err.Error(),
		}
		log.Errorf("error: %v", err)
		return
	}
	response[key] = resultToMap(title, qr)
}

func resultToMap(title string, qr *sqltypes.Result) map[string]interface{} {
	fields := make([]string, 0, len(qr.Fields))
	for _, field := range qr.Fields {
		fields = append(fields, field.Name)
	}
	rows := make([][]string, 0, len(qr.Rows))
	for _, row := range qr.Rows {
		srow := make([]string, 0, len(row))
		for _, value := range row {
			srow = append(srow, value.ToString())
		}
		rows = append(rows, srow)
	}
	return map[string]interface{}{
		"title":        title,
		"fields":       fields,
		"rows":         rows,
		"rowsaffected": int64(qr.RowsAffected),
		"insertid":     int64(qr.InsertID),
	}
}

func streamQuerylog(port int) (<-chan string, error) {
	request := fmt.Sprintf("http://localhost:%d/debug/querylog", port)
	resp, err := http.Get(request)
	if err != nil {
		log.Errorf("Error reading stream: %v: %v", request, err)
		return nil, err
	}
	ch := make(chan string, 100)
	go func() {
		buffered := bufio.NewReader(resp.Body)
		for {
			str, err := buffered.ReadString('\n')
			if err != nil {
				log.Errorf("Error reading stream: %v: %v", request, err)
				close(ch)
				resp.Body.Close()
				return
			}
			splits := strings.Split(str, "\t")
			if len(splits) < 13 {
				continue
			}
			trimmed := strings.Trim(splits[12], `"`)
			if trimmed == "" {
				continue
			}
			splitQueries := strings.Split(trimmed, ";")
			var final []string
			for _, query := range splitQueries {
				if strings.Contains(query, "1 != 1") {
					continue
				}
				final = append(final, query)
			}
			select {
			case ch <- strings.Join(final, "; "):
			default:
			}
		}
	}()
	return ch, nil
}
<|endoftext|>


<commit_before>package cornellbox
<commit_msg>Remove dead code<commit_after><|endoftext|>


<commit_before>// Package wkhtmltopdf contains wrappers around the wkhtmltopdf commandline tool
package wkhtmltopdf

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
)

//the cached mutexed path as used by findPath()
type stringStore struct {
	val string
	sync.Mutex
}

func (ss *stringStore) Get() string {
	ss.Lock()
	defer ss.Unlock()
	return ss.val
}

func (ss *stringStore) Set(s string) {
	ss.Lock()
	ss.val = s
	ss.Unlock()
}

var binPath stringStore

// SetPath sets the path to wkhtmltopdf
func SetPath(path string) {
	binPath.Set(path)
}

// GetPath gets the path to wkhtmltopdf
func GetPath() string {
	return binPath.Get()
}

// Page is the input struct for each page
type Page struct {
	Input string
	PageOptions
}

// InputFile returns the input string and is part of the page interface
func (p *Page) InputFile() string {
	return p.Input
}

// Args returns the argument slice and is part of the page interface
func (p *Page) Args() []string {
	return p.PageOptions.Args()
}

// Reader returns the io.Reader and is part of the page interface
func (p *Page) Reader() io.Reader {
	return nil
}

// NewPage creates a new input page from a local or web resource (filepath or URL)
func NewPage(input string) *Page {
	return &Page{
		Input:       input,
		PageOptions: NewPageOptions(),
	}
}

// PageReader is one input page (a HTML document) that is read from an io.Reader
// You can add only one Page from a reader
type PageReader struct {
	Input io.Reader
	PageOptions
}

// InputFile returns the input string and is part of the page interface
func (pr *PageReader) InputFile() string {
	return "-"
}

// Args returns the argument slice and is part of the page interface
func (pr *PageReader) Args() []string {
	return pr.PageOptions.Args()
}

//Reader returns the io.Reader and is part of the page interface
func (pr *PageReader) Reader() io.Reader {
	return pr.Input
}

// NewPageReader creates a new PageReader from an io.Reader
func NewPageReader(input io.Reader) *PageReader {
	return &PageReader{
		Input:       input,
		PageOptions: NewPageOptions(),
	}
}

type page interface {
	Args() []string
	InputFile() string
	Reader() io.Reader
}

// PageOptions are options for each input page
type PageOptions struct {
	pageOptions
	headerAndFooterOptions
}

// Args returns the argument slice
func (po *PageOptions) Args() []string {
	return append(append([]string{}, po.pageOptions.Args()...), po.headerAndFooterOptions.Args()...)
}

// NewPageOptions returns a new PageOptions struct with all options
func NewPageOptions() PageOptions {
	return PageOptions{
		pageOptions:            newPageOptions(),
		headerAndFooterOptions: newHeaderAndFooterOptions(),
	}
}

// cover page
type cover struct {
	Input string
	pageOptions
}

// table of contents
type toc struct {
	Include bool
	allTocOptions
}

type allTocOptions struct {
	pageOptions
	tocOptions
}

// PDFGenerator is the main wkhtmltopdf struct, always use NewPDFGenerator to obtain a new PDFGenerator struct
type PDFGenerator struct {
	globalOptions
	outlineOptions

	Cover      cover
	TOC        toc
	OutputFile string //filename to write to, default empty (writes to internal buffer)

	binPath   string
	outbuf    bytes.Buffer
	outWriter io.Writer
	pages     []page
}

//Args returns the commandline arguments as a string slice
func (pdfg *PDFGenerator) Args() []string {
	args := append([]string{}, pdfg.globalOptions.Args()...)
	args = append(args, pdfg.outlineOptions.Args()...)
	if pdfg.Cover.Input != "" {
		args = append(args, "cover")
		args = append(args, pdfg.Cover.Input)
		args = append(args, pdfg.Cover.pageOptions.Args()...)
	}
	if pdfg.TOC.Include {
		args = append(args, "toc")
		args = append(args, pdfg.TOC.pageOptions.Args()...)
		args = append(args, pdfg.TOC.tocOptions.Args()...)
	}
	for _, page := range pdfg.pages {
		args = append(args, "page")
		args = append(args, page.InputFile())
		args = append(args, page.Args()...)
	}
	if pdfg.OutputFile != "" {
		args = append(args, pdfg.OutputFile)
	} else {
		args = append(args, "-")
	}
	return args
}

// ArgString returns Args as a single string
func (pdfg *PDFGenerator) ArgString() string {
	return strings.Join(pdfg.Args(), " ")
}

// AddPage adds a new input page to the document.
// A page is an input HTML page, it can span multiple pages in the output document.
// It is a Page when read from file or URL or a PageReader when read from memory.
func (pdfg *PDFGenerator) AddPage(p page) {
	pdfg.pages = append(pdfg.pages, p)
}

// SetPages resets all pages
func (pdfg *PDFGenerator) SetPages(p []page) {
	pdfg.pages = p
}

// ResetPages drops all pages previously added by AddPage or SetPages.
// This allows reuse of current instance of PDFGenerator with all of it's configuration preserved.
func (pdfg *PDFGenerator) ResetPages() {
	pdfg.pages = []page{}
}

// Buffer returns the embedded output buffer used if OutputFile is empty
func (pdfg *PDFGenerator) Buffer() *bytes.Buffer {
	return &pdfg.outbuf
}

// Bytes returns the output byte slice from the output buffer used if OutputFile is empty
func (pdfg *PDFGenerator) Bytes() []byte {
	return pdfg.outbuf.Bytes()
}

// SetOutput sets the output to write the PDF to, when this method is called, the internal buffer will not be used,
// so the Bytes(), Buffer() and WriteFile() methods will not work.
func (pdfg *PDFGenerator) SetOutput(w io.Writer) {
	pdfg.outWriter = w
}

// WriteFile writes the contents of the output buffer to a file
func (pdfg *PDFGenerator) WriteFile(filename string) error {
	return ioutil.WriteFile(filename, pdfg.Bytes(), 0666)
}

//findPath finds the path to wkhtmltopdf by
//- first looking in the current dir
//- looking in the PATH and PATHEXT environment dirs
//- using the WKHTMLTOPDF_PATH environment dir
//The path is cached, meaning you can not change the location of wkhtmltopdf in
//a running program once it has been found
func (pdfg *PDFGenerator) findPath() error {
	const exe = "wkhtmltopdf"
	pdfg.binPath = GetPath()
	if pdfg.binPath != "" {
		// wkhtmltopdf has already already found, return
		return nil
	}
	exeDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return err
	}
	path, err := exec.LookPath(filepath.Join(exeDir, exe))
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	path, err = exec.LookPath(exe)
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	dir := os.Getenv("WKHTMLTOPDF_PATH")
	if dir == "" {
		return fmt.Errorf("%s not found", exe)
	}
	path, err = exec.LookPath(filepath.Join(dir, exe))
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	return fmt.Errorf("%s not found", exe)
}

// Create creates the PDF document and stores it in the internal buffer if no error is returned
func (pdfg *PDFGenerator) Create() error {
	return pdfg.run()
}

func (pdfg *PDFGenerator) run() error {

	errbuf := &bytes.Buffer{}

	cmd := exec.Command(pdfg.binPath, pdfg.Args()...)
	cmd.Stderr = errbuf

	// set output to the desired writer or the internal buffer
	if pdfg.outWriter != nil {
		cmd.Stdout = pdfg.outWriter
	} else {
		cmd.Stdout = &pdfg.outbuf
	}

	// if there is a pageReader page (from Stdin) we set Stdin to that reader
	for _, page := range pdfg.pages {
		if page.Reader() != nil {
			cmd.Stdin = page.Reader()
			break
		}
	}

	err := cmd.Run()
	if err != nil {
		errStr := errbuf.String()
		if strings.TrimSpace(errStr) == "" {
			errStr = err.Error()
		}
		return errors.New(errStr)
	}
	return nil
}

// NewPDFGenerator returns a new PDFGenerator struct with all options created and
// checks if wkhtmltopdf can be found on the system
func NewPDFGenerator() (*PDFGenerator, error) {
	pdfg := &PDFGenerator{
		globalOptions:  newGlobalOptions(),
		outlineOptions: newOutlineOptions(),
		Cover: cover{
			pageOptions: newPageOptions(),
		},
		TOC: toc{
			allTocOptions: allTocOptions{
				tocOptions:  newTocOptions(),
				pageOptions: newPageOptions(),
			},
		},
	}
	err := pdfg.findPath()
	return pdfg, err
}

// NewPDFPreparer returns a PDFGenerator object without looking for the wkhtmltopdf executable file.
// This is useful to prepare a PDF file that is generated elsewhere and you just want to save the config as JSON.
// Note that Create() can not be called on this object unless you call SetPath yourself.
func NewPDFPreparer() *PDFGenerator {
	return &PDFGenerator{
		globalOptions:  newGlobalOptions(),
		outlineOptions: newOutlineOptions(),
		Cover: cover{
			pageOptions: newPageOptions(),
		},
		TOC: toc{
			allTocOptions: allTocOptions{
				tocOptions:  newTocOptions(),
				pageOptions: newPageOptions(),
			},
		},
	}
}
<commit_msg>inline NewPDFPreparer<commit_after>// Package wkhtmltopdf contains wrappers around the wkhtmltopdf commandline tool
package wkhtmltopdf

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
)

//the cached mutexed path as used by findPath()
type stringStore struct {
	val string
	sync.Mutex
}

func (ss *stringStore) Get() string {
	ss.Lock()
	defer ss.Unlock()
	return ss.val
}

func (ss *stringStore) Set(s string) {
	ss.Lock()
	ss.val = s
	ss.Unlock()
}

var binPath stringStore

// SetPath sets the path to wkhtmltopdf
func SetPath(path string) {
	binPath.Set(path)
}

// GetPath gets the path to wkhtmltopdf
func GetPath() string {
	return binPath.Get()
}

// Page is the input struct for each page
type Page struct {
	Input string
	PageOptions
}

// InputFile returns the input string and is part of the page interface
func (p *Page) InputFile() string {
	return p.Input
}

// Args returns the argument slice and is part of the page interface
func (p *Page) Args() []string {
	return p.PageOptions.Args()
}

// Reader returns the io.Reader and is part of the page interface
func (p *Page) Reader() io.Reader {
	return nil
}

// NewPage creates a new input page from a local or web resource (filepath or URL)
func NewPage(input string) *Page {
	return &Page{
		Input:       input,
		PageOptions: NewPageOptions(),
	}
}

// PageReader is one input page (a HTML document) that is read from an io.Reader
// You can add only one Page from a reader
type PageReader struct {
	Input io.Reader
	PageOptions
}

// InputFile returns the input string and is part of the page interface
func (pr *PageReader) InputFile() string {
	return "-"
}

// Args returns the argument slice and is part of the page interface
func (pr *PageReader) Args() []string {
	return pr.PageOptions.Args()
}

//Reader returns the io.Reader and is part of the page interface
func (pr *PageReader) Reader() io.Reader {
	return pr.Input
}

// NewPageReader creates a new PageReader from an io.Reader
func NewPageReader(input io.Reader) *PageReader {
	return &PageReader{
		Input:       input,
		PageOptions: NewPageOptions(),
	}
}

type page interface {
	Args() []string
	InputFile() string
	Reader() io.Reader
}

// PageOptions are options for each input page
type PageOptions struct {
	pageOptions
	headerAndFooterOptions
}

// Args returns the argument slice
func (po *PageOptions) Args() []string {
	return append(append([]string{}, po.pageOptions.Args()...), po.headerAndFooterOptions.Args()...)
}

// NewPageOptions returns a new PageOptions struct with all options
func NewPageOptions() PageOptions {
	return PageOptions{
		pageOptions:            newPageOptions(),
		headerAndFooterOptions: newHeaderAndFooterOptions(),
	}
}

// cover page
type cover struct {
	Input string
	pageOptions
}

// table of contents
type toc struct {
	Include bool
	allTocOptions
}

type allTocOptions struct {
	pageOptions
	tocOptions
}

// PDFGenerator is the main wkhtmltopdf struct, always use NewPDFGenerator to obtain a new PDFGenerator struct
type PDFGenerator struct {
	globalOptions
	outlineOptions

	Cover      cover
	TOC        toc
	OutputFile string //filename to write to, default empty (writes to internal buffer)

	binPath   string
	outbuf    bytes.Buffer
	outWriter io.Writer
	pages     []page
}

//Args returns the commandline arguments as a string slice
func (pdfg *PDFGenerator) Args() []string {
	args := append([]string{}, pdfg.globalOptions.Args()...)
	args = append(args, pdfg.outlineOptions.Args()...)
	if pdfg.Cover.Input != "" {
		args = append(args, "cover")
		args = append(args, pdfg.Cover.Input)
		args = append(args, pdfg.Cover.pageOptions.Args()...)
	}
	if pdfg.TOC.Include {
		args = append(args, "toc")
		args = append(args, pdfg.TOC.pageOptions.Args()...)
		args = append(args, pdfg.TOC.tocOptions.Args()...)
	}
	for _, page := range pdfg.pages {
		args = append(args, "page")
		args = append(args, page.InputFile())
		args = append(args, page.Args()...)
	}
	if pdfg.OutputFile != "" {
		args = append(args, pdfg.OutputFile)
	} else {
		args = append(args, "-")
	}
	return args
}

// ArgString returns Args as a single string
func (pdfg *PDFGenerator) ArgString() string {
	return strings.Join(pdfg.Args(), " ")
}

// AddPage adds a new input page to the document.
// A page is an input HTML page, it can span multiple pages in the output document.
// It is a Page when read from file or URL or a PageReader when read from memory.
func (pdfg *PDFGenerator) AddPage(p page) {
	pdfg.pages = append(pdfg.pages, p)
}

// SetPages resets all pages
func (pdfg *PDFGenerator) SetPages(p []page) {
	pdfg.pages = p
}

// ResetPages drops all pages previously added by AddPage or SetPages.
// This allows reuse of current instance of PDFGenerator with all of it's configuration preserved.
func (pdfg *PDFGenerator) ResetPages() {
	pdfg.pages = []page{}
}

// Buffer returns the embedded output buffer used if OutputFile is empty
func (pdfg *PDFGenerator) Buffer() *bytes.Buffer {
	return &pdfg.outbuf
}

// Bytes returns the output byte slice from the output buffer used if OutputFile is empty
func (pdfg *PDFGenerator) Bytes() []byte {
	return pdfg.outbuf.Bytes()
}

// SetOutput sets the output to write the PDF to, when this method is called, the internal buffer will not be used,
// so the Bytes(), Buffer() and WriteFile() methods will not work.
func (pdfg *PDFGenerator) SetOutput(w io.Writer) {
	pdfg.outWriter = w
}

// WriteFile writes the contents of the output buffer to a file
func (pdfg *PDFGenerator) WriteFile(filename string) error {
	return ioutil.WriteFile(filename, pdfg.Bytes(), 0666)
}

//findPath finds the path to wkhtmltopdf by
//- first looking in the current dir
//- looking in the PATH and PATHEXT environment dirs
//- using the WKHTMLTOPDF_PATH environment dir
//The path is cached, meaning you can not change the location of wkhtmltopdf in
//a running program once it has been found
func (pdfg *PDFGenerator) findPath() error {
	const exe = "wkhtmltopdf"
	pdfg.binPath = GetPath()
	if pdfg.binPath != "" {
		// wkhtmltopdf has already already found, return
		return nil
	}
	exeDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		return err
	}
	path, err := exec.LookPath(filepath.Join(exeDir, exe))
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	path, err = exec.LookPath(exe)
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	dir := os.Getenv("WKHTMLTOPDF_PATH")
	if dir == "" {
		return fmt.Errorf("%s not found", exe)
	}
	path, err = exec.LookPath(filepath.Join(dir, exe))
	if err == nil && path != "" {
		binPath.Set(path)
		pdfg.binPath = path
		return nil
	}
	return fmt.Errorf("%s not found", exe)
}

// Create creates the PDF document and stores it in the internal buffer if no error is returned
func (pdfg *PDFGenerator) Create() error {
	return pdfg.run()
}

func (pdfg *PDFGenerator) run() error {

	errbuf := &bytes.Buffer{}

	cmd := exec.Command(pdfg.binPath, pdfg.Args()...)
	cmd.Stderr = errbuf

	// set output to the desired writer or the internal buffer
	if pdfg.outWriter != nil {
		cmd.Stdout = pdfg.outWriter
	} else {
		cmd.Stdout = &pdfg.outbuf
	}

	// if there is a pageReader page (from Stdin) we set Stdin to that reader
	for _, page := range pdfg.pages {
		if page.Reader() != nil {
			cmd.Stdin = page.Reader()
			break
		}
	}

	err := cmd.Run()
	if err != nil {
		errStr := errbuf.String()
		if strings.TrimSpace(errStr) == "" {
			errStr = err.Error()
		}
		return errors.New(errStr)
	}
	return nil
}

// NewPDFGenerator returns a new PDFGenerator struct with all options created and
// checks if wkhtmltopdf can be found on the system
func NewPDFGenerator() (*PDFGenerator, error) {
	pdfg := NewPDFPreparer()
	err := pdfg.findPath()
	return pdfg, err
}

// NewPDFPreparer returns a PDFGenerator object without looking for the wkhtmltopdf executable file.
// This is useful to prepare a PDF file that is generated elsewhere and you just want to save the config as JSON.
// Note that Create() can not be called on this object unless you call SetPath yourself.
func NewPDFPreparer() *PDFGenerator {
	return &PDFGenerator{
		globalOptions:  newGlobalOptions(),
		outlineOptions: newOutlineOptions(),
		Cover: cover{
			pageOptions: newPageOptions(),
		},
		TOC: toc{
			allTocOptions: allTocOptions{
				tocOptions:  newTocOptions(),
				pageOptions: newPageOptions(),
			},
		},
	}
}
<|endoftext|>


<commit_before>package ble

const (
	serviceInterface        = "org.bluez.GattService1"
	characteristicInterface = "org.bluez.GattCharacteristic1"
	descriptorInterface     = "org.bluez.GattDescriptor1"
)

// The GattHandle interface wraps common operations on GATT objects.
type GattHandle interface {
	BaseObject

	UUID() string
}

// UUID returns the handle's UUID
func (handle *blob) UUID() string {
	return handle.properties["UUID"].Value().(string)
}

// The Service type corresponds to the org.bluez.GattService1 interface.
// See bluez/doc/gatt-api.txt
type Service interface {
	GattHandle
}

// GetService finds a Service in the object cache with the given UUID.
func (cache *ObjectCache) GetService(uuid string) (Service, error) {
	return cache.find(serviceInterface, func(serv *blob) bool {
		return serv.UUID() == uuid
	})
}

// The ReadWriteHandle interface describes GATT objects that provide
// ReadValue and WriteValue operations.
type ReadWriteHandle interface {
	GattHandle

	ReadValue() ([]byte, error)
	WriteValue([]byte) error
}

func (handle *blob) ReadValue() ([]byte, error) {
	var data []byte
	err := handle.callv("ReadValue").Store(&data)
	return data, err
}

func (handle *blob) WriteValue(data []byte) error {
	return handle.call("WriteValue", data)
}

// A function of type NotifyHandler is used to handle notifications.
type NotifyHandler func([]byte)

// The Characteristic type corresponds to the org.bluez.GattCharacteristic1 interface.
// See bluez/doc/gatt-api.txt
type Characteristic interface {
	ReadWriteHandle

	Notifying() bool

	StartNotify() error
	StopNotify() error

	HandleNotify(NotifyHandler) error
}

// GetCharacteristic finds a Characteristic in the object cache with the given UUID.
func (cache *ObjectCache) GetCharacteristic(uuid string) (Characteristic, error) {
	return cache.find(characteristicInterface, func(char *blob) bool {
		return char.UUID() == uuid
	})
}

func (char *blob) Notifying() bool {
	return char.properties["Notifying"].Value().(bool)
}

func (char *blob) StartNotify() error {
	return char.call("StartNotify")
}

func (char *blob) StopNotify() error {
	return char.call("StopNotify")
}

// The Descriptor type corresponds to the org.bluez.GattDescriptor1 interface.
// See bluez/doc/gatt-api.txt
type Descriptor interface {
	ReadWriteHandle
}

// GetDescriptor finds a Descriptor in the object cache with the given UUID.
func (cache *ObjectCache) GetDescriptor(uuid string) (Descriptor, error) {
	return cache.find(descriptorInterface, func(desc *blob) bool {
		return desc.UUID() == uuid
	})
}
<commit_msg>Factor out common getObject function<commit_after>package ble

const (
	serviceInterface        = "org.bluez.GattService1"
	characteristicInterface = "org.bluez.GattCharacteristic1"
	descriptorInterface     = "org.bluez.GattDescriptor1"
)

func (cache *ObjectCache) getObject(iface string, uuid string) (*blob, error) {
	return cache.find(iface, func(desc *blob) bool {
		return desc.UUID() == uuid
	})
}

// The GattHandle interface wraps common operations on GATT objects.
type GattHandle interface {
	BaseObject

	UUID() string
}

// UUID returns the handle's UUID
func (handle *blob) UUID() string {
	return handle.properties["UUID"].Value().(string)
}

// The Service type corresponds to the org.bluez.GattService1 interface.
// See bluez/doc/gatt-api.txt
type Service interface {
	GattHandle
}

// GetService finds a Service in the object cache with the given UUID.
func (cache *ObjectCache) GetService(uuid string) (Service, error) {
	return cache.getObject(serviceInterface, uuid)
}

// The ReadWriteHandle interface describes GATT objects that provide
// ReadValue and WriteValue operations.
type ReadWriteHandle interface {
	GattHandle

	ReadValue() ([]byte, error)
	WriteValue([]byte) error
}

func (handle *blob) ReadValue() ([]byte, error) {
	var data []byte
	err := handle.callv("ReadValue").Store(&data)
	return data, err
}

func (handle *blob) WriteValue(data []byte) error {
	return handle.call("WriteValue", data)
}

// A function of type NotifyHandler is used to handle notifications.
type NotifyHandler func([]byte)

// The Characteristic type corresponds to the org.bluez.GattCharacteristic1 interface.
// See bluez/doc/gatt-api.txt
type Characteristic interface {
	ReadWriteHandle

	Notifying() bool

	StartNotify() error
	StopNotify() error

	HandleNotify(NotifyHandler) error
}

// GetCharacteristic finds a Characteristic in the object cache with the given UUID.
func (cache *ObjectCache) GetCharacteristic(uuid string) (Characteristic, error) {
	return cache.getObject(characteristicInterface, uuid)
}

func (char *blob) Notifying() bool {
	return char.properties["Notifying"].Value().(bool)
}

func (char *blob) StartNotify() error {
	return char.call("StartNotify")
}

func (char *blob) StopNotify() error {
	return char.call("StopNotify")
}

// The Descriptor type corresponds to the org.bluez.GattDescriptor1 interface.
// See bluez/doc/gatt-api.txt
type Descriptor interface {
	ReadWriteHandle
}

// GetDescriptor finds a Descriptor in the object cache with the given UUID.
func (cache *ObjectCache) GetDescriptor(uuid string) (Descriptor, error) {
	return cache.getObject(descriptorInterface, uuid)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/PeoplePerHour/shippable-go"
)

func main() {
	token := os.Getenv("apiToken")
	c := shippable.NewClient(token)
	projects, _, _ := c.Projects.GetProjects()
	proj := (*projects)[0]
	fmt.Println(*proj.Name)

	project, _, err := c.Projects.GetProject("54e2287a5ab6cc13528c39d2")
	fmt.Printf("%+v\n", project)

	builds, _, err := c.Projects.GetRunningBuilds(*proj.ID)
	fmt.Println(builds, err)

}
<commit_msg>removed useless examples<commit_after><|endoftext|>


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

package consent

import (
	"time"

	"github.com/ory/fosite"
	"github.com/ory/hydra/pkg"
	"github.com/pkg/errors"
)

type MemoryManager struct {
	consentRequests        map[string]ConsentRequest
	handledConsentRequests map[string]HandledConsentRequest
	authRequests           map[string]AuthenticationRequest
	handledAuthRequests    map[string]HandledAuthenticationRequest
	authSessions           map[string]AuthenticationSession
}

func NewMemoryManager() *MemoryManager {
	return &MemoryManager{
		consentRequests:        map[string]ConsentRequest{},
		handledConsentRequests: map[string]HandledConsentRequest{},
		authRequests:           map[string]AuthenticationRequest{},
		handledAuthRequests:    map[string]HandledAuthenticationRequest{},
		authSessions:           map[string]AuthenticationSession{},
	}
}

func (m *MemoryManager) CreateConsentRequest(c *ConsentRequest) error {
	m.consentRequests[c.Challenge] = *c
	return nil
}

func (m *MemoryManager) GetConsentRequest(challenge string) (*ConsentRequest, error) {
	if c, ok := m.consentRequests[challenge]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) HandleConsentRequest(challenge string, r *HandledConsentRequest) (*ConsentRequest, error) {
	m.handledConsentRequests[r.Challenge] = *r
	return m.GetConsentRequest(challenge)
}

func (m *MemoryManager) VerifyAndInvalidateConsentRequest(verifier string) (*HandledConsentRequest, error) {
	for _, c := range m.consentRequests {
		if c.Verifier == verifier {
			for _, h := range m.handledConsentRequests {
				if h.Challenge == c.Challenge {
					if h.WasUsed {
						return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug("Consent verifier has been used already"))
					}

					h.WasUsed = true
					if _, err := m.HandleConsentRequest(h.Challenge, &h); err != nil {
						return nil, err
					}

					h.ConsentRequest = &c
					return &h, nil
				}
			}
		}
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) FindPreviouslyGrantedConsentRequests(client string, subject string) ([]HandledConsentRequest, error) {
	var rs []HandledConsentRequest
	for _, c := range m.handledConsentRequests {
		cr, err := m.GetConsentRequest(c.Challenge)
		if err != nil {
			return nil, err
		}

		if client != cr.Client.GetID() {
			continue
		}

		if subject != cr.Subject {
			continue
		}

		if c.Error != nil {
			continue
		}

		if !c.Remember {
			continue
		}

		if cr.Skip {
			continue
		}

		if c.RememberFor > 0 && c.RequestedAt.Add(time.Duration(c.RememberFor)*time.Second).Before(time.Now().UTC()) {
			continue
		}

		c.ConsentRequest = cr
		rs = append(rs, c)
	}
	if len(rs) == 0 {
		return []HandledConsentRequest{}, nil
	}

	return rs, nil
}

func (m *MemoryManager) GetAuthenticationSession(id string) (*AuthenticationSession, error) {
	if c, ok := m.authSessions[id]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) CreateAuthenticationSession(a *AuthenticationSession) error {
	m.authSessions[a.ID] = *a
	return nil
}

func (m *MemoryManager) DeleteAuthenticationSession(id string) error {
	delete(m.authSessions, id)
	return nil
}

func (m *MemoryManager) CreateAuthenticationRequest(a *AuthenticationRequest) error {
	m.authRequests[a.Challenge] = *a
	return nil
}

func (m *MemoryManager) GetAuthenticationRequest(challenge string) (*AuthenticationRequest, error) {
	if c, ok := m.authRequests[challenge]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) HandleAuthenticationRequest(challenge string, r *HandledAuthenticationRequest) (*AuthenticationRequest, error) {
	m.handledAuthRequests[r.Challenge] = *r
	return m.GetAuthenticationRequest(challenge)
}

func (m *MemoryManager) VerifyAndInvalidateAuthenticationRequest(verifier string) (*HandledAuthenticationRequest, error) {
	for _, c := range m.authRequests {
		if c.Verifier == verifier {
			for _, h := range m.handledAuthRequests {
				if h.Challenge == c.Challenge {
					if h.WasUsed {
						return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug("Authentication verifier has been used already"))
					}

					h.WasUsed = true
					if _, err := m.HandleAuthenticationRequest(h.Challenge, &h); err != nil {
						return nil, err
					}

					h.AuthenticationRequest = &c
					return &h, nil
				}
			}
		}
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}
<commit_msg>consent: Adds mutex to memory manager<commit_after>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @Copyright 	2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package consent

import (
	"sync"
	"time"

	"github.com/ory/fosite"
	"github.com/ory/hydra/pkg"
	"github.com/pkg/errors"
)

type MemoryManager struct {
	consentRequests        map[string]ConsentRequest
	handledConsentRequests map[string]HandledConsentRequest
	authRequests           map[string]AuthenticationRequest
	handledAuthRequests    map[string]HandledAuthenticationRequest
	authSessions           map[string]AuthenticationSession
	sync.RWMutex
}

func NewMemoryManager() *MemoryManager {
	return &MemoryManager{
		consentRequests:        map[string]ConsentRequest{},
		handledConsentRequests: map[string]HandledConsentRequest{},
		authRequests:           map[string]AuthenticationRequest{},
		handledAuthRequests:    map[string]HandledAuthenticationRequest{},
		authSessions:           map[string]AuthenticationSession{},
	}
}

func (m *MemoryManager) CreateConsentRequest(c *ConsentRequest) error {
	m.Lock()
	defer m.Unlock()
	m.consentRequests[c.Challenge] = *c
	return nil
}

func (m *MemoryManager) GetConsentRequest(challenge string) (*ConsentRequest, error) {
	m.RLock()
	defer m.RUnlock()
	if c, ok := m.consentRequests[challenge]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) HandleConsentRequest(challenge string, r *HandledConsentRequest) (*ConsentRequest, error) {
	m.Lock()
	m.handledConsentRequests[r.Challenge] = *r
	m.Unlock()
	return m.GetConsentRequest(challenge)
}

func (m *MemoryManager) VerifyAndInvalidateConsentRequest(verifier string) (*HandledConsentRequest, error) {
	for _, c := range m.consentRequests {
		if c.Verifier == verifier {
			for _, h := range m.handledConsentRequests {
				if h.Challenge == c.Challenge {
					if h.WasUsed {
						return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug("Consent verifier has been used already"))
					}

					h.WasUsed = true
					if _, err := m.HandleConsentRequest(h.Challenge, &h); err != nil {
						return nil, err
					}

					h.ConsentRequest = &c
					return &h, nil
				}
			}
		}
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) FindPreviouslyGrantedConsentRequests(client string, subject string) ([]HandledConsentRequest, error) {
	var rs []HandledConsentRequest
	for _, c := range m.handledConsentRequests {
		cr, err := m.GetConsentRequest(c.Challenge)
		if err != nil {
			return nil, err
		}

		if client != cr.Client.GetID() {
			continue
		}

		if subject != cr.Subject {
			continue
		}

		if c.Error != nil {
			continue
		}

		if !c.Remember {
			continue
		}

		if cr.Skip {
			continue
		}

		if c.RememberFor > 0 && c.RequestedAt.Add(time.Duration(c.RememberFor)*time.Second).Before(time.Now().UTC()) {
			continue
		}

		c.ConsentRequest = cr
		rs = append(rs, c)
	}
	if len(rs) == 0 {
		return []HandledConsentRequest{}, nil
	}

	return rs, nil
}

func (m *MemoryManager) GetAuthenticationSession(id string) (*AuthenticationSession, error) {
	m.RLock()
	defer m.RUnlock()
	if c, ok := m.authSessions[id]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) CreateAuthenticationSession(a *AuthenticationSession) error {
	m.Lock()
	defer m.Unlock()
	m.authSessions[a.ID] = *a
	return nil
}

func (m *MemoryManager) DeleteAuthenticationSession(id string) error {
	m.Lock()
	defer m.Unlock()
	delete(m.authSessions, id)
	return nil
}

func (m *MemoryManager) CreateAuthenticationRequest(a *AuthenticationRequest) error {
	m.Lock()
	defer m.Unlock()
	m.authRequests[a.Challenge] = *a
	return nil
}

func (m *MemoryManager) GetAuthenticationRequest(challenge string) (*AuthenticationRequest, error) {
	m.RLock()
	defer m.RUnlock()
	if c, ok := m.authRequests[challenge]; ok {
		return &c, nil
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}

func (m *MemoryManager) HandleAuthenticationRequest(challenge string, r *HandledAuthenticationRequest) (*AuthenticationRequest, error) {
	m.Lock()
	defer m.Unlock()
	m.handledAuthRequests[r.Challenge] = *r
	return m.GetAuthenticationRequest(challenge)
}

func (m *MemoryManager) VerifyAndInvalidateAuthenticationRequest(verifier string) (*HandledAuthenticationRequest, error) {
	for _, c := range m.authRequests {
		if c.Verifier == verifier {
			for _, h := range m.handledAuthRequests {
				if h.Challenge == c.Challenge {
					if h.WasUsed {
						return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug("Authentication verifier has been used already"))
					}

					h.WasUsed = true
					if _, err := m.HandleAuthenticationRequest(h.Challenge, &h); err != nil {
						return nil, err
					}

					h.AuthenticationRequest = &c
					return &h, nil
				}
			}
		}
	}
	return nil, errors.WithStack(pkg.ErrNotFound)
}
<|endoftext|>


<commit_before>// +build enterprise

package admin

import (
	"enterprise.getqor.com/microsite"
	"enterprise.getqor.com/microsite/develop/aws_manager"
	"github.com/jinzhu/configor"
	"github.com/qor/admin"
	"github.com/qor/l10n"
	"github.com/qor/publish2"
	"github.com/qor/qor-example/config"
)

var MicroSite *microsite.MicroSite

type QorMicroSite struct {
	microsite.QorMicroSite
	publish2.Version
	publish2.Schedule
	publish2.Visible
	l10n.Locale
}

type AWSManagerConfig struct {
	AccessID  string `env:"AWS_ACCESS_KEY_ID" required:"true"`
	AccessKey string `env:"AWS_SECRET_ACCESS_KEY" required:"true"`
	Region    string `env:"AWS_Region" required:"true"`
	Bucket    string `env:"AWS_Bucket" required:"true"`
}

func init() {
	initWidgets()
	awsConfig := AWSManagerConfig{}
	configor.Load(&awsConfig)

	MicroSite = microsite.New(&microsite.Config{Dir: config.Root + "/public/microsites", Widgets: Widgets, DevelopManager: aws_manager.New(&aws_manager.Config{
		AccessID:  awsConfig.AccessID,
		AccessKey: awsConfig.AccessKey,
		Region:    awsConfig.Region,
		Bucket:    awsConfig.Bucket,
	})})

	MicroSite.Resource = Admin.AddResource(&QorMicroSite{}, &admin.Config{Name: "MicroSite"})
	MicroSite.Resource.SetPrimaryFields("ID", "VersionName")

	Admin.AddResource(MicroSite)
}
<commit_msg>Fix panic<commit_after>// +build enterprise

package admin

import (
	"enterprise.getqor.com/microsite"
	"enterprise.getqor.com/microsite/develop/aws_manager"
	"github.com/jinzhu/configor"
	"github.com/qor/admin"
	"github.com/qor/l10n"
	"github.com/qor/publish2"
)

var MicroSite *microsite.MicroSite

type QorMicroSite struct {
	microsite.QorMicroSite
	publish2.Version
	publish2.Schedule
	publish2.Visible
	l10n.Locale
}

type AWSManagerConfig struct {
	AccessID  string `env:"AWS_ACCESS_KEY_ID" required:"true"`
	AccessKey string `env:"AWS_SECRET_ACCESS_KEY" required:"true"`
	Region    string `env:"AWS_Region" required:"true"`
	Bucket    string `env:"AWS_Bucket" required:"true"`
}

func init() {
	initWidgets()
	awsConfig := AWSManagerConfig{}
	configor.Load(&awsConfig)

	MicroSite = microsite.New(&microsite.Config{Widgets: Widgets, DevelopManager: aws_manager.New(&aws_manager.Config{
		AccessID:  awsConfig.AccessID,
		AccessKey: awsConfig.AccessKey,
		Region:    awsConfig.Region,
		Bucket:    awsConfig.Bucket,
	})})

	MicroSite.Resource = Admin.AddResource(&QorMicroSite{}, &admin.Config{Name: "MicroSite"})
	MicroSite.Resource.SetPrimaryFields("ID", "VersionName")

	Admin.AddResource(MicroSite)
}
<|endoftext|>