<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/juju/cmd"
	"github.com/juju/names"
	"github.com/juju/utils"
	"github.com/juju/utils/ssh"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/environs/config"
)

func newSSHCommand() cmd.Command {
	return modelcmd.Wrap(&sshCommand{})
}

// sshCommand is responsible for launching a ssh shell on a given unit or machine.
type sshCommand struct {
	SSHCommon
}

// SSHCommon provides common methods for sshCommand, SCPCommand and DebugHooksCommand.
type SSHCommon struct {
	modelcmd.ModelCommandBase
	proxy     bool
	pty       bool
	Target    string
	Args      []string
	apiClient sshAPIClient
	apiAddr   string
}

func (c *SSHCommon) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.proxy, "proxy", true, "proxy through the API server")
	f.BoolVar(&c.pty, "pty", true, "enable pseudo-tty allocation")
}

// setProxyCommand sets the proxy command option.
func (c *SSHCommon) setProxyCommand(options *ssh.Options) error {
	apiServerHost, _, err := net.SplitHostPort(c.apiAddr)
	if err != nil {
		return fmt.Errorf("failed to get proxy address: %v", err)
	}
	juju, err := getJujuExecutable()
	if err != nil {
		return fmt.Errorf("failed to get juju executable path: %v", err)
	}
	options.SetProxyCommand(juju, "ssh", "--proxy=false", "--pty=false", apiServerHost, "nc", "%h", "%p")
	return nil
}

const sshDoc = `
Launch an ssh shell on the machine identified by the <target> parameter.
<target> can be either a machine id  as listed by "juju status" in the
"machines" section or a unit name as listed in the "services" section.
Any extra parameters are passed as extra parameters to the ssh command.

Examples:

Connect to machine 0:

    juju ssh 0

Connect to machine 1 and run 'uname -a':

    juju ssh 1 uname -a

Connect to the first mysql unit:

    juju ssh mysql/0

Connect to the first mysql unit and run 'ls -la /var/log/juju':

    juju ssh mysql/0 ls -la /var/log/juju

Connect to the first jenkins unit as the user jenkins:

    juju ssh jenkins@jenkins/0
`

func (c *sshCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Args:    "<target> [<ssh args>...]",
		Purpose: "launch an ssh shell on a given unit or machine",
		Doc:     sshDoc,
	}
}

func (c *sshCommand) Init(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("no target name specified")
	}
	c.Target, c.Args = args[0], args[1:]
	return nil
}

// getJujuExecutable returns the path to the juju
// executable, or an error if it could not be found.
var getJujuExecutable = func() (string, error) {
	return exec.LookPath(os.Args[0])
}

// getSSHOptions configures and returns SSH options and proxy settings.
func (c *SSHCommon) getSSHOptions(enablePty bool) (*ssh.Options, error) {
	var options ssh.Options

	// TODO(waigani) do not save fingerprint only until this bug is addressed:
	// lp:892552. Also see lp:1334481.
	options.SetKnownHostsFile("/dev/null")
	if enablePty {
		options.EnablePTY()
	}
	var err error
	if c.proxy, err = c.proxySSH(); err != nil {
		return nil, err
	} else if c.proxy {
		if err := c.setProxyCommand(&options); err != nil {
			return nil, err
		}
	}
	return &options, nil
}

// Run resolves c.Target to a machine, to the address of a i
// machine or unit forks ssh passing any arguments provided.
func (c *sshCommand) Run(ctx *cmd.Context) error {
	if c.apiClient == nil {
		// If the apClient is not already opened and it is opened
		// by ensureAPIClient, then close it when we're done.
		defer func() {
			if c.apiClient != nil {
				c.apiClient.Close()
				c.apiClient = nil
			}
		}()
	}
	options, err := c.getSSHOptions(c.pty)
	if err != nil {
		return err
	}

	user, host, err := c.userHostFromTarget(c.Target)
	if err != nil {
		return err
	}
	cmd := ssh.Command(user+"@"+host, c.Args, options)
	cmd.Stdin = ctx.Stdin
	cmd.Stdout = ctx.Stdout
	cmd.Stderr = ctx.Stderr
	return cmd.Run()
}

// proxySSH returns true iff both c.proxy and
// the proxy-ssh environment configuration
// are true.
func (c *SSHCommon) proxySSH() (bool, error) {
	if !c.proxy {
		return false, nil
	}
	if _, err := c.ensureAPIClient(); err != nil {
		return false, err
	}
	var cfg *config.Config
	attrs, err := c.apiClient.ModelGet()
	if err == nil {
		cfg, err = config.New(config.NoDefaults, attrs)
	}
	if err != nil {
		return false, err
	}
	logger.Debugf("proxy-ssh is %v", cfg.ProxySSH())
	return cfg.ProxySSH(), nil
}

func (c *SSHCommon) ensureAPIClient() (sshAPIClient, error) {
	if c.apiClient != nil {
		return c.apiClient, nil
	}
	return c.initAPIClient()
}

// initAPIClient initialises the API connection.
// It is the caller's responsibility to close the connection.
func (c *SSHCommon) initAPIClient() (sshAPIClient, error) {
	st, err := c.NewAPIRoot()
	if err != nil {
		return nil, err
	}
	c.apiClient = st.Client()
	c.apiAddr = st.Addr()
	return c.apiClient, nil
}

type sshAPIClient interface {
	ModelGet() (map[string]interface{}, error)
	PublicAddress(target string) (string, error)
	PrivateAddress(target string) (string, error)
	Close() error
}

// attemptStarter is an interface corresponding to utils.AttemptStrategy
type attemptStarter interface {
	Start() attempt
}

type attempt interface {
	Next() bool
}

type attemptStrategy utils.AttemptStrategy

func (s attemptStrategy) Start() attempt {
	return utils.AttemptStrategy(s).Start()
}

var sshHostFromTargetAttemptStrategy attemptStarter = attemptStrategy{
	Total: 5 * time.Second,
	Delay: 500 * time.Millisecond,
}

func (c *SSHCommon) userHostFromTarget(target string) (user, host string, err error) {
	if i := strings.IndexRune(target, '@'); i != -1 {
		user = target[:i]
		target = target[i+1:]
	} else {
		user = "ubuntu"
	}

	// If the target is neither a machine nor a unit,
	// assume it's a hostname and try it directly.
	if !names.IsValidMachine(target) && !names.IsValidUnit(target) {
		return user, target, nil
	}

	// A target may not initially have an address (e.g. the
	// address updater hasn't yet run), so we must do this in
	// a loop.
	if _, err := c.ensureAPIClient(); err != nil {
		return "", "", err
	}
	for a := sshHostFromTargetAttemptStrategy.Start(); a.Next(); {
		var addr string
		if c.proxy {
			addr, err = c.apiClient.PrivateAddress(target)
		} else {
			addr, err = c.apiClient.PublicAddress(target)
		}
		if err == nil {
			return user, addr, nil
		}
	}
	return "", "", err
}

// AllowInterspersedFlags for ssh/scp is set to false so that
// flags after the unit name are passed through to ssh, for eg.
// `juju ssh -v service-name/0 uname -a`.
func (c *SSHCommon) AllowInterspersedFlags() bool {
	return false
}
<commit_msg>Drive-by spelling correction.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/juju/cmd"
	"github.com/juju/names"
	"github.com/juju/utils"
	"github.com/juju/utils/ssh"
	"launchpad.net/gnuflag"

	"github.com/juju/juju/cmd/modelcmd"
	"github.com/juju/juju/environs/config"
)

func newSSHCommand() cmd.Command {
	return modelcmd.Wrap(&sshCommand{})
}

// sshCommand is responsible for launching a ssh shell on a given unit or machine.
type sshCommand struct {
	SSHCommon
}

// SSHCommon provides common methods for sshCommand, SCPCommand and DebugHooksCommand.
type SSHCommon struct {
	modelcmd.ModelCommandBase
	proxy     bool
	pty       bool
	Target    string
	Args      []string
	apiClient sshAPIClient
	apiAddr   string
}

func (c *SSHCommon) SetFlags(f *gnuflag.FlagSet) {
	f.BoolVar(&c.proxy, "proxy", true, "proxy through the API server")
	f.BoolVar(&c.pty, "pty", true, "enable pseudo-tty allocation")
}

// setProxyCommand sets the proxy command option.
func (c *SSHCommon) setProxyCommand(options *ssh.Options) error {
	apiServerHost, _, err := net.SplitHostPort(c.apiAddr)
	if err != nil {
		return fmt.Errorf("failed to get proxy address: %v", err)
	}
	juju, err := getJujuExecutable()
	if err != nil {
		return fmt.Errorf("failed to get juju executable path: %v", err)
	}
	options.SetProxyCommand(juju, "ssh", "--proxy=false", "--pty=false", apiServerHost, "nc", "%h", "%p")
	return nil
}

const sshDoc = `
Launch an ssh shell on the machine identified by the <target> parameter.
<target> can be either a machine id  as listed by "juju status" in the
"machines" section or a unit name as listed in the "services" section.
Any extra parameters are passed as extra parameters to the ssh command.

Examples:

Connect to machine 0:

    juju ssh 0

Connect to machine 1 and run 'uname -a':

    juju ssh 1 uname -a

Connect to the first mysql unit:

    juju ssh mysql/0

Connect to the first mysql unit and run 'ls -la /var/log/juju':

    juju ssh mysql/0 ls -la /var/log/juju

Connect to the first jenkins unit as the user jenkins:

    juju ssh jenkins@jenkins/0
`

func (c *sshCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "ssh",
		Args:    "<target> [<ssh args>...]",
		Purpose: "launch an ssh shell on a given unit or machine",
		Doc:     sshDoc,
	}
}

func (c *sshCommand) Init(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf("no target name specified")
	}
	c.Target, c.Args = args[0], args[1:]
	return nil
}

// getJujuExecutable returns the path to the juju
// executable, or an error if it could not be found.
var getJujuExecutable = func() (string, error) {
	return exec.LookPath(os.Args[0])
}

// getSSHOptions configures and returns SSH options and proxy settings.
func (c *SSHCommon) getSSHOptions(enablePty bool) (*ssh.Options, error) {
	var options ssh.Options

	// TODO(waigani) do not save fingerprint only until this bug is addressed:
	// lp:892552. Also see lp:1334481.
	options.SetKnownHostsFile("/dev/null")
	if enablePty {
		options.EnablePTY()
	}
	var err error
	if c.proxy, err = c.proxySSH(); err != nil {
		return nil, err
	} else if c.proxy {
		if err := c.setProxyCommand(&options); err != nil {
			return nil, err
		}
	}
	return &options, nil
}

// Run resolves c.Target to a machine, to the address of a i
// machine or unit forks ssh passing any arguments provided.
func (c *sshCommand) Run(ctx *cmd.Context) error {
	if c.apiClient == nil {
		// If the apClient is not already opened and it is opened
		// by ensureAPIClient, then close it when we're done.
		defer func() {
			if c.apiClient != nil {
				c.apiClient.Close()
				c.apiClient = nil
			}
		}()
	}
	options, err := c.getSSHOptions(c.pty)
	if err != nil {
		return err
	}

	user, host, err := c.userHostFromTarget(c.Target)
	if err != nil {
		return err
	}
	cmd := ssh.Command(user+"@"+host, c.Args, options)
	cmd.Stdin = ctx.Stdin
	cmd.Stdout = ctx.Stdout
	cmd.Stderr = ctx.Stderr
	return cmd.Run()
}

// proxySSH returns true if both c.proxy and
// the proxy-ssh environment configuration
// are true.
func (c *SSHCommon) proxySSH() (bool, error) {
	if !c.proxy {
		return false, nil
	}
	if _, err := c.ensureAPIClient(); err != nil {
		return false, err
	}
	var cfg *config.Config
	attrs, err := c.apiClient.ModelGet()
	if err == nil {
		cfg, err = config.New(config.NoDefaults, attrs)
	}
	if err != nil {
		return false, err
	}
	logger.Debugf("proxy-ssh is %v", cfg.ProxySSH())
	return cfg.ProxySSH(), nil
}

func (c *SSHCommon) ensureAPIClient() (sshAPIClient, error) {
	if c.apiClient != nil {
		return c.apiClient, nil
	}
	return c.initAPIClient()
}

// initAPIClient initialises the API connection.
// It is the caller's responsibility to close the connection.
func (c *SSHCommon) initAPIClient() (sshAPIClient, error) {
	st, err := c.NewAPIRoot()
	if err != nil {
		return nil, err
	}
	c.apiClient = st.Client()
	c.apiAddr = st.Addr()
	return c.apiClient, nil
}

type sshAPIClient interface {
	ModelGet() (map[string]interface{}, error)
	PublicAddress(target string) (string, error)
	PrivateAddress(target string) (string, error)
	Close() error
}

