<commit_before>package seven5

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
)

const (
	REDIRECT_HOST_TEST = "http://localhost:%d"
	HEROKU_HOST        = "https://%s.herokuapp.com"
	DEFAULT_TEST_PORT  = 3003
)

//RemoteDeployment is a very simple implementation of DeploymentEnvironment that knows the beginning of a
//remote url and uses the environment for knowing if we are running in test mode or not.
type RemoteDeployment struct {
	url      string
	isTest   bool
	testPort int
}

type HerokuDeploy struct {
	*EnvironmentVars
	name string
}

//NewHerokuDeploy returns a new HerokuDeploy object that implements DeploymentEnvironment.
func NewHerokuDeploy(herokuName string, localName string) *HerokuDeploy {
	result := &HerokuDeploy{
		EnvironmentVars: NewEnvironmentVars(localName),
		name:            herokuName,
	}
	return result
}

func (self *HerokuDeploy) GetQbsStore() *QbsStore {
	if self.IsTest() {
		return NewQbsStore(self.MustAppValue("TESTDBNAME"),
			self.MustAppValue("TESTDRIVER"), self)
	}
	db := os.Getenv("DATABASE_URL")
	if db == "" {
		panic("no DATABASE_URL found, cannot connect to a *QbsStore")
	}
	log.Printf("found a database:%s", db)
	pair := strings.SplitN(db, ":", 1)
	if len(pair) != 2 {
		panic(fmt.Sprintf("DATABASE_URL does not start with driver: %v", db))
	}
	log.Printf("pair %v %v", pair[0], pair[1])
	return NewQbsStore(pair[1], pair[0], self)
}

func (self *HerokuDeploy) IsTest() bool {
	t := self.GetAppValue("TEST")
	return t != ""
}

//Port reads the value of the environment variable PORT to get the value to return here.  It
//will panic if the environment variable is not set or it's not a number.
func (self *HerokuDeploy) Port() int {
	p := self.EnvironmentVars.GetValueOrPanic("PORT")
	i, err := strconv.Atoi(p)
	if err != nil {
		panic(err)
	}
	return i
}

//RedirectHost is needed in cases where you are using oauth because this must sent to the
//"other side" of the handshake without any extra knowlege.
func (self *HerokuDeploy) RedirectHost(string) string {
	if self.IsTest() {
		return fmt.Sprintf(REDIRECT_HOST_TEST, self.Port())
	}
	return HerokuName(self.name)

}

//NewRemoteDeployment returns an implementation of Deployment that points URLs to the fullUrl
//provided unless in test mode.  If testPort>0 then we are assumed to be in test mode.
func NewRemoteDeployment(fullUrl string, testPort int) *RemoteDeployment {
	return &RemoteDeployment{
		url:      fullUrl,
		isTest:   testPort > 1023,
		testPort: testPort,
	}
}

//HerokuName calculates the full url of a deployed Heroku app. Useful in conjunction with
//NewRemoteDeployment.
func HerokuName(n string) string {
	return fmt.Sprintf(HEROKU_HOST, n)
}

func (self *RemoteDeployment) IsTest() bool {
	return self.isTest
}
func (self *RemoteDeployment) Port() int {
	return self.testPort
}

func (self *RemoteDeployment) RedirectHost(string) string {
	if self.IsTest() {
		return fmt.Sprintf(REDIRECT_HOST_TEST, self.Port())
	}
	return self.url
}
<commit_msg>string manip bug<commit_after>package seven5

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
)

const (
	REDIRECT_HOST_TEST = "http://localhost:%d"
	HEROKU_HOST        = "https://%s.herokuapp.com"
	DEFAULT_TEST_PORT  = 3003
)

//RemoteDeployment is a very simple implementation of DeploymentEnvironment that knows the beginning of a
//remote url and uses the environment for knowing if we are running in test mode or not.
type RemoteDeployment struct {
	url      string
	isTest   bool
	testPort int
}

type HerokuDeploy struct {
	*EnvironmentVars
	name string
}

//NewHerokuDeploy returns a new HerokuDeploy object that implements DeploymentEnvironment.
func NewHerokuDeploy(herokuName string, localName string) *HerokuDeploy {
	result := &HerokuDeploy{
		EnvironmentVars: NewEnvironmentVars(localName),
		name:            herokuName,
	}
	return result
}

func (self *HerokuDeploy) GetQbsStore() *QbsStore {
	if self.IsTest() {
		return NewQbsStore(self.MustAppValue("TESTDBNAME"),
			self.MustAppValue("TESTDRIVER"), self)
	}
	db := os.Getenv("DATABASE_URL")
	if db == "" {
		panic("no DATABASE_URL found, cannot connect to a *QbsStore")
	}
	log.Printf("found a database:%s", db)
	pair := strings.SplitN(db, ":", 2)
	if len(pair) != 2 {
		panic(fmt.Sprintf("DATABASE_URL does not start with driver: %v", db))
	}
	log.Printf("pair %v %v", pair[0], pair[1])
	return NewQbsStore(pair[1], pair[0], self)
}

func (self *HerokuDeploy) IsTest() bool {
	t := self.GetAppValue("TEST")
	return t != ""
}

//Port reads the value of the environment variable PORT to get the value to return here.  It
//will panic if the environment variable is not set or it's not a number.
func (self *HerokuDeploy) Port() int {
	p := self.EnvironmentVars.GetValueOrPanic("PORT")
	i, err := strconv.Atoi(p)
	if err != nil {
		panic(err)
	}
	return i
}

//RedirectHost is needed in cases where you are using oauth because this must sent to the
//"other side" of the handshake without any extra knowlege.
func (self *HerokuDeploy) RedirectHost(string) string {
	if self.IsTest() {
		return fmt.Sprintf(REDIRECT_HOST_TEST, self.Port())
	}
	return HerokuName(self.name)

}

//NewRemoteDeployment returns an implementation of Deployment that points URLs to the fullUrl
//provided unless in test mode.  If testPort>0 then we are assumed to be in test mode.
func NewRemoteDeployment(fullUrl string, testPort int) *RemoteDeployment {
	return &RemoteDeployment{
		url:      fullUrl,
		isTest:   testPort > 1023,
		testPort: testPort,
	}
}

//HerokuName calculates the full url of a deployed Heroku app. Useful in conjunction with
//NewRemoteDeployment.
func HerokuName(n string) string {
	return fmt.Sprintf(HEROKU_HOST, n)
}

func (self *RemoteDeployment) IsTest() bool {
	return self.isTest
}
func (self *RemoteDeployment) Port() int {
	return self.testPort
}

func (self *RemoteDeployment) RedirectHost(string) string {
	if self.IsTest() {
		return fmt.Sprintf(REDIRECT_HOST_TEST, self.Port())
	}
	return self.url
}
<|endoftext|>


<commit_before>package deploy

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/github/hub/git"
	hub "github.com/remind101/deploy/Godeps/_workspace/src/github.com/github/hub/github"
	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/google/go-github/github"
)

const (
	Name  = "deploy"
	Usage = "A command for creating GitHub deployments"
)

const (
	DefaultRef     = "master"
	DefaultTimeout = 20 * time.Second
)

var errTimeout = errors.New("Timed out waiting for build to start. Did you add a webhook to handle deployment events?")

func init() {
	cli.AppHelpTemplate = `USAGE:
   # Deploy the master branch of remind101/acme-inc to staging
   {{.Name}} --env=staging --ref=master remind101/acme-inc

   # Deploy HEAD of the current branch to staging
   {{.Name}} --env=staging remind101/acme-inc

   # Deploy the current GitHub repo to staging
   {{.Name}} --env=staging
{{if .Flags}}
OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}{{end}}
`
}

var flags = []cli.Flag{
	cli.StringFlag{
		Name:  "ref, branch, commit, tag",
		Value: "",
		Usage: "The git ref to deploy. Can be a git commit, branch or tag.",
	},
	cli.StringFlag{
		Name:  "env, e",
		Value: "",
		Usage: "The environment to deploy to.",
	},
	cli.BoolFlag{
		Name:  "force, f",
		Usage: "Ignore commit status checks.",
	},
	cli.BoolFlag{
		Name:  "detached, d",
		Usage: "Don't wait for the deployment to complete.",
	},
	cli.BoolFlag{
		Name:  "quiet, q",
		Usage: "Silence any output to STDOUT.",
	},
	cli.BoolFlag{
		Name:  "update, u",
		Usage: "Update the binary",
	},
}

var ProtectedEnvironments = map[string]bool{
	"production": true,
	"prod":       true,
}

// NewApp returns a new cli.App for the deploy command.
func NewApp() *cli.App {
	app := cli.NewApp()
	app.Version = Version
	app.Name = Name
	app.Usage = Usage
	app.Flags = flags
	app.Action = func(c *cli.Context) {
		if c.Bool("update") {
			updater := NewUpdater()
			if err := updater.Update(); err != nil {
				fmt.Println(err)
				os.Exit(-1)
			} else {
				os.Exit(0)
			}
		}

		if err := RunDeploy(c); err != nil {
			msg := err.Error()
			if err, ok := err.(*github.ErrorResponse); ok {
				if strings.HasPrefix(err.Message, "Conflict: Commit status checks failed for") {
					msg = "Commit status checks failed. You can bypass commit status checks with the --force flag."
				} else if strings.HasPrefix(err.Message, "No ref found for") {
					msg = fmt.Sprintf("%s. Did you push it to GitHub?", err.Message)
				} else {
					msg = err.Message
				}
			}

			fmt.Println(msg)
			os.Exit(-1)
		}
	}

	return app
}

// RunDeploy performs a deploy.
func RunDeploy(c *cli.Context) error {
	var w io.Writer
	if c.Bool("quiet") {
		w = ioutil.Discard
	} else {
		w = c.App.Writer
	}

	h, err := hub.CurrentConfig().PromptForHost("github.com")
	if err != nil {
		return err
	}

	client, err := newGitHubClient(h)
	if err != nil {
		return err
	}

	nwo, err := Repo(c.Args())
	if err != nil {
		return err
	}

	owner, repo, err := SplitRepo(nwo, os.Getenv("GITHUB_ORGANIZATION"))
	if err != nil {
		return fmt.Errorf("Invalid GitHub repo: %s", nwo)
	}

	err = displayNewCommits(owner, repo, c, client)
	if err != nil {
		return err
	}

	r, err := newDeploymentRequest(c)
	if err != nil {
		return err
	}

	fmt.Fprintf(w, "Deploying %s/%s@%s to %s...\n", owner, repo, *r.Ref, *r.Environment)

	if c.Bool("detached") {
		return nil
	}

	d, _, err := client.Repositories.CreateDeployment(owner, repo, r)
	if err != nil {
		return err
	}

	started := make(chan *github.DeploymentStatus)
	completed := make(chan *github.DeploymentStatus)

	go func() {
		started <- waitState(pendingStates, owner, repo, *d.ID, client)
	}()

	go func() {
		completed <- waitState(completedStates, owner, repo, *d.ID, client)
	}()

	select {
	case <-time.After(DefaultTimeout):
		return errTimeout
	case status := <-started:
		var url string
		if status.TargetURL != nil {
			url = *status.TargetURL
		}
		fmt.Fprintf(w, "%s\n", url)
	}

	status := <-completed

	if isFailed(*status.State) {
		return errors.New("Failed to deploy")
	}

	return nil
}

func displayNewCommits(owner string, repo string, c *cli.Context, client *github.Client) error {
	ref := Ref(c.String("ref"), git.Head)

	opt := &github.DeploymentsListOptions{
		Environment: c.String("env"),
	}

	deployments, _, err := client.Repositories.ListDeployments(owner, repo, opt)
	if err != nil {
		return err
	}
	if len(deployments) == 0 {
		return nil
	}

	sha := *deployments[0].SHA
	compare, _, err := client.Repositories.CompareCommits(owner, repo, sha, ref)
	if err != nil {
		return err
	}
	if len(compare.Commits) == 0 {
		return nil
	}

	fmt.Println("Deploying the following commits:\n")
	for _, commit := range compare.Commits {
		message := *commit.Commit.Message
		fmt.Printf("%-20s\t%s\n", *commit.Commit.Author.Name, strings.Split(message, "\n")[0])
	}
	fmt.Printf("\nSee entire diff here: https://github.com/%s/%s/compare/%s...%s\n\n", owner, repo, sha, ref)
	return nil
}

