<commit_before>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	"github.com/nais/naisd/api/naisrequest"
	"github.com/stretchr/testify/assert"
	v1 "k8s.io/api/core/v1"
	"testing"
)

func TestRedisResource(t *testing.T) {
	redisName := fmt.Sprintf("%s-redis", appName)

	t.Run("Replicas should always be 1", func(t *testing.T) {
		spec := app.Spec{Application: appName, Namespace: namespace, Team: "teamBeam"}
		manifest := NaisManifest{Redis: Redis{Enabled: true}}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)
		deploymentSpec := createRedisDeploymentSpec(redisName, spec, manifest.Redis)
		expectedReplicas := int32(1)
		assert.Equal(t, &expectedReplicas, deploymentSpec.Replicas)
	})

	t.Run("Custom resources", func(t *testing.T) {
		manifest := NaisManifest{
			Redis: Redis{
				Enabled: true,
				Limits: ResourceList{
					Cpu: "1337m",
				},
				Requests: ResourceList{
					Memory: "512Mi",
				},
			},
		}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)

		podSpec := createRedisPodSpec(manifest.Redis)
		container := podSpec.Containers[0]
		assert.Equal(t, "redis", container.Name)
		resources := container.Resources
		assert.Equal(t, "1337m", resources.Limits.Cpu().String())
		assert.Equal(t, "128Mi", resources.Limits.Memory().String())
		assert.Equal(t, "100m", resources.Requests.Cpu().String())
		assert.Equal(t, "512Mi", resources.Requests.Memory().String())
	})

	t.Run("REDIS_HOST env var should be set when redis: true", func(t *testing.T) {
		spec := app.Spec{Application: appName, Namespace: namespace, Team: "teamBeam"}
		manifest := NaisManifest{Redis: Redis{Enabled: true}}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)
		env, err := createEnvironmentVariables(spec, naisrequest.Deploy{}, manifest, []NaisResource{})

		assert.NoError(t, err)
		assert.Contains(t, env, v1.EnvVar{Name: "REDIS_HOST", Value: redisName})
	})
}
<commit_msg>Rullet tilbake endring i test<commit_after>package api

import (
	"fmt"
	"github.com/nais/naisd/api/app"
	"github.com/nais/naisd/api/naisrequest"
	"github.com/stretchr/testify/assert"
	v1 "k8s.io/api/core/v1"
	"testing"
)

func TestRedisResource(t *testing.T) {
	redisName := fmt.Sprintf("%s-redis", appName)

	t.Run("Replicas should always be 1", func(t *testing.T) {
		spec := app.Spec{Application: appName, Namespace: namespace, Team: "teamBeam"}
		manifest := NaisManifest{Redis: Redis{Enabled: true}}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)
		deploymentSpec := createRedisDeploymentSpec(redisName, spec, manifest.Redis)
		expectedReplicas := int32(1)
		assert.Equal(t, &expectedReplicas, deploymentSpec.Replicas)
	})

	t.Run("Custom resources", func(t *testing.T) {
		manifest := NaisManifest{
			Redis: Redis{
				Enabled: true,
				Limits: ResourceList{
					Cpu: "1337m",
				},
				Requests: ResourceList{
					Memory: "512Mi",
				},
			},
		}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)

		podSpec := createRedisPodSpec(manifest.Redis)
		container := podSpec.Containers[0]
		assert.Equal(t, "redis", container.Name)
		resources := container.Resources
		assert.Equal(t, "1337m", resources.Limits.Cpu().String())
		assert.Equal(t, "128Mi", resources.Limits.Memory().String())
		assert.Equal(t, "100m", resources.Requests.Cpu().String())
		assert.Equal(t, "512Mi", resources.Requests.Memory().String())
	})

	t.Run("REDIS_HOST env var should be set when redis: true", func(t *testing.T) {
		spec := app.Spec{Application: appName, Namespace: namespace, Team: "teamBeam"}
		manifest := NaisManifest{Redis: Redis{Enabled: true}}
		manifest.Redis = updateDefaultRedisValues(manifest.Redis)
		env, err := createEnvironmentVariables(spec, naisrequest.Deploy{}, manifest, []NaisResource{})

		assert.NoError(t, err)
		assert.Contains(t, env, v1.EnvVar{Name: "REDIS_HOST", Value: "rfs-" + spec.ResourceName()})
	})
}
<|endoftext|>


<commit_before>package morningStar

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

func readBody(body io.ReadCloser) ([]byte, error) {
	defer body.Close()
	return ioutil.ReadAll(body)
}

func getBody(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf(`Error while retrieving data from %s: %v`, url, err)
	}

	if response.StatusCode >= 400 {
		return nil, fmt.Errorf(`Got error %d while getting %s`, response.StatusCode, url)
	}

	body, err := readBody(response.Body)
	if err != nil {
		return nil, fmt.Errorf(`Error while reading body of %s: %v`, url, err)
	}

	return body, nil
}
<commit_msg>Update fetch.go<commit_after>package morningStar

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

func readBody(body io.ReadCloser) ([]byte, error) {
	defer body.Close()
	return ioutil.ReadAll(body)
}

func getBody(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf(`Error while retrieving data from %s: %v`, url, err)
	}

	if response.StatusCode >= http.StatusBadRequest {
		return nil, fmt.Errorf(`Got error %d while getting %s`, response.StatusCode, url)
	}

	body, err := readBody(response.Body)
	if err != nil {
		return nil, fmt.Errorf(`Error while reading body of %s: %v`, url, err)
	}

	return body, nil
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"time"

	_ "github.com/k0kubun/pp"
	"github.com/urfave/cli"
	"gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
	"gopkg.in/yaml.v2"
)

type CLI struct {
	Client *ForceClient
	Config *Config
	Logger *Logger
	Error  error
}

type Config struct {
	Username       string
	Password       string
	Endpoint       string
	ApiVersion     string
	PollSeconds    int
	TimeoutSeconds int
	PackageFile    string
}

type PackageFile struct {
	Packages []string
}

const (
	APP_VERSION        string = "0.1.0"
	DEFAULT_REPOSITORY string = "github.com"
)

func (c *CLI) Run(args []string) (err error) {
	if c.Logger == nil {
		c.Logger = NewLogger(os.Stdout, os.Stderr)
	}
	c.Config = &Config{}

	app := cli.NewApp()
	app.Name = "spm"

	app.Usage = "Salesforce Package Manager"
	app.Version = APP_VERSION
	app.Commands = []cli.Command{
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "Install salesforce packages on public remote repository(i.g. github)",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:        "username, u",
					Destination: &c.Config.Username,
					EnvVar:      "SF_USERNAME",
				},
				cli.StringFlag{
					Name:        "password, p",
					Destination: &c.Config.Password,
					EnvVar:      "SF_PASSWORD",
				},
				cli.StringFlag{
					Name:        "endpoint, e",
					Value:       "login.salesforce.com",
					Destination: &c.Config.Endpoint,
					EnvVar:      "SF_ENDPOINT",
				},
				cli.StringFlag{
					Name:        "apiversion",
					Value:       "38.0",
					Destination: &c.Config.ApiVersion,
					EnvVar:      "SF_APIVERSION",
				},
				cli.IntFlag{
					Name:        "pollSeconds",
					Value:       5,
					Destination: &c.Config.PollSeconds,
					EnvVar:      "SF_POLLSECONDS",
				},
				cli.IntFlag{
					Name:        "timeoutSeconds",
					Value:       0,
					Destination: &c.Config.TimeoutSeconds,
					EnvVar:      "SF_TIMEOUTSECONDS",
				},
				cli.StringFlag{
					Name:        "packages, P",
					Destination: &c.Config.PackageFile,
				},
			},
			Action: func(ctx *cli.Context) error {
				urls := []string{}
				if c.Config.PackageFile != "" {
					packageFile, err := c.readPackageFile()
					if err != nil {
						c.Error = err
						return nil
					}
					for _, pkg := range packageFile.Packages {
						url, err := c.convertToUrl(pkg)
						if err != nil {
							c.Error = err
							return nil
						}
						urls = append(urls, url)
					}
				} else {
					url, err := c.convertToUrl(ctx.Args().First())
					if err != nil {
						c.Error = err
						return nil
					}
					urls = []string{url}

				}
				if len(urls) == 0 {
					c.Error = errors.New("Repository not specified")
					return nil
				}
				c.Error = c.install(urls)
				return nil
			},
		},
	}

	app.Run(args)
	if c.Error != nil {
		c.Logger.Error(c.Error)
	}
	return c.Error
}

func (c *CLI) install(urls []string) error {
	err := c.checkConfigration()
	if err != nil {
		return err
	}
	err = c.setClient()
	if err != nil {
		return err
	}

	for _, url := range urls {
		r := regexp.MustCompile(`^(https://([^/]+?)/([^/]+?)/([^/@]+?))(@([^/]+))?$`)
		group := r.FindAllStringSubmatch(url, -1)
		uri := group[0][1]
		directory := group[0][4]
		branch := group[0][6]
		if branch == "" {
			branch = "master"
		}

		err = c.installToSalesforce(uri, directory, branch)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *CLI) setClient() error {
	c.Client = NewForceClient(c.Config.Endpoint, c.Config.ApiVersion)
	err := c.Client.Login(c.Config.Username, c.Config.Password)
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) convertToUrl(target string) (string, error) {
	if target == "" {
		return "", errors.New("Repository not specified")
	}
	url := target
	r := regexp.MustCompile(`^[^/]+/[^/@]+(@[^/]+)?$`)
	if r.MatchString(url) {
		url = DEFAULT_REPOSITORY + "/" + url
	}
	return "https://" + url, nil
}

func (c *CLI) readPackageFile() (*PackageFile, error) {
	packageFile := PackageFile{}
	readBody, err := ioutil.ReadFile(c.Config.PackageFile)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(readBody), &packageFile)
	if err != nil {
		return nil, err
	}
	return &packageFile, nil
}

func (c *CLI) checkConfigration() error {
	if c.Config.Username == "" {
		return errors.New("Username is required")
	}
	if c.Config.Password == "" {
		return errors.New("Password is required")
	}
	return nil
}

func (c *CLI) installToSalesforce(url string, directory string, branch string) error {
	cloneDir := filepath.Join(os.TempDir(), directory)
	c.Logger.Info("Clone repository from " + url + " (branch: " + branch + ")")
	err := c.cloneFromRemoteRepository(cloneDir, url, branch)
	if err != nil {
		return err
	}
	defer c.cleanTempDirectory(cloneDir)
	err = c.deployToSalesforce(filepath.Join(cloneDir, "src"))
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) cleanTempDirectory(directory string) error {
	if err := os.RemoveAll(directory); err != nil {
		return err
	}
	return nil
}

func (c *CLI) createFilesystemRepository(directory string, url string, paramBranch string, retry bool) (r *git.Repository, err error) {
	branch := "master"
	if paramBranch != "" {
		branch = paramBranch
	}
	r, err = git.NewFilesystemRepository(directory)
	err = r.Clone(&git.CloneOptions{
		URL:           url,
		ReferenceName: plumbing.ReferenceName("refs/heads/" + branch),
	})
	if err != nil {
		if err.Error() != "repository non empty" {
			return
		}
		if retry == true {
			return
		}
		c.Logger.Warningf("repository non empty: %s", directory)
		c.Logger.Infof("remove directory: %s", directory)
		err = c.cleanTempDirectory(directory)
		if err != nil {
			return
		}
		r, err = c.createFilesystemRepository(directory, url, paramBranch, true)
	}
	return
}