// attemptStarter is an interface corresponding to utils.AttemptStrategy
type attemptStarter interface {
	Start() attempt
}

type attempt interface {
	Next() bool
}

type attemptStrategy utils.AttemptStrategy

func (s attemptStrategy) Start() attempt {
	return utils.AttemptStrategy(s).Start()
}

var sshHostFromTargetAttemptStrategy attemptStarter = attemptStrategy{
	Total: 5 * time.Second,
	Delay: 500 * time.Millisecond,
}

func (c *SSHCommon) userHostFromTarget(target string) (user, host string, err error) {
	if i := strings.IndexRune(target, '@'); i != -1 {
		user = target[:i]
		target = target[i+1:]
	} else {
		user = "ubuntu"
	}

	// If the target is neither a machine nor a unit,
	// assume it's a hostname and try it directly.
	if !names.IsValidMachine(target) && !names.IsValidUnit(target) {
		return user, target, nil
	}

	// A target may not initially have an address (e.g. the
	// address updater hasn't yet run), so we must do this in
	// a loop.
	if _, err := c.ensureAPIClient(); err != nil {
		return "", "", err
	}
	for a := sshHostFromTargetAttemptStrategy.Start(); a.Next(); {
		var addr string
		if c.proxy {
			addr, err = c.apiClient.PrivateAddress(target)
		} else {
			addr, err = c.apiClient.PublicAddress(target)
		}
		if err == nil {
			return user, addr, nil
		}
	}
	return "", "", err
}

// AllowInterspersedFlags for ssh/scp is set to false so that
// flags after the unit name are passed through to ssh, for eg.
// `juju ssh -v service-name/0 uname -a`.
func (c *SSHCommon) AllowInterspersedFlags() bool {
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/minio-io/minio/pkgs/erasure"
)

func main() {
	app := cli.NewApp()
	app.Name = "minio-decode"
	app.Usage = "erasure decode a byte stream"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "input,i",
			Value: "",
			Usage: "Input file",
		},
		cli.StringFlag{
			Name:  "output,o",
			Value: "",
			Usage: "Output file",
		},
		cli.IntFlag{
			Name:  "k",
			Value: 10,
			Usage: "k value of encoder parameters",
		},
		cli.IntFlag{
			Name:  "m",
			Value: 5,
			Usage: "m value of encoder parameters",
		},
	}
	app.Action = func(c *cli.Context) {
		// check if minio-encode called without parameters
		if len(c.Args()) == 1 {
			cli.ShowAppHelp(c)
		}

		// get input path
		if c.String("input") == "" {
			log.Fatal("No input specified")
		}
		inputFilePath := c.String("input")

		// get output path
		outputFilePath := inputFilePath
		if c.String("output") != "" {
			outputFilePath = c.String("output")
		}

		k := c.Int("k")
		m := c.Int("m")

		// get chunks
		chunks := make([][]byte, k+m)
		for i := 0; i < k+m; i++ {
			var err error
			chunks[i], err = ioutil.ReadFile(inputFilePath + "." + strconv.Itoa(i))
			if err != nil {
				continue
			}
		}

		// get length
		lengthBytes, err := ioutil.ReadFile(inputFilePath + ".length")
		if err != nil {
			log.Fatal(err)
		}
		lengthString := string(lengthBytes)
		length, err := strconv.Atoi(lengthString)
		if err != nil {
			log.Fatal(err)
		}

		// set up encoder
		erasureParameters, _ := erasure.ValidateParams(k, m, 8, erasure.CAUCHY)

		// decode data
		decodedData, err := erasure.Decode(chunks, erasureParameters, length)
		if err != nil {
			log.Fatal(err)
		}

		// write decode data out
		ioutil.WriteFile(outputFilePath, decodedData, 0600)
	}
	app.Run(os.Args)
}
<commit_msg>Simplifying code<commit_after>package main

import (
	"io/ioutil"
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/minio-io/minio/pkgs/erasure"
)