func newDeploymentRequest(c *cli.Context) (*github.DeploymentRequest, error) {
	ref := Ref(c.String("ref"), git.Head)

	env := c.String("env")
	if env == "" {
		return nil, fmt.Errorf("--env flag is required")
	}

	if ProtectedEnvironments[env] {
		yes := askYN(fmt.Sprintf("Are you sure you want to deploy %s to %s?", ref, env))
		if !yes {
			return nil, fmt.Errorf("Deployment aborted.")
		}
	}

	var contexts *[]string
	if c.Bool("force") {
		s := []string{}
		contexts = &s
	}

	return &github.DeploymentRequest{
		Ref:              github.String(ref),
		Task:             github.String("deploy"),
		AutoMerge:        github.Bool(false),
		Environment:      github.String(env),
		RequiredContexts: contexts,
		Payload: map[string]interface{}{
			"force": c.Bool("force"),
		},
		// TODO Description:
	}, nil
}

var (
	pendingStates   = []string{"pending"}
	completedStates = []string{"success", "error", "failure"}
)

func isFailed(state string) bool {
	return state == "error" || state == "failure"
}

// waitState waits for a deployment status that matches the given states, then
// sends on the returned channel.
func waitState(states []string, owner, repo string, deploymentID int, c *github.Client) *github.DeploymentStatus {
	for {
		<-time.After(1 * time.Second)

		statuses, _, err := c.Repositories.ListDeploymentStatuses(owner, repo, deploymentID, nil)
		if err != nil {
			continue
		}

		status := firstStatus(states, statuses)
		if status != nil {
			return status
		}
	}
}

// firstStatus takes a slice of github.DeploymentStatus and returns the
// first status that matches the provided slice of states.
func firstStatus(states []string, statuses []github.DeploymentStatus) *github.DeploymentStatus {
	for _, ds := range statuses {
		for _, s := range states {
			if ds.State != nil && *ds.State == s {
				return &ds
			}
		}
	}

	return nil
}

// refRegex is a regular expression that matches a full git HEAD ref.
var refRegex = regexp.MustCompile(`^refs/heads/(.*)$`)

// Ref attempts to return the proper git ref to deploy. If a ref is provided,
// that will be returned. If not, it will fallback to calling headFunc. If an
// error is returned (not in a git repo), then it will fallback to DefaultRef.
func Ref(ref string, headFunc func() (string, error)) string {
	if ref != "" {
		return ref
	}

	ref, err := headFunc()
	if err != nil {
		// An error means that we're either not in a GitRepo or we're
		// not on a branch. In this case, we just fallback to the
		// DefaultRef.
		return DefaultRef
	}

	// Convert `refs/heads/test-deploy` => `test-deploy`
	return refRegex.ReplaceAllString(ref, "$1")
}

// Repo will determine the correct GitHub repo to deploy to, based on a set of
// arguments.
func Repo(arguments []string) (string, error) {
	if len(arguments) != 0 {
		return arguments[0], nil
	}

	remotes, err := hub.Remotes()
	if err != nil {
		return "", err
	}

	repo := GitHubRepo(remotes)
	if repo == "" {
		return repo, errors.New("no GitHub repo found in .git/config")
	}

	return repo, nil
}

// A regular expression that can convert a URL.Path into a GitHub repo name.
var remoteRegex = regexp.MustCompile(`^/(.*)\.git$`)

// GitHubRepo, given a list of git remotes, will determine what the GitHub repo
// is.
func GitHubRepo(remotes []hub.Remote) string {
	// We only want to look at the `origin` remote.
	remote := findRemote("origin", remotes)
	if remote == nil {
		return ""
	}

	// Remotes that are not pointed at a GitHub repo are not valid.
	if remote.URL.Host != "github.com" {
		return ""
	}

	// Convert `/remind101/acme-inc.git` => `remind101/acme-inc`.
	return remoteRegex.ReplaceAllString(remote.URL.Path, "$1")
}

func findRemote(name string, remotes []hub.Remote) *hub.Remote {
	for _, r := range remotes {
		if r.Name == name {
			return &r
		}
	}

	return nil
}

var errInvalidRepo = errors.New("invalid repo")

// SplitRepo splits a repo string in the form remind101/acme-inc into it's owner
// and repo components.
func SplitRepo(nwo, defaultOrg string) (owner string, repo string, err error) {
	parts := strings.Split(nwo, "/")

	// If we were only given a repo name, and a default organization is set,
	// we'll use the defaultOrg as the owner.
	if len(parts) == 1 && defaultOrg != "" && parts[0] != "" {
		owner = defaultOrg
		repo = parts[0]
		return
	}

	if len(parts) != 2 {
		err = errInvalidRepo
		return
	}

	owner = parts[0]
	repo = parts[1]

	return
}

func askYN(prompt string) bool {
	r := bufio.NewReader(os.Stdin)
	fmt.Printf("%s (y/N)\n", prompt)
	a, _ := r.ReadString('\n')
	return strings.ToUpper(a) == "Y\n"
}
<commit_msg>Make go vet happy.<commit_after>package deploy

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/codegangsta/cli"
	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/github/hub/git"
	hub "github.com/remind101/deploy/Godeps/_workspace/src/github.com/github/hub/github"
	"github.com/remind101/deploy/Godeps/_workspace/src/github.com/google/go-github/github"
)

const (
	Name  = "deploy"
	Usage = "A command for creating GitHub deployments"
)

const (
	DefaultRef     = "master"
	DefaultTimeout = 20 * time.Second
)

var errTimeout = errors.New("Timed out waiting for build to start. Did you add a webhook to handle deployment events?")

func init() {
	cli.AppHelpTemplate = `USAGE:
   # Deploy the master branch of remind101/acme-inc to staging
   {{.Name}} --env=staging --ref=master remind101/acme-inc

   # Deploy HEAD of the current branch to staging
   {{.Name}} --env=staging remind101/acme-inc

   # Deploy the current GitHub repo to staging
   {{.Name}} --env=staging
{{if .Flags}}
OPTIONS:
   {{range .Flags}}{{.}}
   {{end}}{{end}}
`
}

var flags = []cli.Flag{
	cli.StringFlag{
		Name:  "ref, branch, commit, tag",
		Value: "",
		Usage: "The git ref to deploy. Can be a git commit, branch or tag.",
	},
	cli.StringFlag{
		Name:  "env, e",
		Value: "",
		Usage: "The environment to deploy to.",
	},
	cli.BoolFlag{
		Name:  "force, f",
		Usage: "Ignore commit status checks.",
	},
	cli.BoolFlag{
		Name:  "detached, d",
		Usage: "Don't wait for the deployment to complete.",
	},
	cli.BoolFlag{
		Name:  "quiet, q",
		Usage: "Silence any output to STDOUT.",
	},
	cli.BoolFlag{
		Name:  "update, u",
		Usage: "Update the binary",
	},
}

var ProtectedEnvironments = map[string]bool{
	"production": true,
	"prod":       true,
}

// NewApp returns a new cli.App for the deploy command.
func NewApp() *cli.App {
	app := cli.NewApp()
	app.Version = Version
	app.Name = Name
	app.Usage = Usage
	app.Flags = flags
	app.Action = func(c *cli.Context) {
		if c.Bool("update") {
			updater := NewUpdater()
			if err := updater.Update(); err != nil {
				fmt.Println(err)
				os.Exit(-1)
			} else {
				os.Exit(0)
			}
		}

		if err := RunDeploy(c); err != nil {
			msg := err.Error()
			if err, ok := err.(*github.ErrorResponse); ok {
				if strings.HasPrefix(err.Message, "Conflict: Commit status checks failed for") {
					msg = "Commit status checks failed. You can bypass commit status checks with the --force flag."
				} else if strings.HasPrefix(err.Message, "No ref found for") {
					msg = fmt.Sprintf("%s. Did you push it to GitHub?", err.Message)
				} else {
					msg = err.Message
				}
			}

			fmt.Println(msg)
			os.Exit(-1)
		}
	}

	return app
}

// RunDeploy performs a deploy.
func RunDeploy(c *cli.Context) error {
	var w io.Writer
	if c.Bool("quiet") {
		w = ioutil.Discard
	} else {
		w = c.App.Writer
	}

	h, err := hub.CurrentConfig().PromptForHost("github.com")
	if err != nil {
		return err
	}

	client, err := newGitHubClient(h)
	if err != nil {
		return err
	}

	nwo, err := Repo(c.Args())
	if err != nil {
		return err
	}

	owner, repo, err := SplitRepo(nwo, os.Getenv("GITHUB_ORGANIZATION"))
	if err != nil {
		return fmt.Errorf("Invalid GitHub repo: %s", nwo)
	}

	err = displayNewCommits(owner, repo, c, client)
	if err != nil {
		return err
	}

	r, err := newDeploymentRequest(c)
	if err != nil {
		return err
	}

	fmt.Fprintf(w, "Deploying %s/%s@%s to %s...\n", owner, repo, *r.Ref, *r.Environment)

	if c.Bool("detached") {
		return nil
	}

	d, _, err := client.Repositories.CreateDeployment(owner, repo, r)
	if err != nil {
		return err
	}

	started := make(chan *github.DeploymentStatus)
	completed := make(chan *github.DeploymentStatus)

	go func() {
		started <- waitState(pendingStates, owner, repo, *d.ID, client)
	}()

	go func() {
		completed <- waitState(completedStates, owner, repo, *d.ID, client)
	}()

	select {
	case <-time.After(DefaultTimeout):
		return errTimeout
	case status := <-started:
		var url string
		if status.TargetURL != nil {
			url = *status.TargetURL
		}
		fmt.Fprintf(w, "%s\n", url)
	}

	status := <-completed

	if isFailed(*status.State) {
		return errors.New("Failed to deploy")
	}

	return nil
}

func displayNewCommits(owner string, repo string, c *cli.Context, client *github.Client) error {
	ref := Ref(c.String("ref"), git.Head)

	opt := &github.DeploymentsListOptions{
		Environment: c.String("env"),
	}

	deployments, _, err := client.Repositories.ListDeployments(owner, repo, opt)
	if err != nil {
		return err
	}
	if len(deployments) == 0 {
		return nil
	}

	sha := *deployments[0].SHA
	compare, _, err := client.Repositories.CompareCommits(owner, repo, sha, ref)
	if err != nil {
		return err
	}
	if len(compare.Commits) == 0 {
		return nil
	}

	fmt.Printf("%s\n\n", "Deploying the following commits:")
	for _, commit := range compare.Commits {
		message := *commit.Commit.Message
		fmt.Printf("%-20s\t%s\n", *commit.Commit.Author.Name, strings.Split(message, "\n")[0])
	}
	fmt.Printf("\nSee entire diff here: https://github.com/%s/%s/compare/%s...%s\n\n", owner, repo, sha, ref)
	return nil
}

func newDeploymentRequest(c *cli.Context) (*github.DeploymentRequest, error) {
	ref := Ref(c.String("ref"), git.Head)

	env := c.String("env")
	if env == "" {
		return nil, fmt.Errorf("--env flag is required")
	}

	if ProtectedEnvironments[env] {
		yes := askYN(fmt.Sprintf("Are you sure you want to deploy %s to %s?", ref, env))
		if !yes {
			return nil, fmt.Errorf("Deployment aborted.")
		}
	}

	var contexts *[]string
	if c.Bool("force") {
		s := []string{}
		contexts = &s
	}

	return &github.DeploymentRequest{
		Ref:              github.String(ref),
		Task:             github.String("deploy"),
		AutoMerge:        github.Bool(false),
		Environment:      github.String(env),
		RequiredContexts: contexts,
		Payload: map[string]interface{}{
			"force": c.Bool("force"),
		},
		// TODO Description:
	}, nil
}

var (
	pendingStates   = []string{"pending"}
	completedStates = []string{"success", "error", "failure"}
)

func isFailed(state string) bool {
	return state == "error" || state == "failure"
}

// waitState waits for a deployment status that matches the given states, then
// sends on the returned channel.
func waitState(states []string, owner, repo string, deploymentID int, c *github.Client) *github.DeploymentStatus {
	for {
		<-time.After(1 * time.Second)

		statuses, _, err := c.Repositories.ListDeploymentStatuses(owner, repo, deploymentID, nil)
		if err != nil {
			continue
		}

		status := firstStatus(states, statuses)
		if status != nil {
			return status
		}
	}
}