func (c *CLI) cloneFromRemoteRepository(directory string, url string, branch string) error {
	r, err := c.createFilesystemRepository(directory, url, branch, false)
	if err != nil {
		return err
	}

	// ... retrieving the branch being pointed by HEAD
	ref, _ := r.Head()

	// ... retrieving the commit object
	commit, _ := r.Commit(ref.Hash())

	// ... we get all the files from the commit
	files, _ := commit.Files()

	_, err = r.Head()
	err = files.ForEach(func(f *object.File) error {
		abs := filepath.Join(directory, "src", f.Name)
		dir := filepath.Dir(abs)

		os.MkdirAll(dir, 0777)
		file, err := os.Create(abs)
		if err != nil {
			return err
		}

		defer file.Close()
		r, err := f.Reader()
		if err != nil {
			return err
		}

		defer r.Close()

		if err := file.Chmod(f.Mode); err != nil {
			return err
		}

		_, err = io.Copy(file, r)
		return err
	})
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) find(targetDir string) ([]string, error) {
	var paths []string
	err := filepath.Walk(targetDir,
		func(path string, info os.FileInfo, err error) error {
			rel, err := filepath.Rel(targetDir, path)
			if err != nil {
				return err
			}

			if info.IsDir() {
				paths = append(paths, fmt.Sprintf(filepath.Join("%s", ""), rel))
				return nil
			}

			paths = append(paths, rel)

			return nil
		})

	if err != nil {
		return nil, err
	}

	return paths, nil
}

func (c *CLI) zipDirectory(directory string) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	zwriter := zip.NewWriter(buf)
	defer zwriter.Close()

	files, err := c.find(directory)
	if err != nil {
		return nil, err
	}

	for _, file := range files {
		absPath, _ := filepath.Abs(filepath.Join(directory, file))
		info, _ := os.Stat(absPath)

		f, err := zwriter.Create(filepath.Join("src", file))

		if info.IsDir() {
			continue
		}

		body, err := ioutil.ReadFile(absPath)
		if err != nil {
			return nil, err
		}
		f.Write(body)
	}

	return buf, nil
}

func (c *CLI) deployToSalesforce(directory string) error {
	buf, err := c.zipDirectory(directory)
	if err != nil {
		return err
	}

	response, err := c.Client.Deploy(buf.Bytes())
	if err != nil {
		return err
	}

	err = c.checkDeployStatus(response.Result.Id)
	if err != nil {
		return err
	}
	c.Logger.Info("Deploy is successful")

	return nil
}

func (c *CLI) checkDeployStatus(resultId *ID) error {
	totalTime := 0
	for {
		time.Sleep(time.Duration(c.Config.PollSeconds) * time.Second)
		c.Logger.Info("Check Deploy Result...")

		response, err := c.Client.CheckDeployStatus(resultId)
		if err != nil {
			return err
		}
		if response.Result.Done {
			return nil
		}
		if c.Config.TimeoutSeconds != 0 {
			totalTime += c.Config.PollSeconds
			if totalTime > c.Config.TimeoutSeconds {
				c.Logger.Error("Deploy is timeout. Please check release status for the deployment")
				return nil
			}
		}
	}
}
<commit_msg>Add sub directory feature<commit_after>package main

import (
	"archive/zip"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"time"

	_ "github.com/k0kubun/pp"
	"github.com/urfave/cli"
	"gopkg.in/src-d/go-git.v4"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/plumbing/object"
	"gopkg.in/yaml.v2"
)

type CLI struct {
	Client *ForceClient
	Config *Config
	Logger *Logger
	Error  error
}

type Config struct {
	Username       string
	Password       string
	Endpoint       string
	ApiVersion     string
	PollSeconds    int
	TimeoutSeconds int
	PackageFile    string
}

type PackageFile struct {
	Packages []string
}

const (
	APP_VERSION        string = "0.1.0"
	DEFAULT_REPOSITORY string = "github.com"
)

func (c *CLI) Run(args []string) (err error) {
	if c.Logger == nil {
		c.Logger = NewLogger(os.Stdout, os.Stderr)
	}
	c.Config = &Config{}

	app := cli.NewApp()
	app.Name = "spm"

	app.Usage = "Salesforce Package Manager"
	app.Version = APP_VERSION
	app.Commands = []cli.Command{
		{
			Name:    "install",
			Aliases: []string{"i"},
			Usage:   "Install salesforce packages on public remote repository(i.g. github)",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:        "username, u",
					Destination: &c.Config.Username,
					EnvVar:      "SF_USERNAME",
				},
				cli.StringFlag{
					Name:        "password, p",
					Destination: &c.Config.Password,
					EnvVar:      "SF_PASSWORD",
				},
				cli.StringFlag{
					Name:        "endpoint, e",
					Value:       "login.salesforce.com",
					Destination: &c.Config.Endpoint,
					EnvVar:      "SF_ENDPOINT",
				},
				cli.StringFlag{
					Name:        "apiversion",
					Value:       "38.0",
					Destination: &c.Config.ApiVersion,
					EnvVar:      "SF_APIVERSION",
				},
				cli.IntFlag{
					Name:        "pollSeconds",
					Value:       5,
					Destination: &c.Config.PollSeconds,
					EnvVar:      "SF_POLLSECONDS",
				},
				cli.IntFlag{
					Name:        "timeoutSeconds",
					Value:       0,
					Destination: &c.Config.TimeoutSeconds,
					EnvVar:      "SF_TIMEOUTSECONDS",
				},
				cli.StringFlag{
					Name:        "packages, P",
					Destination: &c.Config.PackageFile,
				},
			},
			Action: func(ctx *cli.Context) error {
				urls := []string{}
				if c.Config.PackageFile != "" {
					packageFile, err := c.readPackageFile()
					if err != nil {
						c.Error = err
						return nil
					}
					for _, pkg := range packageFile.Packages {
						url, err := c.convertToUrl(pkg)
						if err != nil {
							c.Error = err
							return nil
						}
						urls = append(urls, url)
					}
				} else {
					url, err := c.convertToUrl(ctx.Args().First())
					if err != nil {
						c.Error = err
						return nil
					}
					urls = []string{url}

				}
				if len(urls) == 0 {
					c.Error = errors.New("Repository not specified")
					return nil
				}
				c.Error = c.install(urls)
				return nil
			},
		},
	}

	app.Run(args)
	if c.Error != nil {
		c.Logger.Error(c.Error)
	}
	return c.Error
}

func (c *CLI) install(urls []string) error {
	err := c.checkConfigration()
	if err != nil {
		return err
	}
	err = c.setClient()
	if err != nil {
		return err
	}

	for _, url := range urls {
		r := regexp.MustCompile(`^(https://([^/]+?)/([^/]+?)/([^/@]+?))(/([^@]+))?(@([^/]+))?$`)
		group := r.FindAllStringSubmatch(url, -1)
		uri := group[0][1]
		directory := group[0][4]
		targetDirectory := group[0][6]
		branch := group[0][8]
		if branch == "" {
			branch = "master"
		}

		err = c.installToSalesforce(uri, directory, targetDirectory, branch)
		if err != nil {
			return err
		}
	}
	return nil
}

func (c *CLI) setClient() error {
	c.Client = NewForceClient(c.Config.Endpoint, c.Config.ApiVersion)
	err := c.Client.Login(c.Config.Username, c.Config.Password)
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) convertToUrl(target string) (string, error) {
	if target == "" {
		return "", errors.New("Repository not specified")
	}
	url := target
	r := regexp.MustCompile(`^[^/]+?/[^/@]+?(/[^@]+?)?(@[^/]+)?$`)
	if r.MatchString(url) {
		url = DEFAULT_REPOSITORY + "/" + url
	}
	return "https://" + url, nil
}

func (c *CLI) readPackageFile() (*PackageFile, error) {
	packageFile := PackageFile{}
	readBody, err := ioutil.ReadFile(c.Config.PackageFile)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal([]byte(readBody), &packageFile)
	if err != nil {
		return nil, err
	}
	return &packageFile, nil
}

func (c *CLI) checkConfigration() error {
	if c.Config.Username == "" {
		return errors.New("Username is required")
	}
	if c.Config.Password == "" {
		return errors.New("Password is required")
	}
	return nil
}

func (c *CLI) installToSalesforce(url string, directory string, targetDirectory string, branch string) error {
	cloneDir := filepath.Join(os.TempDir(), directory)
	c.Logger.Info("Clone repository from " + url + " (branch: " + branch + ")")
	err := c.cloneFromRemoteRepository(cloneDir, url, branch)
	if err != nil {
		return err
	}
	defer c.cleanTempDirectory(cloneDir)
	err = c.deployToSalesforce(filepath.Join(cloneDir, "src", targetDirectory))
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) cleanTempDirectory(directory string) error {
	if err := os.RemoveAll(directory); err != nil {
		return err
	}
	return nil
}

func (c *CLI) createFilesystemRepository(directory string, url string, paramBranch string, retry bool) (r *git.Repository, err error) {
	branch := "master"
	if paramBranch != "" {
		branch = paramBranch
	}
	r, err = git.NewFilesystemRepository(directory)
	err = r.Clone(&git.CloneOptions{
		URL:           url,
		ReferenceName: plumbing.ReferenceName("refs/heads/" + branch),
	})
	if err != nil {
		if err.Error() != "repository non empty" {
			return
		}
		if retry == true {
			return
		}
		c.Logger.Warningf("repository non empty: %s", directory)
		c.Logger.Infof("remove directory: %s", directory)
		err = c.cleanTempDirectory(directory)
		if err != nil {
			return
		}
		r, err = c.createFilesystemRepository(directory, url, paramBranch, true)
	}
	return
}

func (c *CLI) cloneFromRemoteRepository(directory string, url string, branch string) error {
	r, err := c.createFilesystemRepository(directory, url, branch, false)
	if err != nil {
		return err
	}

	// ... retrieving the branch being pointed by HEAD
	ref, _ := r.Head()

	// ... retrieving the commit object
	commit, _ := r.Commit(ref.Hash())

	// ... we get all the files from the commit
	files, _ := commit.Files()

	_, err = r.Head()
	err = files.ForEach(func(f *object.File) error {
		abs := filepath.Join(directory, "src", f.Name)
		dir := filepath.Dir(abs)

		os.MkdirAll(dir, 0777)
		file, err := os.Create(abs)
		if err != nil {
			return err
		}

		defer file.Close()
		r, err := f.Reader()
		if err != nil {
			return err
		}

		defer r.Close()

		if err := file.Chmod(f.Mode); err != nil {
			return err
		}

		_, err = io.Copy(file, r)
		return err
	})
	if err != nil {
		return err
	}
	return nil
}

func (c *CLI) find(targetDir string) ([]string, error) {
	var paths []string
	err := filepath.Walk(targetDir,
		func(path string, info os.FileInfo, err error) error {
			rel, err := filepath.Rel(targetDir, path)
			if err != nil {
				return err
			}

			if info.IsDir() {
				paths = append(paths, fmt.Sprintf(filepath.Join("%s", ""), rel))
				return nil
			}

			paths = append(paths, rel)

			return nil
		})

	if err != nil {
		return nil, err
	}

	return paths, nil
}

func (c *CLI) zipDirectory(directory string) (*bytes.Buffer, error) {
	buf := new(bytes.Buffer)
	zwriter := zip.NewWriter(buf)
	defer zwriter.Close()

	files, err := c.find(directory)
	if err != nil {
		return nil, err
	}

	for _, file := range files {
		absPath, _ := filepath.Abs(filepath.Join(directory, file))
		info, _ := os.Stat(absPath)

		f, err := zwriter.Create(filepath.Join("src", file))

		if info.IsDir() {
			continue
		}

		body, err := ioutil.ReadFile(absPath)
		if err != nil {
			return nil, err
		}
		f.Write(body)
	}

	return buf, nil
}