func main() {
	app := cli.NewApp()
	app.Name = "minio-decode"
	app.Usage = "erasure decode a byte stream"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "input,i",
			Value: "",
			Usage: "Input file",
		},
		cli.StringFlag{
			Name:  "output,o",
			Value: "",
			Usage: "Output file",
		},
		cli.IntFlag{
			Name:  "k",
			Value: 10,
			Usage: "k value of encoder parameters",
		},
		cli.IntFlag{
			Name:  "m",
			Value: 5,
			Usage: "m value of encoder parameters",
		},
	}
	app.Action = func(c *cli.Context) {
		// check if minio-encode called without parameters
		if len(c.Args()) == 1 {
			cli.ShowAppHelp(c)
		}

		// get input path
		if c.String("input") == "" {
			log.Fatal("No input specified")
		}
		inputFilePath := c.String("input")

		// get output path
		outputFilePath := inputFilePath
		if c.String("output") != "" {
			outputFilePath = c.String("output")
		}

		k := c.Int("k")
		m := c.Int("m")

		// get chunks
		chunks := make([][]byte, k+m)
		for i := 0; i < k+m; i++ {
			chunks[i], _ = ioutil.ReadFile(inputFilePath + "." + strconv.Itoa(i))
		}

		// get length
		lengthBytes, err := ioutil.ReadFile(inputFilePath + ".length")
		if err != nil {
			log.Fatal(err)
		}
		lengthString := string(lengthBytes)
		length, err := strconv.Atoi(lengthString)
		if err != nil {
			log.Fatal(err)
		}

		// set up encoder
		erasureParameters, _ := erasure.ValidateParams(k, m, 8, erasure.CAUCHY)

		// decode data
		decodedData, err := erasure.Decode(chunks, erasureParameters, length)
		if err != nil {
			log.Fatal(err)
		}

		// write decode data out
		ioutil.WriteFile(outputFilePath, decodedData, 0600)
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package cli

import (
	"os"

	"github.com/tus/tusd"
	"github.com/tus/tusd/filestore"
	"github.com/tus/tusd/limitedstore"
	"github.com/tus/tusd/memorylocker"
	"github.com/tus/tusd/s3store"
	"github.com/tus/tusd/gcsstore"

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

var Composer *tusd.StoreComposer

func CreateComposer() {
	// Attempt to use S3 as a backend if the -s3-bucket option has been supplied.
	// If not, we default to storing them locally on disk.
	Composer = tusd.NewStoreComposer()
	if Flags.S3Bucket != "" {
		s3Config := aws.NewConfig()

		if Flags.S3Endpoint == "" {
			stdout.Printf("Using 's3://%s' as S3 bucket for storage.\n", Flags.S3Bucket)
		} else {
			stdout.Printf("Using '%s/%s' as S3 endpoint and bucket for storage.\n", Flags.S3Endpoint, Flags.S3Bucket)

			s3Config = s3Config.WithEndpoint(Flags.S3Endpoint).WithS3ForcePathStyle(true)
		}

		// Derive credentials from AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID and
		// AWS_REGION environment variables.
		s3Config = s3Config.WithCredentials(credentials.NewEnvCredentials())
		store := s3store.New(Flags.S3Bucket, s3.New(session.New(), s3Config))
		store.UseIn(Composer)

		locker := memorylocker.New()
		locker.UseIn(Composer)
	} else if Flags.GCSBucket != "" {
		// Derivce credentials from service account file path passed in
		// GCS_SERVICE_ACCOUNT_FILE environment variable.
		gcsSAF := os.Getenv("GCS_SERVICE_ACCOUNT_FILE")
		if gcsSAF == "" {
			stderr.Fatalf("No service account file provided for Google Cloud Storage using the GCS_SERVICE_ACCOUNT_FILE environment variable.\n")
		}

		service, err := gcsstore.NewGCSService(gcsSAF)
		if err != nil {
			stderr.Fatalf("Unable to create Google Cloud Storage service: %s\n", err)
		}

		stdout.Printf("Using 'gcs://%s' as GCS bucket for storage.\n", Flags.GCSBucket)

		store := gcsstore.New(Flags.GCSBucket, service)
		store.UseIn(Composer)

		locker := memorylocker.New()
		locker.UseIn(Composer)
	} else {
		dir := Flags.UploadDir

		stdout.Printf("Using '%s' as directory storage.\n", dir)
		if err := os.MkdirAll(dir, os.FileMode(0774)); err != nil {
			stderr.Fatalf("Unable to ensure directory exists: %s", err)
		}

		store := filestore.New(dir)
		store.UseIn(Composer)
	}

	storeSize := Flags.StoreSize
	maxSize := Flags.MaxSize

	if storeSize > 0 {
		limitedstore.New(storeSize, Composer.Core, Composer.Terminater).UseIn(Composer)
		stdout.Printf("Using %.2fMB as storage size.\n", float64(storeSize)/1024/1024)

		// We need to ensure that a single upload can fit into the storage size
		if maxSize > storeSize || maxSize == 0 {
			Flags.MaxSize = storeSize
		}
	}

	stdout.Printf("Using %.2fMB as maximum size.\n", float64(Flags.MaxSize)/1024/1024)
}
<commit_msg>Allow AWS-SDK to handle gathering credentials. This change enables ec2 instance assumed roles, environment variables, and shared configs as is standard for the aws-sdk.<commit_after>package cli

import (
	"os"

	"github.com/tus/tusd"
	"github.com/tus/tusd/filestore"
	"github.com/tus/tusd/limitedstore"
	"github.com/tus/tusd/memorylocker"
	"github.com/tus/tusd/s3store"
	"github.com/tus/tusd/gcsstore"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
)

var Composer *tusd.StoreComposer

func CreateComposer() {
	// Attempt to use S3 as a backend if the -s3-bucket option has been supplied.
	// If not, we default to storing them locally on disk.
	Composer = tusd.NewStoreComposer()
	if Flags.S3Bucket != "" {
		s3Config := aws.NewConfig()

		if Flags.S3Endpoint == "" {
			stdout.Printf("Using 's3://%s' as S3 bucket for storage.\n", Flags.S3Bucket)
		} else {
			stdout.Printf("Using '%s/%s' as S3 endpoint and bucket for storage.\n", Flags.S3Endpoint, Flags.S3Bucket)

			s3Config = s3Config.WithEndpoint(Flags.S3Endpoint).WithS3ForcePathStyle(true)
		}

		// Derive credentials from default credential chain (env, shared, ec2 instance role)
		// as per https://github.com/aws/aws-sdk-go#configuring-credentials
		store := s3store.New(Flags.S3Bucket, s3.New(session.Must(session.NewSession()), s3Config))
		store.UseIn(Composer)

		locker := memorylocker.New()
		locker.UseIn(Composer)
	} else if Flags.GCSBucket != "" {
		// Derivce credentials from service account file path passed in
		// GCS_SERVICE_ACCOUNT_FILE environment variable.
		gcsSAF := os.Getenv("GCS_SERVICE_ACCOUNT_FILE")
		if gcsSAF == "" {
			stderr.Fatalf("No service account file provided for Google Cloud Storage using the GCS_SERVICE_ACCOUNT_FILE environment variable.\n")
		}

		service, err := gcsstore.NewGCSService(gcsSAF)
		if err != nil {
			stderr.Fatalf("Unable to create Google Cloud Storage service: %s\n", err)
		}

		stdout.Printf("Using 'gcs://%s' as GCS bucket for storage.\n", Flags.GCSBucket)

		store := gcsstore.New(Flags.GCSBucket, service)
		store.UseIn(Composer)

		locker := memorylocker.New()
		locker.UseIn(Composer)
	} else {
		dir := Flags.UploadDir

		stdout.Printf("Using '%s' as directory storage.\n", dir)
		if err := os.MkdirAll(dir, os.FileMode(0774)); err != nil {
			stderr.Fatalf("Unable to ensure directory exists: %s", err)
		}

		store := filestore.New(dir)
		store.UseIn(Composer)
	}

	storeSize := Flags.StoreSize
	maxSize := Flags.MaxSize

	if storeSize > 0 {
		limitedstore.New(storeSize, Composer.Core, Composer.Terminater).UseIn(Composer)
		stdout.Printf("Using %.2fMB as storage size.\n", float64(storeSize)/1024/1024)

		// We need to ensure that a single upload can fit into the storage size
		if maxSize > storeSize || maxSize == 0 {
			Flags.MaxSize = storeSize
		}
	}

	stdout.Printf("Using %.2fMB as maximum size.\n", float64(Flags.MaxSize)/1024/1024)
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package log

// These tests are too simple.

import (
	"bytes"
	"fmt"
	"os"
	"regexp"
	"strings"
	"testing"
	"time"
)

const (
	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
)

type tester struct {
	flag    int
	prefix  string
	pattern string // regexp that log output must match; we add ^ and expected_text$ always
}

var tests = []tester{
	// individual pieces:
	{0, "", ""},
	{0, "XXX", "XXX"},
	{Ldate, "", Rdate + " "},
	{Ltime, "", Rtime + " "},
	{Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
	{Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
	{Llongfile, "", Rlongfile + " "},
	{Lshortfile, "", Rshortfile + " "},
	{Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
	// everything at once:
	{Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
	{Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
}

// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
	buf := new(bytes.Buffer)
	SetOutput(buf)
	SetFlags(flag)
	SetPrefix(prefix)
	if useFormat {
		Printf("hello %d world", 23)
	} else {
		Println("hello", 23, "world")
	}
	line := buf.String()
	line = line[0 : len(line)-1]
	pattern = "^" + pattern + "hello 23 world$"
	matched, err4 := regexp.MatchString(pattern, line)
	if err4 != nil {
		t.Fatal("pattern did not compile:", err4)
	}
	if !matched {
		t.Errorf("log output should match %q is %q", pattern, line)
	}
	SetOutput(os.Stderr)
}

func TestAll(t *testing.T) {
	for _, testcase := range tests {
		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
	}
}

func TestOutput(t *testing.T) {
	const testString = "test"
	var b bytes.Buffer
	l := New(&b, "", 0)
	l.Println(testString)
	if expect := testString + "\n"; b.String() != expect {
		t.Errorf("log output should match %q is %q", expect, b.String())
	}
}

func TestFlagAndPrefixSetting(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Test:", LstdFlags)
	f := l.Flags()
	if f != LstdFlags {
		t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
	}
	l.SetFlags(f | Lmicroseconds)
	f = l.Flags()
	if f != LstdFlags|Lmicroseconds {
		t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
	}
	p := l.Prefix()
	if p != "Test:" {
		t.Errorf(`Prefix: expected "Test:" got %q`, p)
	}
	l.SetPrefix("Reality:")
	p = l.Prefix()
	if p != "Reality:" {
		t.Errorf(`Prefix: expected "Reality:" got %q`, p)
	}
	// Verify a log message looks right, with our prefix and microseconds present.
	l.Print("hello")
	pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
	matched, err := regexp.Match(pattern, b.Bytes())
	if err != nil {
		t.Fatalf("pattern %q did not compile: %s", pattern, err)
	}
	if !matched {
		t.Error("message did not match pattern")
	}
}

func TestUTCFlag(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Test:", LstdFlags)
	l.SetFlags(Ldate | Ltime | LUTC)
	// Verify a log message looks right in the right time zone. Quantize to the second only.
	now := time.Now().UTC()
	l.Print("hello")
	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
	got := b.String()
	if got == want {
		return
	}
	// It's possible we crossed a second boundary between getting now and logging,
	// so add a second and try again. This should very nearly always work.
	now.Add(time.Second)
	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute())
	if got == want {
		return
	}
	t.Errorf("got %q; want %q", got, want)
}

func TestEmptyPrintCreatesLine(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Header:", LstdFlags)
	l.Print()
	l.Println("non-empty")
	output := b.String()
	if n := strings.Count(output, "Header"); n != 2 {
		t.Errorf("expected 2 headers, got %d", n)
	}
	if n := strings.Count(output, "\n"); n != 2 {
		t.Errorf("expected 2 lines, got %d", n)
	}
}

func BenchmarkItoa(b *testing.B) {
	dst := make([]byte, 0, 64)
	for i := 0; i < b.N; i++ {
		dst = dst[0:0]
		itoa(&dst, 2015, 4)   // year
		itoa(&dst, 1, 2)      // month
		itoa(&dst, 30, 2)     // day
		itoa(&dst, 12, 2)     // hour
		itoa(&dst, 56, 2)     // minute
		itoa(&dst, 0, 2)      // second
		itoa(&dst, 987654, 6) // microsecond
	}
}

func BenchmarkPrintln(b *testing.B) {
	const testString = "test"
	var buf bytes.Buffer
	l := New(&buf, "", LstdFlags)
	for i := 0; i < b.N; i++ {
		buf.Reset()
		l.Println(testString)
	}
}
<commit_msg>log: fix flaky test<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package log

// These tests are too simple.

import (
	"bytes"
	"fmt"
	"os"
	"regexp"
	"strings"
	"testing"
	"time"
)

const (
	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
)

type tester struct {
	flag    int
	prefix  string
	pattern string // regexp that log output must match; we add ^ and expected_text$ always
}

var tests = []tester{
	// individual pieces:
	{0, "", ""},
	{0, "XXX", "XXX"},
	{Ldate, "", Rdate + " "},
	{Ltime, "", Rtime + " "},
	{Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
	{Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
	{Llongfile, "", Rlongfile + " "},
	{Lshortfile, "", Rshortfile + " "},
	{Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
	// everything at once:
	{Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
	{Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
}

// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
	buf := new(bytes.Buffer)
	SetOutput(buf)
	SetFlags(flag)
	SetPrefix(prefix)
	if useFormat {
		Printf("hello %d world", 23)
	} else {
		Println("hello", 23, "world")
	}
	line := buf.String()
	line = line[0 : len(line)-1]
	pattern = "^" + pattern + "hello 23 world$"
	matched, err4 := regexp.MatchString(pattern, line)
	if err4 != nil {
		t.Fatal("pattern did not compile:", err4)
	}
	if !matched {
		t.Errorf("log output should match %q is %q", pattern, line)
	}
	SetOutput(os.Stderr)
}

func TestAll(t *testing.T) {
	for _, testcase := range tests {
		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
		testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
	}
}

func TestOutput(t *testing.T) {
	const testString = "test"
	var b bytes.Buffer
	l := New(&b, "", 0)
	l.Println(testString)
	if expect := testString + "\n"; b.String() != expect {
		t.Errorf("log output should match %q is %q", expect, b.String())
	}
}

func TestFlagAndPrefixSetting(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Test:", LstdFlags)
	f := l.Flags()
	if f != LstdFlags {
		t.Errorf("Flags 1: expected %x got %x", LstdFlags, f)
	}
	l.SetFlags(f | Lmicroseconds)
	f = l.Flags()
	if f != LstdFlags|Lmicroseconds {
		t.Errorf("Flags 2: expected %x got %x", LstdFlags|Lmicroseconds, f)
	}
	p := l.Prefix()
	if p != "Test:" {
		t.Errorf(`Prefix: expected "Test:" got %q`, p)
	}
	l.SetPrefix("Reality:")
	p = l.Prefix()
	if p != "Reality:" {
		t.Errorf(`Prefix: expected "Reality:" got %q`, p)
	}
	// Verify a log message looks right, with our prefix and microseconds present.
	l.Print("hello")
	pattern := "^Reality:" + Rdate + " " + Rtime + Rmicroseconds + " hello\n"
	matched, err := regexp.Match(pattern, b.Bytes())
	if err != nil {
		t.Fatalf("pattern %q did not compile: %s", pattern, err)
	}
	if !matched {
		t.Error("message did not match pattern")
	}
}

func TestUTCFlag(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Test:", LstdFlags)
	l.SetFlags(Ldate | Ltime | LUTC)
	// Verify a log message looks right in the right time zone. Quantize to the second only.
	now := time.Now().UTC()
	l.Print("hello")
	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
	got := b.String()
	if got == want {
		return
	}
	// It's possible we crossed a second boundary between getting now and logging,
	// so add a second and try again. This should very nearly always work.
	now = now.Add(time.Second)
	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
	if got == want {
		return
	}
	t.Errorf("got %q; want %q", got, want)
}

func TestEmptyPrintCreatesLine(t *testing.T) {
	var b bytes.Buffer
	l := New(&b, "Header:", LstdFlags)
	l.Print()
	l.Println("non-empty")
	output := b.String()
	if n := strings.Count(output, "Header"); n != 2 {
		t.Errorf("expected 2 headers, got %d", n)
	}
	if n := strings.Count(output, "\n"); n != 2 {
		t.Errorf("expected 2 lines, got %d", n)
	}
}

func BenchmarkItoa(b *testing.B) {
	dst := make([]byte, 0, 64)
	for i := 0; i < b.N; i++ {
		dst = dst[0:0]
		itoa(&dst, 2015, 4)   // year
		itoa(&dst, 1, 2)      // month
		itoa(&dst, 30, 2)     // day
		itoa(&dst, 12, 2)     // hour
		itoa(&dst, 56, 2)     // minute
		itoa(&dst, 0, 2)      // second
		itoa(&dst, 987654, 6) // microsecond
	}
}

func BenchmarkPrintln(b *testing.B) {
	const testString = "test"
	var buf bytes.Buffer
	l := New(&buf, "", LstdFlags)
	for i := 0; i < b.N; i++ {
		buf.Reset()
		l.Println(testString)
	}
}
<|endoftext|>


<commit_before>package file

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/luopengift/log"
)

// Tail tail
type Tail struct {
	*File
	cname    string //config name
	line     chan []byte
	reader   *bufio.Reader
	interval int64
	Handler  // file name handle interface
	//EOF
	//@ true: stop
	//@ false: wait
	endstop bool
}

// NewTail new tail
func NewTail(cname string, handler Handler) *Tail {
	name := handler.Handle(cname)
	file := NewFile(name, os.O_RDONLY)

	tail := new(Tail)
	tail.File = NewFile(name, os.O_RDONLY)
	tail.cname = cname
	tail.line = make(chan []byte, 1)
	tail.reader = bufio.NewReader(file.fd)
	tail.interval = 1000 //ms
	tail.endstop = false
	tail.Handler = handler
	return tail
}

// EndStop end stop
func (t *Tail) EndStop(b bool) {
	t.endstop = b
}

// Close close
func (t *Tail) Close() error {
	close(t.line)
	return t.File.Close()
}

// ReOpen re open
func (t *Tail) ReOpen() error {
	if err := t.File.Close(); err != nil {
		return log.Errorf("name: %v, %v", t.name, err)
	}
	t.name = t.Handler.Handle(t.cname)
	err := t.Open()
	if err != nil {
		return err
	}
	t.reader = bufio.NewReader(t.fd)
	return nil
}

// Stop stop
func (t *Tail) Stop() {
	t.File.Close()
	close(t.line)
}

// ReadLine read line
func (t *Tail) ReadLine() {
	go func() {
		offset, err := t.TrancateOffsetByLF(t.seek)
		if err != nil {
			log.Error("<Trancate offset:%d,Error:%+v>", t.seek, err)
		}
		err = t.Seek(offset)
		if err != nil {
			log.Error("<seek offset[%d] error:%+v>", t.seek, err)
		}

		for {
			line, err := t.reader.ReadBytes('\n')
			switch {
			case err == io.EOF:
				if t.endstop {
					//log.Info("<file %s is END:%+v>", t.name, err)
					t.Stop()
					return
				}
				time.Sleep(time.Duration(t.interval) * time.Millisecond)
				if t.name == t.cname {
					if t.IsSameFile(t.name) {
						continue
					} else {
						t.ReOpen()
					}
				} else {
					if t.name == t.Handler.Handle(t.cname) { //检测是否需要按时间轮转新文件
						continue
					} else {
						t.ReOpen()
					}
				}

			case err != nil && err != io.EOF:
				time.Sleep(time.Duration(t.interval) * time.Millisecond)
				//log.Error("<Read file error:%v,%v>", line, err)
				t.ReOpen()
				continue
			default:
				msg := bytes.TrimRight(line, "\n")
				t.line <- msg
				t.seek += int64(len(line))
			}
		}
	}()
}

// NextLine nextline
func (t *Tail) NextLine() chan []byte {
	return t.line
}

// Read read
func (t *Tail) Read(p []byte) (int, error) {
	msg, ok := <-t.line
	if !ok {
		return 0, fmt.Errorf("file is closed")
	}
	if len(msg) > len(p) {
		return 0, errors.New("message is large than buf")
	}
	n := copy(p, msg)
	return n, nil
}
<commit_msg>update<commit_after>package file

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/luopengift/log"
)

// Tail tail
type Tail struct {
	*File
	cname    string //config name
	line     chan []byte
	reader   *bufio.Reader
	interval int64
	Handler  // file name handle interface
	//EOF
	//@ true: stop
	//@ false: wait
	endstop bool
}

// NewTail new tail
func NewTail(cname string, handler Handler) *Tail {
	name := handler.Handle(cname)
	file := NewFile(name, os.O_RDONLY)

	tail := new(Tail)
	tail.File = NewFile(name, os.O_RDONLY)
	tail.cname = cname
	tail.line = make(chan []byte, 1)
	tail.reader = bufio.NewReader(file.fd)
	tail.interval = 1000 //ms
	tail.endstop = false
	tail.Handler = handler
	return tail
}

// EndStop end stop
func (t *Tail) EndStop(b bool) {
	t.endstop = b
}

// Close close
func (t *Tail) Close() error {
	close(t.line)
	return t.File.Close()
}

// ReOpen re open
func (t *Tail) ReOpen() error {
	if err := t.File.Close(); err != nil {
		return log.Errorf("name: %v, %v", t.name, err)
	}
	t.name = t.Handler.Handle(t.cname)
	err := t.Open()
	if err != nil {
		return err
	}
	t.reader = bufio.NewReader(t.fd)
	return nil
}

// Stop stop
func (t *Tail) Stop() {
	t.File.Close()
	close(t.line)
}

// ReadLine read line
func (t *Tail) ReadLine() {
	go func() {
		offset, err := t.TrancateOffsetByLF(t.seek)
		if err != nil {
			log.Error("<Trancate offset:%d,Error:%+v>", t.seek, err)
			return
		}
		err = t.Seek(offset)
		if err != nil {
			log.Error("<seek offset[%d] error:%+v>", t.seek, err)
			return
		}

		for {
			line, err := t.reader.ReadBytes('\n')
			switch {
			case err == io.EOF:
				if t.endstop {
					//log.Info("<file %s is END:%+v>", t.name, err)
					t.Stop()
					return
				}
				time.Sleep(time.Duration(t.interval) * time.Millisecond)
				if t.name == t.cname {
					if t.IsSameFile(t.name) {
						continue
					} else {
						t.ReOpen()
					}
				} else {
					if t.name == t.Handler.Handle(t.cname) { //检测是否需要按时间轮转新文件
						continue
					} else {
						t.ReOpen()
					}
				}

			case err != nil && err != io.EOF:
				time.Sleep(time.Duration(t.interval) * time.Millisecond)
				//log.Error("<Read file error:%v,%v>", line, err)
				t.ReOpen()
				continue
			default:
				msg := bytes.TrimRight(line, "\n")
				t.line <- msg
				t.seek += int64(len(line))
			}
		}
	}()
}

// NextLine nextline
func (t *Tail) NextLine() chan []byte {
	return t.line
}

// Read read
func (t *Tail) Read(p []byte) (int, error) {
	msg, ok := <-t.line
	if !ok {
		return 0, fmt.Errorf("file is closed")
	}
	if len(msg) > len(p) {
		return 0, errors.New("message is large than buf")
	}
	n := copy(p, msg)
	return n, nil
}
<|endoftext|>


<commit_before>package kuberos

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"github.com/negz/kuberos/extractor"

	oidc "github.com/coreos/go-oidc"
	"github.com/gorilla/schema"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
)

const (
	// DefaultKubeCfgEndpoint is the default endpoint to which clients should
	// be redirected after authentication.
	DefaultKubeCfgEndpoint = "/ui"

	schemeHTTP  = "http"
	schemeHTTPS = "https"

	urlParamState            = "state"
	urlParamCode             = "code"
	urlParamError            = "error"
	urlParamErrorDescription = "error_description"
	urlParamErrorURI         = "error_uri"

	templateUser             = "kuberos"
	templateAuthProvider     = "oidc"
	templateOIDCClientID     = "client-id"
	templateOIDCClientSecret = "client-secret"
	templateOIDCIDToken      = "id-token"
	templateOIDCIssuer       = "idp-issuer-url"
	templateOIDCRefreshToken = "refresh-token"

	templateFormParseMemory = 32 << 20 // 32MB
)

var (
	// DefaultScopes are the minimum required oauth2 scopes for every
	// authentication request.
	DefaultScopes = []string{oidc.ScopeOpenID, "profile", "email"}

	// ErrInvalidKubeCfgEndpoint indicates an unparseable redirect endpoint.
	ErrInvalidKubeCfgEndpoint = errors.New("invalid redirect endpoint")

	// ErrInvalidState indicates the provided state param was not as expected.
	ErrInvalidState = errors.New("invalid state parameter")

	// ErrMissingCode indicates a response without an OAuth 2.0 authorization
	// code
	ErrMissingCode = errors.New("response missing authorization code")

	// ErrNoYAMLSerializer indicates we're unable to serialize Kubernetes
	// objects as YAML.
	ErrNoYAMLSerializer = errors.New("no YAML serializer registered")

	decoder = schema.NewDecoder()
)

// A StateFn should take an HTTP request and return a difficult to predict yet
// deterministic state string.
type StateFn func(*http.Request) string

func defaultStateFn(secret []byte) StateFn {
	// Writing to a hash never returns an error.
	// nolint: errcheck, gas
	return func(r *http.Request) string {
		h := sha256.New()
		h.Write(secret)
		h.Write([]byte(r.Host))
		h.Write([]byte(r.RemoteAddr))
		h.Write([]byte(r.UserAgent()))
		return fmt.Sprintf("%x", h.Sum(nil))
	}
}

// OfflineAsScope determines whether an offline refresh token is requested via
// a scope per the spec or via Google's custom access_type=offline method.
//
// See http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess and
// https://developers.google.com/identity/protocols/OAuth2WebServer#offline
func OfflineAsScope(p *oidc.Provider) bool {
	var s struct {
		Scopes []string `json:"scopes_supported"`
	}
	if err := p.Claims(&s); err != nil {
		return true
	}
	if len(s.Scopes) == 0 {
		return true
	}
	for _, scope := range s.Scopes {
		if scope == oidc.ScopeOfflineAccess {
			return true
		}
	}
	return false
}

// ScopeRequests configures the oauth2 scopes to request during authentication.
type ScopeRequests struct {
	OfflineAsScope bool
	ExtraScopes    []string
}

// Get the scopes to request during authentication.
func (r *ScopeRequests) Get() []string {
	scopes := DefaultScopes
	if r.OfflineAsScope {
		scopes = append(scopes, oidc.ScopeOfflineAccess)
	}
	return append(scopes, r.ExtraScopes...)
}

// Handlers provides HTTP handlers for the Kubernary service.
type Handlers struct {
	cfg        *oauth2.Config
	e          extractor.OIDC
	oo         []oauth2.AuthCodeOption
	state      StateFn
	httpClient *http.Client
	endpoint   *url.URL
}

// An Option represents a Handlers option.
type Option func(*Handlers) error

// StateFunction allows the use of a bespoke state generator function.
func StateFunction(fn StateFn) Option {
	return func(h *Handlers) error {
		h.state = fn
		return nil
	}
}

// HTTPClient allows the use of a bespoke HTTP client for OIDC requests.
func HTTPClient(c *http.Client) Option {
	return func(h *Handlers) error {
		h.httpClient = c
		return nil
	}
}

// AuthCodeOptions allows the use of bespoke OAuth2 options.
func AuthCodeOptions(oo []oauth2.AuthCodeOption) Option {
	return func(h *Handlers) error {
		h.oo = oo
		return nil
	}
}

// NewHandlers returns a new set of Kuberos HTTP handlers.
func NewHandlers(c *oauth2.Config, e extractor.OIDC, ho ...Option) (*Handlers, error) {
	h := &Handlers{
		cfg:        c,
		e:          e,
		oo:         []oauth2.AuthCodeOption{oauth2.AccessTypeOffline},
		state:      defaultStateFn([]byte(c.ClientSecret)),
		httpClient: http.DefaultClient,
		endpoint:   &url.URL{Path: DefaultKubeCfgEndpoint},
	}

	// Assume we're using a Googley request for offline access.
	for _, s := range c.Scopes {
		// ...Unless we find an offline scope
		if s == oidc.ScopeOfflineAccess {
			h.oo = []oauth2.AuthCodeOption{}
		}
	}

	for _, o := range ho {
		if err := o(h); err != nil {
			return nil, errors.Wrap(err, "cannot apply handlers option")
		}
	}
	return h, nil
}

// Login redirects to an OIDC provider per the supplied oauth2 config.
func (h *Handlers) Login(w http.ResponseWriter, r *http.Request) {
	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	http.Redirect(w, r, c.AuthCodeURL(h.state(r), h.oo...), http.StatusSeeOther)
}

// KubeCfg returns a handler that forms helpers for kubecfg authentication.
func (h *Handlers) KubeCfg(w http.ResponseWriter, r *http.Request) {
	if r.FormValue(urlParamState) != h.state(r) {
		http.Error(w, ErrInvalidState.Error(), http.StatusForbidden)
		return
	}

	if e := r.FormValue(urlParamError); e != "" {
		msg := e
		if desc := r.FormValue(urlParamErrorDescription); desc != "" {
			msg = fmt.Sprintf("%s: %s", msg, desc)
		}
		if uri := r.FormValue(urlParamErrorURI); uri != "" {
			msg = fmt.Sprintf("%s (see %s)", msg, uri)
		}
		http.Error(w, msg, http.StatusForbidden)
		return
	}

	code := r.FormValue(urlParamCode)
	if code == "" {
		http.Error(w, ErrMissingCode.Error(), http.StatusBadRequest)
		return
	}

	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	rsp, err := h.e.Process(r.Context(), c, code)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot process OAuth2 code").Error(), http.StatusForbidden)
		return
	}

	j, err := json.Marshal(rsp)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot marshal JSON").Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if _, err := w.Write(j); err != nil {
		http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
	}
}

func redirectURL(r *http.Request, endpoint *url.URL) string {
	if r.URL.IsAbs() {
		return fmt.Sprint(r.URL.ResolveReference(endpoint))
	}
	u := &url.URL{}
	u.Scheme = schemeHTTP
	if r.TLS != nil {
		u.Scheme = schemeHTTPS
	}
	u.Host = r.Host
	return fmt.Sprint(u.ResolveReference(endpoint))
}

// Template returns an HTTP handler that returns a new kubecfg by taking a
// template with existing clusters and adding a user and context for each based
// on the URL parameters passed to it.
func Template(cfg *api.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		r.ParseMultipartForm(templateFormParseMemory)
		p := &extractor.OIDCAuthenticationParams{}

		// TODO(negz): Return an error if any required parameter is absent.
		if err := decoder.Decode(p, r.Form); err != nil {
			http.Error(w, errors.Wrap(err, "cannot parse URL parameter").Error(), http.StatusBadRequest)
			return
		}

		c := &api.Config{}
		c.AuthInfos = make(map[string]*api.AuthInfo)
		c.Clusters = make(map[string]*api.Cluster)
		c.Contexts = make(map[string]*api.Context)
		c.AuthInfos[templateUser] = &api.AuthInfo{
			Username: p.Username,
			AuthProvider: &api.AuthProviderConfig{
				Name: templateAuthProvider,
				Config: map[string]string{
					templateOIDCClientID:     p.ClientID,
					templateOIDCClientSecret: p.ClientSecret,
					templateOIDCIDToken:      p.IDToken,
					templateOIDCRefreshToken: p.RefreshToken,
					templateOIDCIssuer:       p.IssuerURL,
				},
			},
		}
		for name, cluster := range cfg.Clusters {
			c.Clusters[name] = cluster
			c.Contexts[name] = &api.Context{Cluster: name, AuthInfo: templateUser}
		}

		y, err := clientcmd.Write(*c)
		if err != nil {
			http.Error(w, errors.Wrap(err, "cannot marshal template to YAML").Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "text/x-yaml; charset=utf-8")
		w.Header().Set("Content-Disposition", "attachment")
		if _, err := w.Write(y); err != nil {
			http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
		}
	}
}
<commit_msg>Redirect to HTTPS if request comes from an HTTPS ELB<commit_after>package kuberos

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"

	"github.com/negz/kuberos/extractor"

	oidc "github.com/coreos/go-oidc"
	"github.com/gorilla/schema"
	"github.com/pkg/errors"
	"golang.org/x/oauth2"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/client-go/tools/clientcmd/api"
)

const (
	// DefaultKubeCfgEndpoint is the default endpoint to which clients should
	// be redirected after authentication.
	DefaultKubeCfgEndpoint = "/ui"

	schemeHTTP              = "http"
	schemeHTTPS             = "https"
	elbHeaderForwardedProto = "X-Forwarded-Proto"

	urlParamState            = "state"
	urlParamCode             = "code"
	urlParamError            = "error"
	urlParamErrorDescription = "error_description"
	urlParamErrorURI         = "error_uri"

	templateUser             = "kuberos"
	templateAuthProvider     = "oidc"
	templateOIDCClientID     = "client-id"
	templateOIDCClientSecret = "client-secret"
	templateOIDCIDToken      = "id-token"
	templateOIDCIssuer       = "idp-issuer-url"
	templateOIDCRefreshToken = "refresh-token"

	templateFormParseMemory = 32 << 20 // 32MB
)

var (
	// DefaultScopes are the minimum required oauth2 scopes for every
	// authentication request.
	DefaultScopes = []string{oidc.ScopeOpenID, "profile", "email"}

	// ErrInvalidKubeCfgEndpoint indicates an unparseable redirect endpoint.
	ErrInvalidKubeCfgEndpoint = errors.New("invalid redirect endpoint")

	// ErrInvalidState indicates the provided state param was not as expected.
	ErrInvalidState = errors.New("invalid state parameter")

	// ErrMissingCode indicates a response without an OAuth 2.0 authorization
	// code
	ErrMissingCode = errors.New("response missing authorization code")

	// ErrNoYAMLSerializer indicates we're unable to serialize Kubernetes
	// objects as YAML.
	ErrNoYAMLSerializer = errors.New("no YAML serializer registered")

	decoder = schema.NewDecoder()
)

// A StateFn should take an HTTP request and return a difficult to predict yet
// deterministic state string.
type StateFn func(*http.Request) string

func defaultStateFn(secret []byte) StateFn {
	// Writing to a hash never returns an error.
	// nolint: errcheck, gas
	return func(r *http.Request) string {
		h := sha256.New()
		h.Write(secret)
		h.Write([]byte(r.Host))
		h.Write([]byte(r.RemoteAddr))
		h.Write([]byte(r.UserAgent()))
		return fmt.Sprintf("%x", h.Sum(nil))
	}
}

// OfflineAsScope determines whether an offline refresh token is requested via
// a scope per the spec or via Google's custom access_type=offline method.
//
// See http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess and
// https://developers.google.com/identity/protocols/OAuth2WebServer#offline
func OfflineAsScope(p *oidc.Provider) bool {
	var s struct {
		Scopes []string `json:"scopes_supported"`
	}
	if err := p.Claims(&s); err != nil {
		return true
	}
	if len(s.Scopes) == 0 {
		return true
	}
	for _, scope := range s.Scopes {
		if scope == oidc.ScopeOfflineAccess {
			return true
		}
	}
	return false
}

// ScopeRequests configures the oauth2 scopes to request during authentication.
type ScopeRequests struct {
	OfflineAsScope bool
	ExtraScopes    []string
}

// Get the scopes to request during authentication.
func (r *ScopeRequests) Get() []string {
	scopes := DefaultScopes
	if r.OfflineAsScope {
		scopes = append(scopes, oidc.ScopeOfflineAccess)
	}
	return append(scopes, r.ExtraScopes...)
}

// Handlers provides HTTP handlers for the Kubernary service.
type Handlers struct {
	cfg        *oauth2.Config
	e          extractor.OIDC
	oo         []oauth2.AuthCodeOption
	state      StateFn
	httpClient *http.Client
	endpoint   *url.URL
}

// An Option represents a Handlers option.
type Option func(*Handlers) error

// StateFunction allows the use of a bespoke state generator function.
func StateFunction(fn StateFn) Option {
	return func(h *Handlers) error {
		h.state = fn
		return nil
	}
}

// HTTPClient allows the use of a bespoke HTTP client for OIDC requests.
func HTTPClient(c *http.Client) Option {
	return func(h *Handlers) error {
		h.httpClient = c
		return nil
	}
}

// AuthCodeOptions allows the use of bespoke OAuth2 options.
func AuthCodeOptions(oo []oauth2.AuthCodeOption) Option {
	return func(h *Handlers) error {
		h.oo = oo
		return nil
	}
}

// NewHandlers returns a new set of Kuberos HTTP handlers.
func NewHandlers(c *oauth2.Config, e extractor.OIDC, ho ...Option) (*Handlers, error) {
	h := &Handlers{
		cfg:        c,
		e:          e,
		oo:         []oauth2.AuthCodeOption{oauth2.AccessTypeOffline},
		state:      defaultStateFn([]byte(c.ClientSecret)),
		httpClient: http.DefaultClient,
		endpoint:   &url.URL{Path: DefaultKubeCfgEndpoint},
	}

	// Assume we're using a Googley request for offline access.
	for _, s := range c.Scopes {
		// ...Unless we find an offline scope
		if s == oidc.ScopeOfflineAccess {
			h.oo = []oauth2.AuthCodeOption{}
		}
	}

	for _, o := range ho {
		if err := o(h); err != nil {
			return nil, errors.Wrap(err, "cannot apply handlers option")
		}
	}
	return h, nil
}

// Login redirects to an OIDC provider per the supplied oauth2 config.
func (h *Handlers) Login(w http.ResponseWriter, r *http.Request) {
	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	http.Redirect(w, r, c.AuthCodeURL(h.state(r), h.oo...), http.StatusSeeOther)
}

// KubeCfg returns a handler that forms helpers for kubecfg authentication.
func (h *Handlers) KubeCfg(w http.ResponseWriter, r *http.Request) {
	if r.FormValue(urlParamState) != h.state(r) {
		http.Error(w, ErrInvalidState.Error(), http.StatusForbidden)
		return
	}

	if e := r.FormValue(urlParamError); e != "" {
		msg := e
		if desc := r.FormValue(urlParamErrorDescription); desc != "" {
			msg = fmt.Sprintf("%s: %s", msg, desc)
		}
		if uri := r.FormValue(urlParamErrorURI); uri != "" {
			msg = fmt.Sprintf("%s (see %s)", msg, uri)
		}
		http.Error(w, msg, http.StatusForbidden)
		return
	}

	code := r.FormValue(urlParamCode)
	if code == "" {
		http.Error(w, ErrMissingCode.Error(), http.StatusBadRequest)
		return
	}

	c := &oauth2.Config{
		ClientID:     h.cfg.ClientID,
		ClientSecret: h.cfg.ClientSecret,
		Endpoint:     h.cfg.Endpoint,
		Scopes:       h.cfg.Scopes,
		RedirectURL:  redirectURL(r, h.endpoint),
	}

	rsp, err := h.e.Process(r.Context(), c, code)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot process OAuth2 code").Error(), http.StatusForbidden)
		return
	}

	j, err := json.Marshal(rsp)
	if err != nil {
		http.Error(w, errors.Wrap(err, "cannot marshal JSON").Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	if _, err := w.Write(j); err != nil {
		http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
	}
}

func redirectURL(r *http.Request, endpoint *url.URL) string {
	if r.URL.IsAbs() {
		return fmt.Sprint(r.URL.ResolveReference(endpoint))
	}
	u := &url.URL{}
	u.Scheme = schemeHTTP
	if r.TLS != nil {
		u.Scheme = schemeHTTPS
	}

	// Redirect to HTTPS if we're listening on HTTP behind an HTTPS ELB.
	for h, v := range r.Header {
		if h == elbHeaderForwardedProto {
			for _, proto := range v {
				if proto == schemeHTTPS {
					u.Scheme = schemeHTTPS
				}
			}
		}
	}
	// TODO(negz): Set port if X-Forwarded-Port exists?
	u.Host = r.Host
	return fmt.Sprint(u.ResolveReference(endpoint))
}

// Template returns an HTTP handler that returns a new kubecfg by taking a
// template with existing clusters and adding a user and context for each based
// on the URL parameters passed to it.
func Template(cfg *api.Config) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		r.ParseMultipartForm(templateFormParseMemory)
		p := &extractor.OIDCAuthenticationParams{}

		// TODO(negz): Return an error if any required parameter is absent.
		if err := decoder.Decode(p, r.Form); err != nil {
			http.Error(w, errors.Wrap(err, "cannot parse URL parameter").Error(), http.StatusBadRequest)
			return
		}

		c := &api.Config{}
		c.AuthInfos = make(map[string]*api.AuthInfo)
		c.Clusters = make(map[string]*api.Cluster)
		c.Contexts = make(map[string]*api.Context)
		c.AuthInfos[templateUser] = &api.AuthInfo{
			Username: p.Username,
			AuthProvider: &api.AuthProviderConfig{
				Name: templateAuthProvider,
				Config: map[string]string{
					templateOIDCClientID:     p.ClientID,
					templateOIDCClientSecret: p.ClientSecret,
					templateOIDCIDToken:      p.IDToken,
					templateOIDCRefreshToken: p.RefreshToken,
					templateOIDCIssuer:       p.IssuerURL,
				},
			},
		}
		for name, cluster := range cfg.Clusters {
			c.Clusters[name] = cluster
			c.Contexts[name] = &api.Context{Cluster: name, AuthInfo: templateUser}
		}

		y, err := clientcmd.Write(*c)
		if err != nil {
			http.Error(w, errors.Wrap(err, "cannot marshal template to YAML").Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "text/x-yaml; charset=utf-8")
		w.Header().Set("Content-Disposition", "attachment")
		if _, err := w.Write(y); err != nil {
			http.Error(w, errors.Wrap(err, "cannot write response").Error(), http.StatusInternalServerError)
		}
	}
}
<|endoftext|>


<commit_before>/* 	kylixor.go
_________________________________
Main code for Kylixor Discord Bot
Andrew Langhill
kylixor.com
*/

package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/jasonlvhit/gocron"
)

// ----- GLOBAL VARIABLES -----

//Config - structure to hold variables from the config file
type Config struct {
	Admin  string //Admin's Discord ID
	APIKey string //Discord bot api key
	Coins  string //Name of currency that bot uses (i.e. <gold> coins)
	Follow bool   //Whether or not the bot joins/follows into voice channels for anthems
	LogID  string //ID of channel for logging
	Noise  bool   //Whether the bot will use function that play sound
	Prefix string //Prefix the bot will respond to
	Status string //Status of the bot (Playing <v1.0>)
}

var config = Config{}                              //Config structure from file
var currentVoiceChannel *discordgo.VoiceConnection //Current voice channel bot is in, nil if none
var self *discordgo.User                           //discord user type of self (for storing bots user account)

//InitConfFile - Initialize config file if one is not found
func InitConfFile() {
	//Default values
	config.Prefix = "k!"
	config.Status = "k!help"

	//Create and indent proper json output for the config
	configData, err := json.MarshalIndent(config, "", "    ")
	if err != nil {
		panic(err)
	}
	// Open file
	jsonFile, err := os.Create("data/conf.json")
	if err != nil {
		panic(err)
	}
	// Write to file
	_, err = jsonFile.Write(configData)
	if err != nil {
		panic(err)
	}
	// Cleanup
	jsonFile.Close()
}

//ReadConfig - Read in config file into Config structure
func (c *Config) ReadConfig() {
	file, _ := os.Open("data/conf.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&c)
	if err != nil {
		panic(err)
	}
	file.Close()
}

//WriteConfig - Write out the current Config structure to file, indented nicely
func (c *Config) WriteConfig() {
	//Indent so its readable
	configData, err := json.MarshalIndent(c, "", "    ")
	if err != nil {
		panic(err)
	}
	//Open file
	jsonFile, err := os.Create("data/conf.json")
	if err != nil {
		panic(err)
	}
	// Write to file
	_, err = jsonFile.Write(configData)
	if err != nil {
		panic(err)
	}
	// Cleanup
	jsonFile.Close()
}

//UpdateConfig - update configuration file by reading then writing
//Updates config file to correct syntax
func (c *Config) UpdateConfig() {
	config.ReadConfig()
	config.WriteConfig()
}

//ResetDailies - Function to call once a day to reset dailies
func ResetDailies() {
	// for j := range USArray.Users {
	// 	USArray.Users[j].Dailies = false
	// }
	// USArray.WriteUserFile()
}

func main() {
	//Get random seed for later random number generation
	rand.Seed(time.Now().Unix())

	//Check to see if bot token is provided
	if config.APIKey == "" {
		fmt.Println("No token provided. Please place your API key into the config.json file")
		return
	}

	// Read in config file if exists
	if _, err := os.Stat("data/conf.json"); os.IsNotExist(err) {
		fmt.Println("\nCannot find conf.json, creating new...")
		InitConfFile()
	}

	// Update config to account for any data structure changes
	config.UpdateConfig()

	// Read in user data file if exists
	if _, err := os.Stat("data/users.json"); os.IsNotExist(err) {
		fmt.Println("\nCannot find users.json, creating new...")
		// InitUserFile()
	}

	// Reset all anthems
	// USArray.ReadUserFile()
	// for j := range USArray.Users {
	// 	USArray.Users[j].PlayAnthem = true
	// }
	// USArray.WriteUserFile

	// Create a new Discord session using the provided bot token.
	ky, err := discordgo.New("Bot " + config.APIKey)
	if err != nil {
		fmt.Println("Error creating Discord session: ", err)
		return
	}

	// Register ready for the ready event
	ky.AddHandlerOnce(ready)

	// Register messageCreate for the messageCreate events
	ky.AddHandler(messageCreate)

	// Register messageDelete for the messageDelete events
	// ky.AddHandler(messageDelete)

	// Register presenceUpdate to see who is online
	ky.AddHandler(presenceUpdate)

	// Register VoiceStateUpdate to check when users enter channel
	ky.AddHandler(voiceStateUpdate)

	// Open the websocket and begin listening for above events.
	err = ky.Open()
	if err != nil {
		fmt.Println("Error opening Discord session: ", err)
	}

	// Wait here until CTRL-C or other term signal is received.
	fmt.Println("Kylixor is now running.  Press CTRL-C to exit.")
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Cleanly close down the Discord session by disconnecting
	// from any connected voice channels
	if currentVoiceChannel != nil {
		if currentVoiceChannel.ChannelID != "" {
			currentVoiceChannel.Disconnect()
		}
	}
	ky.Close()
}

// This function will be called (due to AddHandler above) when the bot receives
// the "ready" event from Discord.
func ready(s *discordgo.Session, event *discordgo.Ready) {
	// Set the playing status.
	s.UpdateStatus(0, config.Status)
	self = event.User
	// USArray.GID = event.Guilds[0].ID

	// Start cronjobs
	go func() {
		gocron.Every(1).Day().At("19:00").Do(ResetDailies) //Reset dailies task

		<-gocron.Start() //Start waiting for the cronjobs
	}()
}

//presenceUpdate - Called when any user changes their status (online, away, playing a game, etc)
func presenceUpdate(s *discordgo.Session, p *discordgo.PresenceUpdate) {

}

//VoiceStateUpdate - Called whenever a user changes their voice state (muted, deafen, connected, disconnected)
func voiceStateUpdate(s *discordgo.Session, v *discordgo.VoiceStateUpdate) {

}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {

}
<commit_msg>Moved api key check to after config check<commit_after>/* 	kylixor.go
_________________________________
Main code for Kylixor Discord Bot
Andrew Langhill
kylixor.com
*/

package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/jasonlvhit/gocron"
)

// ----- GLOBAL VARIABLES -----

//Config - structure to hold variables from the config file
type Config struct {
	Admin  string //Admin's Discord ID
	APIKey string //Discord bot api key
	Coins  string //Name of currency that bot uses (i.e. <gold> coins)
	Follow bool   //Whether or not the bot joins/follows into voice channels for anthems
	LogID  string //ID of channel for logging
	Noise  bool   //Whether the bot will use function that play sound
	Prefix string //Prefix the bot will respond to
	Status string //Status of the bot (Playing <v1.0>)
}

var config = Config{}                              //Config structure from file
var currentVoiceChannel *discordgo.VoiceConnection //Current voice channel bot is in, nil if none
var self *discordgo.User                           //discord user type of self (for storing bots user account)

//InitConfFile - Initialize config file if one is not found
func InitConfFile() {
	//Default values
	config.Prefix = "k!"
	config.Status = "k!help"

	//Create and indent proper json output for the config
	configData, err := json.MarshalIndent(config, "", "    ")
	if err != nil {
		panic(err)
	}
	// Open file
	jsonFile, err := os.Create("data/conf.json")
	if err != nil {
		panic(err)
	}
	// Write to file
	_, err = jsonFile.Write(configData)
	if err != nil {
		panic(err)
	}
	// Cleanup
	jsonFile.Close()
}

//ReadConfig - Read in config file into Config structure
func (c *Config) ReadConfig() {
	file, _ := os.Open("data/conf.json")
	decoder := json.NewDecoder(file)
	err := decoder.Decode(&c)
	if err != nil {
		panic(err)
	}
	file.Close()
}

//WriteConfig - Write out the current Config structure to file, indented nicely
func (c *Config) WriteConfig() {
	//Indent so its readable
	configData, err := json.MarshalIndent(c, "", "    ")
	if err != nil {
		panic(err)
	}
	//Open file
	jsonFile, err := os.Create("data/conf.json")
	if err != nil {
		panic(err)
	}
	// Write to file
	_, err = jsonFile.Write(configData)
	if err != nil {
		panic(err)
	}
	// Cleanup
	jsonFile.Close()
}

//UpdateConfig - update configuration file by reading then writing
//Updates config file to correct syntax
func (c *Config) UpdateConfig() {
	config.ReadConfig()
	config.WriteConfig()
}

//ResetDailies - Function to call once a day to reset dailies
func ResetDailies() {
	// for j := range USArray.Users {
	// 	USArray.Users[j].Dailies = false
	// }
	// USArray.WriteUserFile()
}

func main() {
	//Get random seed for later random number generation
	rand.Seed(time.Now().Unix())

	// Read in config file if exists
	if _, err := os.Stat("data/conf.json"); os.IsNotExist(err) {
		fmt.Println("\nCannot find conf.json, creating new...")
		InitConfFile()
	}

	// Update config to account for any data structure changes
	config.UpdateConfig()

	// Read in user data file if exists
	if _, err := os.Stat("data/users.json"); os.IsNotExist(err) {
		fmt.Println("\nCannot find users.json, creating new...")
		// InitUserFile()
	}

	// Reset all anthems
	// USArray.ReadUserFile()
	// for j := range USArray.Users {
	// 	USArray.Users[j].PlayAnthem = true
	// }
	// USArray.WriteUserFile

	//Check to see if bot token is provided
	if config.APIKey == "" {
		fmt.Println("No token provided. Please place your API key into the config.json file")
		return
	}

	// Create a new Discord session using the provided bot token.
	ky, err := discordgo.New("Bot " + config.APIKey)
	if err != nil {
		fmt.Println("Error creating Discord session: ", err)
		return
	}

	// Register ready for the ready event
	ky.AddHandlerOnce(ready)

	// Register messageCreate for the messageCreate events
	ky.AddHandler(messageCreate)

	// Register messageDelete for the messageDelete events
	// ky.AddHandler(messageDelete)

	// Register presenceUpdate to see who is online
	ky.AddHandler(presenceUpdate)

	// Register VoiceStateUpdate to check when users enter channel
	ky.AddHandler(voiceStateUpdate)

	// Open the websocket and begin listening for above events.
	err = ky.Open()
	if err != nil {
		fmt.Println("Error opening Discord session: ", err)
	}

	// Wait here until CTRL-C or other term signal is received.
	fmt.Println("Kylixor is now running.  Press CTRL-C to exit.")
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Cleanly close down the Discord session by disconnecting
	// from any connected voice channels
	if currentVoiceChannel != nil {
		if currentVoiceChannel.ChannelID != "" {
			currentVoiceChannel.Disconnect()
		}
	}
	ky.Close()
}

// This function will be called (due to AddHandler above) when the bot receives
// the "ready" event from Discord.
func ready(s *discordgo.Session, event *discordgo.Ready) {
	// Set the playing status.
	s.UpdateStatus(0, config.Status)
	self = event.User
	// USArray.GID = event.Guilds[0].ID

	// Start cronjobs
	go func() {
		gocron.Every(1).Day().At("19:00").Do(ResetDailies) //Reset dailies task

		<-gocron.Start() //Start waiting for the cronjobs
	}()
}

//presenceUpdate - Called when any user changes their status (online, away, playing a game, etc)
func presenceUpdate(s *discordgo.Session, p *discordgo.PresenceUpdate) {

}

//VoiceStateUpdate - Called whenever a user changes their voice state (muted, deafen, connected, disconnected)
func voiceStateUpdate(s *discordgo.Session, v *discordgo.VoiceStateUpdate) {

}

func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {

}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/dynport/gocloud/aws/s3"
	"github.com/dynport/gossh"
)

var logger = log.New(os.Stderr, "", 0)

const sshExample = "ubuntu@127.0.0.1"

func main() {
	dir := flag.String("dir", "", "Dir to build. Default: current directory")
	host := flag.String("host", os.Getenv("DEV_HOST"), "Host to build on. Example: "+sshExample)
	deploy := flag.String("deploy", "", "Deploy to host after building. Example: "+sshExample)
	bucket := flag.String("bucket", "", "Upload binary to s3 bucket after building")
	verbose := flag.Bool("verbose", false, "Build using -v flag")

	flag.Parse()
	logger.Printf("running with %q", *host)
	b := &build{Host: *host, Dir: *dir, DeployTo: *deploy, Bucket: *bucket, verbose: *verbose}
	e := b.Run()
	if e != nil {
		logger.Fatal("ERROR: %s", e)
	}
}

type build struct {
	Host     string
	Dir      string
	Bucket   string
	DeployTo string
	verbose  bool
}

func benchmark(message string) func() {
	started := time.Now()
	logger.Printf("started  %s", message)
	return func() {
		logger.Printf("finished %s in %.06f", message, time.Since(started).Seconds())
	}
}

func (r *build) deps() ([]string, error) {
	s, e := r.exec("go", "list", "-f", `{{ join .Deps " " }}`)
	if e != nil {
		return nil, e
	}
	return strings.Fields(s), nil
}

func (r *build) exec(cmd string, vals ...string) (string, error) {
	c := exec.Command(cmd, vals...)
	c.Dir = r.Dir
	out, e := c.CombinedOutput()
	if e != nil {
		return "", e
	}
	return string(out), nil
}

func (r *build) currentPackage() (string, error) {
	s, e := r.exec("go", "list")
	if e != nil {
		return "", e
	}
	return strings.TrimSpace(s), nil
}

func (r *build) filesMap() (map[string]os.FileInfo, error) {
	cp, e := r.currentPackage()
	if e != nil {
		return nil, e
	}
	pkgs, e := r.deps()
	if e != nil {
		return nil, e
	}
	pkgs = append(pkgs, cp)
	files := map[string]os.FileInfo{}
	sum := int64(0)
	for _, p := range pkgs {
		if !strings.Contains(p, ".") {
			continue
		}
		prefix := os.ExpandEnv("$GOPATH/src")
		dbg.Printf("walking %q", p)
		e := filepath.Walk(os.ExpandEnv(prefix+"/"+p+"/"), func(p string, info os.FileInfo, e error) error {
			skip := func() bool {
				for _, s := range []string{".git", ".bzr", ".hg"} {
					if strings.Contains(p, "/"+s+"/") {
						return true
					}
				}
				return false
			}()
			if skip {
				return nil
			}
			if _, ok := files[p]; !ok {
				sum += info.Size()
				files[p] = info
			}
			return nil
		})
		if e != nil {
			return nil, e
		}
	}
	return files, nil
}

func (b *build) createArchive() (string, error) {
	defer benchmark("create archive")()
	var name string
	e := func() error {
		f, e := ioutil.TempFile("/tmp", "gobuild-archive-")
		if e != nil {
			return e
		}
		name = f.Name()
		defer f.Close()
		files, e := b.filesMap()
		if e != nil {
			return e
		}

		gz := gzip.NewWriter(f)
		sum := int64(0)
		defer gz.Close()
		t := tar.NewWriter(gz)
		defer t.Close()

		for p, info := range files {
			name := strings.TrimPrefix(p, os.ExpandEnv("$GOPATH/src/"))
			if info.IsDir() {
				continue
			}
			dbg.Printf("adding %q", p)
			h := &tar.Header{ModTime: info.ModTime(), Size: info.Size(), Mode: int64(info.Mode()), Name: name}
			e = t.WriteHeader(h)
			if e != nil {
				return e
			}
			e := func() error {
				f, e := os.Open(p)
				if e != nil {
					return e
				}
				defer f.Close()
				i, e := io.Copy(t, f)
				sum += i
				return e
			}()
			if e != nil {
				return e
			}
		}
		dbg.Printf("%s", sizePretty(sum))
		return nil
	}()
	return name, e
}

type buildConfig struct {
	Current string
	Sudo    bool
	Verbose bool
	Version string
}

func (b *buildConfig) Goroot() string {
	return "{{ .BuildHome }}/.go/go-{{ .Version }}/go"
}

func (b *buildConfig) Gopath() string {
	return "{{ .BuildHome }}/{{ .Current }}"
}

func (b *buildConfig) BuildHome() string {
	return "$HOME/.gobuild"
}

func (b *buildConfig) BinName() string {
	return path.Base(b.Current)
}

func (b *build) Run() error {
	defer benchmark("build")()
	currentPkg, e := b.currentPackage()
	if e != nil {
		return e
	}

	cfg, e := parseConfig(b.Host)
	if e != nil {
		return e
	}
	dbg.Printf("using config %#v", cfg)
	con, e := cfg.Connection()
	if e != nil {
		return e
	}
	defer con.Close()

	name, e := b.createArchive()
	if e != nil {
		return e
	}
	dbg.Printf("created archive at %q", name)
	defer os.RemoveAll(name)
	f, e := os.Open(name)
	if e != nil {
		return e
	}
	defer f.Close()

	ses, e := con.NewSession()
	if e != nil {
		return e
	}
	ses.Stdin = f
	ses.Stdout = os.Stdout
	ses.Stderr = os.Stderr

	buildCfg := &buildConfig{
		Current: currentPkg,
		Sudo:    cfg.User != "root",
		Verbose: b.verbose,
		Version: "1.3.1",
	}

	cmd := renderRecursive(buildCmd, buildCfg)
	e = ses.Run(cmd)
	if e != nil {
		return e
	}

	name = path.Base(currentPkg)
	var binPath string

	if b.Bucket != "" || b.DeployTo != "" {
		defer os.RemoveAll(binPath)
		e = func() error {
			ses, e := con.NewSession()
			if e != nil {
				return e
			}
			defer ses.Close()

			f, e := ioutil.TempFile("/tmp", "gobuild-bin-")
			if e != nil {
				return e
			}
			binPath = f.Name()
			defer f.Close()
			ses.Stdout = f
			ses.Stderr = os.Stderr

			cmd := renderRecursive("cat {{ .Gopath }}/bin/{{ .BinName }}", buildCfg)
			e = ses.Run(cmd)
			if e != nil {
				return e
			}
			return nil
		}()
		if e != nil {
			return e
		}
	}
	if name != "" {
		defer os.RemoveAll(binPath)
	}
	if b.Bucket != "" {
		e = func() error {
			f, e := os.Open(binPath)
			if e != nil {
				return e
			}
			defer f.Close()
			client := s3.NewFromEnv()
			client.CustomEndpointHost = "s3-eu-west-1.amazonaws.com"

			parts := strings.Split(b.Bucket, "/")
			bucket := parts[0]
			key := name
			if len(parts) > 1 {
				key = strings.Join(parts[1:], "/") + "/" + key
			}
			logger.Printf("uploading to bucket=%q key=%q", bucket, key)
			return client.PutStream(bucket, key, f, nil)
		}()
		if e != nil {
			return e
		}
		logger.Printf("uploaded to bucket %q", b.Bucket)
	}

	if b.DeployTo != "" {
		e := func() error {
			cfg, e := parseConfig(b.DeployTo)
			if e != nil {
				return e
			}
			con, e := cfg.Connection()
			if e != nil {
				return e
			}
			defer con.Close()
			ses, e := con.NewSession()
			if e != nil {
				return e
			}
			defer ses.Close()
			f, e := os.Open(binPath)
			if e != nil {
				return e
			}
			defer f.Close()
			ses.Stdin = f
			ses.Stdout = os.Stdout
			ses.Stderr = os.Stderr
			s := struct {
				Name string
				Sudo bool
			}{
				Name: name, Sudo: cfg.User != "root",
			}
			cmd := renderRecursive("cd /usr/local/bin && {{ if .Sudo }}sudo {{ end }}cat - > {{ .Name }}.tmp && {{ if .Sudo }}sudo {{ end }}chmod 0755 {{ .Name }}.tmp && {{ if .Sudo }}sudo {{ end }}mv {{ .Name }}.tmp {{ .Name }}", s)
			dbg.Printf("%s", cmd)
			return ses.Run(cmd)
		}()
		if e != nil {
			return e
		}
	}
	return nil
}

func parseConfig(s string) (*gossh.Config, error) {
	cfg := &gossh.Config{}
	parts := strings.Split(s, "@")
	switch len(parts) {
	case 0:
		return nil, fmt.Errorf("Host must be set")
	case 1:
		cfg.Host = parts[0]
	case 2:
		cfg.User = parts[0]
		cfg.Host = parts[1]
	case 3:
		return nil, fmt.Errorf("format of host %q not understood", s)
	}
	return cfg, nil
}

const buildCmd = `#!/bin/bash
export BUILD_HOME={{ .BuildHome }}
export GOPATH={{ .Gopath }}
export GOROOT={{ .Goroot }}
export PATH=$GOROOT/bin:$PATH

if [ ! -f $GOROOT/bin/go ]; then
  echo "installing go {{ .Version }}"
  tmp=$(dirname $GOROOT)
  mkdir -p $tmp
  cd $tmp
  curl -sL "https://storage.googleapis.com/golang/go{{ .Version }}.linux-amd64.tar.gz" | tar xfz -
fi

set -xe
rm -Rf $GOPATH
mkdir -p $GOPATH/src
cd $GOPATH/src
tar xfz -
cd {{ .Current }}
go get {{ if .Verbose }}-v{{ end }} .
{{ with .Sudo }}sudo {{ end }}cp $GOPATH/bin/{{ .BinName }} /usr/local/bin/
`

func debugStream() io.Writer {
	if os.Getenv("DEBUG") == "true" {
		return os.Stderr
	}
	return ioutil.Discard
}

var dbg = log.New(debugStream(), "[DEBUG] ", log.Lshortfile)

func renderRecursive(tpl string, i interface{}) string {
	s := tpl
	for j := 0; j < 10; j++ {
		rendered := mustRender([]byte(s), i)
		if rendered == s {
			return rendered
		}
		s = rendered
	}
	logger.Fatal("rendering loop, rendered 10 times")
	return ""
}

func mustRender(raw []byte, i interface{}) string {
	out, e := render(raw, i)
	if e != nil {
		logger.Fatal(e)
	}
	return out
}

func render(raw []byte, i interface{}) (string, error) {
	tpl, e := template.New(string(raw)).Parse(string(raw))
	if e != nil {
		return "", e
	}
	buf := &bytes.Buffer{}
	e = tpl.Execute(buf, i)
	if e != nil {
		return "", e
	}
	return buf.String(), nil
}

var (
	oneKb = 1024.0
	oneMb = oneKb * 1024.0
	oneGb = oneMb * 1024.0
)

func sizePretty(raw int64) string {
	f := float64(raw)
	if f < oneKb {
		return fmt.Sprintf("%.0f", f)
	} else if f < oneMb {
		return fmt.Sprintf("%.2fKB", f/oneKb)
	} else if f < oneGb {
		return fmt.Sprintf("%.2fMB", f/oneMb)
	} else {
		return fmt.Sprintf("%.2fGB", f/oneGb)
	}
}
<commit_msg>fix log statement<commit_after>package main

import (
	"archive/tar"
	"bytes"
	"compress/gzip"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/dynport/gocloud/aws/s3"
	"github.com/dynport/gossh"
)

var logger = log.New(os.Stderr, "", 0)

const sshExample = "ubuntu@127.0.0.1"

func main() {
	dir := flag.String("dir", "", "Dir to build. Default: current directory")
	host := flag.String("host", os.Getenv("DEV_HOST"), "Host to build on. Example: "+sshExample)
	deploy := flag.String("deploy", "", "Deploy to host after building. Example: "+sshExample)
	bucket := flag.String("bucket", "", "Upload binary to s3 bucket after building")
	verbose := flag.Bool("verbose", false, "Build using -v flag")

	flag.Parse()
	logger.Printf("running with %q", *host)
	b := &build{Host: *host, Dir: *dir, DeployTo: *deploy, Bucket: *bucket, verbose: *verbose}
	e := b.Run()
	if e != nil {
		logger.Fatalf("ERROR: %s", e)
	}
}

type build struct {
	Host     string
	Dir      string
	Bucket   string
	DeployTo string
	verbose  bool
}

func benchmark(message string) func() {
	started := time.Now()
	logger.Printf("started  %s", message)
	return func() {
		logger.Printf("finished %s in %.06f", message, time.Since(started).Seconds())
	}
}

func (r *build) deps() ([]string, error) {
	s, e := r.exec("go", "list", "-f", `{{ join .Deps " " }}`)
	if e != nil {
		return nil, e
	}
	return strings.Fields(s), nil
}

func (r *build) exec(cmd string, vals ...string) (string, error) {
	c := exec.Command(cmd, vals...)
	c.Dir = r.Dir
	out, e := c.CombinedOutput()
	if e != nil {
		return "", e
	}
	return string(out), nil
}

func (r *build) currentPackage() (string, error) {
	s, e := r.exec("go", "list")
	if e != nil {
		return "", e
	}
	return strings.TrimSpace(s), nil
}

func (r *build) filesMap() (map[string]os.FileInfo, error) {
	cp, e := r.currentPackage()
	if e != nil {
		return nil, e
	}
	pkgs, e := r.deps()
	if e != nil {
		return nil, e
	}
	pkgs = append(pkgs, cp)
	files := map[string]os.FileInfo{}
	sum := int64(0)
	for _, p := range pkgs {
		if !strings.Contains(p, ".") {
			continue
		}
		prefix := os.ExpandEnv("$GOPATH/src")
		dbg.Printf("walking %q", p)
		e := filepath.Walk(os.ExpandEnv(prefix+"/"+p+"/"), func(p string, info os.FileInfo, e error) error {
			skip := func() bool {
				for _, s := range []string{".git", ".bzr", ".hg"} {
					if strings.Contains(p, "/"+s+"/") {
						return true
					}
				}
				return false
			}()
			if skip {
				return nil
			}
			if _, ok := files[p]; !ok {
				sum += info.Size()
				files[p] = info
			}
			return nil
		})
		if e != nil {
			return nil, e
		}
	}
	return files, nil
}

func (b *build) createArchive() (string, error) {
	defer benchmark("create archive")()
	var name string
	e := func() error {
		f, e := ioutil.TempFile("/tmp", "gobuild-archive-")
		if e != nil {
			return e
		}
		name = f.Name()
		defer f.Close()
		files, e := b.filesMap()
		if e != nil {
			return e
		}

		gz := gzip.NewWriter(f)
		sum := int64(0)
		defer gz.Close()
		t := tar.NewWriter(gz)
		defer t.Close()

		for p, info := range files {
			name := strings.TrimPrefix(p, os.ExpandEnv("$GOPATH/src/"))
			if info.IsDir() {
				continue
			}
			dbg.Printf("adding %q", p)
			h := &tar.Header{ModTime: info.ModTime(), Size: info.Size(), Mode: int64(info.Mode()), Name: name}
			e = t.WriteHeader(h)
			if e != nil {
				return e
			}
			e := func() error {
				f, e := os.Open(p)
				if e != nil {
					return e
				}
				defer f.Close()
				i, e := io.Copy(t, f)
				sum += i
				return e
			}()
			if e != nil {
				return e
			}
		}
		dbg.Printf("%s", sizePretty(sum))
		return nil
	}()
	return name, e
}

type buildConfig struct {
	Current string
	Sudo    bool
	Verbose bool
	Version string
}

func (b *buildConfig) Goroot() string {
	return "{{ .BuildHome }}/.go/go-{{ .Version }}/go"
}

func (b *buildConfig) Gopath() string {
	return "{{ .BuildHome }}/{{ .Current }}"
}

func (b *buildConfig) BuildHome() string {
	return "$HOME/.gobuild"
}

func (b *buildConfig) BinName() string {
	return path.Base(b.Current)
}

func (b *build) Run() error {
	defer benchmark("build")()
	currentPkg, e := b.currentPackage()
	if e != nil {
		return e
	}

	cfg, e := parseConfig(b.Host)
	if e != nil {
		return e
	}
	dbg.Printf("using config %#v", cfg)
	con, e := cfg.Connection()
	if e != nil {
		return e
	}
	defer con.Close()

	name, e := b.createArchive()
	if e != nil {
		return e
	}
	dbg.Printf("created archive at %q", name)
	defer os.RemoveAll(name)
	f, e := os.Open(name)
	if e != nil {
		return e
	}
	defer f.Close()

	ses, e := con.NewSession()
	if e != nil {
		return e
	}
	ses.Stdin = f
	ses.Stdout = os.Stdout
	ses.Stderr = os.Stderr

	buildCfg := &buildConfig{
		Current: currentPkg,
		Sudo:    cfg.User != "root",
		Verbose: b.verbose,
		Version: "1.3.1",
	}

	cmd := renderRecursive(buildCmd, buildCfg)
	e = ses.Run(cmd)
	if e != nil {
		return e
	}

	name = path.Base(currentPkg)
	var binPath string

	if b.Bucket != "" || b.DeployTo != "" {
		defer os.RemoveAll(binPath)
		e = func() error {
			ses, e := con.NewSession()
			if e != nil {
				return e
			}
			defer ses.Close()

			f, e := ioutil.TempFile("/tmp", "gobuild-bin-")
			if e != nil {
				return e
			}
			binPath = f.Name()
			defer f.Close()
			ses.Stdout = f
			ses.Stderr = os.Stderr

			cmd := renderRecursive("cat {{ .Gopath }}/bin/{{ .BinName }}", buildCfg)
			e = ses.Run(cmd)
			if e != nil {
				return e
			}
			return nil
		}()
		if e != nil {
			return e
		}
	}
	if name != "" {
		defer os.RemoveAll(binPath)
	}
	if b.Bucket != "" {
		e = func() error {
			f, e := os.Open(binPath)
			if e != nil {
				return e
			}
			defer f.Close()
			client := s3.NewFromEnv()
			client.CustomEndpointHost = "s3-eu-west-1.amazonaws.com"

			parts := strings.Split(b.Bucket, "/")
			bucket := parts[0]
			key := name
			if len(parts) > 1 {
				key = strings.Join(parts[1:], "/") + "/" + key
			}
			logger.Printf("uploading to bucket=%q key=%q", bucket, key)
			return client.PutStream(bucket, key, f, nil)
		}()
		if e != nil {
			return e
		}
		logger.Printf("uploaded to bucket %q", b.Bucket)
	}

	if b.DeployTo != "" {
		e := func() error {
			cfg, e := parseConfig(b.DeployTo)
			if e != nil {
				return e
			}
			con, e := cfg.Connection()
			if e != nil {
				return e
			}
			defer con.Close()
			ses, e := con.NewSession()
			if e != nil {
				return e
			}
			defer ses.Close()
			f, e := os.Open(binPath)
			if e != nil {
				return e
			}
			defer f.Close()
			ses.Stdin = f
			ses.Stdout = os.Stdout
			ses.Stderr = os.Stderr
			s := struct {
				Name string
				Sudo bool
			}{
				Name: name, Sudo: cfg.User != "root",
			}
			cmd := renderRecursive("cd /usr/local/bin && {{ if .Sudo }}sudo {{ end }}cat - > {{ .Name }}.tmp && {{ if .Sudo }}sudo {{ end }}chmod 0755 {{ .Name }}.tmp && {{ if .Sudo }}sudo {{ end }}mv {{ .Name }}.tmp {{ .Name }}", s)
			dbg.Printf("%s", cmd)
			return ses.Run(cmd)
		}()
		if e != nil {
			return e
		}
	}
	return nil
}

func parseConfig(s string) (*gossh.Config, error) {
	cfg := &gossh.Config{}
	parts := strings.Split(s, "@")
	switch len(parts) {
	case 0:
		return nil, fmt.Errorf("Host must be set")
	case 1:
		cfg.Host = parts[0]
	case 2:
		cfg.User = parts[0]
		cfg.Host = parts[1]
	case 3:
		return nil, fmt.Errorf("format of host %q not understood", s)
	}
	return cfg, nil
}

const buildCmd = `#!/bin/bash
export BUILD_HOME={{ .BuildHome }}
export GOPATH={{ .Gopath }}
export GOROOT={{ .Goroot }}
export PATH=$GOROOT/bin:$PATH

if [ ! -f $GOROOT/bin/go ]; then
  echo "installing go {{ .Version }}"
  tmp=$(dirname $GOROOT)
  mkdir -p $tmp
  cd $tmp
  curl -sL "https://storage.googleapis.com/golang/go{{ .Version }}.linux-amd64.tar.gz" | tar xfz -
fi

set -xe
rm -Rf $GOPATH
mkdir -p $GOPATH/src
cd $GOPATH/src
tar xfz -
cd {{ .Current }}
go get {{ if .Verbose }}-v{{ end }} .
{{ with .Sudo }}sudo {{ end }}cp $GOPATH/bin/{{ .BinName }} /usr/local/bin/
`

func debugStream() io.Writer {
	if os.Getenv("DEBUG") == "true" {
		return os.Stderr
	}
	return ioutil.Discard
}

var dbg = log.New(debugStream(), "[DEBUG] ", log.Lshortfile)

func renderRecursive(tpl string, i interface{}) string {
	s := tpl
	for j := 0; j < 10; j++ {
		rendered := mustRender([]byte(s), i)
		if rendered == s {
			return rendered
		}
		s = rendered
	}
	logger.Fatal("rendering loop, rendered 10 times")
	return ""
}

func mustRender(raw []byte, i interface{}) string {
	out, e := render(raw, i)
	if e != nil {
		logger.Fatal(e)
	}
	return out
}

func render(raw []byte, i interface{}) (string, error) {
	tpl, e := template.New(string(raw)).Parse(string(raw))
	if e != nil {
		return "", e
	}
	buf := &bytes.Buffer{}
	e = tpl.Execute(buf, i)
	if e != nil {
		return "", e
	}
	return buf.String(), nil
}

var (
	oneKb = 1024.0
	oneMb = oneKb * 1024.0
	oneGb = oneMb * 1024.0
)

func sizePretty(raw int64) string {
	f := float64(raw)
	if f < oneKb {
		return fmt.Sprintf("%.0f", f)
	} else if f < oneMb {
		return fmt.Sprintf("%.2fKB", f/oneKb)
	} else if f < oneGb {
		return fmt.Sprintf("%.2fMB", f/oneMb)
	} else {
		return fmt.Sprintf("%.2fGB", f/oneGb)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package weave

import (
	"fmt"

	"github.com/aclements/go-misc/go-weave/amb"
)

type Scheduler struct {
	Strategy amb.Strategy

	as amb.Scheduler

	nextid               int
	threads              []*thread
	runThread, curThread *thread
	goErr                interface{}
}

type thread struct {
	id   int
	wake chan bool
}

func (t *thread) String() string {
	return fmt.Sprintf("t%d", t.id)
}

const debug = false

func (s *Scheduler) Run(main func()) {
	s.as = amb.Scheduler{Strategy: s.Strategy}

	s.as.Run(func() {
		// Initialize state.
		s.nextid = 0
		s.threads = nil
		s.runThread = &thread{-1, make(chan bool)}
		s.curThread = s.runThread
		s.goErr = nil
		s.Go(main)
		if s.goErr != nil {
			// TODO: Abort all threads.
			panic(s.goErr)
		}
		if debug {
			fmt.Println("run done")
		}
	})
}

func (s *Scheduler) Go(f func()) {
	thr := &thread{s.nextid, make(chan bool)}
	s.nextid++
	s.threads = append(s.threads, thr)
	go func() {
		defer func() {
			goErr := recover()
			if goErr != nil {
				// Return to the Run thread.
				s.goErr = goErr
				if debug {
					fmt.Printf("%v panicked: %v\n", thr, goErr)
				}
				s.runThread.wake <- true
				return
			}
			// Remove this thread.
			if debug {
				fmt.Printf("%v exited\n", thr)
			}
			for i, thr2 := range s.threads {
				if thr == thr2 {
					copy(s.threads[i:], s.threads[i+1:])
					s.threads = s.threads[:len(s.threads)-1]
					close(thr.wake)
					s.Sched()
					return
				}
			}
			panic("thread not found in threads")
		}()
		if debug {
			fmt.Printf("%v started\n", thr)
		}
		<-thr.wake
		f()
	}()
	s.Sched()
}

func (s *Scheduler) Sched() {
	this := s.curThread

	// Pick a thread to run next.
	if len(s.threads) == 0 {
		// The last thread exited. Return to the Run thread.
		s.runThread.wake <- true
		return
	}
	s.curThread = s.threads[s.as.Amb(len(s.threads))]

	if debug {
		fmt.Printf("scheduling %v from %v\n", s.curThread, s.threads)
	}

	// Switch to that thread.
	if this == s.curThread {
		return
	}
	s.curThread.wake <- true
	<-this.wake
}

func (s *Scheduler) Amb(n int) int {
	return s.as.Amb(n)
}
<commit_msg>go-weave: clean up all threads if one panics<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package weave

import (
	"errors"
	"fmt"

	"github.com/aclements/go-misc/go-weave/amb"
)

type Scheduler struct {
	Strategy amb.Strategy

	as amb.Scheduler

	nextid               int
	threads              []*thread
	runThread, curThread *thread
	goErr                interface{}
}

type thread struct {
	id   int
	wake chan bool
}

func (t *thread) String() string {
	return fmt.Sprintf("t%d", t.id)
}

const debug = false

func (s *Scheduler) Run(main func()) {
	s.as = amb.Scheduler{Strategy: s.Strategy}

	s.as.Run(func() {
		// Initialize state.
		s.nextid = 0
		s.threads = nil
		s.runThread = &thread{-1, make(chan bool)}
		s.curThread = s.runThread
		s.goErr = nil
		s.Go(main)
		if goErr := s.goErr; goErr != nil {
			// Exit all threads. They should all be
			// stopped in desched right now.
			for _, thr := range s.threads {
				thr.wake <- false
			}
			panic(goErr)
		}
		if debug {
			fmt.Println("run done")
		}
	})
}

func (s *Scheduler) Go(f func()) {
	thr := &thread{s.nextid, make(chan bool)}
	s.nextid++
	s.threads = append(s.threads, thr)
	go func() {
		defer func() {
			goErr := recover()
			if goErr == threadAbort {
				if debug {
					fmt.Printf("%v aborted\n", thr)
				}
				return
			}
			// Remove this thread.
			if debug {
				if goErr != nil {
					fmt.Printf("%v panicked: %v\n", thr, goErr)
				} else {
					fmt.Printf("%v exiting normally\n", thr)
				}
			}
			for i, thr2 := range s.threads {
				if thr == thr2 {
					copy(s.threads[i:], s.threads[i+1:])
					s.threads = s.threads[:len(s.threads)-1]
					goto found
				}
			}
			panic("thread not found in threads")

		found:
			// If we're panicking, pass the error to Run
			// so it can shut down this execution.
			if goErr != nil {
				s.goErr = goErr
				s.runThread.wake <- true
				return
			}
			// Otherwise, this is a regular thread exit.
			// Close our wake channel so Sched returns
			// immediately and release this goroutine.
			close(thr.wake)
			s.Sched()
		}()
		if debug {
			fmt.Printf("%v started\n", thr)
		}
		thr.desched()
		f()
	}()
	s.Sched()
}

// desched deschedules thread t until the scheduler selects it or all
// threads are aborted. In the case of a thread abort, it panics with
// threadAbort.
func (t *thread) desched() {
	if cont, ok := <-t.wake; ok && !cont {
		panic(threadAbort)
	}
}

var threadAbort = errors.New("thread aborted because of panic in another thread")

func (s *Scheduler) Sched() {
	this := s.curThread

	// Pick a thread to run next.
	if len(s.threads) == 0 {
		// The last thread exited. Return to the Run thread.
		s.runThread.wake <- true
		return
	}
	s.curThread = s.threads[s.as.Amb(len(s.threads))]

	if debug {
		fmt.Printf("scheduling %v from %v\n", s.curThread, s.threads)
	}

	// Switch to that thread.
	if this == s.curThread {
		return
	}
	s.curThread.wake <- true
	this.desched()
}

func (s *Scheduler) Amb(n int) int {
	return s.as.Amb(n)
}
<|endoftext|>


<commit_before>package markdown

// implementation to refactor

import (
	"fmt"
	"strings"
)

// Render translates markdown to HTML
func Render(markdown string) string {
	header := 0
	markdown = strings.Replace(markdown, "__", "", 1)
	markdown = strings.Replace(markdown, "__", "", 1)
	markdown = strings.Replace(markdown, "_", "", 1)
	markdown = strings.Replace(markdown, "_", "", 1)
	pos := 0
	list := 0
	html := ""
	for {
		char := markdown[pos]
		if char == '#' {
			for char == '#' {
				header++
				pos++
				char = markdown[pos]
			}
			html += fmt.Sprintf("<h%d>", header)
			pos++
			continue
		}
		if char == '*' {
			if list == 0 {
				html += "
"
			}
			html += "
"
			list++
			pos += 2
			continue
		}
		if char == '\n' {
			if list > 0 {
				html += "
"
			}
			if header > 0 {
				html += fmt.Sprintf("</h%d>", header)
				header = 0
			}
			pos++
			continue
		}
		html += string(char)
		pos++
		if pos >= len(markdown) {
			break
		}
	}
	if header > 0 {
		return html + fmt.Sprintf("</h%d>", header)
	}
	if list > 0 {
		return html + "

"
	}
	return "
" + html + "
"

}
<commit_msg>Extract helpers to handle bold and italics<commit_after>package markdown

import (
	"fmt"
	"strings"
)

// Render translates markdown to HTML
func Render(markdown string) (html string) {
	header := 0
	temp := handleItalic(handleBold(markdown))
	pos := 0
	list := 0
	html = ""
	for {
		char := temp[pos]
		if char == '#' {
			for char == '#' {
				header++
				pos++
				char = temp[pos]
			}
			html += fmt.Sprintf("<h%d>", header)
			pos++
			continue
		}
		if char == '*' {
			if list == 0 {
				html += "
"
			}
			html += "
"
			list++
			pos += 2
			continue
		}
		if char == '\n' {
			if list > 0 {
				html += "
"
			}
			if header > 0 {
				html += fmt.Sprintf("</h%d>", header)
				header = 0
			}
			pos++
			continue
		}
		html += string(char)
		pos++
		if pos >= len(temp) {
			break
		}
	}
	if header > 0 {
		return html + fmt.Sprintf("</h%d>", header)
	}
	if list > 0 {
		return html + "

"
	}
	return "
" + html + "
"
}

func handleBold(markdown string) string {
	markdown = strings.Replace(markdown, "__", "", 1)
	markdown = strings.Replace(markdown, "__", "", 1)
	return markdown
}

func handleItalic(markdown string) (result string) {
	markdown = strings.Replace(markdown, "_", "", 1)
	markdown = strings.Replace(markdown, "_", "", 1)
	return markdown
}
<|endoftext|>