// firstStatus takes a slice of github.DeploymentStatus and returns the
// first status that matches the provided slice of states.
func firstStatus(states []string, statuses []github.DeploymentStatus) *github.DeploymentStatus {
	for _, ds := range statuses {
		for _, s := range states {
			if ds.State != nil && *ds.State == s {
				return &ds
			}
		}
	}

	return nil
}

// refRegex is a regular expression that matches a full git HEAD ref.
var refRegex = regexp.MustCompile(`^refs/heads/(.*)$`)

// Ref attempts to return the proper git ref to deploy. If a ref is provided,
// that will be returned. If not, it will fallback to calling headFunc. If an
// error is returned (not in a git repo), then it will fallback to DefaultRef.
func Ref(ref string, headFunc func() (string, error)) string {
	if ref != "" {
		return ref
	}

	ref, err := headFunc()
	if err != nil {
		// An error means that we're either not in a GitRepo or we're
		// not on a branch. In this case, we just fallback to the
		// DefaultRef.
		return DefaultRef
	}

	// Convert `refs/heads/test-deploy` => `test-deploy`
	return refRegex.ReplaceAllString(ref, "$1")
}

// Repo will determine the correct GitHub repo to deploy to, based on a set of
// arguments.
func Repo(arguments []string) (string, error) {
	if len(arguments) != 0 {
		return arguments[0], nil
	}

	remotes, err := hub.Remotes()
	if err != nil {
		return "", err
	}

	repo := GitHubRepo(remotes)
	if repo == "" {
		return repo, errors.New("no GitHub repo found in .git/config")
	}

	return repo, nil
}

// A regular expression that can convert a URL.Path into a GitHub repo name.
var remoteRegex = regexp.MustCompile(`^/(.*)\.git$`)

// GitHubRepo, given a list of git remotes, will determine what the GitHub repo
// is.
func GitHubRepo(remotes []hub.Remote) string {
	// We only want to look at the `origin` remote.
	remote := findRemote("origin", remotes)
	if remote == nil {
		return ""
	}

	// Remotes that are not pointed at a GitHub repo are not valid.
	if remote.URL.Host != "github.com" {
		return ""
	}

	// Convert `/remind101/acme-inc.git` => `remind101/acme-inc`.
	return remoteRegex.ReplaceAllString(remote.URL.Path, "$1")
}

func findRemote(name string, remotes []hub.Remote) *hub.Remote {
	for _, r := range remotes {
		if r.Name == name {
			return &r
		}
	}

	return nil
}

var errInvalidRepo = errors.New("invalid repo")

// SplitRepo splits a repo string in the form remind101/acme-inc into it's owner
// and repo components.
func SplitRepo(nwo, defaultOrg string) (owner string, repo string, err error) {
	parts := strings.Split(nwo, "/")

	// If we were only given a repo name, and a default organization is set,
	// we'll use the defaultOrg as the owner.
	if len(parts) == 1 && defaultOrg != "" && parts[0] != "" {
		owner = defaultOrg
		repo = parts[0]
		return
	}

	if len(parts) != 2 {
		err = errInvalidRepo
		return
	}

	owner = parts[0]
	repo = parts[1]

	return
}

func askYN(prompt string) bool {
	r := bufio.NewReader(os.Stdin)
	fmt.Printf("%s (y/N)\n", prompt)
	a, _ := r.ReadString('\n')
	return strings.ToUpper(a) == "Y\n"
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			cmd.SetOutput(dockerCli.Err())
			cmd.HelpFunc()(cmd, args)
			return nil
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			return dockerCli.Initialize(opts)
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}
<commit_msg>Skip cli initialization for daemon command<commit_after>package main

import (
	"fmt"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/types/versions"
	"github.com/docker/docker/cli"
	"github.com/docker/docker/cli/command"
	"github.com/docker/docker/cli/command/commands"
	cliflags "github.com/docker/docker/cli/flags"
	"github.com/docker/docker/cliconfig"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/term"
	"github.com/docker/docker/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func newDockerCommand(dockerCli *command.DockerCli) *cobra.Command {
	opts := cliflags.NewClientOptions()
	var flags *pflag.FlagSet

	cmd := &cobra.Command{
		Use:              "docker [OPTIONS] COMMAND [ARG...]",
		Short:            "A self-sufficient runtime for containers",
		SilenceUsage:     true,
		SilenceErrors:    true,
		TraverseChildren: true,
		Args:             noArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			if opts.Version {
				showVersion()
				return nil
			}
			cmd.SetOutput(dockerCli.Err())
			cmd.HelpFunc()(cmd, args)
			return nil
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// daemon command is special, we redirect directly to another binary
			if cmd.Name() == "daemon" {
				return nil
			}
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			return dockerCli.Initialize(opts)
		},
	}
	cli.SetupRootCommand(cmd)

	cmd.SetHelpFunc(func(ccmd *cobra.Command, args []string) {
		if dockerCli.Client() == nil {
			// flags must be the top-level command flags, not cmd.Flags()
			opts.Common.SetDefaultOptions(flags)
			dockerPreRun(opts)
			dockerCli.Initialize(opts)
		}

		hideUnsupportedFeatures(ccmd, dockerCli.Client().ClientVersion(), dockerCli.HasExperimental())

		if err := ccmd.Help(); err != nil {
			ccmd.Println(err)
		}
	})

	flags = cmd.Flags()
	flags.BoolVarP(&opts.Version, "version", "v", false, "Print version information and quit")
	flags.StringVar(&opts.ConfigDir, "config", cliconfig.ConfigDir(), "Location of client config files")
	opts.Common.InstallFlags(flags)

	cmd.SetOutput(dockerCli.Out())
	cmd.AddCommand(newDaemonCommand())
	commands.AddCommands(cmd, dockerCli)

	return cmd
}

func noArgs(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return nil
	}
	return fmt.Errorf(
		"docker: '%s' is not a docker command.\nSee 'docker --help'.", args[0])
}

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

func showVersion() {
	fmt.Printf("Docker version %s, build %s\n", dockerversion.Version, dockerversion.GitCommit)
}

func dockerPreRun(opts *cliflags.ClientOptions) {
	cliflags.SetLogLevel(opts.Common.LogLevel)

	if opts.ConfigDir != "" {
		cliconfig.SetConfigDir(opts.ConfigDir)
	}

	if opts.Common.Debug {
		utils.EnableDebug()
	}
}

func hideUnsupportedFeatures(cmd *cobra.Command, clientVersion string, hasExperimental bool) {
	cmd.Flags().VisitAll(func(f *pflag.Flag) {
		// hide experimental flags
		if !hasExperimental {
			if _, ok := f.Annotations["experimental"]; ok {
				f.Hidden = true
			}
		}

		// hide flags not supported by the server
		if flagVersion, ok := f.Annotations["version"]; ok && len(flagVersion) == 1 && versions.LessThan(clientVersion, flagVersion[0]) {
			f.Hidden = true
		}

	})

	for _, subcmd := range cmd.Commands() {
		// hide experimental subcommands
		if !hasExperimental {
			if _, ok := subcmd.Tags["experimental"]; ok {
				subcmd.Hidden = true
			}
		}

		// hide subcommands not supported by the server
		if subcmdVersion, ok := subcmd.Tags["version"]; ok && versions.LessThan(clientVersion, subcmdVersion) {
			subcmd.Hidden = true
		}
	}
}
<|endoftext|>


<commit_before>package daemon

import (
	"flag"
	"log"
	"os"
	"syscall"
	"time"
)

func Example() {
	signal := flag.String("s", "", "send signal to daemon")

	handler := func(sig os.Signal) error {
		log.Println("signal:", sig)
		if sig == syscall.SIGTERM {
			return ErrStop
		}
		return nil
	}

	// Define command: command-line arg, system signal and handler
	AddCommand(StringFlag(signal, "term"), syscall.SIGTERM, handler)
	AddCommand(StringFlag(signal, "reload"), syscall.SIGHUP, handler)

	// Define daemon context
	dmn := &Context{
		PidFileName: "/var/run/daemon.pid",
		PidFilePerm: 0644,
		LogFileName: "/var/log/daemon.log",
		LogFilePerm: 0640,
		WorkDir:     "/",
		Umask:       027,
	}

	// Process daemon operations - send signal if present flag or daemonize
	child, err := dmn.Reborn()
	if err != nil {
		log.Fatalln(err)
	}
	if child != nil {
		return
	}
	defer dmn.Release()

	// Run main operation
	go func() {
		for {
			time.Sleep(0)
		}
	}()

	err = ServeSignals()
	if err != nil {
		log.Println("Error:", err)
	}
}
<commit_msg>Updated documentation<commit_after>package daemon

import (
	"flag"
	"log"
	"os"
	"syscall"
	"time"
)