func (c *CLI) deployToSalesforce(directory string) error {
	buf, err := c.zipDirectory(directory)
	if err != nil {
		return err
	}

	response, err := c.Client.Deploy(buf.Bytes())
	if err != nil {
		return err
	}

	err = c.checkDeployStatus(response.Result.Id)
	if err != nil {
		return err
	}
	c.Logger.Info("Deploy is successful")

	return nil
}

func (c *CLI) checkDeployStatus(resultId *ID) error {
	totalTime := 0
	for {
		time.Sleep(time.Duration(c.Config.PollSeconds) * time.Second)
		c.Logger.Info("Check Deploy Result...")

		response, err := c.Client.CheckDeployStatus(resultId)
		if err != nil {
			return err
		}
		if response.Result.Done {
			return nil
		}
		if c.Config.TimeoutSeconds != 0 {
			totalTime += c.Config.PollSeconds
			if totalTime > c.Config.TimeoutSeconds {
				c.Logger.Error("Deploy is timeout. Please check release status for the deployment")
				return nil
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"cloud.google.com/go/spanner"
	"github.com/chzyer/readline"
	"github.com/olekukonko/tablewriter"
)

type Delimiter string

const (
	DelimiterHorizontal Delimiter = ";"
	DelimiterVertical   Delimiter = "\\G"
)

type DisplayMode int

const (
	DisplayModeTable DisplayMode = iota
	DisplayModeVertical
	DisplayModeTab
)

const (
	DefaultPrompt = `spanner\t> `
)

const (
	ExitCodeSuccess = 0
	ExitCodeError   = 1
)

type Cli struct {
	Session *Session
	Prompt  string
}

func NewCli(projectId, instanceId, databaseId string, prompt string) (*Cli, error) {
	ctx := context.Background()
	session, err := NewSession(ctx, projectId, instanceId, databaseId, spanner.ClientConfig{})
	if err != nil {
		return nil, err
	}

	if prompt == "" {
		prompt = DefaultPrompt
	}

	return &Cli{
		Session: session,
		Prompt:  prompt,
	}, nil
}

func (c *Cli) RunInteractive() int {
	rl, err := readline.NewEx(&readline.Config{
		HistoryFile: "/tmp/spanner_cli_readline.tmp",
	})
	if err != nil {
		return c.ExitOnError(err)
	}

	exists, err := c.Session.DatabaseExists()
	if err != nil {
		return c.ExitOnError(err)
	}
	if exists {
		fmt.Printf("Connected.\n")
	} else {
		return c.ExitOnError(fmt.Errorf("Unknown database '%s'", c.Session.databaseId))
	}

	for {
		prompt := c.Session.InterpolatePromptVariable(c.Prompt)
		rl.SetPrompt(prompt)

		input, delimiter, err := readInteractiveInput(rl)
		if err == io.EOF {
			return c.Exit()
		}

		stmt, err := BuildStatement(input)
		if err != nil {
			fmt.Printf("ERROR: %s\n", err)
			continue
		}

		if _, ok := stmt.(*ExitStatement); ok {
			return c.Exit()
		}

		if s, ok := stmt.(*UseStatement); ok {
			ctx := context.Background()
			newSession, err := NewSession(ctx, c.Session.projectId, c.Session.instanceId, s.Database, spanner.ClientConfig{})
			if err != nil {
				fmt.Printf("ERROR: %s\n", err)
				continue
			}

			exists, err := newSession.DatabaseExists()
			if err != nil {
				fmt.Printf("ERROR: %s\n", err)
				continue
			}
			if !exists {
				fmt.Printf("ERROR: Unknown database '%s'\n", s.Database)
				continue
			}

			c.Session.client.Close()
			c.Session.adminClient.Close()
			c.Session = newSession
			fmt.Println("Database changed")
			continue
		}

		ticker := printProgressingMark()
		result, err := stmt.Execute(c.Session)
		ticker.Stop()
		fmt.Printf("\r") // clear progressing mark
		if err != nil {
			fmt.Printf("ERROR: %s\n", err)
			continue
		}

		if delimiter == DelimiterHorizontal {
			printResult(result, DisplayModeTable, true)
		} else {
			printResult(result, DisplayModeVertical, true)
		}

		fmt.Printf("\n")
	}
}

func (c *Cli) RunBatch(input string, displayTable bool) int {
	for _, separated := range separateInput(input) {
		stmt, err := BuildStatement(separated.Statement)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			return ExitCodeError
		}

		result, err := stmt.Execute(c.Session)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			return ExitCodeError
		}

		if displayTable {
			printResult(result, DisplayModeTable, false)
		} else if separated.Delimiter == DelimiterVertical {
			printResult(result, DisplayModeVertical, false)
		} else {
			printResult(result, DisplayModeTab, false)
		}
	}
	return ExitCodeSuccess
}

func (c *Cli) Exit() int {
	c.Session.Close()
	fmt.Println("Bye")
	return ExitCodeSuccess
}

func (c *Cli) ExitOnError(err error) int {
	c.Session.Close()
	fmt.Printf("ERROR: %s\n", err)
	return ExitCodeError
}

func printResult(result *Result, mode DisplayMode, withStats bool) {
	if mode == DisplayModeTable {
		table := tablewriter.NewWriter(os.Stdout)
		for _, row := range result.Rows {
			table.Append(row.Columns)
		}
		table.SetHeader(result.ColumnNames)
		if len(result.Rows) > 0 {
			table.SetAutoFormatHeaders(false)
			table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
			table.SetAlignment(tablewriter.ALIGN_LEFT)
			table.Render()
		}
	} else if mode == DisplayModeVertical {
		max := 0
		for _, columnName := range result.ColumnNames {
			if len(columnName) > max {
				max = len(columnName)
			}
		}
		format := fmt.Sprintf("%%%ds: %%s\n", max) // for align right
		for i, row := range result.Rows {
			fmt.Printf("*************************** %d. row ***************************\n", i+1)
			for j, column := range row.Columns {
				fmt.Printf(format, result.ColumnNames[j], column)
			}
		}
	} else if mode == DisplayModeTab {
		if len(result.ColumnNames) > 0 {
			fmt.Println(strings.Join(result.ColumnNames, "\t"))
			for _, row := range result.Rows {
				fmt.Println(strings.Join(row.Columns, "\t"))
			}
		}
	}

	if withStats {
		if result.IsMutation {
			fmt.Printf("Query OK, %d rows affected (%s)\n", result.Stats.AffectedRows, result.Stats.ElapsedTime)
		} else {
			if result.Stats.AffectedRows == 0 {
				fmt.Printf("Empty set (%s)\n", result.Stats.ElapsedTime)
			} else {
				fmt.Printf("%d rows in set (%s)\n", result.Stats.AffectedRows, result.Stats.ElapsedTime)
			}
		}
	}
}

type InputStatement struct {
	Statement string
	Delimiter Delimiter
}

func readInteractiveInput(rl *readline.Instance) (string, Delimiter, error) {
	lines := make([]string, 0)
	origPrompt := rl.Config.Prompt
	defer rl.SetPrompt(origPrompt)

	for {
		line, err := rl.Readline()
		if err != nil {
			return "", Delimiter("UNKNOWN"), err
		}

		line = strings.TrimSpace(line)
		if len(line) != 0 {
			// check comment literal
			if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "--") {
				continue
			}
			for _, delimiter := range []Delimiter{DelimiterHorizontal, DelimiterVertical} {
				if strings.HasSuffix(line, string(delimiter)) {
					line = strings.TrimRight(line, string(delimiter))
					lines = append(lines, line)
					return strings.TrimSpace(strings.Join(lines, " ")), delimiter, nil
				}
			}
		}
		lines = append(lines, line)
		rl.SetPrompt("      -> ") // same length to original prompt
	}
}

// separate to each statement
func separateInput(input string) []InputStatement {
	input = strings.TrimSpace(input)
	statements := make([]InputStatement, 0)

	// NOTE: This logic doesn't do syntactic analysis, but just checks the delimiter position,
	// so it's fragile for the case that delimiters appear in strings.
	for input != "" {
		if idx := strings.Index(input, string(DelimiterHorizontal)); idx != -1 {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input[:idx]),
				Delimiter: DelimiterHorizontal,
			})
			input = strings.TrimSpace(input[idx+1:])
		} else if idx := strings.Index(input, string(DelimiterVertical)); idx != -1 {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input[:idx]),
				Delimiter: DelimiterVertical,
			})
			input = strings.TrimSpace(input[idx+2:]) // +2 for \ and G
		} else {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input),
				Delimiter: DelimiterHorizontal, // default horizontal
			})
			break
		}
	}
	return statements
}

func printProgressingMark() *time.Ticker {
	progressMarks := []string{"-", "\\", "|", "/"}
	ticker := time.NewTicker(time.Millisecond * 100)
	go func() {
		i := 0
		for {
			<-ticker.C
			mark := progressMarks[i%len(progressMarks)]
			fmt.Printf("\r%s", mark)
			i++
		}
	}()
	return ticker
}
<commit_msg>tweak<commit_after>package main

import (
	"context"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"cloud.google.com/go/spanner"
	"github.com/chzyer/readline"
	"github.com/olekukonko/tablewriter"
)

type Delimiter string

const (
	DelimiterHorizontal Delimiter = ";"
	DelimiterVertical   Delimiter = "\\G"
)

type DisplayMode int

const (
	DisplayModeTable DisplayMode = iota
	DisplayModeVertical
	DisplayModeTab
)

const (
	DefaultPrompt = `spanner\t> `
)

const (
	ExitCodeSuccess = 0
	ExitCodeError   = 1
)

type Cli struct {
	Session *Session
	Prompt  string
}

func NewCli(projectId, instanceId, databaseId string, prompt string) (*Cli, error) {
	ctx := context.Background()
	session, err := NewSession(ctx, projectId, instanceId, databaseId, spanner.ClientConfig{})
	if err != nil {
		return nil, err
	}

	if prompt == "" {
		prompt = DefaultPrompt
	}

	return &Cli{
		Session: session,
		Prompt:  prompt,
	}, nil
}

func (c *Cli) RunInteractive() int {
	rl, err := readline.NewEx(&readline.Config{
		HistoryFile: "/tmp/spanner_cli_readline.tmp",
	})
	if err != nil {
		return c.ExitOnError(err)
	}

	exists, err := c.Session.DatabaseExists()
	if err != nil {
		return c.ExitOnError(err)
	}
	if exists {
		fmt.Printf("Connected.\n")
	} else {
		return c.ExitOnError(fmt.Errorf("Unknown database '%s'", c.Session.databaseId))
	}

	for {
		prompt := c.Session.InterpolatePromptVariable(c.Prompt)
		rl.SetPrompt(prompt)

		input, delimiter, err := readInteractiveInput(rl)
		if err == io.EOF {
			return c.Exit()
		}

		stmt, err := BuildStatement(input)
		if err != nil {
			fmt.Printf("ERROR: %s\n", err)
			continue
		}

		if _, ok := stmt.(*ExitStatement); ok {
			return c.Exit()
		}

		if s, ok := stmt.(*UseStatement); ok {
			ctx := context.Background()
			newSession, err := NewSession(ctx, c.Session.projectId, c.Session.instanceId, s.Database, spanner.ClientConfig{})
			if err != nil {
				fmt.Printf("ERROR: %s\n", err)
				continue
			}

			exists, err := newSession.DatabaseExists()
			if err != nil {
				fmt.Printf("ERROR: %s\n", err)
				continue
			}
			if !exists {
				fmt.Printf("ERROR: Unknown database '%s'\n", s.Database)
				continue
			}

			c.Session.client.Close()
			c.Session.adminClient.Close()
			c.Session = newSession
			fmt.Println("Database changed")
			continue
		}

		stop := printProgressingMark()
		result, err := stmt.Execute(c.Session)
		stop()
		if err != nil {
			fmt.Printf("ERROR: %s\n", err)
			continue
		}

		if delimiter == DelimiterHorizontal {
			printResult(result, DisplayModeTable, true)
		} else {
			printResult(result, DisplayModeVertical, true)
		}

		fmt.Printf("\n")
	}
}