func Example() {
	signal := flag.String("s", "", "send signal to daemon")

	handler := func(sig os.Signal) error {
		log.Println("signal:", sig)
		if sig == syscall.SIGTERM {
			return ErrStop
		}
		return nil
	}

	// Define command: command-line arg, system signal and handler
	AddCommand(StringFlag(signal, "term"), syscall.SIGTERM, handler)
	AddCommand(StringFlag(signal, "reload"), syscall.SIGHUP, handler)
	flag.Parse()

	// Define daemon context
	dmn := &Context{
		PidFileName: "/var/run/daemon.pid",
		PidFilePerm: 0644,
		LogFileName: "/var/log/daemon.log",
		LogFilePerm: 0640,
		WorkDir:     "/",
		Umask:       027,
	}

	// Send commands if needed
	if len(ActiveFlags()) > 0 {
		d, err := dmn.Search()
		if err != nil {
			log.Fatalln("Unable send signal to the daemon:", err)
		}
		SendCommands(d)
		return
	}

	// Process daemon operations - send signal if present flag or daemonize
	child, err := dmn.Reborn()
	if err != nil {
		log.Fatalln(err)
	}
	if child != nil {
		return
	}
	defer dmn.Release()

	// Run main operation
	go func() {
		for {
			time.Sleep(0)
		}
	}()

	err = ServeSignals()
	if err != nil {
		log.Println("Error:", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

// +build darwin
// +build arm arm64

package sensor

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreMotion
#import "darwin_armx.h"
*/
import "C"
import (
	"fmt"
	"sync"
	"time"
	"unsafe"
)

var (
	mu    sync.Mutex
	doneA chan struct{}
)

type manager struct {
	m unsafe.Pointer
}

func (m *manager) initialize() {
	m.m = unsafe.Pointer(C.GoIOS_createManager())
}

func (m *manager) enable(s sender, t Type, delay time.Duration) error {
	mu.Lock()
	mu.Unlock()

	switch t {
	case Accelerometer:
		if doneA != nil {
			return fmt.Errorf("sensor: cannot enable; %v sensor is already enabled", t)
		}
		// TODO(jbd): Check if acceloremeter is available.
		C.GoIOS_startAccelerometer(m.m)
		m.startAccelometer(s, delay)
		doneA = make(chan struct{})
	case Gyroscope:
	case Magnetometer:
	default:
		return fmt.Errorf("sensor: unknown sensor type: %v", t)
	}
	return nil
}

func (m *manager) disable(t Type) error {
	mu.Lock()
	mu.Unlock()

	switch t {
	case Accelerometer:
		if doneA == nil {
			return fmt.Errorf("sensor: cannot disable; %v sensor is not enabled", t)
		}
		doneA <- struct{}{}
		C.GoIOS_stopAccelerometer(m.m)
		doneA = nil
	case Gyroscope:
	case Magnetometer:
	default:
		return fmt.Errorf("sensor: unknown sensor type: %v", t)
	}
	return nil
}

func (m *manager) startAccelometer(app sender, d time.Duration) {
	go func() {
		ev := make([]C.float, 4)
		var lastTimestamp int64
		for {
			select {
			case <-doneA:
				return
			default:
				C.GoIOS_readAccelerometer(m.m, (*C.float)(unsafe.Pointer(&ev[0])))
				t := int64(ev[0] * 1000 * 1000)
				if t > lastTimestamp {
					app.Send(Event{
						Sensor:    Accelerometer,
						Timestamp: t,
						Data:      []float64{float64(ev[1]), float64(ev[2]), float64(ev[3])},
					})
					lastTimestamp = t
					<-time.Tick(d)
				} else {
					<-time.Tick(d / 2)
				}
			}
		}
	}()
}

func (m *manager) read(ch chan interface{}) {}

func (m *manager) close() error {
	C.GoIOS_destroyManager(m.m)
	return nil
}
<commit_msg>Add TODO to normalize the values.<commit_after>// Copyright 2015 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.

// +build darwin
// +build arm arm64

package sensor

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework CoreMotion
#import "darwin_armx.h"
*/
import "C"
import (
	"fmt"
	"sync"
	"time"
	"unsafe"
)

var (
	mu    sync.Mutex
	doneA chan struct{}
)

type manager struct {
	m unsafe.Pointer
}

func (m *manager) initialize() {
	m.m = unsafe.Pointer(C.GoIOS_createManager())
}

func (m *manager) enable(s sender, t Type, delay time.Duration) error {
	mu.Lock()
	mu.Unlock()

	switch t {
	case Accelerometer:
		if doneA != nil {
			return fmt.Errorf("sensor: cannot enable; %v sensor is already enabled", t)
		}
		// TODO(jbd): Check if acceloremeter is available.
		C.GoIOS_startAccelerometer(m.m)
		m.startAccelometer(s, delay)
		doneA = make(chan struct{})
	case Gyroscope:
	case Magnetometer:
	default:
		return fmt.Errorf("sensor: unknown sensor type: %v", t)
	}
	return nil
}

func (m *manager) disable(t Type) error {
	mu.Lock()
	mu.Unlock()

	switch t {
	case Accelerometer:
		if doneA == nil {
			return fmt.Errorf("sensor: cannot disable; %v sensor is not enabled", t)
		}
		doneA <- struct{}{}
		C.GoIOS_stopAccelerometer(m.m)
		doneA = nil
	case Gyroscope:
	case Magnetometer:
	default:
		return fmt.Errorf("sensor: unknown sensor type: %v", t)
	}
	return nil
}

func (m *manager) startAccelometer(app sender, d time.Duration) {
	go func() {
		ev := make([]C.float, 4)
		var lastTimestamp int64
		for {
			select {
			case <-doneA:
				return
			default:
				C.GoIOS_readAccelerometer(m.m, (*C.float)(unsafe.Pointer(&ev[0])))
				t := int64(ev[0] * 1000 * 1000)
				if t > lastTimestamp {
					// TODO(jbd): Do we need to normalize the values?
					// How does the sensor rage compares with iOS?
					app.Send(Event{
						Sensor:    Accelerometer,
						Timestamp: t,
						Data:      []float64{float64(ev[1]), float64(ev[2]), float64(ev[3])},
					})
					lastTimestamp = t
					<-time.Tick(d)
				} else {
					<-time.Tick(d / 2)
				}
			}
		}
	}()
}

func (m *manager) read(ch chan interface{}) {}

func (m *manager) close() error {
	C.GoIOS_destroyManager(m.m)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math"

	"github.com/bcurren/go-hue"
	"github.com/bitly/go-simplejson"
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-ninja/devices"
)

func NewLight(l *hue.Light, bus *ninja.DriverBus, bridge *hue.Bridge, user *hue.User) (*HueLightContext, error) {

	log.Infof("Making hue light with Bridge: %s Id: %+v", bridge.UniqueId, l.Id)

	sigs, _ := simplejson.NewJson([]byte(`{
			"ninja:manufacturer": "Phillips",
			"ninja:productName": "Hue",
			"manufacturer:productModelId": "",
			"ninja:productType": "Light",
			"ninja:thingType": "light"
	}`))

	la, _ := user.GetLightAttributes(l.Id)

	sigs.Set("manufacturer:productModelId", la.ModelId)

	deviceBus, err := bus.AnnounceDevice(l.Id, "hue", l.Name, sigs)

	if err != nil {
		log.FatalError(err, "Failed to create light device bus ")
	}

	light, err := devices.CreateLightDevice(l.Id, deviceBus)

	if err != nil {
		log.FatalError(err, "Failed to create light device")
	}

	if err := light.EnableOnOffChannel(); err != nil {
		log.FatalError(err, "Could not enable hue on-off channel")
	}

	if err := light.EnableBrightnessChannel(); err != nil {
		log.FatalError(err, "Could not enable hue brightness channel")
	}

	if err := light.EnableColorChannel("temperature", "hue"); err != nil {
		log.FatalError(err, "Could not enable hue color channel")
	}

	if err := light.EnableTransitionChannel(); err != nil {
		log.FatalError(err, "Could not enable hue transition channel")
	}

	hl := &HueLightContext{
		ID:         l.Id,
		Name:       l.Name,
		Bridge:     bridge,
		User:       user,
		Light:      light,
		LightState: &hue.LightState{},
	}

	light.ApplyOnOff = hl.ApplyOnOff
	light.ApplyLightState = hl.ApplyLightState

	return hl, nil
}

type HueLightContext struct {
	ID         string
	Name       string
	Bridge     *hue.Bridge
	User       *hue.User
	Light      *devices.LightDevice
	LightState *hue.LightState
}

func (hl *HueLightContext) ApplyOnOff(state bool) error {

	ls := createLightState()

	ls.On = &state

	return hl.SetLightState(hl.ID, ls)
}

func (hl *HueLightContext) ApplyLightState(state *devices.LightDeviceState) error {

	log.Infof("Sending light state to hue bulb: %+v", state)

	if state.OnOff != nil {
		err := hl.ApplyOnOff(*state.OnOff)
		if err != nil {
			return err
		}
	}

	if state.Color != nil || state.Brightness != nil || state.Transition != nil {
		if state.Color == nil {
			return fmt.Errorf("Color value missing from batch set")
		}

		if state.Brightness == nil {
			return fmt.Errorf("Brightness value missing from batch set")
		}

		if state.Transition == nil {
			return fmt.Errorf("Transition value missing from batch set")
		}

		switch state.Color.Mode {
		case "hue":
			ls := createLightState()

			ls.Hue = getHue(state)
			ls.Saturation = getSaturation(state)
			ls.Brightness = getBrightness(state)
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		case "xy":

			ls := createLightState()

			ls.Hue = getHue(state)
			ls.Saturation = getSaturation(state)
			ls.Brightness = getBrightness(state)
			ls.XY = []float64{*state.Color.X, *state.Color.Y}
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		case "temperature":

			ls := createLightState()
			ls.ColorTemp = getColorTemp(state)
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		default:
			return fmt.Errorf("Unknown color mode %s", state.Color.Mode)
		}

	}

	return nil
}

func (hl *HueLightContext) SetLightState(lightID string, lightState *hue.LightState) error {

	log.Infof(spew.Sprintf("Sending light state to hue bulb: %s %+v", lightID, lightState))

	if err := hl.User.SetLightState(hl.ID, lightState); err != nil {
		return err
	}

	//la, _ := hl.User.GetLightAttributes(hl.ID)

	//hl.Light.SetLightState(hueToNinjaLightState(la.State))

	return nil

}

func getTransitionTime(state *devices.LightDeviceState) *uint16 {
	var transTime uint16
	if *state.Transition > 0 && *state.Transition < math.MaxUint16 {
		transTime = uint16(*state.Transition / 100) //HUE API uses 1/10th of a second
	} else {
		transTime = 0
	}
	return &transTime
}

func getHue(state *devices.LightDeviceState) *uint16 {
	hue := uint16(*state.Color.Hue * math.MaxUint16)
	return &hue
}

func getSaturation(state *devices.LightDeviceState) *uint8 {
	saturation := uint8(*state.Color.Saturation * math.MaxUint16)
	return &saturation
}

func getBrightness(state *devices.LightDeviceState) *uint8 {
	brightness := uint8(*state.Brightness * math.MaxUint16)
	return &brightness
}

func getColorTemp(state *devices.LightDeviceState) *uint16 {
	temp := uint16(*state.Color.Temperature)
	return &temp
}

func createLightState() *hue.LightState {

	on := bool(false)
	brightness := uint8(0)
	saturation := uint8(0)
	hueVal := uint16(0)
	transitionTime := uint16(0)
	alert := ""
	temp := uint16(0)
	xy := []float64{0, 0}

	lightState := &hue.LightState{
		On:             &on,
		Brightness:     &brightness,
		Saturation:     &saturation,
		Hue:            &hueVal,
		ColorTemp:      &temp,
		TransitionTime: &transitionTime,
		Alert:          alert,
		XY:             xy,
	}

	return lightState
}

func hueToNinjaLightState(huestate *hue.LightState) *devices.LightDeviceState {

	onOff := *huestate.On
	brightness := float64(*huestate.Brightness) / float64(math.MaxUint16)
	hue := float64(*huestate.Hue) / float64(math.MaxUint16)
	saturation := float64(*huestate.Saturation) / float64(math.MaxUint16)

	return &devices.LightDeviceState{
		Color: &channels.ColorState{
			Mode:       "hue",
			Hue:        &hue,
			Saturation: &saturation,
		},
		Brightness: &brightness,
		OnOff:      &onOff,
	}
}
<commit_msg>Sorted out some debugging.<commit_after>package main

import (
	"fmt"
	"math"

	"github.com/bcurren/go-hue"
	"github.com/bitly/go-simplejson"
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja"
	"github.com/ninjasphere/go-ninja/channels"
	"github.com/ninjasphere/go-ninja/devices"
)

func NewLight(l *hue.Light, bus *ninja.DriverBus, bridge *hue.Bridge, user *hue.User) (*HueLightContext, error) {

	log.Infof("Making hue light with Bridge: %s Id: %+v", bridge.UniqueId, l.Id)

	sigs, _ := simplejson.NewJson([]byte(`{
			"ninja:manufacturer": "Phillips",
			"ninja:productName": "Hue",
			"manufacturer:productModelId": "",
			"ninja:productType": "Light",
			"ninja:thingType": "light"
	}`))

	la, _ := user.GetLightAttributes(l.Id)

	sigs.Set("manufacturer:productModelId", la.ModelId)

	deviceBus, err := bus.AnnounceDevice(l.Id, "hue", l.Name, sigs)

	if err != nil {
		log.FatalError(err, "Failed to create light device bus ")
	}

	light, err := devices.CreateLightDevice(l.Id, deviceBus)

	if err != nil {
		log.FatalError(err, "Failed to create light device")
	}

	if err := light.EnableOnOffChannel(); err != nil {
		log.FatalError(err, "Could not enable hue on-off channel")
	}

	if err := light.EnableBrightnessChannel(); err != nil {
		log.FatalError(err, "Could not enable hue brightness channel")
	}

	if err := light.EnableColorChannel("temperature", "hue"); err != nil {
		log.FatalError(err, "Could not enable hue color channel")
	}

	if err := light.EnableTransitionChannel(); err != nil {
		log.FatalError(err, "Could not enable hue transition channel")
	}

	hl := &HueLightContext{
		ID:         l.Id,
		Name:       l.Name,
		Bridge:     bridge,
		User:       user,
		Light:      light,
		LightState: &hue.LightState{},
	}

	light.ApplyOnOff = hl.ApplyOnOff
	light.ApplyLightState = hl.ApplyLightState

	return hl, nil
}

type HueLightContext struct {
	ID         string
	Name       string
	Bridge     *hue.Bridge
	User       *hue.User
	Light      *devices.LightDevice
	LightState *hue.LightState
}

func (hl *HueLightContext) ApplyOnOff(state bool) error {

	ls := createLightState()

	ls.On = &state

	return hl.SetLightState(hl.ID, ls)
}

func (hl *HueLightContext) ApplyLightState(state *devices.LightDeviceState) error {

	log.Debugf(spew.Sprintf("Sending light state to hue bulb: %+v", state))

	if state.OnOff != nil {
		err := hl.ApplyOnOff(*state.OnOff)
		if err != nil {
			return err
		}
	}

	if state.Color != nil || state.Brightness != nil || state.Transition != nil {
		if state.Color == nil {
			return fmt.Errorf("Color value missing from batch set")
		}

		if state.Brightness == nil {
			return fmt.Errorf("Brightness value missing from batch set")
		}

		if state.Transition == nil {
			return fmt.Errorf("Transition value missing from batch set")
		}

		switch state.Color.Mode {
		case "hue":
			ls := createLightState()

			ls.Hue = getHue(state)
			ls.Saturation = getSaturation(state)
			ls.Brightness = getBrightness(state)
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		case "xy":

			ls := createLightState()

			ls.Hue = getHue(state)
			ls.Saturation = getSaturation(state)
			ls.Brightness = getBrightness(state)
			ls.XY = []float64{*state.Color.X, *state.Color.Y}
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		case "temperature":

			ls := createLightState()
			ls.ColorTemp = getColorTemp(state)
			ls.TransitionTime = getTransitionTime(state)

			return hl.SetLightState(hl.ID, ls)
		default:
			return fmt.Errorf("Unknown color mode %s", state.Color.Mode)
		}

	}

	return nil
}

func (hl *HueLightContext) SetLightState(lightID string, lightState *hue.LightState) error {

	log.Debugf(spew.Sprintf("Sending light state to hue bulb: %s %+v", lightID, lightState))

	if err := hl.User.SetLightState(hl.ID, lightState); err != nil {
		return err
	}

	//la, _ := hl.User.GetLightAttributes(hl.ID)

	//hl.Light.SetLightState(hueToNinjaLightState(la.State))

	return nil

}

func getTransitionTime(state *devices.LightDeviceState) *uint16 {
	var transTime uint16
	if *state.Transition > 0 && *state.Transition < math.MaxUint16 {
		transTime = uint16(*state.Transition / 100) //HUE API uses 1/10th of a second
	} else {
		transTime = 0
	}
	return &transTime
}

func getHue(state *devices.LightDeviceState) *uint16 {
	hue := uint16(*state.Color.Hue * math.MaxUint16)
	return &hue
}

func getSaturation(state *devices.LightDeviceState) *uint8 {
	saturation := uint8(*state.Color.Saturation * math.MaxUint16)
	return &saturation
}

func getBrightness(state *devices.LightDeviceState) *uint8 {
	brightness := uint8(*state.Brightness * math.MaxUint16)
	return &brightness
}

func getColorTemp(state *devices.LightDeviceState) *uint16 {
	temp := uint16(*state.Color.Temperature)
	return &temp
}

func createLightState() *hue.LightState {

	on := bool(false)
	brightness := uint8(0)
	saturation := uint8(0)
	hueVal := uint16(0)
	transitionTime := uint16(0)
	alert := ""
	temp := uint16(0)
	xy := []float64{0, 0}

	lightState := &hue.LightState{
		On:             &on,
		Brightness:     &brightness,
		Saturation:     &saturation,
		Hue:            &hueVal,
		ColorTemp:      &temp,
		TransitionTime: &transitionTime,
		Alert:          alert,
		XY:             xy,
	}

	return lightState
}

func hueToNinjaLightState(huestate *hue.LightState) *devices.LightDeviceState {

	onOff := *huestate.On
	brightness := float64(*huestate.Brightness) / float64(math.MaxUint16)
	hue := float64(*huestate.Hue) / float64(math.MaxUint16)
	saturation := float64(*huestate.Saturation) / float64(math.MaxUint16)

	return &devices.LightDeviceState{
		Color: &channels.ColorState{
			Mode:       "hue",
			Hue:        &hue,
			Saturation: &saturation,
		},
		Brightness: &brightness,
		OnOff:      &onOff,
	}
}
<|endoftext|>


<commit_before>package server

import (
	"flag"
	"github.com/LapisBlue/Lapitar/lapitar"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"log"
	"net/http"
	"os"
)

var (
	defaults *config
	//decoder  = schema.NewDecoder()
)

func start(conf *config, www string) {
	defaults = conf
	flag.Set("bind", conf.Address) // Uh, I guess that's a bit strange
	if conf.Proxy {
		goji.Insert(middleware.RealIP, middleware.Logger)
	}

	goji.Use(serveLapitar)

	register("/skin/:player", serveSkin)

	register("/face/:player", serveFaceNormal)
	register("/face/:size/:player", serveFaceWithSize)
	register("/helm/:player", serveHelmNormal)
	register("/helm/:size/:player", serveHelmWithSize)

	register("/head/:player", serveHeadNormal)
	register("/head/:size/:player", serveHeadWithSize)
	register("/portrait/:player", servePortraitNormal)
	register("/portrait/:size/:player", servePortraitWithSize)
	register("/player/:player", servePlayerNormal)
	register("/player/:size/:player", servePlayerWithSize)

	if exists(www) {
		goji.Get("/*", http.FileServer(http.Dir(www)))
	} else {
		log.Println("Failed to find website files at", www)
	}

	goji.Serve()
}

func exists(dir string) bool {
	stat, err := os.Stat(dir)
	if err != nil {
		return false
	}

	return stat.IsDir()
}

func register(pattern string, handler interface{}) {
	goji.Get(pattern+".png", handler)
	goji.Get(pattern, handler)
}

func serveLapitar(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", lapitar.DisplayName)
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Simplify this a little bit<commit_after>package server

import (
	"flag"
	"github.com/LapisBlue/Lapitar/lapitar"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"log"
	"net/http"
	"os"
)

var (
	defaults *config
	//decoder  = schema.NewDecoder()
)

func start(conf *config, www string) {
	defaults = conf
	flag.Set("bind", conf.Address) // Uh, I guess that's a bit strange
	if conf.Proxy {
		goji.Insert(middleware.RealIP, middleware.Logger)
	}

	goji.Use(serveLapitar)

	register("/skin/:player", serveSkin)

	register("/face/:player", serveFaceNormal)
	register("/face/:size/:player", serveFaceWithSize)
	register("/helm/:player", serveHelmNormal)
	register("/helm/:size/:player", serveHelmWithSize)

	register("/head/:player", serveHeadNormal)
	register("/head/:size/:player", serveHeadWithSize)
	register("/portrait/:player", servePortraitNormal)
	register("/portrait/:size/:player", servePortraitWithSize)
	register("/player/:player", servePlayerNormal)
	register("/player/:size/:player", servePlayerWithSize)

	if exists(www) {
		goji.Get("/*", http.FileServer(http.Dir(www)))
	} else {
		log.Println("Failed to find website files at", www)
	}

	goji.Serve()
}

func exists(dir string) bool {
	stat, err := os.Stat(dir)
	if err != nil {
		return false
	}

	return stat.IsDir()
}

func register(pattern string, handler interface{}) {
	goji.Get(pattern+".png", handler)
	goji.Get(pattern, handler)
}

func serveLapitar(c *web.C, h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", lapitar.DisplayName)
		h.ServeHTTP(w, r)
	})
}
<|endoftext|>


<commit_before>package authentication
<commit_msg>settings, environment settings<commit_after>package authentication

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
)

var environments = map[string]string{
	"production":    "../../authentication/settings/prod.json",
	"preproduction": "../../authentication/settings/pre.json",
	"tests":         "../../authentication/settings/tests.json",
}

type Settings struct {
	PrivateKeyPath     string
	PublicKeyPath      string
	JWTExpirationDelta int
}

<|endoftext|>


<commit_before>package cmd

import (
	"github.com/docker/libcompose/project"
	rancherApp "github.com/rancher/rancher-compose/app"
	"github.com/urfave/cli"
)

func UpCommand() cli.Command {
	factory := &projectFactory{}
	cmd := rancherApp.UpCommand(factory)
	cmd.Flags = append(cmd.Flags, []cli.Flag{
		cli.StringFlag{
			Name:  "rancher-file",
			Usage: "Specify an alternate Rancher compose file (default: rancher-compose.yml)",
		},
		cli.StringFlag{
			Name:  "env-file,e",
			Usage: "Specify a file from which to read environment variables",
		},
		cli.StringSliceFlag{
			Name:   "file,f",
			Usage:  "Specify one or more alternate compose files (default: docker-compose.yml)",
			Value:  &cli.StringSlice{},
			EnvVar: "COMPOSE_FILE",
		},
		cli.StringFlag{
			Name:  "stack,s",
			Usage: "Specify an alternate project name (default: directory name)",
		},
	}...)
	return cmd
}

type projectFactory struct {
}

func (p *projectFactory) Create(c *cli.Context) (project.APIProject, error) {
	config, err := lookupConfig(c)
	if err != nil {
		return nil, err
	}

	url, err := config.EnvironmentURL()
	if err != nil {
		return nil, err
	}

	// from config
	c.GlobalSet("url", url)
	c.GlobalSet("access-key", config.AccessKey)
	c.GlobalSet("secret-key", config.SecretKey)

	// copy from flags
	c.GlobalSet("rancher-file", c.String("rancher-file"))
	c.GlobalSet("env-file", c.String("env-file"))
	c.GlobalSet("project-name", c.String("stack"))
	for _, f := range c.StringSlice("file") {
		c.GlobalSet("file", f)
	}

	factory := &rancherApp.ProjectFactory{}
	return factory.Create(c)
}
<commit_msg>Fixes from rancher-compose-executor import<commit_after>package cmd

import (
	"github.com/rancher/rancher-compose-executor/app"
	"github.com/rancher/rancher-compose-executor/project"
	"github.com/urfave/cli"
)

func UpCommand() cli.Command {
	factory := &projectFactory{}
	cmd := app.UpCommand(factory)
	cmd.Flags = append(cmd.Flags, []cli.Flag{
		cli.StringFlag{
			Name:  "rancher-file",
			Usage: "Specify an alternate Rancher compose file (default: rancher-compose.yml)",
		},
		cli.StringFlag{
			Name:  "env-file,e",
			Usage: "Specify a file from which to read environment variables",
		},
		cli.StringSliceFlag{
			Name:   "file,f",
			Usage:  "Specify one or more alternate compose files (default: docker-compose.yml)",
			Value:  &cli.StringSlice{},
			EnvVar: "COMPOSE_FILE",
		},
		cli.StringFlag{
			Name:  "stack,s",
			Usage: "Specify an alternate project name (default: directory name)",
		},
	}...)
	return cmd
}

type projectFactory struct {
}

func (p *projectFactory) Create(c *cli.Context) (*project.Project, error) {
	config, err := lookupConfig(c)
	if err != nil {
		return nil, err
	}

	url, err := config.EnvironmentURL()
	if err != nil {
		return nil, err
	}

	// from config
	c.GlobalSet("url", url)
	c.GlobalSet("access-key", config.AccessKey)
	c.GlobalSet("secret-key", config.SecretKey)

	// copy from flags
	c.GlobalSet("rancher-file", c.String("rancher-file"))
	c.GlobalSet("env-file", c.String("env-file"))
	c.GlobalSet("project-name", c.String("stack"))
	for _, f := range c.StringSlice("file") {
		c.GlobalSet("file", f)
	}

	factory := &app.RancherProjectFactory{}
	return factory.Create(c)
}
<|endoftext|>


<commit_before>package db

import (
	"encoding/json"
	"fmt"
	"os"
	"syscall"
)

type Entry struct {
	Command string
	Term    int
}

type Log struct {
	data     []byte
	Entries  []Entry
	fd       int
	filename string
	file     *os.File
}

func (log *Log) load() {
	err := json.Unmarshal(log.data, &log.Entries)
	if err != nil {
		fmt.Println("Error unmarshalling initial data into map: ", err)
	}
}

func (log *Log) mmap(size int) {
	fmt.Println("mmapping log file: ", size)
	data, err := syscall.Mmap(log.fd, 0, size, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Println("Error mmapping: ", err)
	}
	log.data = data
}

func (log *Log) resize(size int) {
	fmt.Println("Resizing log file: ", size)
	err := syscall.Ftruncate(log.fd, int64(size))
	if err != nil {
		fmt.Println("Error resizing log file: ", err)
	}
}

func (log *Log) open() {
	fmt.Println("Getting log file descriptor")
	f, err := os.OpenFile(log.filename, os.O_CREATE|os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open log file: ", err)
	}
	log.fd = int(f.Fd())
	log.file = f
}

func (log *Log) extend(size int) {
	log.file.Close()
	log.open()
	log.resize(size)
	log.mmap(size)
}

func (log *Log) rewriteLog(entries []Entry) {
	log.Entries = entries
	b, err := json.Marshal(log.Entries)
	if err != nil {
		fmt.Println("Error marshalling log: ", err)
	}
	if len(b) > len(log.data) {
		log.extend(len(b))
	}
	copy(log.data, b)
}

func (log *Log) appendEntry(entry Entry) {
	log.Entries = append(log.Entries, Entry)
	b, err := json.Marshal(log.Entries)
	if err != nil {
		fmt.Println("Error marshalling log: ", err)
	}
	if len(b) > len(log.data) {
		log.extend(len(b))
	}
	copy(log.data, b)
}

func initLog(filename string) *Log {
	var data []byte
	var entries []Entry
	var fd int
	var file *os.File
	log := &Log{data, entries, fd, filename, file}
	log.open()
	f, err := os.Stat(filename)
	if err != nil {
		fmt.Println("Could not stat file: ", err)
	}
	size := int(f.Size())
	if size == 0 {
		size = 10
		log.resize(size)
	}
	log.mmap(size)
	return log
}
<commit_msg>zero compiler errors :)<commit_after>package db