func (c *Cli) RunBatch(input string, displayTable bool) int {
	for _, separated := range separateInput(input) {
		stmt, err := BuildStatement(separated.Statement)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			return ExitCodeError
		}

		result, err := stmt.Execute(c.Session)
		if err != nil {
			fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
			return ExitCodeError
		}

		if displayTable {
			printResult(result, DisplayModeTable, false)
		} else if separated.Delimiter == DelimiterVertical {
			printResult(result, DisplayModeVertical, false)
		} else {
			printResult(result, DisplayModeTab, false)
		}
	}
	return ExitCodeSuccess
}

func (c *Cli) Exit() int {
	c.Session.Close()
	fmt.Println("Bye")
	return ExitCodeSuccess
}

func (c *Cli) ExitOnError(err error) int {
	c.Session.Close()
	fmt.Printf("ERROR: %s\n", err)
	return ExitCodeError
}

func printResult(result *Result, mode DisplayMode, withStats bool) {
	if mode == DisplayModeTable {
		table := tablewriter.NewWriter(os.Stdout)
		for _, row := range result.Rows {
			table.Append(row.Columns)
		}
		table.SetHeader(result.ColumnNames)
		if len(result.Rows) > 0 {
			table.SetAutoFormatHeaders(false)
			table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
			table.SetAlignment(tablewriter.ALIGN_LEFT)
			table.Render()
		}
	} else if mode == DisplayModeVertical {
		max := 0
		for _, columnName := range result.ColumnNames {
			if len(columnName) > max {
				max = len(columnName)
			}
		}
		format := fmt.Sprintf("%%%ds: %%s\n", max) // for align right
		for i, row := range result.Rows {
			fmt.Printf("*************************** %d. row ***************************\n", i+1)
			for j, column := range row.Columns {
				fmt.Printf(format, result.ColumnNames[j], column)
			}
		}
	} else if mode == DisplayModeTab {
		if len(result.ColumnNames) > 0 {
			fmt.Println(strings.Join(result.ColumnNames, "\t"))
			for _, row := range result.Rows {
				fmt.Println(strings.Join(row.Columns, "\t"))
			}
		}
	}

	if withStats {
		if result.IsMutation {
			fmt.Printf("Query OK, %d rows affected (%s)\n", result.Stats.AffectedRows, result.Stats.ElapsedTime)
		} else {
			if result.Stats.AffectedRows == 0 {
				fmt.Printf("Empty set (%s)\n", result.Stats.ElapsedTime)
			} else {
				fmt.Printf("%d rows in set (%s)\n", result.Stats.AffectedRows, result.Stats.ElapsedTime)
			}
		}
	}
}

type InputStatement struct {
	Statement string
	Delimiter Delimiter
}

func readInteractiveInput(rl *readline.Instance) (string, Delimiter, error) {
	lines := make([]string, 0)
	origPrompt := rl.Config.Prompt
	defer rl.SetPrompt(origPrompt)

	for {
		line, err := rl.Readline()
		if err != nil {
			return "", Delimiter("UNKNOWN"), err
		}

		line = strings.TrimSpace(line)
		if len(line) != 0 {
			// check comment literal
			if strings.HasPrefix(line, "#") || strings.HasPrefix(line, "--") {
				continue
			}
			for _, delimiter := range []Delimiter{DelimiterHorizontal, DelimiterVertical} {
				if strings.HasSuffix(line, string(delimiter)) {
					line = strings.TrimRight(line, string(delimiter))
					lines = append(lines, line)
					return strings.TrimSpace(strings.Join(lines, " ")), delimiter, nil
				}
			}
		}
		lines = append(lines, line)
		rl.SetPrompt("      -> ") // same length to original prompt
	}
}

// separate to each statement
func separateInput(input string) []InputStatement {
	input = strings.TrimSpace(input)
	statements := make([]InputStatement, 0)

	// NOTE: This logic doesn't do syntactic analysis, but just checks the delimiter position,
	// so it's fragile for the case that delimiters appear in strings.
	for input != "" {
		if idx := strings.Index(input, string(DelimiterHorizontal)); idx != -1 {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input[:idx]),
				Delimiter: DelimiterHorizontal,
			})
			input = strings.TrimSpace(input[idx+1:])
		} else if idx := strings.Index(input, string(DelimiterVertical)); idx != -1 {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input[:idx]),
				Delimiter: DelimiterVertical,
			})
			input = strings.TrimSpace(input[idx+2:]) // +2 for \ and G
		} else {
			statements = append(statements, InputStatement{
				Statement: strings.TrimSpace(input),
				Delimiter: DelimiterHorizontal, // default horizontal
			})
			break
		}
	}
	return statements
}

func printProgressingMark() func() {
	progressMarks := []string{`-`, `\`, `|`, `/`}
	ticker := time.NewTicker(time.Millisecond * 100)
	go func() {
		i := 0
		for {
			<-ticker.C
			mark := progressMarks[i%len(progressMarks)]
			fmt.Printf("\r%s", mark)
			i++
		}
	}()

	stop := func() {
		ticker.Stop()
		fmt.Printf("\r") // clear progressing mark
	}
	return stop
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"

	"strings"

	"github.com/google/go-github/github"
	"github.com/olekukonko/tablewriter"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
)

const (
	// DefaultOutput is default output file name
	DefaultOutput = "LICENSE"
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {

	var LicenseInfo LicenseInfo
	var output string

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprintf(cli.errStream, helpText)
	}

	flags.StringVar(&LicenseInfo.Author, "author", "", "")
	flags.StringVar(&output, "output", DefaultOutput, "")

	flList := flags.Bool("list", false, "")
	// flChoose := flags.Bool("choose", false, "")

	flDebug := flags.Bool("debug", false, "")
	flVersion := flags.Bool("version", false, "")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if *flVersion {
		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		return ExitCodeOK
	}

	// Set Debug environmental variable
	if *flDebug {
		if err := os.Setenv(EnvDebug, "1"); err != nil {
			// Should not reach here
			panic(err)
		}
	}

	// Check file exist or not
	// TODO: -force option
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		fmt.Fprintf(cli.errStream, "Cannot create file %q: file exists\n", output)
		return ExitCodeError
	}

	client := github.NewClient(nil)

	if *flList {
		Debugf("Show list of LICENSE")
		list, res, err := client.Licenses.List()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE list: %s\n", err.Error())
			return ExitCodeError
		}

		if res.StatusCode != http.StatusOK {
			fmt.Fprintf(cli.errStream, "Invalidd status code from GitHub\n %s\n", res.String())
			return ExitCodeError
		}

		outBuffer := new(bytes.Buffer)
		table := tablewriter.NewWriter(outBuffer)

		header := []string{"Key", "Name"}
		table.SetHeader(header)
		for _, l := range list {
			Debugf("%s (%s)", *l.Name, *l.Key)
			table.Append([]string{*l.Key, *l.Name})
		}
		table.Render()

		fmt.Fprintf(cli.outStream, outBuffer.String())
		return ExitCodeOK
	}

	parsedArgs := flags.Args()
	if len(parsedArgs) > 1 {
		fmt.Fprintf(cli.errStream, "Invalid arguments")
		return ExitCodeError
	}

	// TODO, select key from list
	var key string
	if len(parsedArgs) == 1 {
		key = parsedArgs[0]
	}

	Debugf("Get license by key: %s", key)
	license, res, err := client.Licenses.Get(key)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE: %s\n", err.Error())
		return ExitCodeError
	}

	if res.StatusCode != http.StatusOK {
		fmt.Fprintf(cli.errStream, "Invalidd status code from GitHub\n %s\n", res.String())
		return ExitCodeError
	}

	licenseName := *license.Name
	Debugf("Fetched license name: %s", licenseName)

	licenseBody := *license.Body
	Debugf("Fetched license body:\n\n%s", licenseBody)

	r := strings.NewReader(licenseBody)
	w, err := os.Create(output)
	if err != nil {
		panic(err)
	}
	defer w.Close()
	Debugf("Output filename: %s", output)

	i, err := io.Copy(w, r)
	if i < 0 || err != nil {
		fmt.Fprintf(cli.errStream, "Failed to write license body to %q: %s\n", output)
		return ExitCodeError
	}
	Debugf("Written: %d", i)

	fmt.Fprintf(cli.outStream, "Successfully generated %q \n", licenseName)
	return ExitCodeOK
}

var helpText = `Usage: license [option] [KEY]

  Generate LICENSE file. If you provide KEY, it will try to get LICENSE by
  it. If you don't provide it, it will ask you to choose from avairable list.
  You can check avairable LICESE list by '-list' option.

Options:

  -list               Show all avairable LICENSE list and quit.
                      It will fetch information from GitHub.

  -output=NAME        Change output file name.
                      By default, output file name is 'LICENSE'

`
<commit_msg>Check file is exist or not after -list execution<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"

	"strings"

	"github.com/google/go-github/github"
	"github.com/olekukonko/tablewriter"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
	ExitCodeOK    int = 0
	ExitCodeError int = 1 + iota
)

const (
	// DefaultOutput is default output file name
	DefaultOutput = "LICENSE"
)

// CLI is the command line object
type CLI struct {
	// outStream and errStream are the stdout and stderr
	// to write message from the CLI.
	outStream, errStream io.Writer
}

// Run invokes the CLI with the given arguments.
func (cli *CLI) Run(args []string) int {

	var LicenseInfo LicenseInfo
	var output string

	// Define option flag parse
	flags := flag.NewFlagSet(Name, flag.ContinueOnError)
	flags.SetOutput(cli.errStream)
	flags.Usage = func() {
		fmt.Fprintf(cli.errStream, helpText)
	}

	flags.StringVar(&LicenseInfo.Author, "author", "", "")
	flags.StringVar(&output, "output", DefaultOutput, "")

	flList := flags.Bool("list", false, "")
	// flChoose := flags.Bool("choose", false, "")

	flDebug := flags.Bool("debug", false, "")
	flVersion := flags.Bool("version", false, "")

	// Parse commandline flag
	if err := flags.Parse(args[1:]); err != nil {
		return ExitCodeError
	}

	// Show version
	if *flVersion {
		fmt.Fprintf(cli.errStream, "%s version %s\n", Name, Version)
		return ExitCodeOK
	}

	// Set Debug environmental variable
	if *flDebug {
		if err := os.Setenv(EnvDebug, "1"); err != nil {
			// Should not reach here
			panic(err)
		}
	}

	if *flList {

		client := github.NewClient(nil)

		Debugf("Show list of LICENSE")
		list, res, err := client.Licenses.List()
		if err != nil {
			fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE list: %s\n", err.Error())
			return ExitCodeError
		}

		if res.StatusCode != http.StatusOK {
			fmt.Fprintf(cli.errStream, "Invalidd status code from GitHub\n %s\n", res.String())
			return ExitCodeError
		}

		outBuffer := new(bytes.Buffer)
		table := tablewriter.NewWriter(outBuffer)

		header := []string{"Key", "Name"}
		table.SetHeader(header)
		for _, l := range list {
			Debugf("%s (%s)", *l.Name, *l.Key)
			table.Append([]string{*l.Key, *l.Name})
		}
		table.Render()

		fmt.Fprintf(cli.outStream, outBuffer.String())
		return ExitCodeOK
	}

	parsedArgs := flags.Args()
	if len(parsedArgs) > 1 {
		fmt.Fprintf(cli.errStream, "Invalid arguments")
		return ExitCodeError
	}

	// TODO, select key from list
	var key string
	if len(parsedArgs) == 1 {
		key = parsedArgs[0]
	}

	// Check file exist or not
	// TODO: -force option
	if _, err := os.Stat(output); !os.IsNotExist(err) {
		fmt.Fprintf(cli.errStream, "Cannot create file %q: file exists\n", output)
		return ExitCodeError
	}

	Debugf("Get license by key: %s", key)
	client := github.NewClient(nil)
	license, res, err := client.Licenses.Get(key)
	if err != nil {
		fmt.Fprintf(cli.errStream, "Failed to fetch LICENSE: %s\n", err.Error())
		return ExitCodeError
	}

	if res.StatusCode != http.StatusOK {
		fmt.Fprintf(cli.errStream, "Invalidd status code from GitHub\n %s\n", res.String())
		return ExitCodeError
	}

	licenseName := *license.Name
	Debugf("Fetched license name: %s", licenseName)

	licenseBody := *license.Body
	Debugf("Fetched license body:\n\n%s", licenseBody)

	r := strings.NewReader(licenseBody)
	w, err := os.Create(output)
	if err != nil {
		panic(err)
	}
	defer w.Close()
	Debugf("Output filename: %s", output)

	i, err := io.Copy(w, r)
	if i < 0 || err != nil {
		fmt.Fprintf(cli.errStream, "Failed to write license body to %q: %s\n", output)
		return ExitCodeError
	}
	Debugf("Written: %d", i)

	fmt.Fprintf(cli.outStream, "Successfully generated %q \n", licenseName)
	return ExitCodeOK
}

var helpText = `Usage: license [option] [KEY]

  Generate LICENSE file. If you provide KEY, it will try to get LICENSE by
  it. If you don't provide it, it will ask you to choose from avairable list.
  You can check avairable LICESE list by '-list' option.

Options:

  -list               Show all avairable LICENSE list and quit.
                      It will fetch information from GitHub.

  -output=NAME        Change output file name.
                      By default, output file name is 'LICENSE'

`
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/lunixbochs/ghostrace/ghost"
	"github.com/lunixbochs/ghostrace/ghost/sys/call"
)

func main() {
	fs := flag.NewFlagSet("ghostrace", flag.ExitOnError)
	// follow := fs.Bool("f", false, "follow subprocesses")
	pid := fs.Int("p", -1, "attach to pid")
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] -p <pid> | <exe> [args...]\n", os.Args[0])
		fs.PrintDefaults()
	}
	fs.Parse(os.Args[1:])
	args := fs.Args()

	var trace chan *ghost.Event
	var err error
	tracer := ghost.NewTracer()
	if pid != nil && *pid >= 0 {
		trace, err = tracer.Trace(*pid)
	} else {
		if len(args) > 0 {
			trace, err = tracer.Spawn(args[0], args...)
		} else {
			fs.Usage()
			os.Exit(1)
		}
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error starting trace: %s\n", err)
		os.Exit(1)
	}
	tracer.ExecFilter(func(c *call.Execve) (bool, bool) {
		// fmt.Println("exec filter", c)
		return true, true
	})
	for sc := range trace {
		fmt.Fprintf(os.Stderr, "%+v\n", sc)
	}
}
<commit_msg>fix cli.go for new execCb api<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/lunixbochs/ghostrace/ghost"
)

func main() {
	fs := flag.NewFlagSet("ghostrace", flag.ExitOnError)
	follow := fs.Bool("f", false, "follow subprocesses")
	pid := fs.Int("p", -1, "attach to pid")
	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] -p <pid> | <exe> [args...]\n", os.Args[0])
		fs.PrintDefaults()
	}
	fs.Parse(os.Args[1:])
	args := fs.Args()

	var trace chan *ghost.Event
	var err error
	tracer := ghost.NewTracer()
	if pid != nil && *pid >= 0 {
		trace, err = tracer.Trace(*pid)
	} else {
		if len(args) > 0 {
			trace, err = tracer.Spawn(args[0], args...)
		} else {
			fs.Usage()
			os.Exit(1)
		}
	}
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error starting trace: %s\n", err)
		os.Exit(1)
	}
	tracer.ExecFilter(func(c *ghost.Event) (bool, bool) {
		// fmt.Println("exec filter", c)
		// keepParent, followChild
		return true, *follow
	})
	for sc := range trace {
		fmt.Fprintf(os.Stderr, "%+v\n", sc)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/exec"
)

type CLI struct {
	arguments map[string]interface{}
}

func newCLI(arguments map[string]interface{}) *CLI {
	return &CLI{arguments}
}

func (cli *CLI) Run() {
	grep := cli.grep()
	sed := cli.sed()
	grepOut, _ := grep.StdoutPipe()
	grep.Start()
	sed.Stdin = grepOut
	output, _ := sed.CombinedOutput()
	fmt.Print(string(output))
}

func (cli *CLI) grep() *exec.Cmd {
	grepArgs := []string{"grep", "-El", fmt.Sprintf("%s", cli.arguments["<search-pattern>"])}
	if cli.arguments["<path>"] != nil {
		grepArgs = append(grepArgs, cli.arguments["<path>"].(string))
	}
	return exec.Command("git", grepArgs...)
}

func (cli *CLI) sed() *exec.Cmd {
	search := fmt.Sprintf("s/%s/%s/g", cli.arguments["<search-pattern>"], cli.arguments["<replace-pattern>"])
	return exec.Command("xargs", "sed", "-ri", search)
}
<commit_msg>exit with status 1 if sed exited with nonzero status<commit_after>package main

import (
	"fmt"
	"os/exec"
	"os"
)

type CLI struct {
	arguments map[string]interface{}
}

func newCLI(arguments map[string]interface{}) *CLI {
	return &CLI{arguments}
}

func (cli *CLI) Run() {
	grep := cli.grep()
	sed := cli.sed()
	grepOut, _ := grep.StdoutPipe()
	grep.Start()
	sed.Stdin = grepOut
	output, err := sed.CombinedOutput()
	fmt.Print(string(output))
	if err != nil {
		os.Exit(1)
	}
}

func (cli *CLI) grep() *exec.Cmd {
	grepArgs := []string{"grep", "-El", fmt.Sprintf("%s", cli.arguments["<search-pattern>"])}
	if cli.arguments["<path>"] != nil {
		grepArgs = append(grepArgs, cli.arguments["<path>"].(string))
	}
	return exec.Command("git", grepArgs...)
}

func (cli *CLI) sed() *exec.Cmd {
	search := fmt.Sprintf("s/%s/%s/g", cli.arguments["<search-pattern>"], cli.arguments["<replace-pattern>"])
	return exec.Command("xargs", "sed", "-ri", search)
}
<|endoftext|>


<commit_before>// Package static provides go.h compatible hashed static assets. This allows
// for providing long lived cache headers for resources which change URLs as
// their content changes.
package static

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime"
	"net/http"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/daaku/go.h"
)

const (
	maxAge  = time.Hour * 24 * 365 * 10
	hashLen = 8
)

var (
	errZeroNames = errors.New("static: zero names given")
	cacheControl = fmt.Sprintf("public, max-age=%d", int(maxAge.Seconds()))
)

func disableCaching(w http.ResponseWriter) {
	header := w.Header()
	header.Set("Cache-Control", "no-cache")
	header.Set("Pragma", "no-cache")
}

func notFound(w http.ResponseWriter) {
	disableCaching(w)
	w.WriteHeader(http.StatusNotFound)
	io.WriteString(w, http.StatusText(http.StatusNotFound))
}

func badRequest(w http.ResponseWriter) {
	disableCaching(w)
	w.WriteHeader(http.StatusBadRequest)
	io.WriteString(w, http.StatusText(http.StatusBadRequest))
}

type errInvalidURL string

func (e errInvalidURL) Error() string {
	return fmt.Sprintf("static: invalid URL %q", string(e))
}

// we drop base64 padding in our URLs
func dropPadding(s string) string {
	return strings.TrimRight(s, "=")
}

// so we only allocate these strings once
var paddings = [...]string{
	"=",
	"==",
	"===",
}

func addPadding(s string) string {
	if l := len(s) % 4; l > 0 {
		return s + paddings[3-l]
	}
	return s
}

type file struct {
	Name    string
	Content []byte
	Hash    string
}

func encode(files []*file) (string, error) {
	parts := make([][2]string, 0, len(files))
	for _, f := range files {
		parts = append(parts, [2]string{f.Name, f.Hash})
	}

	b, err := json.Marshal(parts)
	if err != nil {
		return "", errors.New("static: could not encode URL")
	}

	return dropPadding(base64.URLEncoding.EncodeToString(b)), nil
}

func decode(value string) ([]*file, error) {
	decoded, err := base64.URLEncoding.DecodeString(addPadding(value))
	if err != nil {
		return nil, errInvalidURL(value)
	}

	var parts [][]string
	if err := json.NewDecoder(bytes.NewReader(decoded)).Decode(&parts); err != nil {
		return nil, errInvalidURL(value)
	}

	var files []*file
	for _, part := range parts {
		if len(part) != 2 {
			return nil, errInvalidURL(value)
		}
		files = append(files, &file{
			Name: part[0],
			Hash: part[1],
		})
	}

	return files, nil
}

// Box is where the files are loaded from. Practically you'll probably want to
// use https://github.com/GeertJohan/go.rice.
type Box interface {
	Bytes(name string) ([]byte, error)
}

// Handler serves and provides URLs for static resources.
type Handler struct {
	Path string // Path at which Handler is configured.
	Box  Box    // Box of files to serve.

	mu    sync.RWMutex
	files map[string]*file
}

func (h *Handler) load(name string) (*file, error) {
	// fast path
	h.mu.RLock()
	f := h.files[name]
	h.mu.RUnlock()

	if f != nil {
		return f, nil
	}

	// slow path
	h.mu.Lock()
	defer h.mu.Unlock()

	// check again in case someone else populated it
	f = h.files[name]
	if f != nil {
		return f, nil
	}

	contents, err := h.Box.Bytes(name)
	if err != nil {
		return nil, err
	}

	hash := fmt.Sprintf("%x", md5.Sum(contents))
	f = &file{
		Name:    name,
		Content: contents,
		Hash:    hash[:hashLen],
	}
	if h.files == nil {
		h.files = make(map[string]*file)
	}
	h.files[name] = f

	return f, nil
}

// URL returns a hashed URL for all the given component names. It uses the
// extension of the first file as the extension for the generated URL.
func (h *Handler) URL(names ...string) (string, error) {
	if len(names) == 0 {
		return "", errZeroNames
	}

	var files []*file
	for _, name := range names {
		f, err := h.load(name)
		if err != nil {
			return "", err
		}
		files = append(files, f)
	}

	value, err := encode(files)
	if err != nil {
		return "", err
	}

	if ext := filepath.Ext(names[0]); ext != "" {
		value = value + ext
	}

	return path.Join(h.Path, value), nil
}

// ServeHTTP handles requests for hashed URLs.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	if !strings.HasPrefix(path, h.Path) {
		notFound(w)
		return
	}

	contentType := ""
	encoded := path[len(h.Path):]
	if ext := filepath.Ext(encoded); ext != "" {
		encoded = encoded[:len(encoded)-len(ext)]
		contentType = mime.TypeByExtension(ext)
	}

	files, err := decode(encoded)
	if err != nil {
		badRequest(w)
		return
	}

	// fill in the contents and calculate the length
	var contentLength int
	for i, f := range files {
		loaded, err := h.load(f.Name)
		if err != nil {
			notFound(w)
			return
		}
		if loaded.Hash != f.Hash {
			notFound(w)
			return
		}
		contentLength += len(loaded.Content)
		files[i] = loaded
	}

	header := w.Header()
	header.Set("Cache-Control", cacheControl)
	header.Set("Content-Length", strconv.Itoa(contentLength))
	if contentType != "" {
		header.Set("Content-Type", contentType)
	}

	for _, f := range files {
		w.Write(f.Content)
	}
}

// LinkStyle provides a h.LinkStyle where the HREFs are combined and served
// using the specified Handler.
type LinkStyle struct {
	Handler *Handler
	HREF    []string
}

// HTML returns the <link> tag with the appropriate attributes.
func (l *LinkStyle) HTML() (h.HTML, error) {
	url, err := l.Handler.URL(l.HREF...)
	if err != nil {
		return nil, err
	}
	return &h.LinkStyle{HREF: url}, nil
}

// Script provides a h.Script where the Srcs are combined and served using the
// specified Handler.
type Script struct {
	Handler *Handler
	Src     []string
	Async   bool
}

// HTML returns the <script> tag with the appropriate attributes.
func (l *Script) HTML() (h.HTML, error) {
	url, err := l.Handler.URL(l.Src...)
	if err != nil {
		return nil, err
	}
	return &h.Script{
		Src:   url,
		Async: l.Async,
	}, nil
}

// Img provides a h.Img where the src is served using the specified Handler.
type Img struct {
	Handler *Handler
	ID      string
	Class   string
	Style   string
	Src     string
	Alt     string
}

// HTML returns the <img> tag with the appropriate attributes.
func (i *Img) HTML() (h.HTML, error) {
	src, err := i.Handler.URL(i.Src)
	if err != nil {
		return nil, err
	}
	return &h.Img{
		ID:    i.ID,
		Class: i.Class,
		Style: i.Style,
		Src:   src,
		Alt:   i.Alt,
	}, nil
}
<commit_msg>some more array use in decode<commit_after>// Package static provides go.h compatible hashed static assets. This allows
// for providing long lived cache headers for resources which change URLs as
// their content changes.
package static

import (
	"bytes"
	"crypto/md5"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"mime"
	"net/http"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/daaku/go.h"
)

const (
	maxAge  = time.Hour * 24 * 365 * 10
	hashLen = 8
)

var (
	errZeroNames = errors.New("static: zero names given")
	cacheControl = fmt.Sprintf("public, max-age=%d", int(maxAge.Seconds()))
)

func disableCaching(w http.ResponseWriter) {
	header := w.Header()
	header.Set("Cache-Control", "no-cache")
	header.Set("Pragma", "no-cache")
}

func notFound(w http.ResponseWriter) {
	disableCaching(w)
	w.WriteHeader(http.StatusNotFound)
	io.WriteString(w, http.StatusText(http.StatusNotFound))
}

func badRequest(w http.ResponseWriter) {
	disableCaching(w)
	w.WriteHeader(http.StatusBadRequest)
	io.WriteString(w, http.StatusText(http.StatusBadRequest))
}

type errInvalidURL string

func (e errInvalidURL) Error() string {
	return fmt.Sprintf("static: invalid URL %q", string(e))
}

// we drop base64 padding in our URLs
func dropPadding(s string) string {
	return strings.TrimRight(s, "=")
}

// so we only allocate these strings once
var paddings = [...]string{
	"=",
	"==",
	"===",
}

func addPadding(s string) string {
	if l := len(s) % 4; l > 0 {
		return s + paddings[3-l]
	}
	return s
}

type file struct {
	Name    string
	Content []byte
	Hash    string
}

func encode(files []*file) (string, error) {
	parts := make([][2]string, 0, len(files))
	for _, f := range files {
		parts = append(parts, [2]string{f.Name, f.Hash})
	}

	b, err := json.Marshal(parts)
	if err != nil {
		return "", errors.New("static: could not encode URL")
	}

	return dropPadding(base64.URLEncoding.EncodeToString(b)), nil
}

func decode(value string) ([]*file, error) {
	decoded, err := base64.URLEncoding.DecodeString(addPadding(value))
	if err != nil {
		return nil, errInvalidURL(value)
	}

	var parts [][2]string
	if err := json.NewDecoder(bytes.NewReader(decoded)).Decode(&parts); err != nil {
		return nil, errInvalidURL(value)
	}

	files := make([]*file, 0, len(parts))
	for _, part := range parts {
		if len(part) != 2 || part[0] == "" || part[1] == "" {
			return nil, errInvalidURL(value)
		}
		files = append(files, &file{
			Name: part[0],
			Hash: part[1],
		})
	}

	return files, nil
}

// Box is where the files are loaded from. Practically you'll probably want to
// use https://github.com/GeertJohan/go.rice.
type Box interface {
	Bytes(name string) ([]byte, error)
}

// Handler serves and provides URLs for static resources.
type Handler struct {
	Path string // Path at which Handler is configured.
	Box  Box    // Box of files to serve.

	mu    sync.RWMutex
	files map[string]*file
}

func (h *Handler) load(name string) (*file, error) {
	// fast path
	h.mu.RLock()
	f := h.files[name]
	h.mu.RUnlock()

	if f != nil {
		return f, nil
	}

	// slow path
	h.mu.Lock()
	defer h.mu.Unlock()

	// check again in case someone else populated it
	f = h.files[name]
	if f != nil {
		return f, nil
	}

	contents, err := h.Box.Bytes(name)
	if err != nil {
		return nil, err
	}

	hash := fmt.Sprintf("%x", md5.Sum(contents))
	f = &file{
		Name:    name,
		Content: contents,
		Hash:    hash[:hashLen],
	}
	if h.files == nil {
		h.files = make(map[string]*file)
	}
	h.files[name] = f

	return f, nil
}

// URL returns a hashed URL for all the given component names. It uses the
// extension of the first file as the extension for the generated URL.
func (h *Handler) URL(names ...string) (string, error) {
	if len(names) == 0 {
		return "", errZeroNames
	}

	var files []*file
	for _, name := range names {
		f, err := h.load(name)
		if err != nil {
			return "", err
		}
		files = append(files, f)
	}

	value, err := encode(files)
	if err != nil {
		return "", err
	}

	if ext := filepath.Ext(names[0]); ext != "" {
		value = value + ext
	}

	return path.Join(h.Path, value), nil
}

// ServeHTTP handles requests for hashed URLs.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	if !strings.HasPrefix(path, h.Path) {
		notFound(w)
		return
	}

	contentType := ""
	encoded := path[len(h.Path):]
	if ext := filepath.Ext(encoded); ext != "" {
		encoded = encoded[:len(encoded)-len(ext)]
		contentType = mime.TypeByExtension(ext)
	}

	files, err := decode(encoded)
	if err != nil {
		badRequest(w)
		return
	}

	// fill in the contents and calculate the length
	var contentLength int
	for i, f := range files {
		loaded, err := h.load(f.Name)
		if err != nil {
			notFound(w)
			return
		}
		if loaded.Hash != f.Hash {
			notFound(w)
			return
		}
		contentLength += len(loaded.Content)
		files[i] = loaded
	}

	header := w.Header()
	header.Set("Cache-Control", cacheControl)
	header.Set("Content-Length", strconv.Itoa(contentLength))
	if contentType != "" {
		header.Set("Content-Type", contentType)
	}

	for _, f := range files {
		w.Write(f.Content)
	}
}

// LinkStyle provides a h.LinkStyle where the HREFs are combined and served
// using the specified Handler.
type LinkStyle struct {
	Handler *Handler
	HREF    []string
}

// HTML returns the <link> tag with the appropriate attributes.
func (l *LinkStyle) HTML() (h.HTML, error) {
	url, err := l.Handler.URL(l.HREF...)
	if err != nil {
		return nil, err
	}
	return &h.LinkStyle{HREF: url}, nil
}

// Script provides a h.Script where the Srcs are combined and served using the
// specified Handler.
type Script struct {
	Handler *Handler
	Src     []string
	Async   bool
}

// HTML returns the <script> tag with the appropriate attributes.
func (l *Script) HTML() (h.HTML, error) {
	url, err := l.Handler.URL(l.Src...)
	if err != nil {
		return nil, err
	}
	return &h.Script{
		Src:   url,
		Async: l.Async,
	}, nil
}

// Img provides a h.Img where the src is served using the specified Handler.
type Img struct {
	Handler *Handler
	ID      string
	Class   string
	Style   string
	Src     string
	Alt     string
}

// HTML returns the <img> tag with the appropriate attributes.
func (i *Img) HTML() (h.HTML, error) {
	src, err := i.Handler.URL(i.Src)
	if err != nil {
		return nil, err
	}
	return &h.Img{
		ID:    i.ID,
		Class: i.Class,
		Style: i.Style,
		Src:   src,
		Alt:   i.Alt,
	}, nil
}
<|endoftext|>


<commit_before>package mesh

import (
	"fmt"
	"net"
)

// Status is our current state as a peer, as taken from a router.
// This is designed to be used as diagnostic information.
type Status struct {
	Protocol           string
	ProtocolMinVersion int
	ProtocolMaxVersion int
	Encryption         bool
	PeerDiscovery      bool
	Name               string
	NickName           string
	Port               int
	Peers              []PeerStatus
	UnicastRoutes      []unicastRouteStatus
	BroadcastRoutes    []broadcastRouteStatus
	Connections        []LocalConnectionStatus
	TerminationCount   int
	Targets            []string
	OverlayDiagnostics interface{}
	TrustedSubnets     []string
}

// NewStatus returns a Status object, taken as a snapshot from the router.
func NewStatus(router *Router) *Status {
	return &Status{
		Protocol:           Protocol,
		ProtocolMinVersion: ProtocolMinVersion,
		ProtocolMaxVersion: ProtocolMaxVersion,
		Encryption:         router.usingPassword(),
		PeerDiscovery:      router.PeerDiscovery,
		Name:               router.Ourself.Name.String(),
		NickName:           router.Ourself.NickName,
		Port:               router.Port,
		Peers:              makePeerStatusSlice(router.Peers),
		UnicastRoutes:      makeUnicastRouteStatusSlice(router.Routes),
		BroadcastRoutes:    makeBroadcastRouteStatusSlice(router.Routes),
		Connections:        makeLocalConnectionStatusSlice(router.ConnectionMaker),
		TerminationCount:   router.ConnectionMaker.terminationCount,
		Targets:            router.ConnectionMaker.Targets(false),
		OverlayDiagnostics: router.Overlay.Diagnostics(),
		TrustedSubnets:     makeTrustedSubnetsSlice(router.TrustedSubnets),
	}
}

// PeerStatus is the current state of a peer in the mesh.
type PeerStatus struct {
	Name        string
	NickName    string
	UID         PeerUID
	ShortID     PeerShortID
	Version     uint64
	Connections []connectionStatus
}

// makePeerStatusSlice takes a snapshot of the state of peers.
func makePeerStatusSlice(peers *Peers) []PeerStatus {
	var slice []PeerStatus

	peers.forEach(func(peer *Peer) {
		var connections []connectionStatus
		if peer == peers.ourself.Peer {
			for conn := range peers.ourself.getConnections() {
				connections = append(connections, makeConnectionStatus(conn))
			}
		} else {
			// Modifying peer.connections requires a write lock on
			// Peers, and since we are holding a read lock (due to the
			// ForEach), access without locking the peer is safe.
			for _, conn := range peer.connections {
				connections = append(connections, makeConnectionStatus(conn))
			}
		}
		slice = append(slice, PeerStatus{
			peer.Name.String(),
			peer.NickName,
			peer.UID,
			peer.ShortID,
			peer.Version,
			connections,
		})
	})

	return slice
}

type connectionStatus struct {
	Name        string
	NickName    string
	Address     string
	Outbound    bool
	Established bool
}

func makeConnectionStatus(c Connection) connectionStatus {
	return connectionStatus{
		Name:        c.Remote().Name.String(),
		NickName:    c.Remote().NickName,
		Address:     c.remoteTCPAddress(),
		Outbound:    c.isOutbound(),
		Established: c.isEstablished(),
	}
}

// unicastRouteStatus is the current state of an established unicast route.
type unicastRouteStatus struct {
	Dest, Via string
}

// makeUnicastRouteStatusSlice takes a snapshot of the unicast routes in routes.
func makeUnicastRouteStatusSlice(r *routes) []unicastRouteStatus {
	r.RLock()
	defer r.RUnlock()

	var slice []unicastRouteStatus
	for dest, via := range r.unicast {
		slice = append(slice, unicastRouteStatus{dest.String(), via.String()})
	}
	return slice
}

// BroadcastRouteStatus is the current state of an established broadcast route.
type broadcastRouteStatus struct {
	Source string
	Via    []string
}

// makeBroadcastRouteStatusSlice takes a snapshot of the broadcast routes in routes.
func makeBroadcastRouteStatusSlice(r *routes) []broadcastRouteStatus {
	r.RLock()
	defer r.RUnlock()

	var slice []broadcastRouteStatus
	for source, via := range r.broadcast {
		var hops []string
		for _, hop := range via {
			hops = append(hops, hop.String())
		}
		slice = append(slice, broadcastRouteStatus{source.String(), hops})
	}
	return slice
}

// LocalConnectionStatus is the current state of a physical connection to a peer.
type LocalConnectionStatus struct {
	Address  string
	Outbound bool
	State    string
	Info     string
	Attrs    map[string]interface{}
}

// makeLocalConnectionStatusSlice takes a snapshot of the active local
// connections in the ConnectionMaker.
func makeLocalConnectionStatusSlice(cm *connectionMaker) []LocalConnectionStatus {
	resultChan := make(chan []LocalConnectionStatus)
	cm.actionChan <- func() bool {
		var slice []LocalConnectionStatus
		for conn := range cm.connections {
			state := "pending"
			if conn.isEstablished() {
				state = "established"
			}
			lc, _ := conn.(*LocalConnection)
			attrs := lc.OverlayConn.Attrs()
			name, ok := attrs["name"]
			if !ok {
				name = "none"
			}
			info := fmt.Sprintf("%-6v %v", name, conn.Remote())
			if lc.router.usingPassword() {
				if lc.untrusted() {
					info = fmt.Sprintf("%-11v %v", "encrypted", info)
				} else {
					info = fmt.Sprintf("%-11v %v", "unencrypted", info)
				}
			}
			slice = append(slice, LocalConnectionStatus{conn.remoteTCPAddress(), conn.isOutbound(), state, info, attrs})
		}
		for address, target := range cm.targets {
			add := func(state, info string) {
				slice = append(slice, LocalConnectionStatus{address, true, state, info, nil})
			}
			switch target.state {
			case targetWaiting:
				until := "never"
				if !target.tryAfter.IsZero() {
					until = target.tryAfter.String()
				}
				if target.lastError == nil { // shouldn't happen
					add("waiting", "until: "+until)
				} else {
					add("failed", target.lastError.Error()+", retry: "+until)
				}
			case targetAttempting:
				if target.lastError == nil {
					add("connecting", "")
				} else {
					add("retrying", target.lastError.Error())
				}
			case targetConnected:
			case targetSuspended:
			}
		}
		resultChan <- slice
		return false
	}
	return <-resultChan
}

// makeTrustedSubnetsSlice makes a human-readable copy of the trustedSubnets.
func makeTrustedSubnetsSlice(trustedSubnets []*net.IPNet) []string {
	trustedSubnetStrs := []string{}
	for _, trustedSubnet := range trustedSubnets {
		trustedSubnetStrs = append(trustedSubnetStrs, trustedSubnet.String())
	}
	return trustedSubnetStrs
}
<commit_msg>Add 'encrypted' flag to connection attributes<commit_after>package mesh

import (
	"fmt"
	"net"
)

// Status is our current state as a peer, as taken from a router.
// This is designed to be used as diagnostic information.
type Status struct {
	Protocol           string
	ProtocolMinVersion int
	ProtocolMaxVersion int
	Encryption         bool
	PeerDiscovery      bool
	Name               string
	NickName           string
	Port               int
	Peers              []PeerStatus
	UnicastRoutes      []unicastRouteStatus
	BroadcastRoutes    []broadcastRouteStatus
	Connections        []LocalConnectionStatus
	TerminationCount   int
	Targets            []string
	OverlayDiagnostics interface{}
	TrustedSubnets     []string
}

// NewStatus returns a Status object, taken as a snapshot from the router.
func NewStatus(router *Router) *Status {
	return &Status{
		Protocol:           Protocol,
		ProtocolMinVersion: ProtocolMinVersion,
		ProtocolMaxVersion: ProtocolMaxVersion,
		Encryption:         router.usingPassword(),
		PeerDiscovery:      router.PeerDiscovery,
		Name:               router.Ourself.Name.String(),
		NickName:           router.Ourself.NickName,
		Port:               router.Port,
		Peers:              makePeerStatusSlice(router.Peers),
		UnicastRoutes:      makeUnicastRouteStatusSlice(router.Routes),
		BroadcastRoutes:    makeBroadcastRouteStatusSlice(router.Routes),
		Connections:        makeLocalConnectionStatusSlice(router.ConnectionMaker),
		TerminationCount:   router.ConnectionMaker.terminationCount,
		Targets:            router.ConnectionMaker.Targets(false),
		OverlayDiagnostics: router.Overlay.Diagnostics(),
		TrustedSubnets:     makeTrustedSubnetsSlice(router.TrustedSubnets),
	}
}

// PeerStatus is the current state of a peer in the mesh.
type PeerStatus struct {
	Name        string
	NickName    string
	UID         PeerUID
	ShortID     PeerShortID
	Version     uint64
	Connections []connectionStatus
}

// makePeerStatusSlice takes a snapshot of the state of peers.
func makePeerStatusSlice(peers *Peers) []PeerStatus {
	var slice []PeerStatus

	peers.forEach(func(peer *Peer) {
		var connections []connectionStatus
		if peer == peers.ourself.Peer {
			for conn := range peers.ourself.getConnections() {
				connections = append(connections, makeConnectionStatus(conn))
			}
		} else {
			// Modifying peer.connections requires a write lock on
			// Peers, and since we are holding a read lock (due to the
			// ForEach), access without locking the peer is safe.
			for _, conn := range peer.connections {
				connections = append(connections, makeConnectionStatus(conn))
			}
		}
		slice = append(slice, PeerStatus{
			peer.Name.String(),
			peer.NickName,
			peer.UID,
			peer.ShortID,
			peer.Version,
			connections,
		})
	})

	return slice
}

type connectionStatus struct {
	Name        string
	NickName    string
	Address     string
	Outbound    bool
	Established bool
}

func makeConnectionStatus(c Connection) connectionStatus {
	return connectionStatus{
		Name:        c.Remote().Name.String(),
		NickName:    c.Remote().NickName,
		Address:     c.remoteTCPAddress(),
		Outbound:    c.isOutbound(),
		Established: c.isEstablished(),
	}
}

// unicastRouteStatus is the current state of an established unicast route.
type unicastRouteStatus struct {
	Dest, Via string
}

// makeUnicastRouteStatusSlice takes a snapshot of the unicast routes in routes.
func makeUnicastRouteStatusSlice(r *routes) []unicastRouteStatus {
	r.RLock()
	defer r.RUnlock()

	var slice []unicastRouteStatus
	for dest, via := range r.unicast {
		slice = append(slice, unicastRouteStatus{dest.String(), via.String()})
	}
	return slice
}

// BroadcastRouteStatus is the current state of an established broadcast route.
type broadcastRouteStatus struct {
	Source string
	Via    []string
}

// makeBroadcastRouteStatusSlice takes a snapshot of the broadcast routes in routes.
func makeBroadcastRouteStatusSlice(r *routes) []broadcastRouteStatus {
	r.RLock()
	defer r.RUnlock()

	var slice []broadcastRouteStatus
	for source, via := range r.broadcast {
		var hops []string
		for _, hop := range via {
			hops = append(hops, hop.String())
		}
		slice = append(slice, broadcastRouteStatus{source.String(), hops})
	}
	return slice
}

// LocalConnectionStatus is the current state of a physical connection to a peer.
type LocalConnectionStatus struct {
	Address  string
	Outbound bool
	State    string
	Info     string
	Attrs    map[string]interface{}
}

// makeLocalConnectionStatusSlice takes a snapshot of the active local
// connections in the ConnectionMaker.
func makeLocalConnectionStatusSlice(cm *connectionMaker) []LocalConnectionStatus {
	resultChan := make(chan []LocalConnectionStatus)
	cm.actionChan <- func() bool {
		var slice []LocalConnectionStatus
		for conn := range cm.connections {
			state := "pending"
			if conn.isEstablished() {
				state = "established"
			}
			lc, _ := conn.(*LocalConnection)
			attrs := lc.OverlayConn.Attrs()
			name, ok := attrs["name"]
			if !ok {
				name = "none"
			}
			info := fmt.Sprintf("%-6v %v", name, conn.Remote())
			if lc.router.usingPassword() {
				if lc.untrusted() {
					info = fmt.Sprintf("%-11v %v", "encrypted", info)
					attrs["encrypted"] = true
				} else {
					info = fmt.Sprintf("%-11v %v", "unencrypted", info)
				}
			}
			slice = append(slice, LocalConnectionStatus{conn.remoteTCPAddress(), conn.isOutbound(), state, info, attrs})
		}
		for address, target := range cm.targets {
			add := func(state, info string) {
				slice = append(slice, LocalConnectionStatus{address, true, state, info, nil})
			}
			switch target.state {
			case targetWaiting:
				until := "never"
				if !target.tryAfter.IsZero() {
					until = target.tryAfter.String()
				}
				if target.lastError == nil { // shouldn't happen
					add("waiting", "until: "+until)
				} else {
					add("failed", target.lastError.Error()+", retry: "+until)
				}
			case targetAttempting:
				if target.lastError == nil {
					add("connecting", "")
				} else {
					add("retrying", target.lastError.Error())
				}
			case targetConnected:
			case targetSuspended:
			}
		}
		resultChan <- slice
		return false
	}
	return <-resultChan
}

// makeTrustedSubnetsSlice makes a human-readable copy of the trustedSubnets.
func makeTrustedSubnetsSlice(trustedSubnets []*net.IPNet) []string {
	trustedSubnetStrs := []string{}
	for _, trustedSubnet := range trustedSubnets {
		trustedSubnetStrs = append(trustedSubnetStrs, trustedSubnet.String())
	}
	return trustedSubnetStrs
}
<|endoftext|>


<commit_before>/* status.dat handling */

package nagios

import (
	"bufio"
	"io"
	"regexp"
)

var blockStartRegex = regexp.MustCompile(`^(contactstatus|hoststatus|info|programstatus|servicecomment|servicestatus)\s\{`)
var blockEndRegex = regexp.MustCompile(`^\s}$`)
var kvRegex = regexp.MustCompile(`^\s*(\S+?)=(.*)$`)

type Status struct {
	Host    map[string]Host `json:"host,omitempty"`
	Service map[string]map[string]Service `json:"service,omitempty"`
}

func LoadStatus(r io.Reader) Status {
	scanner := bufio.NewScanner(r)
	var status Status
	status.Host = make(map[string]Host)
	status.Service = make(map[string]map[string]Service)
	block_type := ""
	block_content := make(map[string]string)
	for scanner.Scan() {
		t := scanner.Text()
		match := blockStartRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_type = match[1]
			continue
		}
		match = kvRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_content[match[1]] = match[2]
			continue
		}
		if blockEndRegex.MatchString(t) {
			if block_type == "servicestatus" {
				s, err := NewServiceFromMap(block_content)
				if err == nil {
					if status.Service[s.Hostname] == nil {
						status.Service[s.Hostname] = make(map[string]Service)
					}
					status.Service[s.Hostname][s.Description] = s

				}

			} else if block_type == "hoststatus" {
				h, err := NewHostFromMap(block_content)
				if err == nil {
					status.Host[h.Hostname] = h
				}

			}
			//end of block summary ,cleanup vars
			block_type = ""
			block_content = make(map[string]string)
			continue
		}
	}
	_ = block_type
	return status
}
<commit_msg>add locking<commit_after>/* status.dat handling */

package nagios

import (
	"bufio"
	"io"
	"regexp"
	"sync"
)

var blockStartRegex = regexp.MustCompile(`^(contactstatus|hoststatus|info|programstatus|servicecomment|servicestatus)\s\{`)
var blockEndRegex = regexp.MustCompile(`^\s}$`)
var kvRegex = regexp.MustCompile(`^\s*(\S+?)=(.*)$`)

type Status struct {
	Host    map[string]Host               `json:"host,omitempty"`
	Service map[string]map[string]Service `json:"service,omitempty"`
	sync.RWMutex
}

func LoadStatus(r io.Reader) Status {
	scanner := bufio.NewScanner(r)
	var status Status
	status.Host = make(map[string]Host)
	status.Service = make(map[string]map[string]Service)
	block_type := ""
	block_content := make(map[string]string)
	for scanner.Scan() {
		t := scanner.Text()
		match := blockStartRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_type = match[1]
			continue
		}
		match = kvRegex.FindStringSubmatch(t)
		if len(match) > 1 {
			block_content[match[1]] = match[2]
			continue
		}
		if blockEndRegex.MatchString(t) {
			if block_type == "servicestatus" {
				s, err := NewServiceFromMap(block_content)
				if err == nil {
					if status.Service[s.Hostname] == nil {
						status.Service[s.Hostname] = make(map[string]Service)
					}
					status.Service[s.Hostname][s.Description] = s

				}

			} else if block_type == "hoststatus" {
				h, err := NewHostFromMap(block_content)
				if err == nil {
					status.Host[h.Hostname] = h
				}

			}
			//end of block summary ,cleanup vars
			block_type = ""
			block_content = make(map[string]string)
			continue
		}
	}
	_ = block_type
	return status
}

func (s *Status)UpdateStatus(r io.Reader) {
	status := LoadStatus(r);
	s.Lock()
	s.Host = status.Host
	s.Service = status.Service
	s.Unlock()
}
<|endoftext|>


<commit_before>package stream

import (
	"bufio"
	"github.com/diggs/glog"
	"math"
	"net/http"
	"time"
)

/**
TODO:
Fix up close
Code clean up
Args for headers and SSL
Tests
**/

const (
	STREAM_INACTIVITY_TIMEOUT_SECONDS int = 90
)

type httpStream struct {
	Url               string
	Data              chan []byte
	Exit              chan bool
	tcpErrCount       int
	httpErrCount      int
	httpThrottleCount int
}

func (s *httpStream) Connect() error {
	go s.enterStreamLoop()
	return nil
}

func (s *httpStream) Close() {
	s.Exit <- true
}

func (s *httpStream) connect() (*http.Response, error) {

	glog.Debugf("Establishing connection to %s...", s.Url)

	client := &http.Client{}

	req, err := http.NewRequest("GET", s.Url, nil)
	if err != nil {
		return nil, err
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (s *httpStream) enterStreamLoop() {

	glog.Debug("Entering stream loop...")
	for {
		select {
		case <-s.Exit:
			glog.Debug("Exit signalled; leaving stream loop.")
			return
		default:
			resp, err := s.connect()
			// TODO Differentiate between transient tcp/ip errors and fatal errors (such as malformed url etc.)
			if err != nil {
				glog.Debugf("Encountered error establishing connection: %v", err)
				s.tcpErrCount++
				// Backoff linearly, starting at 250ms, capping at 16 seconds
				backoff := s.tcpErrCount * 250
				if backoff > 16000 {
					backoff = 16000
				}
				glog.Debugf("Backing off %d milliseconds", backoff)
				time.Sleep(time.Duration(backoff) * time.Millisecond)
				continue
			}

			switch resp.StatusCode {
			case 200, 304:
				// Successful connection, start reading lines...
				glog.Debug("Connection established...")
				s.tcpErrCount = 0
				s.httpErrCount = 0
				s.httpThrottleCount = 0
				s.enterReadLineLoop(resp)
			case 420:
				// Back off exponentially, starting at 1 minute, with no cap
				glog.Debug("Encountered 420 backoff code")
				backoff := int(math.Pow(2, float64(s.httpThrottleCount)))
				glog.Debugf("Backing off %d minute(s)", backoff)
				s.httpThrottleCount++
				time.Sleep(time.Duration(backoff) * time.Minute)
			default:
				// TODO: Fatal errors... 401 etc.
				// Back off exponentially, starting at 5 seconds, capping at 320 seconds
				glog.Debugf("Encountered %d status code", resp.StatusCode)
				backoff := int(math.Pow(2, float64(s.httpErrCount)) * 5)
				if backoff > 320 {
					backoff = 320
				}
				s.httpErrCount++
				glog.Debugf("Backing off %d second(s)", backoff)
				time.Sleep(time.Duration(backoff) * time.Second)
			}
			resp.Body.Close()
		}
	}
}

func (s *httpStream) enterReadLineLoop(resp *http.Response) {

	glog.Debug("Entering read line loop...")

	scanner := bufio.NewScanner(resp.Body)
	for {
		select {
		case <-s.Exit:
			glog.Debug("Exit signalled; leaving readLine loop.")
			return
		default:
			lineCh, errCh := s.readLine(resp, scanner)
			select {
			case err := <-errCh:
				glog.Debugf("Stream error; leaving readLine loop: %v", err)
				return
			case data := <-lineCh:
				glog.Debugf("Read line from stream: %d bytes.", len(data))
				if len(data) > 0 { // drop empty heartbeat lines
					s.Data <- data
				}
			case <-time.After(time.Duration(STREAM_INACTIVITY_TIMEOUT_SECONDS) * time.Second):
				glog.Debugf("Stream inactive for %d seconds; leaving readLine loop.", STREAM_INACTIVITY_TIMEOUT_SECONDS)
				return
			}
		}
	}
}

func (s *httpStream) readLine(resp *http.Response, scanner *bufio.Scanner) (chan []byte, chan error) {
	glog.Debug("Scanning for line...")
	lineCh := make(chan []byte)
	errCh := make(chan error)
	go func() {
		if ok := scanner.Scan(); !ok {
			errCh <- scanner.Err()
			return
		}
		lineCh <- scanner.Bytes()[:]
	}()
	return lineCh, errCh
}

func NewStream(url string, autoConnect bool) *httpStream {
	s := httpStream{}
	s.Url = url
	s.Data = make(chan []byte)
	s.Exit = make(chan bool)
	if autoConnect {
		s.Connect()
	}
	return &s
}
<commit_msg>Use backoff logic from external lib<commit_after>package stream

import (
	"bufio"
	"github.com/diggs/glog"
	"github.com/diggs/go-backoff"
	"net/http"
	"time"
)

/**
TODO:
Fix up close
Args for headers and SSL
Tests
**/

const (
	STREAM_INACTIVITY_TIMEOUT_SECONDS int = 90
)

type httpStream struct {
	Url               string
	Data              chan []byte
	Exit              chan bool
	tcpBackoff       *backoff.Linear
	httpBackoff       *backoff.Exponential
	httpThrottleBackoff *backoff.Exponential
}

func (s *httpStream) Connect() error {
	go s.enterReadStreamLoop()
	return nil
}

func (s *httpStream) Close() {
	s.Exit <- true
}

func (s *httpStream) resetBackoffs() {
	s.tcpBackoff.Reset()
	s.httpBackoff.Reset()
	s.httpThrottleBackoff.Reset()
}

func (s *httpStream) connect() (*http.Response, error) {

	glog.Debugf("Establishing connection to %s...", s.Url)

	client := &http.Client{}

	req, err := http.NewRequest("GET", s.Url, nil)
	if err != nil {
		return nil, err
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

func (s *httpStream) enterReadStreamLoop() {

	glog.Debug("Entering read stream loop...")
	for {
		select {
		case <-s.Exit:
			glog.Debug("Exit signalled; leaving read stream loop.")
			return
		default:
			resp, err := s.connect()
  		// TODO Differentiate between transient tcp/ip errors and fatal errors (such as malformed url etc.)
      if err != nil {
        glog.Debugf("Encountered error establishing connection: %v", err)
        s.tcpBackoff.Backoff()
        glog.Debugf("Backed off %d milliseconds", s.tcpBackoff.LastWait / time.Millisecond)
        continue
      }

			switch resp.StatusCode {
			case 200, 304:
				glog.Debug("Connection established...")
				s.resetBackoffs()
				s.enterReadLineLoop(resp)
			case 420:
				glog.Debug("Encountered 420 backoff code")
				s.httpThrottleBackoff.Backoff()
				glog.Debugf("Backed off %d minute(s)", s.httpThrottleBackoff.LastWait / time.Minute)
			default:
				// TODO: Fatal errors... 401 etc.
				glog.Debugf("Encountered %d status code", resp.StatusCode)
				s.httpBackoff.Backoff()
				glog.Debugf("Backed off %d second(s)", s.httpBackoff.LastWait / time.Second)
			}
			resp.Body.Close()
		}
	}
}

func (s *httpStream) enterReadLineLoop(resp *http.Response) {

	glog.Debug("Entering read line loop...")

	scanner := bufio.NewScanner(resp.Body)
	for {
		select {
		case <-s.Exit:
			glog.Debug("Exit signalled; leaving readLine loop.")
			return
		default:
			lineCh, errCh := s.readLine(resp, scanner)
			select {
			case err := <-errCh:
				glog.Debugf("Stream error; leaving readLine loop: %v", err)
				return
			case data := <-lineCh:
				glog.Debugf("Read line from stream: %d bytes.", len(data))
				if len(data) > 0 { // drop empty heartbeat lines
					s.Data <- data
				}
			case <-time.After(time.Duration(STREAM_INACTIVITY_TIMEOUT_SECONDS) * time.Second):
				glog.Debugf("Stream inactive for %d seconds; leaving readLine loop.", STREAM_INACTIVITY_TIMEOUT_SECONDS)
				return
			}
		}
	}
}

func (s *httpStream) readLine(resp *http.Response, scanner *bufio.Scanner) (chan []byte, chan error) {
	glog.Debug("Scanning for line...")
	lineCh := make(chan []byte)
	errCh := make(chan error)
	go func() {
		if ok := scanner.Scan(); !ok {
			errCh <- scanner.Err()
			return
		}
		lineCh <- scanner.Bytes()[:]
	}()
	return lineCh, errCh
}

func NewStream(url string, autoConnect bool) *httpStream {
	s := httpStream{}
	s.Url = url
	s.Data = make(chan []byte)
	s.Exit = make(chan bool)
	// Back off linearly, starting at 250ms, capping at 16 seconds
	s.tcpBackoff = backoff.NewLinear(250 * time.Millisecond, 16 * time.Second)
	// Back off exponentially, starting at 5 seconds, capping at 320 seconds
	s.httpBackoff = backoff.NewExponential(5 * time.Second, 320 * time.Second)
	// Back off exponentially, starting at 1 minute, with no cap
	s.httpThrottleBackoff = backoff.NewExponential(time.Minute, 0)
	if autoConnect {
		s.Connect()
	}
	return &s
}
<|endoftext|>