import (
	"encoding/json"
	"fmt"
	"os"
	"syscall"
)

type Entry struct {
	Command string
	Term    int
}

type Log struct {
	data     []byte
	Entries  []Entry
	fd       int
	filename string
	file     *os.File
}

func (log *Log) load() {
	err := json.Unmarshal(log.data, &log.Entries)
	if err != nil {
		fmt.Println("Error unmarshalling initial data into map: ", err)
	}
}

func (log *Log) mmap(size int) {
	fmt.Println("mmapping log file: ", size)
	data, err := syscall.Mmap(log.fd, 0, size, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Println("Error mmapping: ", err)
	}
	log.data = data
}

func (log *Log) resize(size int) {
	fmt.Println("Resizing log file: ", size)
	err := syscall.Ftruncate(log.fd, int64(size))
	if err != nil {
		fmt.Println("Error resizing log file: ", err)
	}
}

func (log *Log) open() {
	fmt.Println("Getting log file descriptor")
	f, err := os.OpenFile(log.filename, os.O_CREATE|os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open log file: ", err)
	}
	log.fd = int(f.Fd())
	log.file = f
}

func (log *Log) extend(size int) {
	log.file.Close()
	log.open()
	log.resize(size)
	log.mmap(size)
}

func (log *Log) rewriteLog(entries []Entry) {
	log.Entries = entries
	b, err := json.Marshal(log.Entries)
	if err != nil {
		fmt.Println("Error marshalling log: ", err)
	}
	if len(b) > len(log.data) {
		log.extend(len(b))
	}
	copy(log.data, b)
}

func (log *Log) appendEntry(entry Entry) {
	log.Entries = append(log.Entries, entry)
	b, err := json.Marshal(log.Entries)
	if err != nil {
		fmt.Println("Error marshalling log: ", err)
	}
	if len(b) > len(log.data) {
		log.extend(len(b))
	}
	copy(log.data, b)
}

func initLog(filename string) *Log {
	var data []byte
	var entries []Entry
	var fd int
	var file *os.File
	log := &Log{data, entries, fd, filename, file}
	log.open()
	f, err := os.Stat(filename)
	if err != nil {
		fmt.Println("Could not stat file: ", err)
	}
	size := int(f.Size())
	if size == 0 {
		size = 10
		log.resize(size)
	}
	log.mmap(size)
	return log
}
<|endoftext|>


<commit_before>package main

import (
	"strings"

	"github.com/jroimartin/gocui"
)

func editor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
	state.HideHelp = true

	if state.Mode == modeEscape {
		escEditor(v, key, ch, mod)
		return
	}

	if ch != 0 && mod == 0 {
		v.EditWrite(ch)
	}

	switch key {
	case gocui.KeyEsc:
		state.Mode = modeEscape
		state.KeepAutoscrolling = true

	// Space, backspace, Del
	case gocui.KeySpace:
		v.EditWrite(' ')
	case gocui.KeyBackspace, gocui.KeyBackspace2:
		v.EditDelete(true)
		moveAhead(v)
	case gocui.KeyDelete:
		v.EditDelete(false)

	// Cursor movement
	case gocui.KeyArrowLeft:
		v.MoveCursor(-1, 0, false)
		moveAhead(v)
	case gocui.KeyArrowRight:
		x, _ := v.Cursor()
		x2, _ := v.Origin()
		x += x2
		buf := v.Buffer()
		// I don't know really how this works, this was mostly obtained through trial
		// and error. Anyway, this system impedes going on a newline by moving right.
		// This is usually possible because once you write something to the buffer
		// it automatically adds " \n", which is two characters. Sooo yeah.
		if buf != "" && len(buf) > (x+2) {
			v.MoveCursor(1, 0, false)
		}

	// Insert/Overwrite
	case gocui.KeyInsert:
		if state.Mode == modeInsert {
			state.Mode = modeOverwrite
		} else {
			state.Mode = modeInsert
		}
		v.Overwrite = state.Mode == modeOverwrite

	// History browse
	case gocui.KeyArrowDown:
		n := state.BrowseActions(-1)
		setText(v, n)
	case gocui.KeyArrowUp:
		n := state.BrowseActions(1)
		setText(v, n)

	case gocui.KeyEnter:
		buf := v.Buffer()
		v.Clear()
		v.SetCursor(0, 0)

		if buf != "" {
			buf = buf[:len(buf)-1]
		}
		if strings.TrimSpace(buf) != "" {
			state.PushAction(buf)
			state.ActionIndex = -1
		}

		enterActions[state.Mode](buf)
	}
}

func setText(v *gocui.View, text string) {
	v.Clear()
	v.Write([]byte(text))
	v.SetCursor(len(text), 0)
}

// moveAhead displays the next 10 characters when moving backwards,
// in order to see where we're moving or what we're deleting.
func moveAhead(v *gocui.View) {
	cX, _ := v.Cursor()
	oX, _ := v.Origin()
	if cX < 10 && oX > 0 {
		newOX := oX - 10
		forward := 10
		if newOX < 0 {
			forward += newOX
			newOX = 0
		}
		v.SetOrigin(newOX, 0)
		v.MoveCursor(forward, 0, false)
	}
}

// enterActions is the actions that can be done when KeyEnter is pressed
// (outside of modeEscape), based on the mode.
var enterActions = map[int]func(buf string){
	modeInsert:    enterActionSendMessage,
	modeOverwrite: enterActionSendMessage,
	modeConnect:   enterActionConnect,
}

func enterActionSendMessage(buf string) {
	if state.Conn != nil && strings.TrimSpace(buf) != "" {
		state.User(buf)
		state.Conn.Write(buf)
	}
}

func enterActionConnect(buf string) {
	if buf != "" {
		state.Settings.LastWebsocketURL = buf
		state.Settings.Save()
	}
	state.Mode = modeInsert
	go connect()
}

func moveDown(v *gocui.View) {
	_, yPos := v.Cursor()
	if _, err := v.Line(yPos + 1); err == nil {
		v.MoveCursor(0, 1, false)
	}
}

// escEditor handles keys when esc has been pressed.
func escEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
	switch key {
	case gocui.KeyEsc:
		// silently ignore - we're already in esc mode!
	case gocui.KeyInsert:
		state.Mode = modeInsert

	// Scrolling
	//
	// When one of the movements keys is pressed, autoscrolling is disabled so that
	// the user can move through the output without having text moving underneath
	// the cursor.
	case gocui.KeyArrowUp, gocui.MouseWheelDown:
		state.KeepAutoscrolling = false
		v.MoveCursor(0, -1, false)
	case gocui.KeyArrowDown, gocui.MouseWheelUp:
		state.KeepAutoscrolling = false
		moveDown(v)
	case gocui.KeyArrowLeft:
		state.KeepAutoscrolling = false
		v.MoveCursor(-1, 0, false)
	case gocui.KeyArrowRight:
		state.KeepAutoscrolling = false
		_, y := v.Cursor()
		if _, err := v.Word(0, y); err == nil {
			v.MoveCursor(1, 0, false)
		}
	case gocui.KeyPgup:
		state.KeepAutoscrolling = false
		_, ySize := v.Size()
		for i := 0; i < ySize; i++ {
			v.MoveCursor(0, -1, false)
		}
	case gocui.KeyPgdn:
		state.KeepAutoscrolling = false
		_, ySize := v.Size()
		for i := 0; i < ySize; i++ {
			moveDown(v)
		}
	case gocui.KeyHome:
		state.KeepAutoscrolling = false
		v.SetCursor(0, 0)
		v.SetOrigin(0, 0)
	case gocui.KeyEnd:
		state.KeepAutoscrolling = false
		lines := len(strings.Split(v.ViewBuffer(), "\n"))
		_, y := v.Size()

		origin := lines - y - 1
		if origin < 0 {
			origin = 0
		}
		v.SetOrigin(0, origin)

		cursorY := y - 1
		if lines <= y {
			cursorY = lines - 2
		}
		v.SetCursor(0, cursorY)
	}
	if ch == 0 {
		return
	}

	switch ch {
	case 'c':
		if state.Conn != nil {
			state.Error("You need to close the connection before starting a new one: <ESC>q")
			return
		}
		state.Mode = modeConnect
		return
	case 'q':
		err := state.Conn.Close()
		if err != nil {
			state.Error(err.Error())
		}
		state.Debug("WebSocket closed")
		return
	case 'i':
		// goes into insert mode
	case 'h':
		state.HideHelp = false
	case 'j':
		// toggle JSON formatting
		state.Settings.JSONFormatting = !state.Settings.JSONFormatting
		err := state.Settings.Save()
		if err != nil {
			state.Error(err.Error())
		}
		e := "disabled"
		if state.Settings.JSONFormatting {
			e = "enabled"
		}
		state.Debug("JSON formatting " + e)
	case 't':
		// toggle timestamps
		if state.Settings.Timestamp == "" {
			state.Settings.Timestamp = "2006-01-02 15:04:05 "
		} else {
			state.Settings.Timestamp = ""
		}
		err := state.Settings.Save()
		if err != nil {
			state.Error(err.Error())
		}
		e := "disabled"
		if state.Settings.Timestamp != "" {
			e = "enabled"
		}
		state.Debug("Timestamps " + e)
	case 'R':
		// overwrite mode
		state.Mode = modeOverwrite
		return
	default:
		state.Debug("No action for key '" + string(ch) + "'")
		return
	}

	state.Mode = modeInsert
}
<commit_msg>fix #18<commit_after>package main

import (
	"strings"

	"github.com/jroimartin/gocui"
)

func editor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
	state.HideHelp = true

	if state.Mode == modeEscape {
		escEditor(v, key, ch, mod)
		return
	}

	if ch != 0 && mod == 0 {
		v.EditWrite(ch)
	}

	switch key {
	case gocui.KeyEsc:
		state.Mode = modeEscape
		state.KeepAutoscrolling = true

	// Space, backspace, Del
	case gocui.KeySpace:
		v.EditWrite(' ')
	case gocui.KeyBackspace, gocui.KeyBackspace2:
		v.EditDelete(true)
		moveAhead(v)
	case gocui.KeyDelete:
		v.EditDelete(false)

	// Cursor movement
	case gocui.KeyArrowLeft:
		v.MoveCursor(-1, 0, false)
		moveAhead(v)
	case gocui.KeyArrowRight:
		x, _ := v.Cursor()
		x2, _ := v.Origin()
		x += x2
		buf := v.Buffer()
		// Position of cursor should be on space that gocui adds at the end if at end
		if buf != "" && len(strings.TrimRight(buf, "\r\n")) > x {
			v.MoveCursor(1, 0, false)
		}

	// Insert/Overwrite
	case gocui.KeyInsert:
		if state.Mode == modeInsert {
			state.Mode = modeOverwrite
		} else {
			state.Mode = modeInsert
		}
		v.Overwrite = state.Mode == modeOverwrite

	// History browse
	case gocui.KeyArrowDown:
		n := state.BrowseActions(-1)
		setText(v, n)
	case gocui.KeyArrowUp:
		n := state.BrowseActions(1)
		setText(v, n)

	case gocui.KeyEnter:
		buf := v.Buffer()
		v.Clear()
		v.SetCursor(0, 0)

		if buf != "" {
			buf = buf[:len(buf)-1]
		}
		if strings.TrimSpace(buf) != "" {
			state.PushAction(buf)
			state.ActionIndex = -1
		}

		enterActions[state.Mode](buf)
	}
}

func setText(v *gocui.View, text string) {
	v.Clear()
	v.Write([]byte(text))
	v.SetCursor(len(text), 0)
}

// moveAhead displays the next 10 characters when moving backwards,
// in order to see where we're moving or what we're deleting.
func moveAhead(v *gocui.View) {
	cX, _ := v.Cursor()
	oX, _ := v.Origin()
	if cX < 10 && oX > 0 {
		newOX := oX - 10
		forward := 10
		if newOX < 0 {
			forward += newOX
			newOX = 0
		}
		v.SetOrigin(newOX, 0)
		v.MoveCursor(forward, 0, false)
	}
}

// enterActions is the actions that can be done when KeyEnter is pressed
// (outside of modeEscape), based on the mode.
var enterActions = map[int]func(buf string){
	modeInsert:    enterActionSendMessage,
	modeOverwrite: enterActionSendMessage,
	modeConnect:   enterActionConnect,
}

func enterActionSendMessage(buf string) {
	if state.Conn != nil && strings.TrimSpace(buf) != "" {
		state.User(buf)
		state.Conn.Write(buf)
	}
}

func enterActionConnect(buf string) {
	if buf != "" {
		state.Settings.LastWebsocketURL = buf
		state.Settings.Save()
	}
	state.Mode = modeInsert
	go connect()
}

func moveDown(v *gocui.View) {
	_, yPos := v.Cursor()
	if _, err := v.Line(yPos + 1); err == nil {
		v.MoveCursor(0, 1, false)
	}
}

// escEditor handles keys when esc has been pressed.
func escEditor(v *gocui.View, key gocui.Key, ch rune, mod gocui.Modifier) {
	switch key {
	case gocui.KeyEsc:
		// silently ignore - we're already in esc mode!
	case gocui.KeyInsert:
		state.Mode = modeInsert

	// Scrolling
	//
	// When one of the movements keys is pressed, autoscrolling is disabled so that
	// the user can move through the output without having text moving underneath
	// the cursor.
	case gocui.KeyArrowUp, gocui.MouseWheelDown:
		state.KeepAutoscrolling = false
		v.MoveCursor(0, -1, false)
	case gocui.KeyArrowDown, gocui.MouseWheelUp:
		state.KeepAutoscrolling = false
		moveDown(v)
	case gocui.KeyArrowLeft:
		state.KeepAutoscrolling = false
		v.MoveCursor(-1, 0, false)
	case gocui.KeyArrowRight:
		state.KeepAutoscrolling = false
		_, y := v.Cursor()
		if _, err := v.Word(0, y); err == nil {
			v.MoveCursor(1, 0, false)
		}
	case gocui.KeyPgup:
		state.KeepAutoscrolling = false
		_, ySize := v.Size()
		for i := 0; i < ySize; i++ {
			v.MoveCursor(0, -1, false)
		}
	case gocui.KeyPgdn:
		state.KeepAutoscrolling = false
		_, ySize := v.Size()
		for i := 0; i < ySize; i++ {
			moveDown(v)
		}
	case gocui.KeyHome:
		state.KeepAutoscrolling = false
		v.SetCursor(0, 0)
		v.SetOrigin(0, 0)
	case gocui.KeyEnd:
		state.KeepAutoscrolling = false
		lines := len(strings.Split(v.ViewBuffer(), "\n"))
		_, y := v.Size()

		origin := lines - y - 1
		if origin < 0 {
			origin = 0
		}
		v.SetOrigin(0, origin)

		cursorY := y - 1
		if lines <= y {
			cursorY = lines - 2
		}
		v.SetCursor(0, cursorY)
	}
	if ch == 0 {
		return
	}

	switch ch {
	case 'c':
		if state.Conn != nil {
			state.Error("You need to close the connection before starting a new one: <ESC>q")
			return
		}
		state.Mode = modeConnect
		return
	case 'q':
		err := state.Conn.Close()
		if err != nil {
			state.Error(err.Error())
		}
		state.Debug("WebSocket closed")
		return
	case 'i':
		// goes into insert mode
	case 'h':
		state.HideHelp = false
	case 'j':
		// toggle JSON formatting
		state.Settings.JSONFormatting = !state.Settings.JSONFormatting
		err := state.Settings.Save()
		if err != nil {
			state.Error(err.Error())
		}
		e := "disabled"
		if state.Settings.JSONFormatting {
			e = "enabled"
		}
		state.Debug("JSON formatting " + e)
	case 't':
		// toggle timestamps
		if state.Settings.Timestamp == "" {
			state.Settings.Timestamp = "2006-01-02 15:04:05 "
		} else {
			state.Settings.Timestamp = ""
		}
		err := state.Settings.Save()
		if err != nil {
			state.Error(err.Error())
		}
		e := "disabled"
		if state.Settings.Timestamp != "" {
			e = "enabled"
		}
		state.Debug("Timestamps " + e)
	case 'R':
		// overwrite mode
		state.Mode = modeOverwrite
		return
	default:
		state.Debug("No action for key '" + string(ch) + "'")
		return
	}

	state.Mode = modeInsert
}
<|endoftext|>


<commit_before>package rproxy

import (
	"fmt"
	"net/http"
	//"net/http/httputil"
	//"net/url"
	"log"
)

type Server struct {
	// Matching against req.Host
	name    string
	backend *Backend
}

func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	s.backend.ServeHTTP(rw, req)
}

type Proxy struct {
	servers map[string]*Server
}

func NewProxy() *Proxy {
	p := &Proxy{}
	p.servers = make(map[string]*Server)
	return p
}

func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	log.Printf("Host: %s", req.Host)
	if server, found := p.servers[req.Host]; found {
		server.ServeHTTP(rw, req)
		return
	}
	http.Error(rw, http.StatusText(http.StatusBadGateway), http.StatusBadGateway)
}

func (p *Proxy) ParseServerConfig(req *http.Request) (error, *ServerConfig) {
	req.ParseForm()
	serverName := req.Form.Get("serverName")
	targetUrl := req.Form.Get("targetUrl")
	if serverName == "" || targetUrl == "" {
		return fmt.Errorf("You have to specify 'serverName' and 'targetUrl'"), nil
	}
	return nil, &ServerConfig{
		ServerName: serverName,
		TargetUrl:  targetUrl,
	}
}

func (p *Proxy) Register(serverName, targetUrl string) error {
	var server *Server
	if s, ok := p.servers[serverName]; ok {
		server = s
	} else {
		server = &Server{
			name:    serverName,
			backend: NewBackend(),
		}
	}

	err := server.backend.addNode(targetUrl)

	if err != nil {
		return err
	}

	p.servers[serverName] = server

	return nil
}

func (p *Proxy) Unregister(serverName, targetUrl string) error {
	s, ok := p.servers[serverName]

	if !ok {
		return fmt.Errorf("No server by name %s", serverName)
	}

	err := s.backend.deleteNode(targetUrl)
	if err != nil {
		return err
	}
	// no nodes left then remove server
	if len(s.backend.nodes) == 0 {
		delete(p.servers, serverName)
	}

	return nil
}

func (p *Proxy) RemoveServer(serverName string) error {
	_, ok := p.servers[serverName]
	if !ok {
		return fmt.Errorf("No server by name %s", serverName)
	}
	delete(p.servers, serverName)
	return nil
}
<commit_msg>hmm, InternalServerError is more suitable<commit_after>package rproxy

import (
	"fmt"
	"net/http"
	//"net/http/httputil"
	//"net/url"
	"log"
)

type Server struct {
	// Matching against req.Host
	name    string
	backend *Backend
}

func (s *Server) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	s.backend.ServeHTTP(rw, req)
}

type Proxy struct {
	servers map[string]*Server
}

func NewProxy() *Proxy {
	p := &Proxy{}
	p.servers = make(map[string]*Server)
	return p
}

func (p *Proxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	log.Printf("Host: %s", req.Host)
	if server, found := p.servers[req.Host]; found {
		server.ServeHTTP(rw, req)
		return
	}
	http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}

func (p *Proxy) ParseServerConfig(req *http.Request) (error, *ServerConfig) {
	req.ParseForm()
	serverName := req.Form.Get("serverName")
	targetUrl := req.Form.Get("targetUrl")
	if serverName == "" || targetUrl == "" {
		return fmt.Errorf("You have to specify 'serverName' and 'targetUrl'"), nil
	}
	return nil, &ServerConfig{
		ServerName: serverName,
		TargetUrl:  targetUrl,
	}
}

func (p *Proxy) Register(serverName, targetUrl string) error {
	var server *Server
	if s, ok := p.servers[serverName]; ok {
		server = s
	} else {
		server = &Server{
			name:    serverName,
			backend: NewBackend(),
		}
	}

	err := server.backend.addNode(targetUrl)

	if err != nil {
		return err
	}

	p.servers[serverName] = server

	return nil
}

func (p *Proxy) Unregister(serverName, targetUrl string) error {
	s, ok := p.servers[serverName]

	if !ok {
		return fmt.Errorf("No server by name %s", serverName)
	}

	err := s.backend.deleteNode(targetUrl)
	if err != nil {
		return err
	}
	// no nodes left then remove server
	if len(s.backend.nodes) == 0 {
		delete(p.servers, serverName)
	}

	return nil
}

func (p *Proxy) RemoveServer(serverName string) error {
	_, ok := p.servers[serverName]
	if !ok {
		return fmt.Errorf("No server by name %s", serverName)
	}
	delete(p.servers, serverName)
	return nil
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
	"sort"
	"strconv"
	"strings"
	"text/template"
)

var (
	columnSqlTemplate = initColumnSqlTemplate()
)

// Initializes the Sql template
func initColumnSqlTemplate() *template.Template {
	sql := `
SELECT table_schema
    , {{if eq $.DbSchema "*" }}table_schema || '.' || {{end}}table_name || '.' || column_name  AS compare_name
	, table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
    , is_identity
    , identity_generation
FROM information_schema.columns
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND table_schema NOT LIKE 'pg_%'
AND table_schema <> 'information_schema'
{{else}}
AND table_schema = '{{$.DbSchema}}'
{{end}}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

// ==================================
// Column Rows definition
// ==================================

// ColumnRows is a sortable slice of string maps
type ColumnRows []map[string]string

func (slice ColumnRows) Len() int {
	return len(slice)
}

func (slice ColumnRows) Less(i, j int) bool {
	return slice[i]["compare_name"] < slice[j]["compare_name"]
}

func (slice ColumnRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ==================================
// ColumnSchema definition
// (implements Schema -- defined in pgdiff.go)
// ==================================

// ColumnSchema holds a slice of rows from one of the databases as well as
// a reference to the current row of data we're viewing.
type ColumnSchema struct {
	rows   ColumnRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *ColumnSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *ColumnSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *ColumnSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, Compare needs a ColumnSchema instance", c2)
	}

	val := misc.CompareStrings(c.get("compare_name"), c2.get("compare_name"))
	return val
}

// Add prints SQL to add the column
func (c *ColumnSchema) Add() {

	schema := dbInfo2.DbSchema
	if schema == "*" {
		schema = c.get("table_schema")
	}

    // Knowing the version of db2 would eliminate the need for this warning
    if c.get("is_identity") == "YES" {
        fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
        fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
    }

	if c.get("data_type") == "character varying" {
		maxLength, valid := getMaxLength(c.get("character_maximum_length"))
		if !valid {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying", schema, c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying(%s)", schema, c.get("table_name"), c.get("column_name"), maxLength)
		}
	} else {
		if c.get("data_type") == "ARRAY" {
			fmt.Println("-- Note that adding of array data types are not yet generated properly.")
		}
		fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s %s", schema, c.get("table_name"), c.get("column_name"), c.get("data_type"))
	}

	if c.get("is_nullable") == "NO" {
		fmt.Printf(" NOT NULL")
	}
	if c.get("column_default") != "null" {
		fmt.Printf(" DEFAULT %s", c.get("column_default"))
	}
    // NOTE: there are more identity column sequence options according to the PostgreSQL
    // CREATE TABLE docs, but these do not appear to be available as of version 10.1
    if c.get("is_identity") == "YES" {
        fmt.Printf(" GENERATED %s AS IDENTITY", c.get("identity_generation"))
    }
	fmt.Printf(";\n")
}

// Drop prints SQL to drop the column
func (c *ColumnSchema) Drop() {
	// if dropping column
	fmt.Printf("ALTER TABLE %s.%s DROP COLUMN IF EXISTS %s;\n", c.get("table_schema"), c.get("table_name"), c.get("column_name"))
}

// Change handles the case where the table and column match, but the details do not
func (c *ColumnSchema) Change(obj interface{}) {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance", c2)
	}

	// Detect column type change (mostly varchar length, or number size increase)
	// (integer to/from bigint is OK)
	if c.get("data_type") == c2.get("data_type") {
		if c.get("data_type") == "character varying" {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			max2, max2Valid := getMaxLength(c2.get("character_maximum_length"))
			if !max1Valid && !max2Valid {
				// Leave them alone, they both have undefined max lengths
			} else if (max1Valid || !max2Valid) && (max1 != c2.get("character_maximum_length")) {
				//if !max1Valid {
				//    fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024, which may result in data loss.")
				//}
				max1Int, err1 := strconv.Atoi(max1)
				check("converting string to int", err1)
				max2Int, err2 := strconv.Atoi(max2)
				check("converting string to int", err2)
				if max1Int < max2Int {
					fmt.Println("-- WARNING: The next statement will shorten a character varying column, which may result in data loss.")
				}
				fmt.Printf("-- max1Valid: %v  max2Valid: %v \n", max1Valid, max2Valid)
				fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE character varying(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), max1)
			}
		}
	}

	// Code and test a column change from integer to bigint
	if c.get("data_type") != c2.get("data_type") {
		fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.get("data_type"), c.get("data_type"))
		if strings.HasPrefix(c.get("data_type"), "character") {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			if !max1Valid {
				fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024")
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"), max1)
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"))
		}
	}

	// Detect column default change (or added, dropped)
	if c.get("column_default") == "null" {
		if c.get("column_default") != "null" {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP DEFAULT;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	} else if c.get("column_default") != c2.get("column_default") {
		fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET DEFAULT %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("column_default"))
	}

    // Detect identity column change
    // Save result to variable instead of printing because order for adding/removing
    // is_nullable affects identity columns
    var identitySql string
    if c.get("is_identity") != c2.get("is_identity") {
        // Knowing the version of db2 would eliminate the need for this warning
        fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
        fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
        if c.get("is_identity") == "YES" {
            identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" ADD GENERATED %s AS IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("identity_generation"))
        } else {
            identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" DROP IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
        }
    }

	// Detect not-null and nullable change
	if c.get("is_nullable") != c2.get("is_nullable") {
		if c.get("is_nullable") == "YES" {
            if identitySql != "" {
                fmt.Printf(identitySql)
            }
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
            if identitySql != "" {
                fmt.Printf(identitySql)
            }
		}
	} else {
        if identitySql != "" {
            fmt.Printf(identitySql)
        }
    }
}

// ==================================
// Standalone Functions
// ==================================

// compareColumns outputs SQL to make the columns match between two databases or schemas
func compareColumns(conn1 *sql.DB, conn2 *sql.DB) {

	buf1 := new(bytes.Buffer)
	columnSqlTemplate.Execute(buf1, dbInfo1)

	buf2 := new(bytes.Buffer)
	columnSqlTemplate.Execute(buf2, dbInfo2)

	rowChan1, _ := pgutil.QueryStrings(conn1, buf1.String())
	rowChan2, _ := pgutil.QueryStrings(conn2, buf2.String())

	//rows1 := make([]map[string]string, 500)
	rows1 := make(ColumnRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	//rows2 := make([]map[string]string, 500)
	rows2 := make(ColumnRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(&rows2)

	// We have to explicitly type this as Schema here for some unknown reason
	var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &ColumnSchema{rows: rows2, rowNum: -1}

	// Compare the columns
	doDiff(schema1, schema2)
}

// getMaxLength returns the maximum length and whether or not it is valid
func getMaxLength(maxLength string) (string, bool) {

	if maxLength == "null" {
		// default to 1024
		return "1024", false
	}
	return maxLength, true
}
<commit_msg>Fix indentation issues<commit_after>//
// Copyright (c) 2017 Jon Carlson.  All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//

package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"github.com/joncrlsn/misc"
	"github.com/joncrlsn/pgutil"
	"sort"
	"strconv"
	"strings"
	"text/template"
)

var (
	columnSqlTemplate = initColumnSqlTemplate()
)

// Initializes the Sql template
func initColumnSqlTemplate() *template.Template {
	sql := `
SELECT table_schema
    , {{if eq $.DbSchema "*" }}table_schema || '.' || {{end}}table_name || '.' || column_name  AS compare_name
	, table_name
    , column_name
    , data_type
    , is_nullable
    , column_default
    , character_maximum_length
    , is_identity
    , identity_generation
FROM information_schema.columns
WHERE is_updatable = 'YES'
{{if eq $.DbSchema "*" }}
AND table_schema NOT LIKE 'pg_%'
AND table_schema <> 'information_schema'
{{else}}
AND table_schema = '{{$.DbSchema}}'
{{end}}
ORDER BY compare_name ASC;
`
	t := template.New("ColumnSqlTmpl")
	template.Must(t.Parse(sql))
	return t
}

// ==================================
// Column Rows definition
// ==================================

// ColumnRows is a sortable slice of string maps
type ColumnRows []map[string]string

func (slice ColumnRows) Len() int {
	return len(slice)
}

func (slice ColumnRows) Less(i, j int) bool {
	return slice[i]["compare_name"] < slice[j]["compare_name"]
}

func (slice ColumnRows) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

// ==================================
// ColumnSchema definition
// (implements Schema -- defined in pgdiff.go)
// ==================================

// ColumnSchema holds a slice of rows from one of the databases as well as
// a reference to the current row of data we're viewing.
type ColumnSchema struct {
	rows   ColumnRows
	rowNum int
	done   bool
}

// get returns the value from the current row for the given key
func (c *ColumnSchema) get(key string) string {
	if c.rowNum >= len(c.rows) {
		return ""
	}
	return c.rows[c.rowNum][key]
}

// NextRow increments the rowNum and tells you whether or not there are more
func (c *ColumnSchema) NextRow() bool {
	if c.rowNum >= len(c.rows)-1 {
		c.done = true
	}
	c.rowNum = c.rowNum + 1
	return !c.done
}

// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *ColumnSchema) Compare(obj interface{}) int {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, Compare needs a ColumnSchema instance", c2)
	}

	val := misc.CompareStrings(c.get("compare_name"), c2.get("compare_name"))
	return val
}

// Add prints SQL to add the column
func (c *ColumnSchema) Add() {

	schema := dbInfo2.DbSchema
	if schema == "*" {
		schema = c.get("table_schema")
	}

	// Knowing the version of db2 would eliminate the need for this warning
	if c.get("is_identity") == "YES" {
		fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
		fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
	}

	if c.get("data_type") == "character varying" {
		maxLength, valid := getMaxLength(c.get("character_maximum_length"))
		if !valid {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying", schema, c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s character varying(%s)", schema, c.get("table_name"), c.get("column_name"), maxLength)
		}
	} else {
		if c.get("data_type") == "ARRAY" {
			fmt.Println("-- Note that adding of array data types are not yet generated properly.")
		}
		fmt.Printf("ALTER TABLE %s.%s ADD COLUMN %s %s", schema, c.get("table_name"), c.get("column_name"), c.get("data_type"))
	}

	if c.get("is_nullable") == "NO" {
		fmt.Printf(" NOT NULL")
	}
	if c.get("column_default") != "null" {
		fmt.Printf(" DEFAULT %s", c.get("column_default"))
	}
	// NOTE: there are more identity column sequence options according to the PostgreSQL
	// CREATE TABLE docs, but these do not appear to be available as of version 10.1
	if c.get("is_identity") == "YES" {
		fmt.Printf(" GENERATED %s AS IDENTITY", c.get("identity_generation"))
	}
	fmt.Printf(";\n")
}

// Drop prints SQL to drop the column
func (c *ColumnSchema) Drop() {
	// if dropping column
	fmt.Printf("ALTER TABLE %s.%s DROP COLUMN IF EXISTS %s;\n", c.get("table_schema"), c.get("table_name"), c.get("column_name"))
}

// Change handles the case where the table and column match, but the details do not
func (c *ColumnSchema) Change(obj interface{}) {
	c2, ok := obj.(*ColumnSchema)
	if !ok {
		fmt.Println("Error!!!, ColumnSchema.Change(obj) needs a ColumnSchema instance", c2)
	}

	// Detect column type change (mostly varchar length, or number size increase)
	// (integer to/from bigint is OK)
	if c.get("data_type") == c2.get("data_type") {
		if c.get("data_type") == "character varying" {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			max2, max2Valid := getMaxLength(c2.get("character_maximum_length"))
			if !max1Valid && !max2Valid {
				// Leave them alone, they both have undefined max lengths
			} else if (max1Valid || !max2Valid) && (max1 != c2.get("character_maximum_length")) {
				//if !max1Valid {
				//    fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024, which may result in data loss.")
				//}
				max1Int, err1 := strconv.Atoi(max1)
				check("converting string to int", err1)
				max2Int, err2 := strconv.Atoi(max2)
				check("converting string to int", err2)
				if max1Int < max2Int {
					fmt.Println("-- WARNING: The next statement will shorten a character varying column, which may result in data loss.")
				}
				fmt.Printf("-- max1Valid: %v  max2Valid: %v \n", max1Valid, max2Valid)
				fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE character varying(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), max1)
			}
		}
	}

	// Code and test a column change from integer to bigint
	if c.get("data_type") != c2.get("data_type") {
		fmt.Printf("-- WARNING: This type change may not work well: (%s to %s).\n", c2.get("data_type"), c.get("data_type"))
		if strings.HasPrefix(c.get("data_type"), "character") {
			max1, max1Valid := getMaxLength(c.get("character_maximum_length"))
			if !max1Valid {
				fmt.Println("-- WARNING: varchar column has no maximum length.  Setting to 1024")
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s(%s);\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"), max1)
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s TYPE %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("data_type"))
		}
	}

	// Detect column default change (or added, dropped)
	if c.get("column_default") == "null" {
		if c.get("column_default") != "null" {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP DEFAULT;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	} else if c.get("column_default") != c2.get("column_default") {
		fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET DEFAULT %s;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("column_default"))
	}

	// Detect identity column change
	// Save result to variable instead of printing because order for adding/removing
	// is_nullable affects identity columns
	var identitySql string
	if c.get("is_identity") != c2.get("is_identity") {
		// Knowing the version of db2 would eliminate the need for this warning
		fmt.Println("-- WARNING: identity columns are not supported in PostgreSQL versions < 10.")
		fmt.Println("-- Attempting to create identity columns in earlier versions will probably result in errors.")
		if c.get("is_identity") == "YES" {
			identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" ADD GENERATED %s AS IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"), c.get("identity_generation"))
		} else {
			identitySql = fmt.Sprintf("ALTER TABLE \"%s\".\"%s\" ALTER COLUMN \"%s\" DROP IDENTITY;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		}
	}

	// Detect not-null and nullable change
	if c.get("is_nullable") != c2.get("is_nullable") {
		if c.get("is_nullable") == "YES" {
			if identitySql != "" {
				fmt.Printf(identitySql)
			}
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s DROP NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
		} else {
			fmt.Printf("ALTER TABLE %s.%s ALTER COLUMN %s SET NOT NULL;\n", c2.get("table_schema"), c.get("table_name"), c.get("column_name"))
			if identitySql != "" {
				fmt.Printf(identitySql)
			}
		}
	} else {
		if identitySql != "" {
			fmt.Printf(identitySql)
		}
	}
}

// ==================================
// Standalone Functions
// ==================================

// compareColumns outputs SQL to make the columns match between two databases or schemas
func compareColumns(conn1 *sql.DB, conn2 *sql.DB) {

	buf1 := new(bytes.Buffer)
	columnSqlTemplate.Execute(buf1, dbInfo1)

	buf2 := new(bytes.Buffer)
	columnSqlTemplate.Execute(buf2, dbInfo2)

	rowChan1, _ := pgutil.QueryStrings(conn1, buf1.String())
	rowChan2, _ := pgutil.QueryStrings(conn2, buf2.String())

	//rows1 := make([]map[string]string, 500)
	rows1 := make(ColumnRows, 0)
	for row := range rowChan1 {
		rows1 = append(rows1, row)
	}
	sort.Sort(rows1)

	//rows2 := make([]map[string]string, 500)
	rows2 := make(ColumnRows, 0)
	for row := range rowChan2 {
		rows2 = append(rows2, row)
	}
	sort.Sort(&rows2)

	// We have to explicitly type this as Schema here for some unknown reason
	var schema1 Schema = &ColumnSchema{rows: rows1, rowNum: -1}
	var schema2 Schema = &ColumnSchema{rows: rows2, rowNum: -1}

	// Compare the columns
	doDiff(schema1, schema2)
}

// getMaxLength returns the maximum length and whether or not it is valid
func getMaxLength(maxLength string) (string, bool) {

	if maxLength == "null" {
		// default to 1024
		return "1024", false
	}
	return maxLength, true
}
<|endoftext|>