<commit_before>package build

import (
	"flag"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
)

type Command byte

func (Command) Help() string {
	return strings.TrimSpace(helpText)
}

func (c Command) Run(env packer.Environment, args []string) int {
	var cfgOnly []string

	cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
	cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
	cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 {
		cmdFlags.Usage()
		return 1
	}

	// Read the file into a byte array so that we can parse the template
	log.Printf("Reading template: %s", args[0])
	tplData, err := ioutil.ReadFile(args[0])
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to read template file: %s", err))
		return 1
	}

	// Parse the template into a machine-usable format
	log.Println("Parsing template...")
	tpl, err := packer.ParseTemplate(tplData)
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
		return 1
	}

	// The component finder for our builds
	components := &packer.ComponentFinder{
		Builder:     env.Builder,
		Hook:        env.Hook,
		Provisioner: env.Provisioner,
	}

	// Go through each builder and compile the builds that we care about
	buildNames := tpl.BuildNames()
	builds := make([]packer.Build, 0, len(buildNames))
	for _, buildName := range buildNames {
		if len(cfgOnly) > 0 {
			found := false
			for _, only := range cfgOnly {
				if buildName == only {
					found = true
					break
				}
			}

			if !found {
				log.Printf("Skipping build '%s' because not specified by -only.", buildName)
				continue
			}
		}

		log.Printf("Creating build: %s", buildName)
		build, err := tpl.Build(buildName, components)
		if err != nil {
			env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err))
			return 1
		}

		builds = append(builds, build)
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorYellow,
		packer.UiColorBlue,
		packer.UiColorMagenta,
		packer.UiColorCyan,
	}

	buildUis := make(map[string]packer.Ui)
	for i, b := range builds {
		var ui packer.Ui

		ui = &packer.ColoredUi{
			colors[i%len(colors)],
			env.Ui(),
		}

		ui = &packer.PrefixedUi{
			fmt.Sprintf("==> %s", b.Name()),
			fmt.Sprintf("    %s", b.Name()),
			ui,
		}

		buildUis[b.Name()] = ui
		ui.Say(fmt.Sprintf("%s output will be in this color.", b.Name()))
	}

	// Prepare all the builds
	for _, b := range builds {
		log.Printf("Preparing build: %s", b.Name())
		err := b.Prepare(buildUis[b.Name()])
		if err != nil {
			env.Ui().Error(err.Error())
			return 1
		}
	}

	// Run all the builds in parallel and wait for them to complete
	var wg sync.WaitGroup
	artifacts := make(map[string]packer.Artifact)
	for _, b := range builds {
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Run the build in a goroutine
		go func(b packer.Build) {
			defer wg.Done()

			log.Printf("Starting build run: %s", b.Name())
			artifacts[b.Name()] = b.Run(buildUis[b.Name()])
			log.Printf("Build finished: %s", b.Name())
		}(b)
	}

	// Handle signals
	var interruptWg sync.WaitGroup
	interrupted := false
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)

	go func() {
		<-sigCh
		interruptWg.Add(1)
		defer interruptWg.Done()
		interrupted = true

		log.Println("Interrupted! Cancelling builds...")

		var wg sync.WaitGroup
		for _, b := range builds {
			wg.Add(1)

			go func(b packer.Build) {
				defer wg.Done()

				log.Printf("Stopping build: %s", b.Name())
				b.Cancel()
				log.Printf("Build cancelled: %s", b.Name())
			}(b)
		}

		wg.Wait()
	}()

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	log.Printf("Builds completed. Waiting on interrupt barrier...")
	interruptWg.Wait()
	log.Printf("Interrupt barrier passed.")

	if interrupted {
		env.Ui().Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	// Output all the artifacts
	env.Ui().Say("\n==> The build completed! The artifacts created were:")
	for name, artifact := range artifacts {
		env.Ui().Say(fmt.Sprintf("--> %s:", name))

		if artifact != nil {
			env.Ui().Say(artifact.String())
		} else {
			env.Ui().Say("<nothing>")
		}
	}

	return 0
}

func (Command) Synopsis() string {
	return "build image(s) from template"
}
<commit_msg>command/build: Say the build is finished when it is finished<commit_after>package build

import (
	"flag"
	"fmt"
	"github.com/mitchellh/packer/packer"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strings"
	"sync"
)

type Command byte

func (Command) Help() string {
	return strings.TrimSpace(helpText)
}

func (c Command) Run(env packer.Environment, args []string) int {
	var cfgOnly []string

	cmdFlags := flag.NewFlagSet("build", flag.ContinueOnError)
	cmdFlags.Usage = func() { env.Ui().Say(c.Help()) }
	cmdFlags.Var((*stringSliceValue)(&cfgOnly), "only", "only build the given builds by name")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) != 1 {
		cmdFlags.Usage()
		return 1
	}

	// Read the file into a byte array so that we can parse the template
	log.Printf("Reading template: %s", args[0])
	tplData, err := ioutil.ReadFile(args[0])
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to read template file: %s", err))
		return 1
	}

	// Parse the template into a machine-usable format
	log.Println("Parsing template...")
	tpl, err := packer.ParseTemplate(tplData)
	if err != nil {
		env.Ui().Error(fmt.Sprintf("Failed to parse template: %s", err))
		return 1
	}

	// The component finder for our builds
	components := &packer.ComponentFinder{
		Builder:     env.Builder,
		Hook:        env.Hook,
		Provisioner: env.Provisioner,
	}

	// Go through each builder and compile the builds that we care about
	buildNames := tpl.BuildNames()
	builds := make([]packer.Build, 0, len(buildNames))
	for _, buildName := range buildNames {
		if len(cfgOnly) > 0 {
			found := false
			for _, only := range cfgOnly {
				if buildName == only {
					found = true
					break
				}
			}

			if !found {
				log.Printf("Skipping build '%s' because not specified by -only.", buildName)
				continue
			}
		}

		log.Printf("Creating build: %s", buildName)
		build, err := tpl.Build(buildName, components)
		if err != nil {
			env.Ui().Error(fmt.Sprintf("Failed to create build '%s': \n\n%s", buildName, err))
			return 1
		}

		builds = append(builds, build)
	}

	// Compile all the UIs for the builds
	colors := [5]packer.UiColor{
		packer.UiColorGreen,
		packer.UiColorYellow,
		packer.UiColorBlue,
		packer.UiColorMagenta,
		packer.UiColorCyan,
	}

	buildUis := make(map[string]packer.Ui)
	for i, b := range builds {
		var ui packer.Ui

		ui = &packer.ColoredUi{
			colors[i%len(colors)],
			env.Ui(),
		}

		ui = &packer.PrefixedUi{
			fmt.Sprintf("==> %s", b.Name()),
			fmt.Sprintf("    %s", b.Name()),
			ui,
		}

		buildUis[b.Name()] = ui
		ui.Say(fmt.Sprintf("%s output will be in this color.", b.Name()))
	}

	// Prepare all the builds
	for _, b := range builds {
		log.Printf("Preparing build: %s", b.Name())
		err := b.Prepare(buildUis[b.Name()])
		if err != nil {
			env.Ui().Error(err.Error())
			return 1
		}
	}

	// Run all the builds in parallel and wait for them to complete
	var wg sync.WaitGroup
	artifacts := make(map[string]packer.Artifact)
	for _, b := range builds {
		// Increment the waitgroup so we wait for this item to finish properly
		wg.Add(1)

		// Run the build in a goroutine
		go func(b packer.Build) {
			defer wg.Done()

			log.Printf("Starting build run: %s", b.Name())
			ui := buildUis[b.Name()]
			artifacts[b.Name()] = b.Run(ui)
			ui.Say("Build finished.")
		}(b)
	}

	// Handle signals
	var interruptWg sync.WaitGroup
	interrupted := false
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, os.Interrupt)

	go func() {
		<-sigCh
		interruptWg.Add(1)
		defer interruptWg.Done()
		interrupted = true

		log.Println("Interrupted! Cancelling builds...")

		var wg sync.WaitGroup
		for _, b := range builds {
			wg.Add(1)

			go func(b packer.Build) {
				defer wg.Done()

				log.Printf("Stopping build: %s", b.Name())
				b.Cancel()
				log.Printf("Build cancelled: %s", b.Name())
			}(b)
		}

		wg.Wait()
	}()

	// Wait for both the builds to complete and the interrupt handler,
	// if it is interrupted.
	log.Printf("Waiting on builds to complete...")
	wg.Wait()

	log.Printf("Builds completed. Waiting on interrupt barrier...")
	interruptWg.Wait()
	log.Printf("Interrupt barrier passed.")

	if interrupted {
		env.Ui().Say("Cleanly cancelled builds after being interrupted.")
		return 1
	}

	// Output all the artifacts
	env.Ui().Say("\n==> The build completed! The artifacts created were:")
	for name, artifact := range artifacts {
		env.Ui().Say(fmt.Sprintf("--> %s:", name))

		if artifact != nil {
			env.Ui().Say(artifact.String())
		} else {
			env.Ui().Say("<nothing>")
		}
	}

	return 0
}

func (Command) Synopsis() string {
	return "build image(s) from template"
}
<|endoftext|>


<commit_before>package command

import (
	"path/filepath"
	"sort"
	"testing"

	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

func TestStateRm(t *testing.T) {
	state := &terraform.State{
		Modules: []*terraform.ModuleState{
			&terraform.ModuleState{
				Path: []string{"root"},
				Resources: map[string]*terraform.ResourceState{
					"test_instance.foo": &terraform.ResourceState{
						Type: "test_instance",
						Primary: &terraform.InstanceState{
							ID: "bar",
							Attributes: map[string]string{
								"foo": "value",
								"bar": "value",
							},
						},
					},

					"test_instance.bar": &terraform.ResourceState{
						Type: "test_instance",
						Primary: &terraform.InstanceState{
							ID: "foo",
							Attributes: map[string]string{
								"foo": "value",
								"bar": "value",
							},
						},
					},
				},
			},
		},
	}

	statePath := testStateFile(t, state)

	p := testProvider()
	ui := new(cli.MockUi)
	c := &StateRmCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(p),
			Ui:          ui,
		},
	}

	args := []string{
		"-state", statePath,
		"test_instance.foo",
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}

	// Test it is correct
	testStateOutput(t, statePath, testStateRmOutput)

	// Test we have backups
	backups := testStateBackups(t, filepath.Dir(statePath))
	if len(backups) != 1 {
		t.Fatalf("bad: %#v", backups)
	}
	testStateOutput(t, backups[0], testStateRmOutputOriginal)
}

func TestStateRm_noState(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	p := testProvider()
	ui := new(cli.MockUi)
	c := &StateRmCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(p),
			Ui:          ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}
}

const testStateRmOutputOriginal = `
test_instance.bar:
  ID = foo
  bar = value
  foo = value
test_instance.foo:
  ID = bar
  bar = value
  foo = value
`

const testStateRmOutput = `
test_instance.bar:
  ID = foo
  bar = value
  foo = value
`
<commit_msg>Update state_rm_test.go<commit_after>package command

import (
	"path/filepath"
	"testing"

	"github.com/hashicorp/terraform/terraform"
	"github.com/mitchellh/cli"
)

func TestStateRm(t *testing.T) {
	state := &terraform.State{
		Modules: []*terraform.ModuleState{
			&terraform.ModuleState{
				Path: []string{"root"},
				Resources: map[string]*terraform.ResourceState{
					"test_instance.foo": &terraform.ResourceState{
						Type: "test_instance",
						Primary: &terraform.InstanceState{
							ID: "bar",
							Attributes: map[string]string{
								"foo": "value",
								"bar": "value",
							},
						},
					},

					"test_instance.bar": &terraform.ResourceState{
						Type: "test_instance",
						Primary: &terraform.InstanceState{
							ID: "foo",
							Attributes: map[string]string{
								"foo": "value",
								"bar": "value",
							},
						},
					},
				},
			},
		},
	}

	statePath := testStateFile(t, state)

	p := testProvider()
	ui := new(cli.MockUi)
	c := &StateRmCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(p),
			Ui:          ui,
		},
	}

	args := []string{
		"-state", statePath,
		"test_instance.foo",
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}

	// Test it is correct
	testStateOutput(t, statePath, testStateRmOutput)

	// Test we have backups
	backups := testStateBackups(t, filepath.Dir(statePath))
	if len(backups) != 1 {
		t.Fatalf("bad: %#v", backups)
	}
	testStateOutput(t, backups[0], testStateRmOutputOriginal)
}

func TestStateRm_noState(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	p := testProvider()
	ui := new(cli.MockUi)
	c := &StateRmCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(p),
			Ui:          ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
	}
}

const testStateRmOutputOriginal = `
test_instance.bar:
  ID = foo
  bar = value
  foo = value
test_instance.foo:
  ID = bar
  bar = value
  foo = value
`

const testStateRmOutput = `
test_instance.bar:
  ID = foo
  bar = value
  foo = value
`
<|endoftext|>


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

package stats

import (
	"encoding/json"
	"log"
	"sync"
	"time"

	"github.com/coreos/etcd/raft"
)

// ServerStats encapsulates various statistics about an EtcdServer and its
// communication with other members of the cluster
type ServerStats struct {
	serverStats
	sync.Mutex
}

func NewServerStats(name, id string) *ServerStats {
	ss := &ServerStats{
		serverStats: serverStats{
			Name: name,
			ID:   id,
		},
	}
	now := time.Now()
	ss.StartTime = now
	ss.LeaderInfo.StartTime = now
	ss.sendRateQueue = &statsQueue{back: -1}
	ss.recvRateQueue = &statsQueue{back: -1}
	return ss
}

type serverStats struct {
	Name string `json:"name"`
	// ID is the raft ID of the node.
	// TODO(jonboulle): use ID instead of name?
	ID        string         `json:"id"`
	State     raft.StateType `json:"state"`
	StartTime time.Time      `json:"startTime"`

	LeaderInfo struct {
		Name      string    `json:"leader"`
		Uptime    string    `json:"uptime"`
		StartTime time.Time `json:"startTime"`
	} `json:"leaderInfo"`

	RecvAppendRequestCnt uint64  `json:"recvAppendRequestCnt,"`
	RecvingPkgRate       float64 `json:"recvPkgRate,omitempty"`
	RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"`

	SendAppendRequestCnt uint64  `json:"sendAppendRequestCnt"`
	SendingPkgRate       float64 `json:"sendPkgRate,omitempty"`
	SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`

	sendRateQueue *statsQueue
	recvRateQueue *statsQueue
}

func (ss *ServerStats) JSON() []byte {
	ss.Lock()
	stats := ss.serverStats
	stats.SendingPkgRate, stats.SendingBandwidthRate = stats.sendRateQueue.Rate()
	stats.RecvingPkgRate, stats.RecvingBandwidthRate = stats.recvRateQueue.Rate()
	ss.Unlock()
	stats.LeaderInfo.Uptime = time.Since(stats.LeaderInfo.StartTime).String()
	b, err := json.Marshal(stats)
	// TODO(jonboulle): appropriate error handling?
	if err != nil {
		log.Printf("stats: error marshalling server stats: %v", err)
	}
	return b
}

// RecvAppendReq updates the ServerStats in response to an AppendRequest
// from the given leader being received
func (ss *ServerStats) RecvAppendReq(leader string, reqSize int) {
	ss.Lock()
	defer ss.Unlock()

	now := time.Now()

	ss.State = raft.StateFollower
	if leader != ss.LeaderInfo.Name {
		ss.LeaderInfo.Name = leader
		ss.LeaderInfo.StartTime = now
	}

	ss.recvRateQueue.Insert(
		&RequestStats{
			SendingTime: now,
			Size:        reqSize,
		},
	)
	ss.RecvAppendRequestCnt++
}

// SendAppendReq updates the ServerStats in response to an AppendRequest
// being sent by this server
func (ss *ServerStats) SendAppendReq(reqSize int) {
	ss.Lock()
	defer ss.Unlock()

	ss.becomeLeader()

	ss.sendRateQueue.Insert(
		&RequestStats{
			SendingTime: time.Now(),
			Size:        reqSize,
		},
	)

	ss.SendAppendRequestCnt++
}

func (ss *ServerStats) BecomeLeader() {
	ss.Lock()
	defer ss.Unlock()
	ss.becomeLeader()
}

func (ss *ServerStats) becomeLeader() {
	if ss.State != raft.StateLeader {
		ss.State = raft.StateLeader
		ss.LeaderInfo.Name = ss.ID
		ss.LeaderInfo.StartTime = time.Now()
	}
}
<commit_msg>etcdserver/stats: make all fields guarded by mutex.<commit_after>// Copyright 2015 The etcd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package stats

import (
	"encoding/json"
	"log"
	"sync"
	"time"

	"github.com/coreos/etcd/raft"
)

// ServerStats encapsulates various statistics about an EtcdServer and its
// communication with other members of the cluster
type ServerStats struct {
	serverStats
	sync.Mutex
}

func NewServerStats(name, id string) *ServerStats {
	ss := &ServerStats{
		serverStats: serverStats{
			Name: name,
			ID:   id,
		},
	}
	now := time.Now()
	ss.StartTime = now
	ss.LeaderInfo.StartTime = now
	ss.sendRateQueue = &statsQueue{back: -1}
	ss.recvRateQueue = &statsQueue{back: -1}
	return ss
}

type serverStats struct {
	Name string `json:"name"`
	// ID is the raft ID of the node.
	// TODO(jonboulle): use ID instead of name?
	ID        string         `json:"id"`
	State     raft.StateType `json:"state"`
	StartTime time.Time      `json:"startTime"`

	LeaderInfo struct {
		Name      string    `json:"leader"`
		Uptime    string    `json:"uptime"`
		StartTime time.Time `json:"startTime"`
	} `json:"leaderInfo"`

	RecvAppendRequestCnt uint64  `json:"recvAppendRequestCnt,"`
	RecvingPkgRate       float64 `json:"recvPkgRate,omitempty"`
	RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"`

	SendAppendRequestCnt uint64  `json:"sendAppendRequestCnt"`
	SendingPkgRate       float64 `json:"sendPkgRate,omitempty"`
	SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`

	sendRateQueue *statsQueue
	recvRateQueue *statsQueue
}

func (ss *ServerStats) JSON() []byte {
	ss.Lock()
	stats := ss.serverStats
	stats.SendingPkgRate, stats.SendingBandwidthRate = stats.sendRateQueue.Rate()
	stats.RecvingPkgRate, stats.RecvingBandwidthRate = stats.recvRateQueue.Rate()
	stats.LeaderInfo.Uptime = time.Since(stats.LeaderInfo.StartTime).String()
	ss.Unlock()
	b, err := json.Marshal(stats)
	// TODO(jonboulle): appropriate error handling?
	if err != nil {
		log.Printf("stats: error marshalling server stats: %v", err)
	}
	return b
}

// RecvAppendReq updates the ServerStats in response to an AppendRequest
// from the given leader being received
func (ss *ServerStats) RecvAppendReq(leader string, reqSize int) {
	ss.Lock()
	defer ss.Unlock()

	now := time.Now()

	ss.State = raft.StateFollower
	if leader != ss.LeaderInfo.Name {
		ss.LeaderInfo.Name = leader
		ss.LeaderInfo.StartTime = now
	}

	ss.recvRateQueue.Insert(
		&RequestStats{
			SendingTime: now,
			Size:        reqSize,
		},
	)
	ss.RecvAppendRequestCnt++
}

// SendAppendReq updates the ServerStats in response to an AppendRequest
// being sent by this server
func (ss *ServerStats) SendAppendReq(reqSize int) {
	ss.Lock()
	defer ss.Unlock()

	ss.becomeLeader()

	ss.sendRateQueue.Insert(
		&RequestStats{
			SendingTime: time.Now(),
			Size:        reqSize,
		},
	)

	ss.SendAppendRequestCnt++
}

func (ss *ServerStats) BecomeLeader() {
	ss.Lock()
	defer ss.Unlock()
	ss.becomeLeader()
}

func (ss *ServerStats) becomeLeader() {
	if ss.State != raft.StateLeader {
		ss.State = raft.StateLeader
		ss.LeaderInfo.Name = ss.ID
		ss.LeaderInfo.StartTime = time.Now()
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strconv"

	awssdk "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/elbv2"

	"github.com/gliderlabs/registrator/bridge"
	eureka "github.com/hudl/fargo"
)

// LBInfo represents a ELBv2 endpoint
type LBInfo struct {
	DNSName string
	Port    int64
}

var lbCache = make(map[string]*LBInfo)

// getELBV2ForContainer returns an LBInfo struct with the load balancer DNS name and listener port for a given instanceId and port
// if an error occurs, or the target is not found, an empty LBInfo is returned. Return the DNS:port pair as an identifier to put in the container's registration metadata
// Pass it the instanceID for the docker host, and the the host port to lookup the associated ELB.
func getELBV2ForContainer(instanceID string, port int64, useCache bool) (lbinfo *LBInfo, err error) {

	// Retrieve from basic cache (for heartbeats)
	cacheKey := instanceID + "_" + strconv.FormatInt(port, 10)
	if useCache && lbCache[cacheKey] != nil {
		log.Println("Retrieving value from cache.")
		return lbCache[cacheKey], nil
	}

	var lb []*string
	var lbPort *int64
	info := &LBInfo{}

	sess, err := session.NewSession()
	if err != nil {
		message := fmt.Errorf("Failed to create session connecting to AWS: %s", err)
		return nil, message
	}

	// Need to set the region here - we'll get it from instance metadata
	awsMetadata := GetMetadata()
	svc := elbv2.New(sess, awssdk.NewConfig().WithRegion(awsMetadata.Region))

	// Loop through target group pages and check for port and instanceID
	// TODO: This needs to handle lots of target groups efficiently
	params := &elbv2.DescribeTargetGroupsInput{
		PageSize: awssdk.Int64(400),
	}
	tgs, err := svc.DescribeTargetGroups(params)

	if err != nil {
		log.Printf("An error occurred using DescribeTargetGroups: %s \n", err.Error())
		return nil, err
	}

	// Check each target group for a matching port and instanceID
	// Assumption: that that there is only one LB for the target group (though the data structure allows more)
	for _, tg := range tgs.TargetGroups {
		params4 := &elbv2.DescribeTargetHealthInput{
			TargetGroupArn: awssdk.String(*tg.TargetGroupArn),
		}
		tarH, err := svc.DescribeTargetHealth(params4)

		for _, thd := range tarH.TargetHealthDescriptions {
			if *thd.Target.Port == port && *thd.Target.Id == instanceID {
				lb = tg.LoadBalancerArns
				lbPort = tg.Port
			}

		}
		if err != nil {
			log.Printf("An error occurred using DescribeTargetHealth: %s \n", err.Error())
			return nil, err
		}
	}

	params2 := &elbv2.DescribeLoadBalancersInput{
		LoadBalancerArns: lb,
	}
	lbData, err := svc.DescribeLoadBalancers(params2)

	if err != nil {
		log.Printf("An error occurred using DescribeLoadBalancers: %s \n", err.Error())
		return nil, err
	}
	log.Printf("LB Endpoint is: %s:%s\n", *lbData.LoadBalancers[0].DNSName, strconv.FormatInt(*lbPort, 10))

	info.DNSName = *lbData.LoadBalancers[0].DNSName
	info.Port = *lbPort

	// Add to a basic cache for heartbeats
	lbCache[cacheKey] = info

	return info, err
}

// CheckELBFlags - Helper function to check if the correct config flags are set to use ELBs
func CheckELBFlags(service *bridge.Service) bool {
	if service.Attrs["eureka_use_elbv2_endpoint"] != "" && service.Attrs["eureka_datacenterinfo_name"] != eureka.MyOwn {
		v, err := strconv.ParseBool(service.Attrs["eureka_use_elbv2_endpoint"])
		if err != nil {
			log.Printf("eureka: eureka_use_elbv2_endpoint must be valid boolean, was %v : %s", v, err)
			return false
		}
		return v
	}
	return false
}

// Helper function to create a registration struct, and change container registration
func setRegInfo(service *bridge.Service, registration *eureka.Instance, useCache bool) *eureka.Instance {

	awsMetadata := GetMetadata()

	elbMetadata, err := getELBV2ForContainer(awsMetadata.InstanceID, int64(registration.Port), useCache)

	if err != nil {
		log.Printf("Unable to find associated ELBv2 for: %s, Error: %s\n", registration.HostName, err)
		return nil
	}

	elbStrPort := strconv.FormatInt(elbMetadata.Port, 10)
	elbEndpoint := elbMetadata.DNSName + "_" + elbStrPort

	registration.SetMetadataString("has-elbv2", "true")
	registration.SetMetadataString("elbv2-endpoint", elbEndpoint)

	elbReg := new(eureka.Instance)

	// Put a little metadata in here as required - setting InstanceID to the ELB endpoint prevents double registration
	elbReg.DataCenterInfo.Metadata = eureka.AmazonMetadataType{
		PublicHostname: elbMetadata.DNSName,
		HostName:       elbMetadata.DNSName,
		InstanceID:     elbEndpoint,
	}

	elbReg.Port = int(elbMetadata.Port)
	elbReg.IPAddr = elbMetadata.DNSName
	elbReg.App = service.Name
	elbReg.VipAddress = elbReg.IPAddr
	elbReg.HostName = elbMetadata.DNSName
	elbReg.DataCenterInfo.Name = eureka.Amazon
	elbReg.SetMetadataString("is-elbv2", "true")
	return elbReg
}

// RegisterELBv2 - If specified, also register an ELBv2 (application load balancer, ALB) endpoint in eureka, and alter service name
// for container registrations.  This will mean traffic is directed to the ALB rather than directly to containers
// though they are still registered in eureka for information purposes
func RegisterELBv2(service *bridge.Service, registration *eureka.Instance, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		log.Printf("Found ELBv2 flags, will attempt to register LB for: %s\n", registration.HostName)
		elbReg := setRegInfo(service, registration, false)
		if elbReg != nil {
			client.RegisterInstance(elbReg)
		}
	}
}

// DeregisterELBv2 - If specified, and all containers are gone, also deregister the ELBv2 (application load balancer, ALB) endpoint in eureka.
//
func DeregisterELBv2(service *bridge.Service, regDNSName string, regPort int64, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		// Check if there are any containers around with this ALB still attached
		elbStrPort := strconv.FormatInt(regPort, 10)
		log.Printf("Found ELBv2 flags, will check if it needs to be deregistered too, for: %s:%v\n", regDNSName, elbStrPort)
		albName := regDNSName + "_" + elbStrPort
		appName := "CONTAINER_" + service.Name
		app, err := client.GetApp(appName)
		if app != nil {
			for _, instance := range app.Instances {
				val, err := instance.Metadata.GetString("elbv2_endpoint")
				if err == nil && val == albName {
					log.Printf("Eureka entry still present for one or more ALB linked containers: %s\n", val)
					return
				}
			}
		}
		if err != nil {
			log.Printf("Unable to retrieve app metadata for %s: %s\n", appName, err)
		}

		if app == nil {
			log.Printf("Removing eureka entry for ELBv2: %s\n", albName)
			elbReg := new(eureka.Instance)
			elbReg.IPAddr = regDNSName
			elbReg.App = service.Name
			elbReg.HostName = albName // This uses the full endpoint identifier so eureka can find it to remove
			client.DeregisterInstance(elbReg)
		}
	}
}

// HeartbeatELBv2 - Send a heartbeat to eureka for this ELBv2 registration.  Every host running registrator will send heartbeats, meaning they will
// be received more frequently than the --ttl-refresh interval if there are multiple hosts running registrator.
//
func HeartbeatELBv2(service *bridge.Service, registration *eureka.Instance, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		log.Printf("Heartbeating ELBv2 for container: %s)\n", registration.HostName)

		elbReg := setRegInfo(service, registration, true)
		if elbReg != nil {
			client.HeartBeatInstance(elbReg)
		}
	}
}
<commit_msg>Fixes following CR<commit_after>package aws

import (
	"fmt"
	"log"
	"strconv"

	awssdk "github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/elbv2"

	"github.com/gliderlabs/registrator/bridge"
	eureka "github.com/hudl/fargo"
)

// LBInfo represents a ELBv2 endpoint
type LBInfo struct {
	DNSName string
	Port    int64
}

var lbCache = make(map[string]*LBInfo)

// getELBV2ForContainer returns an LBInfo struct with the load balancer DNS name and listener port for a given instanceId and port
// if an error occurs, or the target is not found, an empty LBInfo is returned.
// Return the DNS:port pair as an identifier to put in the container's registration metadata
// Pass it the instanceID for the docker host, and the the host port to lookup the associated ELB.
// useCache parameter, if true, will retrieve ELBv2 details from memory, rather than calling AWS.
// this is only really safe to use for heartbeat calls, as details can change dynamically
func getELBV2ForContainer(instanceID string, port int64, useCache bool) (lbinfo *LBInfo, err error) {

	// Retrieve from basic cache (for heartbeats)
	cacheKey := instanceID + "_" + strconv.FormatInt(port, 10)
	if val, ok := lbCache[cacheKey]; ok && useCache {
		log.Println("Retrieving value from cache.")
		return val, nil
	}

	var lb []*string
	var lbPort *int64
	info := &LBInfo{}

	sess, err := session.NewSession()
	if err != nil {
		message := fmt.Errorf("Failed to create session connecting to AWS: %s", err)
		return nil, message
	}

	// Need to set the region here - we'll get it from instance metadata
	awsMetadata := GetMetadata()
	svc := elbv2.New(sess, awssdk.NewConfig().WithRegion(awsMetadata.Region))

	// Loop through target group pages and check for port and instanceID
	// TODO: This needs to handle lots of target groups efficiently
	params := &elbv2.DescribeTargetGroupsInput{
		PageSize: awssdk.Int64(400),
	}
	tgs, err := svc.DescribeTargetGroups(params)

	if err != nil {
		log.Printf("An error occurred using DescribeTargetGroups: %s \n", err.Error())
		return nil, err
	}

	// Check each target group for a matching port and instanceID
	// Assumption: that that there is only one LB for the target group (though the data structure allows more)
	for _, tg := range tgs.TargetGroups {
		params4 := &elbv2.DescribeTargetHealthInput{
			TargetGroupArn: awssdk.String(*tg.TargetGroupArn),
		}
		tarH, err := svc.DescribeTargetHealth(params4)

		for _, thd := range tarH.TargetHealthDescriptions {
			if *thd.Target.Port == port && *thd.Target.Id == instanceID {
				lb = tg.LoadBalancerArns
				lbPort = tg.Port
			}

		}
		if err != nil {
			log.Printf("An error occurred using DescribeTargetHealth: %s \n", err.Error())
			return nil, err
		}
	}

	params2 := &elbv2.DescribeLoadBalancersInput{
		LoadBalancerArns: lb,
	}
	lbData, err := svc.DescribeLoadBalancers(params2)

	if err != nil {
		log.Printf("An error occurred using DescribeLoadBalancers: %s \n", err.Error())
		return nil, err
	}
	log.Printf("LB Endpoint is: %s:%s\n", *lbData.LoadBalancers[0].DNSName, strconv.FormatInt(*lbPort, 10))

	info.DNSName = *lbData.LoadBalancers[0].DNSName
	info.Port = *lbPort

	// Add to a basic cache for heartbeats
	lbCache[cacheKey] = info

	return info, nil
}

// CheckELBFlags - Helper function to check if the correct config flags are set to use ELBs
func CheckELBFlags(service *bridge.Service) bool {
	if service.Attrs["eureka_use_elbv2_endpoint"] != "" && service.Attrs["eureka_datacenterinfo_name"] != eureka.MyOwn {
		v, err := strconv.ParseBool(service.Attrs["eureka_use_elbv2_endpoint"])
		if err != nil {
			log.Printf("eureka: eureka_use_elbv2_endpoint must be valid boolean, was %v : %s", v, err)
			return false
		}
		return v
	}
	return false
}

// Helper function to create a registration struct, and change container registration
// useCache parameter is passed to getELBV2ForContainer
func setRegInfo(service *bridge.Service, registration *eureka.Instance, useCache bool) *eureka.Instance {

	awsMetadata := GetMetadata()

	elbMetadata, err := getELBV2ForContainer(awsMetadata.InstanceID, int64(registration.Port), useCache)

	if err != nil {
		log.Printf("Unable to find associated ELBv2 for: %s, Error: %s\n", registration.HostName, err)
		return nil
	}

	elbStrPort := strconv.FormatInt(elbMetadata.Port, 10)
	elbEndpoint := elbMetadata.DNSName + "_" + elbStrPort

	registration.SetMetadataString("has-elbv2", "true")
	registration.SetMetadataString("elbv2-endpoint", elbEndpoint)

	elbReg := new(eureka.Instance)

	// Put a little metadata in here as required - setting InstanceID to the ELB endpoint prevents double registration
	elbReg.DataCenterInfo.Metadata = eureka.AmazonMetadataType{
		PublicHostname: elbMetadata.DNSName,
		HostName:       elbMetadata.DNSName,
		InstanceID:     elbEndpoint,
	}

	elbReg.Port = int(elbMetadata.Port)
	elbReg.IPAddr = elbMetadata.DNSName
	elbReg.App = service.Name
	elbReg.VipAddress = elbReg.IPAddr
	elbReg.HostName = elbMetadata.DNSName
	elbReg.DataCenterInfo.Name = eureka.Amazon
	elbReg.SetMetadataString("is-elbv2", "true")
	return elbReg
}

// RegisterELBv2 - If specified, also register an ELBv2 (application load balancer, ALB) endpoint in eureka, and alter service name
// for container registrations.  This will mean traffic is directed to the ALB rather than directly to containers
// though they are still registered in eureka for information purposes
func RegisterELBv2(service *bridge.Service, registration *eureka.Instance, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		log.Printf("Found ELBv2 flags, will attempt to register LB for: %s\n", registration.HostName)
		elbReg := setRegInfo(service, registration, false)
		if elbReg != nil {
			client.RegisterInstance(elbReg)
		}
	}
}

// DeregisterELBv2 - If specified, and all containers are gone, also deregister the ELBv2 (application load balancer, ALB) endpoint in eureka.
//
func DeregisterELBv2(service *bridge.Service, regDNSName string, regPort int64, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		// Check if there are any containers around with this ALB still attached
		elbStrPort := strconv.FormatInt(regPort, 10)
		log.Printf("Found ELBv2 flags, will check if it needs to be deregistered too, for: %s:%v\n", regDNSName, elbStrPort)
		albName := regDNSName + "_" + elbStrPort
		appName := "CONTAINER_" + service.Name
		app, err := client.GetApp(appName)
		if app != nil {
			for _, instance := range app.Instances {
				val, err := instance.Metadata.GetString("elbv2_endpoint")
				if err == nil && val == albName {
					log.Printf("Eureka entry still present for one or more ALB linked containers: %s\n", val)
					return
				}
			}
		}
		if err != nil {
			log.Printf("Unable to retrieve app metadata for %s: %s\n", appName, err)
		}

		if app == nil {
			log.Printf("Removing eureka entry for ELBv2: %s\n", albName)
			elbReg := new(eureka.Instance)
			elbReg.IPAddr = regDNSName
			elbReg.App = service.Name
			elbReg.HostName = albName // This uses the full endpoint identifier so eureka can find it to remove
			client.DeregisterInstance(elbReg)
		}
	}
}

// HeartbeatELBv2 - Send a heartbeat to eureka for this ELBv2 registration.  Every host running registrator will send heartbeats, meaning they will
// be received more frequently than the --ttl-refresh interval if there are multiple hosts running registrator.
//
func HeartbeatELBv2(service *bridge.Service, registration *eureka.Instance, client eureka.EurekaConnection) {
	if CheckELBFlags(service) {
		log.Printf("Heartbeating ELBv2 for container: %s)\n", registration.HostName)

		elbReg := setRegInfo(service, registration, true) // Can safely use cache when heartbeating
		if elbReg != nil {
			client.HeartBeatInstance(elbReg)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"strconv"
	"strings"
	"time"
)

var errUnknownTimeUnits = errors.New("unknown time units")

// dateParamToEpoch turns a passed string parameter into an epoch we can send to the Zipper
func dateParamToEpoch(s string, d int64) int32 {

	if s == "" {
		// return the default if nothing was passed
		return int32(d)
	}

	// relative timestamp
	if s[0] == '-' {

		offset, err := intervalString(s, -1)
		if err != nil {
			return int32(d)
		}

		return int32(timeNow().Add(time.Duration(offset) * time.Second).Unix())
	}

	if s == "now" {
		return int32(timeNow().Unix())
	}

	sint, err := strconv.Atoi(s)
	if err == nil && len(s) > 8 {
		return int32(sint) // We got a timestamp so returning it
	}

	if strings.Contains(s, "_") {
		s = strings.Replace(s, "_", " ", 1) // Go can't parse _ in date strings
	}

	for _, format := range timeFormats {
		t, err := time.ParseInLocation(format, s, defaultTimeZone)
		if err == nil {
			return int32(t.Unix())
		}
	}
	return int32(d)
}

func intervalString(s string, defaultSign int) (int32, error) {

	sign := defaultSign

	switch s[0] {
	case '-':
		sign = -1
		s = s[1:]
	case '+':
		sign = 1
		s = s[1:]
	}

	var totalInterval int32
	for len(s) > 0 {
		var j int
		for j < len(s) && '0' <= s[j] && s[j] <= '9' {
			j++
		}
		var offsetStr string
		offsetStr, s = s[:j], s[j:]

		j = 0
		for j < len(s) && (s[j] < '0' || '9' < s[j]) {
			j++
		}
		var unitStr string
		unitStr, s = s[:j], s[j:]

		var units int
		switch unitStr {
		case "s", "sec", "secs", "second", "seconds":
			units = 1
		case "min", "mins", "minute", "minutes":
			units = 60
		case "h", "hour", "hours":
			units = 60 * 60
		case "d", "day", "days":
			units = 24 * 60 * 60
		case "w", "week", "weeks":
			units = 7 * 24 * 60 * 60
		case "mon", "month", "months":
			units = 30 * 24 * 60 * 60
		case "y", "year", "years":
			units = 365 * 24 * 60 * 60
		default:
			return 0, errUnknownTimeUnits
		}

		offset, err := strconv.Atoi(offsetStr)
		if err != nil {
			return 0, err
		}
		totalInterval += int32(sign * offset * units)
	}

	return totalInterval, nil
}
<commit_msg>fix comments. honor abstraction (no zipper specific things here)<commit_after>package main

import (
	"errors"
	"strconv"
	"strings"
	"time"
)

var errUnknownTimeUnits = errors.New("unknown time units")

// dateParamToEpoch turns a passed string parameter into a unix epoch
func dateParamToEpoch(s string, d int64) int32 {

	if s == "" {
		// return the default if nothing was passed
		return int32(d)
	}

	// relative timestamp
	if s[0] == '-' {

		offset, err := intervalString(s, -1)
		if err != nil {
			return int32(d)
		}

		return int32(timeNow().Add(time.Duration(offset) * time.Second).Unix())
	}

	if s == "now" {
		return int32(timeNow().Unix())
	}

	sint, err := strconv.Atoi(s)
	if err == nil && len(s) > 8 {
		return int32(sint) // We got a timestamp so returning it
	}

	if strings.Contains(s, "_") {
		s = strings.Replace(s, "_", " ", 1) // Go can't parse _ in date strings
	}

	for _, format := range timeFormats {
		t, err := time.ParseInLocation(format, s, defaultTimeZone)
		if err == nil {
			return int32(t.Unix())
		}
	}
	return int32(d)
}

// intervalString converts a sign and string into a number of seconds
func intervalString(s string, defaultSign int) (int32, error) {

	sign := defaultSign

	switch s[0] {
	case '-':
		sign = -1
		s = s[1:]
	case '+':
		sign = 1
		s = s[1:]
	}

	var totalInterval int32
	for len(s) > 0 {
		var j int
		for j < len(s) && '0' <= s[j] && s[j] <= '9' {
			j++
		}
		var offsetStr string
		offsetStr, s = s[:j], s[j:]

		j = 0
		for j < len(s) && (s[j] < '0' || '9' < s[j]) {
			j++
		}
		var unitStr string
		unitStr, s = s[:j], s[j:]

		var units int
		switch unitStr {
		case "s", "sec", "secs", "second", "seconds":
			units = 1
		case "min", "mins", "minute", "minutes":
			units = 60
		case "h", "hour", "hours":
			units = 60 * 60
		case "d", "day", "days":
			units = 24 * 60 * 60
		case "w", "week", "weeks":
			units = 7 * 24 * 60 * 60
		case "mon", "month", "months":
			units = 30 * 24 * 60 * 60
		case "y", "year", "years":
			units = 365 * 24 * 60 * 60
		default:
			return 0, errUnknownTimeUnits
		}

		offset, err := strconv.Atoi(offsetStr)
		if err != nil {
			return 0, err
		}
		totalInterval += int32(sign * offset * units)
	}

	return totalInterval, nil
}
<|endoftext|>


<commit_before>package i18n

import (
	"regexp"

	"github.com/volatile/core"
)

// Locale contains translations and special i18n values associated to unique keys.
type Locale map[string]string

// Locales contains locales associated to their names.
type Locales map[string]Locale

const (
	// TransNPlaceholder is the placeholder replaced by n in a translation, when using the TransN function.
	TransNPlaceholder = "{{.n}}"

	contextDataKey = "i18nLocale"
)

var (
	useCookie  bool       // Defines if the matched locale must be saved in a cookie after matching.
	cookieName = "locale" // The name of the cookie used to save the client matched locale.

	defaultLocale   string
	locales         *Locales // The map of available locales. It is ensured to not be empty.
	localeKeyRegexp = regexp.MustCompile("^[a-z]{2}$")
)

// ViewsFuncs provides i18n functions that can be set for templates.
var ViewsFuncs = map[string]interface{}{
	"locale":           ClientLocale,
	"num":              Num,
	"sortedLocaleKeys": SortedLocaleKeys,
	"trans":            Trans,
	"transn":           TransN,
}

// Use registers locales l.
// On request, if none match to the client accepted languages, the locale def will be used.
// And if useCookie is true, a cookie will be used to save the most appropriate and available locale key for the client.
func Use(l *Locales, def string, cookie bool) {
	if l == nil {
		panic("i18n: locales map can't be empty")
	}

	for i := range *l {
		if !localeKeyRegexp.MatchString(i) {
			panic(`i18n: locale key must be an ISO 639-1 code (2 letters lowercase), so "` + i + `" is invalid`)
		}
	}
	locales = l

	if !localeExists(def) {
		panic("i18n: default locale " + def + " doesn't exist")
	}
	defaultLocale = def

	useCookie = cookie

	// Trigger ClientLocale to match and set locale at least one time.
	core.Use(func(c *core.Context) {
		ClientLocale(c)
		c.Next()
	})
}
<commit_msg>Remove request handling<commit_after>package i18n

import "regexp"

// Locale contains translations and special i18n values associated to unique keys.
type Locale map[string]string

// Locales contains locales associated to their names.
type Locales map[string]Locale

const (
	// TransNPlaceholder is the placeholder replaced by n in a translation, when using the TransN function.
	TransNPlaceholder = "{{.n}}"

	contextDataKey = "i18nLocale"
)

var (
	useCookie  bool       // Defines if the matched locale must be saved in a cookie after matching.
	cookieName = "locale" // The name of the cookie used to save the client matched locale.

	defaultLocale   string
	locales         *Locales // The map of available locales. It is ensured to not be empty.
	localeKeyRegexp = regexp.MustCompile("^[a-z]{2}$")
)

// ViewsFuncs provides i18n functions that can be set for templates.
var ViewsFuncs = map[string]interface{}{
	"locale":           ClientLocale,
	"num":              Num,
	"sortedLocaleKeys": SortedLocaleKeys,
	"trans":            Trans,
	"transn":           TransN,
}

// Use registers locales l.
// On request, if none match to the client accepted languages, the locale def will be used.
// And if useCookie is true, a cookie will be used to save the most appropriate and available locale key for the client.
func Use(l *Locales, def string, cookie bool) {
	if l == nil {
		panic("i18n: locales map can't be empty")
	}

	for i := range *l {
		if !localeKeyRegexp.MatchString(i) {
			panic(`i18n: locale key must be an ISO 639-1 code (2 letters lowercase), so "` + i + `" is invalid`)
		}
	}
	locales = l

	if !localeExists(def) {
		panic("i18n: default locale " + def + " doesn't exist")
	}
	defaultLocale = def

	useCookie = cookie
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"errors"
	"log"
	"sort"
	"strings"
)

type nameValue struct {
	XMLName xml.Name `xml:""`
	Value   string   `xml:",cdata"`
}

type xmlRootStruct struct {
	Elements []nameValue `xml:",any"`
}

// XMLStructToMap turn XML into struct
func XMLStructToMap(xmlRawData []byte) (result map[string]string, err error) {
	result = make(map[string]string)
	v := new(xmlRootStruct)
	err = xml.Unmarshal(xmlRawData, v)
	if err != nil {
		log.Printf("error: %v", err)
		return nil, err
	}
	//log.Printf("v = %#v\n", v)
	//v = &main.xmlRootStruct{Elements:[]main.nameValue{main.nameValue{XMLName:xml.Name{Space:"", Local:"appid"}, Value:"wx2b029c08a6232582"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"mch_id"}, Value:"1305176001"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"nonce_str"}, Value:"ec2316275641faa3aacf3cc599e8730f"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"transaction_id"}, Value:"4004792001201604285304611529"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"sign"}, Value:"CCE53B58591F386DA7D0FEE640EE15CA"}}}
	for i := 0; i < len(v.Elements); i++ {
		result[v.Elements[i].XMLName.Local] = v.Elements[i].Value
	}
	return result, nil
}

// CompareSignature compare between original sign and calculated sign
func CompareSignature(xmlRawData []byte) (bool, error) {
	if !config.IsLoad {
		return false, errors.New("config not loaded")
	}
	mapData, _ := XMLStructToMap(xmlRawData)
	sign, _ := CalculateSignature(mapData, config.Key)
	if mapData["sign"] == sign {
		return true, nil
	}
	return false, nil
}

// MapToXML roughly turn map back to <xml><key>value</key></xml>
func MapToXML(mapData map[string]string) (result []byte, err error) {
	var xmlString string
	xmlString = "<xml>\n"
	for k, v := range mapData {
		xmlString = xmlString + "<" + k + ">" + v + "</" + k + ">\n"
	}
	xmlString = xmlString + "</xml>"
	result = []byte(xmlString)
	return result, err
}

// CalculateSignature return sign string
func CalculateSignature(fields map[string]string, key string) (result string, err error) {
	var keyList []string
	for k := range fields {
		keyList = append(keyList, k)
	}
	sort.Strings(keyList)
	//log.Printf("%#v\n", keyList)
	var toSignString string
	for _, v := range keyList {
		if v != "sign" {
			toSignString = toSignString + v + "=" + fields[v] + "&"
		}
	}
	toSignString = toSignString + "key=" + key
	//log.Printf("%#v\n", toSignString)
	hasher := md5.New()
	hasher.Write([]byte(toSignString))
	result = hex.EncodeToString(hasher.Sum(nil))
	result = strings.ToUpper(result)
	//log.Printf("%s\n", result)
	return result, nil
}
<commit_msg>fixed empty field problem.<commit_after>package main

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"errors"
	"log"
	"sort"
	"strings"
)

type nameValue struct {
	XMLName xml.Name `xml:""`
	Value   string   `xml:",cdata"`
}

type xmlRootStruct struct {
	Elements []nameValue `xml:",any"`
}

// XMLStructToMap turn XML into struct
func XMLStructToMap(xmlRawData []byte) (result map[string]string, err error) {
	result = make(map[string]string)
	v := new(xmlRootStruct)
	err = xml.Unmarshal(xmlRawData, v)
	if err != nil {
		log.Printf("error: %v", err)
		return nil, err
	}
	//log.Printf("v = %#v\n", v)
	//v = &main.xmlRootStruct{Elements:[]main.nameValue{main.nameValue{XMLName:xml.Name{Space:"", Local:"appid"}, Value:"wx2b029c08a6232582"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"mch_id"}, Value:"1305176001"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"nonce_str"}, Value:"ec2316275641faa3aacf3cc599e8730f"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"transaction_id"}, Value:"4004792001201604285304611529"}, main.nameValue{XMLName:xml.Name{Space:"", Local:"sign"}, Value:"CCE53B58591F386DA7D0FEE640EE15CA"}}}
	for i := 0; i < len(v.Elements); i++ {
		result[v.Elements[i].XMLName.Local] = v.Elements[i].Value
	}
	return result, nil
}

// CompareSignature compare between original sign and calculated sign
func CompareSignature(xmlRawData []byte) (bool, error) {
	if !config.IsLoad {
		return false, errors.New("config not loaded")
	}
	mapData, _ := XMLStructToMap(xmlRawData)
	sign, _ := CalculateSignature(mapData, config.Key)
	if mapData["sign"] == sign {
		return true, nil
	}
	return false, nil
}

// MapToXML roughly turn map back to <xml><key>value</key></xml>
func MapToXML(mapData map[string]string) (result []byte, err error) {
	var xmlString string
	xmlString = "<xml>\n"
	for k, v := range mapData {
		xmlString = xmlString + "<" + k + ">" + v + "</" + k + ">\n"
	}
	xmlString = xmlString + "</xml>"
	result = []byte(xmlString)
	return result, err
}

// CalculateSignature return sign string
func CalculateSignature(fields map[string]string, key string) (result string, err error) {
	//log.Printf("%s\n", key)
	var keyList []string
	for k := range fields {
		keyList = append(keyList, k)
	}
	sort.Strings(keyList)
	//log.Printf("%#v\n", keyList)
	var toSignString string
	for _, v := range keyList {
		if v != "sign" && fields[v] != "" {
			toSignString = toSignString + v + "=" + fields[v] + "&"
		}
	}
	toSignString = toSignString + "key=" + key
	//log.Printf("toSignString, %#v\n", toSignString)
	hasher := md5.New()
	hasher.Write([]byte(toSignString))
	result = hex.EncodeToString(hasher.Sum(nil))
	result = strings.ToUpper(result)
	//log.Printf("%s\n", result)
	return result, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-xdgbasedir 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

package xdgbasedir

import (
	"os"
	"path/filepath"
	"strconv"

	home "github.com/zchee/go-xdgbasedir/home"
)

var (
	defaultDataHome   string
	defaultConfigHome string
	defaultDataDirs   string
	defaultConfigDirs string
	defaultCacheHome  string
	defaultRuntimeDir string
)

func initDir() {
	initOnce.Do(func() {
		switch Mode {
		case Unix:
			defaultDataHome = filepath.Join(home.Dir(), ".local", "share")
			defaultConfigHome = filepath.Join(home.Dir(), ".config")
			defaultDataDirs = filepath.Join("/usr", "local", "share") + string(filepath.ListSeparator) + filepath.Join("/usr", "share")
			defaultConfigDirs = filepath.Join("/etc", "xdg")
			defaultCacheHome = filepath.Join(home.Dir(), ".cache")
			defaultRuntimeDir = filepath.Join("/run", "user", strconv.Itoa(os.Getuid()))
		case Native:
			defaultDataHome = filepath.Join(home.Dir(), "Library", "Application Support")
			defaultConfigHome = filepath.Join(home.Dir(), "Library", "Preferences")
			defaultDataDirs = defaultDataHome
			defaultConfigDirs = defaultConfigHome
			defaultCacheHome = filepath.Join(home.Dir(), "Library", "Caches")
			defaultRuntimeDir = defaultDataHome
		}
	})
}

func dataHome() string {
	initDir()
	return defaultDataHome
}

func configHome() string {
	initDir()
	return defaultConfigHome
}

func dataDirs() string {
	initDir()
	return defaultDataDirs
}

func configDirs() string {
	initDir()
	return defaultConfigDirs
}

func cacheHome() string {
	initDir()
	return defaultCacheHome
}

func runtimeDir() string {
	initDir()
	return defaultRuntimeDir
}
<commit_msg>xdgbasedir: add reference url<commit_after>// Copyright 2017 The go-xdgbasedir 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

package xdgbasedir

import (
	"os"
	"path/filepath"
	"strconv"

	home "github.com/zchee/go-xdgbasedir/home"
)

var (
	defaultDataHome   string
	defaultConfigHome string
	defaultDataDirs   string
	defaultConfigDirs string
	defaultCacheHome  string
	defaultRuntimeDir string
)

func initDir() {
	initOnce.Do(func() {
		switch Mode {
		case Unix:
			defaultDataHome = filepath.Join(home.Dir(), ".local", "share")
			defaultConfigHome = filepath.Join(home.Dir(), ".config")
			defaultDataDirs = filepath.Join("/usr", "local", "share") + string(filepath.ListSeparator) + filepath.Join("/usr", "share")
			defaultConfigDirs = filepath.Join("/etc", "xdg")
			defaultCacheHome = filepath.Join(home.Dir(), ".cache")
			defaultRuntimeDir = filepath.Join("/run", "user", strconv.Itoa(os.Getuid()))
		case Native:
			// ref: https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
			defaultDataHome = filepath.Join(home.Dir(), "Library", "Application Support")
			defaultConfigHome = filepath.Join(home.Dir(), "Library", "Preferences")
			defaultDataDirs = defaultDataHome
			defaultConfigDirs = defaultConfigHome
			defaultCacheHome = filepath.Join(home.Dir(), "Library", "Caches")
			defaultRuntimeDir = defaultDataHome
		}
	})
}

func dataHome() string {
	initDir()
	return defaultDataHome
}

func configHome() string {
	initDir()
	return defaultConfigHome
}

func dataDirs() string {
	initDir()
	return defaultDataDirs
}

func configDirs() string {
	initDir()
	return defaultConfigDirs
}

func cacheHome() string {
	initDir()
	return defaultCacheHome
}

func runtimeDir() string {
	initDir()
	return defaultRuntimeDir
}
<|endoftext|>


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

package testing

import (
	"errors"
	"fmt"
	"github.com/globocom/tsuru/provision"
	"io"
	"strconv"
	"sync"
	"time"
)

func init() {
	provision.Register("fake", &FakeProvisioner{})
}

// Fake implementation for provision.Unit.
type FakeUnit struct {
	Name       string
	Ip         string
	InstanceId string
	Machine    int
	Status     provision.Status
}

func (u *FakeUnit) GetName() string {
	return u.Name
}

func (u *FakeUnit) GetMachine() int {
	return u.Machine
}

func (u *FakeUnit) GetStatus() provision.Status {
	return u.Status
}

func (u *FakeUnit) GetInstanceId() string {
	return u.InstanceId
}

func (u *FakeUnit) GetIp() string {
	return u.Ip
}

// Fake implementation for provision.App.
type FakeApp struct {
	name     string
	platform string
	units    []provision.AppUnit
	logs     []string
	Commands []string
	logMut   sync.Mutex
	ready    bool
}

func NewFakeApp(name, platform string, units int) *FakeApp {
	app := FakeApp{
		name:     name,
		platform: platform,
		units:    make([]provision.AppUnit, units),
	}
	namefmt := "%s/%d"
	for i := 0; i < units; i++ {
		app.units[i] = &FakeUnit{
			Name:       fmt.Sprintf(namefmt, name, i),
			Machine:    i + 1,
			Status:     provision.StatusStarted,
			Ip:         fmt.Sprintf("10.10.10.%d", i+1),
			InstanceId: fmt.Sprintf("i-0%d", i+1),
		}
	}
	return &app
}

func (a *FakeApp) IsReady() bool {
	return a.ready
}

func (a *FakeApp) Ready() error {
	a.ready = true
	return nil
}

func (a *FakeApp) Log(message, source string) error {
	a.logMut.Lock()
	a.logs = append(a.logs, source+message)
	a.logMut.Unlock()
	return nil
}

func (a *FakeApp) GetName() string {
	return a.name
}

func (a *FakeApp) GetPlatform() string {
	return a.platform
}

func (a *FakeApp) ProvisionUnits() []provision.AppUnit {
	return a.units
}

func (a *FakeApp) AddUnit(u *FakeUnit) {
	a.units = append(a.units, u)
}

func (a *FakeApp) RemoveUnit(id string) error {
	index := -1
	for i, u := range a.units {
		if u.GetName() == id {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Unit not found")
	}
	if index < len(a.units)-1 {
		a.units[index] = a.units[len(a.units)-1]
	}
	a.units = a.units[:len(a.units)-1]
	return nil
}

func (a *FakeApp) SetUnitStatus(s provision.Status, index int) {
	if index < len(a.units) {
		a.units[index].(*FakeUnit).Status = s
	}
}

func (a *FakeApp) Restart(w io.Writer) error {
	a.Commands = append(a.Commands, "restart")
	return nil
}

func (a *FakeApp) Run(cmd string, w io.Writer) error {
	a.Commands = append(a.Commands, fmt.Sprintf("ran %s", cmd))
	return nil
}

type Cmd struct {
	Cmd  string
	Args []string
	App  provision.App
}

type failure struct {
	method string
	err    error
}

// Fake implementation for provision.Provisioner.
type FakeProvisioner struct {
	apps        []provision.App
	units       map[string][]provision.Unit
	unitLen     uint
	cmds        []Cmd
	outputs     chan []byte
	failures    chan failure
	cmdMut      sync.Mutex
	unitMut     sync.Mutex
	restarts    map[string]int
	restMut     sync.Mutex
	installDeps map[string]int
	depsMut     sync.Mutex
}

func NewFakeProvisioner() *FakeProvisioner {
	p := FakeProvisioner{}
	p.outputs = make(chan []byte, 8)
	p.failures = make(chan failure, 8)
	p.units = make(map[string][]provision.Unit)
	p.restarts = make(map[string]int)
	p.installDeps = make(map[string]int)
	p.unitLen = 0
	return &p
}

func (p *FakeProvisioner) getError(method string) error {
	select {
	case fail := <-p.failures:
		if fail.method == method {
			return fail.err
		}
		p.failures <- fail
	case <-time.After(1e6):
	}
	return nil
}

func (p *FakeProvisioner) Restarts(app provision.App) int {
	p.restMut.Lock()
	defer p.restMut.Unlock()
	return p.restarts[app.GetName()]
}

func (p *FakeProvisioner) InstalledDeps(app provision.App) int {
	p.depsMut.Lock()
	defer p.depsMut.Unlock()
	return p.installDeps[app.GetName()]
}

func (p *FakeProvisioner) Deploy(app provision.App, w io.Writer) error {
	w.Write([]byte("Deploy called"))
	return nil
}

// Returns the number of calls to restart.
// GetCmds returns a list of commands executed in an app. If you don't specify
// the command (an empty string), it will return all commands executed in the
// given app.
func (p *FakeProvisioner) GetCmds(cmd string, app provision.App) []Cmd {
	var cmds []Cmd
	p.cmdMut.Lock()
	for _, c := range p.cmds {
		if (cmd == "" || c.Cmd == cmd) && app.GetName() == c.App.GetName() {
			cmds = append(cmds, c)
		}
	}
	p.cmdMut.Unlock()
	return cmds
}

func (p *FakeProvisioner) FindApp(app provision.App) int {
	for i, a := range p.apps {
		if a.GetName() == app.GetName() {
			return i
		}
	}
	return -1
}

func (p *FakeProvisioner) GetUnits(app provision.App) []provision.Unit {
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	return p.units[app.GetName()]
}

func (p *FakeProvisioner) PrepareOutput(b []byte) {
	p.outputs <- b
}

func (p *FakeProvisioner) PrepareFailure(method string, err error) {
	p.failures <- failure{method, err}
}

func (p *FakeProvisioner) Reset() {
	p.unitMut.Lock()
	p.units = make(map[string][]provision.Unit)
	p.unitMut.Unlock()

	p.cmdMut.Lock()
	p.cmds = nil
	p.cmdMut.Unlock()

	p.restMut.Lock()
	p.restarts = make(map[string]int)
	p.restMut.Unlock()

	for {
		select {
		case <-p.outputs:
		case <-p.failures:
		default:
			return
		}
	}
}

func (p *FakeProvisioner) Provision(app provision.App) error {
	if err := p.getError("Provision"); err != nil {
		return err
	}
	index := p.FindApp(app)
	if index > -1 {
		return &provision.Error{Reason: "App already provisioned."}
	}
	p.apps = append(p.apps, app)
	p.unitMut.Lock()
	p.units[app.GetName()] = []provision.Unit{
		{
			Name:       app.GetName() + "/0",
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Status:     provision.StatusStarted,
			InstanceId: "i-080",
			Ip:         "10.10.10.1",
			Machine:    1,
		},
	}
	p.unitLen++
	p.unitMut.Unlock()
	return nil
}

func (p *FakeProvisioner) Restart(app provision.App) error {
	if err := p.getError("Restart"); err != nil {
		return err
	}
	p.restMut.Lock()
	v := p.restarts[app.GetName()]
	v++
	p.restarts[app.GetName()] = v
	p.restMut.Unlock()
	return nil
}

func (p *FakeProvisioner) Destroy(app provision.App) error {
	if err := p.getError("Destroy"); err != nil {
		return err
	}
	index := p.FindApp(app)
	if index == -1 {
		return &provision.Error{Reason: "App is not provisioned."}
	}
	copy(p.apps[index:], p.apps[index+1:])
	p.apps = p.apps[:len(p.apps)-1]
	p.unitMut.Lock()
	delete(p.units, app.GetName())
	p.unitLen = 0
	p.unitMut.Unlock()
	p.restMut.Lock()
	delete(p.restarts, app.GetName())
	p.restMut.Unlock()
	return nil
}

func (p *FakeProvisioner) AddUnits(app provision.App, n uint) ([]provision.Unit, error) {
	if err := p.getError("AddUnits"); err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, errors.New("Cannot add 0 units.")
	}
	index := p.FindApp(app)
	if index < 0 {
		return nil, errors.New("App is not provisioned.")
	}
	name := app.GetName()
	platform := app.GetPlatform()
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	length := uint(len(p.units[name]))
	for i := uint(0); i < n; i++ {
		unit := provision.Unit{
			Name:       fmt.Sprintf("%s/%d", name, p.unitLen),
			AppName:    name,
			Type:       platform,
			Status:     provision.StatusStarted,
			InstanceId: fmt.Sprintf("i-08%d", length+i),
			Ip:         fmt.Sprintf("10.10.10.%d", length+i),
			Machine:    int(length + i),
		}
		p.units[name] = append(p.units[name], unit)
		p.unitLen++
	}
	result := make([]provision.Unit, int(n))
	copy(result, p.units[name][length:])
	return result, nil
}

func (p *FakeProvisioner) RemoveUnit(app provision.App, name string) error {
	if err := p.getError("RemoveUnit"); err != nil {
		return err
	}
	index := -1
	appName := app.GetName()
	if index := p.FindApp(app); index < 0 {
		return errors.New("App is not provisioned.")
	}
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	for i, unit := range p.units[appName] {
		if unit.Name == name {
			index = i
			break
		}
	}
	if index == -1 {
		return errors.New("Unit not found.")
	}
	copy(p.units[appName][index:], p.units[appName][index+1:])
	p.units[appName] = p.units[appName][:len(p.units[appName])-1]
	p.unitLen--
	return nil
}

func (p *FakeProvisioner) ExecuteCommand(stdout, stderr io.Writer, app provision.App, cmd string, args ...string) error {
	var (
		output []byte
		err    error
	)
	command := Cmd{
		Cmd:  cmd,
		Args: args,
		App:  app,
	}
	p.cmdMut.Lock()
	p.cmds = append(p.cmds, command)
	p.cmdMut.Unlock()
	select {
	case output = <-p.outputs:
		select {
		case fail := <-p.failures:
			if fail.method == "ExecuteCommand" {
				stderr.Write(output)
				return fail.err
			} else {
				p.failures <- fail
			}
		case <-time.After(1e6):
			stdout.Write(output)
		}
	case fail := <-p.failures:
		if fail.method == "ExecuteCommand" {
			err = fail.err
			select {
			case output = <-p.outputs:
				stderr.Write(output)
			case <-time.After(1e6):
			}
		} else {
			p.failures <- fail
		}
	case <-time.After(2e9):
		return errors.New("FakeProvisioner timed out waiting for output.")
	}
	return err
}

func (p *FakeProvisioner) CollectStatus() ([]provision.Unit, error) {
	if err := p.getError("CollectStatus"); err != nil {
		return nil, err
	}
	units := make([]provision.Unit, len(p.apps))
	for i, app := range p.apps {
		unit := provision.Unit{
			Name:       app.GetName() + "/0",
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Status:     "started",
			InstanceId: fmt.Sprintf("i-0%d", 800+i+1),
			Ip:         "10.10.10." + strconv.Itoa(i+1),
			Machine:    i + 1,
		}
		units[i] = unit
	}
	return units, nil
}

func (p *FakeProvisioner) Addr(app provision.App) (string, error) {
	if err := p.getError("Addr"); err != nil {
		return "", err
	}
	return fmt.Sprintf("%s.fake-lb.tsuru.io", app.GetName()), nil
}

func (p *FakeProvisioner) InstallDeps(app provision.App, w io.Writer) error {
	if err := p.getError("InstallDeps"); err != nil {
		return err
	}
	p.depsMut.Lock()
	v := p.installDeps[app.GetName()]
	v++
	p.installDeps[app.GetName()] = v
	p.depsMut.Unlock()
	return nil
}
<commit_msg>testing: fix some golint warnings<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package testing

import (
	"errors"
	"fmt"
	"github.com/globocom/tsuru/provision"
	"io"
	"strconv"
	"sync"
	"time"
)

func init() {
	provision.Register("fake", &FakeProvisioner{})
}

// Fake implementation for provision.Unit.
type FakeUnit struct {
	Name       string
	Ip         string
	InstanceId string
	Machine    int
	Status     provision.Status
}

func (u *FakeUnit) GetName() string {
	return u.Name
}

func (u *FakeUnit) GetMachine() int {
	return u.Machine
}

func (u *FakeUnit) GetStatus() provision.Status {
	return u.Status
}

func (u *FakeUnit) GetInstanceId() string {
	return u.InstanceId
}

func (u *FakeUnit) GetIp() string {
	return u.Ip
}

// Fake implementation for provision.App.
type FakeApp struct {
	name     string
	platform string
	units    []provision.AppUnit
	logs     []string
	Commands []string
	logMut   sync.Mutex
	ready    bool
}

func NewFakeApp(name, platform string, units int) *FakeApp {
	app := FakeApp{
		name:     name,
		platform: platform,
		units:    make([]provision.AppUnit, units),
	}
	namefmt := "%s/%d"
	for i := 0; i < units; i++ {
		app.units[i] = &FakeUnit{
			Name:       fmt.Sprintf(namefmt, name, i),
			Machine:    i + 1,
			Status:     provision.StatusStarted,
			Ip:         fmt.Sprintf("10.10.10.%d", i+1),
			InstanceId: fmt.Sprintf("i-0%d", i+1),
		}
	}
	return &app
}

func (a *FakeApp) IsReady() bool {
	return a.ready
}

func (a *FakeApp) Ready() error {
	a.ready = true
	return nil
}

func (a *FakeApp) Log(message, source string) error {
	a.logMut.Lock()
	a.logs = append(a.logs, source+message)
	a.logMut.Unlock()
	return nil
}

func (a *FakeApp) GetName() string {
	return a.name
}

func (a *FakeApp) GetPlatform() string {
	return a.platform
}

func (a *FakeApp) ProvisionUnits() []provision.AppUnit {
	return a.units
}

func (a *FakeApp) AddUnit(u *FakeUnit) {
	a.units = append(a.units, u)
}

func (a *FakeApp) RemoveUnit(id string) error {
	index := -1
	for i, u := range a.units {
		if u.GetName() == id {
			index = i
			break
		}
	}
	if index < 0 {
		return errors.New("Unit not found")
	}
	if index < len(a.units)-1 {
		a.units[index] = a.units[len(a.units)-1]
	}
	a.units = a.units[:len(a.units)-1]
	return nil
}

func (a *FakeApp) SetUnitStatus(s provision.Status, index int) {
	if index < len(a.units) {
		a.units[index].(*FakeUnit).Status = s
	}
}

func (a *FakeApp) Restart(w io.Writer) error {
	a.Commands = append(a.Commands, "restart")
	return nil
}

func (a *FakeApp) Run(cmd string, w io.Writer) error {
	a.Commands = append(a.Commands, fmt.Sprintf("ran %s", cmd))
	return nil
}

type Cmd struct {
	Cmd  string
	Args []string
	App  provision.App
}

type failure struct {
	method string
	err    error
}

// Fake implementation for provision.Provisioner.
type FakeProvisioner struct {
	apps        []provision.App
	units       map[string][]provision.Unit
	unitLen     uint
	cmds        []Cmd
	outputs     chan []byte
	failures    chan failure
	cmdMut      sync.Mutex
	unitMut     sync.Mutex
	restarts    map[string]int
	restMut     sync.Mutex
	installDeps map[string]int
	depsMut     sync.Mutex
}

func NewFakeProvisioner() *FakeProvisioner {
	p := FakeProvisioner{}
	p.outputs = make(chan []byte, 8)
	p.failures = make(chan failure, 8)
	p.units = make(map[string][]provision.Unit)
	p.restarts = make(map[string]int)
	p.installDeps = make(map[string]int)
	p.unitLen = 0
	return &p
}

func (p *FakeProvisioner) getError(method string) error {
	select {
	case fail := <-p.failures:
		if fail.method == method {
			return fail.err
		}
		p.failures <- fail
	case <-time.After(1e6):
	}
	return nil
}

func (p *FakeProvisioner) Restarts(app provision.App) int {
	p.restMut.Lock()
	defer p.restMut.Unlock()
	return p.restarts[app.GetName()]
}

func (p *FakeProvisioner) InstalledDeps(app provision.App) int {
	p.depsMut.Lock()
	defer p.depsMut.Unlock()
	return p.installDeps[app.GetName()]
}

func (p *FakeProvisioner) Deploy(app provision.App, w io.Writer) error {
	w.Write([]byte("Deploy called"))
	return nil
}

// Returns the number of calls to restart.
// GetCmds returns a list of commands executed in an app. If you don't specify
// the command (an empty string), it will return all commands executed in the
// given app.
func (p *FakeProvisioner) GetCmds(cmd string, app provision.App) []Cmd {
	var cmds []Cmd
	p.cmdMut.Lock()
	for _, c := range p.cmds {
		if (cmd == "" || c.Cmd == cmd) && app.GetName() == c.App.GetName() {
			cmds = append(cmds, c)
		}
	}
	p.cmdMut.Unlock()
	return cmds
}

func (p *FakeProvisioner) FindApp(app provision.App) int {
	for i, a := range p.apps {
		if a.GetName() == app.GetName() {
			return i
		}
	}
	return -1
}

func (p *FakeProvisioner) GetUnits(app provision.App) []provision.Unit {
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	return p.units[app.GetName()]
}

func (p *FakeProvisioner) PrepareOutput(b []byte) {
	p.outputs <- b
}

func (p *FakeProvisioner) PrepareFailure(method string, err error) {
	p.failures <- failure{method, err}
}

func (p *FakeProvisioner) Reset() {
	p.unitMut.Lock()
	p.units = make(map[string][]provision.Unit)
	p.unitMut.Unlock()

	p.cmdMut.Lock()
	p.cmds = nil
	p.cmdMut.Unlock()

	p.restMut.Lock()
	p.restarts = make(map[string]int)
	p.restMut.Unlock()

	for {
		select {
		case <-p.outputs:
		case <-p.failures:
		default:
			return
		}
	}
}

func (p *FakeProvisioner) Provision(app provision.App) error {
	if err := p.getError("Provision"); err != nil {
		return err
	}
	index := p.FindApp(app)
	if index > -1 {
		return &provision.Error{Reason: "App already provisioned."}
	}
	p.apps = append(p.apps, app)
	p.unitMut.Lock()
	p.units[app.GetName()] = []provision.Unit{
		{
			Name:       app.GetName() + "/0",
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Status:     provision.StatusStarted,
			InstanceId: "i-080",
			Ip:         "10.10.10.1",
			Machine:    1,
		},
	}
	p.unitLen++
	p.unitMut.Unlock()
	return nil
}

func (p *FakeProvisioner) Restart(app provision.App) error {
	if err := p.getError("Restart"); err != nil {
		return err
	}
	p.restMut.Lock()
	v := p.restarts[app.GetName()]
	v++
	p.restarts[app.GetName()] = v
	p.restMut.Unlock()
	return nil
}

func (p *FakeProvisioner) Destroy(app provision.App) error {
	if err := p.getError("Destroy"); err != nil {
		return err
	}
	index := p.FindApp(app)
	if index == -1 {
		return &provision.Error{Reason: "App is not provisioned."}
	}
	copy(p.apps[index:], p.apps[index+1:])
	p.apps = p.apps[:len(p.apps)-1]
	p.unitMut.Lock()
	delete(p.units, app.GetName())
	p.unitLen = 0
	p.unitMut.Unlock()
	p.restMut.Lock()
	delete(p.restarts, app.GetName())
	p.restMut.Unlock()
	return nil
}

func (p *FakeProvisioner) AddUnits(app provision.App, n uint) ([]provision.Unit, error) {
	if err := p.getError("AddUnits"); err != nil {
		return nil, err
	}
	if n == 0 {
		return nil, errors.New("Cannot add 0 units.")
	}
	index := p.FindApp(app)
	if index < 0 {
		return nil, errors.New("App is not provisioned.")
	}
	name := app.GetName()
	platform := app.GetPlatform()
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	length := uint(len(p.units[name]))
	for i := uint(0); i < n; i++ {
		unit := provision.Unit{
			Name:       fmt.Sprintf("%s/%d", name, p.unitLen),
			AppName:    name,
			Type:       platform,
			Status:     provision.StatusStarted,
			InstanceId: fmt.Sprintf("i-08%d", length+i),
			Ip:         fmt.Sprintf("10.10.10.%d", length+i),
			Machine:    int(length + i),
		}
		p.units[name] = append(p.units[name], unit)
		p.unitLen++
	}
	result := make([]provision.Unit, int(n))
	copy(result, p.units[name][length:])
	return result, nil
}

func (p *FakeProvisioner) RemoveUnit(app provision.App, name string) error {
	if err := p.getError("RemoveUnit"); err != nil {
		return err
	}
	index := -1
	appName := app.GetName()
	if index := p.FindApp(app); index < 0 {
		return errors.New("App is not provisioned.")
	}
	p.unitMut.Lock()
	defer p.unitMut.Unlock()
	for i, unit := range p.units[appName] {
		if unit.Name == name {
			index = i
			break
		}
	}
	if index == -1 {
		return errors.New("Unit not found.")
	}
	copy(p.units[appName][index:], p.units[appName][index+1:])
	p.units[appName] = p.units[appName][:len(p.units[appName])-1]
	p.unitLen--
	return nil
}

func (p *FakeProvisioner) ExecuteCommand(stdout, stderr io.Writer, app provision.App, cmd string, args ...string) error {
	var (
		output []byte
		err    error
	)
	command := Cmd{
		Cmd:  cmd,
		Args: args,
		App:  app,
	}
	p.cmdMut.Lock()
	p.cmds = append(p.cmds, command)
	p.cmdMut.Unlock()
	select {
	case output = <-p.outputs:
		select {
		case fail := <-p.failures:
			if fail.method == "ExecuteCommand" {
				stderr.Write(output)
				return fail.err
			}
			p.failures <- fail
		case <-time.After(1e6):
			stdout.Write(output)
		}
	case fail := <-p.failures:
		if fail.method == "ExecuteCommand" {
			err = fail.err
			select {
			case output = <-p.outputs:
				stderr.Write(output)
			case <-time.After(1e6):
			}
		} else {
			p.failures <- fail
		}
	case <-time.After(2e9):
		return errors.New("FakeProvisioner timed out waiting for output.")
	}
	return err
}

func (p *FakeProvisioner) CollectStatus() ([]provision.Unit, error) {
	if err := p.getError("CollectStatus"); err != nil {
		return nil, err
	}
	units := make([]provision.Unit, len(p.apps))
	for i, app := range p.apps {
		unit := provision.Unit{
			Name:       app.GetName() + "/0",
			AppName:    app.GetName(),
			Type:       app.GetPlatform(),
			Status:     "started",
			InstanceId: fmt.Sprintf("i-0%d", 800+i+1),
			Ip:         "10.10.10." + strconv.Itoa(i+1),
			Machine:    i + 1,
		}
		units[i] = unit
	}
	return units, nil
}

func (p *FakeProvisioner) Addr(app provision.App) (string, error) {
	if err := p.getError("Addr"); err != nil {
		return "", err
	}
	return fmt.Sprintf("%s.fake-lb.tsuru.io", app.GetName()), nil
}

func (p *FakeProvisioner) InstallDeps(app provision.App, w io.Writer) error {
	if err := p.getError("InstallDeps"); err != nil {
		return err
	}
	p.depsMut.Lock()
	v := p.installDeps[app.GetName()]
	v++
	p.installDeps[app.GetName()] = v
	p.depsMut.Unlock()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/shiena/ansicolor"

	"../alias"
	"../commands"
	"../completion"
	"../conio"
	"../dos"
	"../history"
	"../interpreter"
	"../lua"
)

var rxAnsiEscCode = regexp.MustCompile("\x1b[^a-zA-Z]*[a-zA-Z]")

var stamp string
var commit string
var version string
var ansiOut io.Writer

func nyagosPrompt(L *lua.Lua) int {
	template, err := L.ToString(-1)
	if err != nil {
		template = "[" + err.Error() + "]"
	}
	text := Format2Prompt(template)
	fmt.Fprint(ansiOut, text)
	text = rxAnsiEscCode.ReplaceAllString(text, "")
	lfPos := strings.LastIndex(text, "\n")
	if lfPos >= 0 {
		text = text[lfPos+1:]
	}
	L.PushInteger(lua.Integer(conio.GetStringWidth(text)))
	return 1
}

func printPrompt(this *conio.LineEditor) int {
	L, ok := this.Tag.(*lua.Lua)
	if !ok {
		panic("printPrompt conio.LineEditor.Tag is not lua.Lua")
	}
	L.GetGlobal("nyagos")
	L.GetField(-1, "prompt")
	L.Remove(-2)
	L.PushString(os.Getenv("PROMPT"))
	L.Call(1, 1)
	length, lengthErr := L.ToInteger(-1)
	if lengthErr == nil {
		return length
	} else {
		fmt.Fprintf(os.Stderr,
			"nyagos.prompt: Length invalid: %s\n",
			lengthErr.Error())
		return 0
	}
}

func when_panic() {
	err := recover()
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, "************ Panic Occured. ***********")
	fmt.Fprintln(os.Stderr, err)
	fmt.Fprintln(os.Stderr, "*** Please copy these error message ***")
	fmt.Fprintln(os.Stderr, "*** And hit ENTER key to quit.      ***")
	var dummy [1]byte
	os.Stdin.Read(dummy[:])
}

func main() {
	defer when_panic()

	conio.DisableCtrlC()

	completion := conio.KeyGoFuncT{F: completion.KeyFuncCompletion}

	if err := conio.BindKeySymbolFunc(conio.K_CTRL_I, "COMPLETE", &completion); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}

	// ANSI Escape Sequence Support
	ansiOut = ansicolor.NewAnsiColorWriter(os.Stdout)

	commands.Init()
	alias.Init()

	// Lua extension
	L := lua.New()
	L.OpenLibs()
	SetLuaFunctions(L)
	L.GetGlobal("nyagos")
	L.PushString(stamp)
	L.SetField(-2, "stamp")
	L.PushString(commit)
	L.SetField(-2, "commit")
	L.PushString(version)
	L.SetField(-2, "version")
	L.PushGoFunction(nyagosPrompt)
	L.SetField(-2, "prompt")
	L.Pop(1)
	defer L.Close()

	if !optionParse(L) {
		return
	}

	appData := filepath.Join(os.Getenv("APPDATA"), "NYAOS_ORG")
	os.Mkdir(appData, 0777)
	histPath := filepath.Join(appData, "nyagos.history")
	history.Load(histPath)
	history.Save(histPath) // cut over max-line

	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	}
	exeFolder := filepath.Dir(exeName)
	nyagos_lua := filepath.Join(exeFolder, "nyagos.lua")
	if _, err := os.Stat(nyagos_lua); err == nil {
		err := L.Source(nyagos_lua)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}

	conio.DefaultEditor.Tag = L
	conio.DefaultEditor.Prompt = printPrompt

	for {
		wd, wdErr := os.Getwd()
		if wdErr == nil {
			conio.SetTitle("NYAGOS - " + wd)
		} else {
			conio.SetTitle("NYAGOS - " + wdErr.Error())
		}
		history_count := conio.DefaultEditor.HistoryLen()
		line, cont := conio.DefaultEditor.ReadLine()
		if !cont {
			break
		}

		var isReplaced bool
		line, isReplaced = history.Replace(line)
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line == "" {
			continue
		}
		if conio.DefaultEditor.HistoryLen() > history_count {
			fd, err := os.OpenFile(histPath, os.O_APPEND, 0600)
			if err == nil {
				fmt.Fprintln(fd, line)
				fd.Close()
			} else {
				fmt.Fprintln(os.Stderr, err.Error())
			}
		} else {
			conio.DefaultEditor.HistoryResetPointer()
		}

		stackPos := L.GetTop()
		L.GetGlobal("nyagos")
		L.GetField(-1, "filter")
		if L.IsFunction(-1) {
			L.PushString(line)
			err := L.Call(1, 1)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			} else {
				if L.IsString(-1) {
					line, err = L.ToString(-1)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
					}
				}
			}
		}
		L.SetTop(stackPos)

		whatToDo, err := interpreter.New().Interpret(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if whatToDo == interpreter.SHUTDOWN {
			break
		}
	}
}
<commit_msg>When it is empty, set nil on nyagos.{version,commit,stamp}<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/shiena/ansicolor"

	"../alias"
	"../commands"
	"../completion"
	"../conio"
	"../dos"
	"../history"
	"../interpreter"
	"../lua"
)

var rxAnsiEscCode = regexp.MustCompile("\x1b[^a-zA-Z]*[a-zA-Z]")

var stamp string
var commit string
var version string
var ansiOut io.Writer

func nyagosPrompt(L *lua.Lua) int {
	template, err := L.ToString(-1)
	if err != nil {
		template = "[" + err.Error() + "]"
	}
	text := Format2Prompt(template)
	fmt.Fprint(ansiOut, text)
	text = rxAnsiEscCode.ReplaceAllString(text, "")
	lfPos := strings.LastIndex(text, "\n")
	if lfPos >= 0 {
		text = text[lfPos+1:]
	}
	L.PushInteger(lua.Integer(conio.GetStringWidth(text)))
	return 1
}

func printPrompt(this *conio.LineEditor) int {
	L, ok := this.Tag.(*lua.Lua)
	if !ok {
		panic("printPrompt conio.LineEditor.Tag is not lua.Lua")
	}
	L.GetGlobal("nyagos")
	L.GetField(-1, "prompt")
	L.Remove(-2)
	L.PushString(os.Getenv("PROMPT"))
	L.Call(1, 1)
	length, lengthErr := L.ToInteger(-1)
	if lengthErr == nil {
		return length
	} else {
		fmt.Fprintf(os.Stderr,
			"nyagos.prompt: Length invalid: %s\n",
			lengthErr.Error())
		return 0
	}
}

func when_panic() {
	err := recover()
	if err == nil {
		return
	}
	fmt.Fprintln(os.Stderr, "************ Panic Occured. ***********")
	fmt.Fprintln(os.Stderr, err)
	fmt.Fprintln(os.Stderr, "*** Please copy these error message ***")
	fmt.Fprintln(os.Stderr, "*** And hit ENTER key to quit.      ***")
	var dummy [1]byte
	os.Stdin.Read(dummy[:])
}

func main() {
	defer when_panic()

	conio.DisableCtrlC()

	completion := conio.KeyGoFuncT{F: completion.KeyFuncCompletion}

	if err := conio.BindKeySymbolFunc(conio.K_CTRL_I, "COMPLETE", &completion); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}

	// ANSI Escape Sequence Support
	ansiOut = ansicolor.NewAnsiColorWriter(os.Stdout)

	commands.Init()
	alias.Init()

	// Lua extension
	L := lua.New()
	L.OpenLibs()
	SetLuaFunctions(L)
	L.GetGlobal("nyagos")
	if stamp != "" {
		L.PushString(stamp)
		L.SetField(-2, "stamp")
	}
	if commit != "" {
		L.PushString(commit)
		L.SetField(-2, "commit")
	}
	if version != "" {
		L.PushString(version)
		L.SetField(-2, "version")
	}
	L.PushGoFunction(nyagosPrompt)
	L.SetField(-2, "prompt")
	L.Pop(1)
	defer L.Close()

	if !optionParse(L) {
		return
	}

	appData := filepath.Join(os.Getenv("APPDATA"), "NYAOS_ORG")
	os.Mkdir(appData, 0777)
	histPath := filepath.Join(appData, "nyagos.history")
	history.Load(histPath)
	history.Save(histPath) // cut over max-line

	exeName, exeNameErr := dos.GetModuleFileName()
	if exeNameErr != nil {
		fmt.Fprintln(os.Stderr, exeNameErr)
	}
	exeFolder := filepath.Dir(exeName)
	nyagos_lua := filepath.Join(exeFolder, "nyagos.lua")
	if _, err := os.Stat(nyagos_lua); err == nil {
		err := L.Source(nyagos_lua)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
	}

	conio.DefaultEditor.Tag = L
	conio.DefaultEditor.Prompt = printPrompt

	for {
		wd, wdErr := os.Getwd()
		if wdErr == nil {
			conio.SetTitle("NYAGOS - " + wd)
		} else {
			conio.SetTitle("NYAGOS - " + wdErr.Error())
		}
		history_count := conio.DefaultEditor.HistoryLen()
		line, cont := conio.DefaultEditor.ReadLine()
		if !cont {
			break
		}

		var isReplaced bool
		line, isReplaced = history.Replace(line)
		if isReplaced {
			fmt.Fprintln(os.Stdout, line)
		}
		if line == "" {
			continue
		}
		if conio.DefaultEditor.HistoryLen() > history_count {
			fd, err := os.OpenFile(histPath, os.O_APPEND, 0600)
			if err == nil {
				fmt.Fprintln(fd, line)
				fd.Close()
			} else {
				fmt.Fprintln(os.Stderr, err.Error())
			}
		} else {
			conio.DefaultEditor.HistoryResetPointer()
		}

		stackPos := L.GetTop()
		L.GetGlobal("nyagos")
		L.GetField(-1, "filter")
		if L.IsFunction(-1) {
			L.PushString(line)
			err := L.Call(1, 1)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			} else {
				if L.IsString(-1) {
					line, err = L.ToString(-1)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
					}
				}
			}
		}
		L.SetTop(stackPos)

		whatToDo, err := interpreter.New().Interpret(line)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		if whatToDo == interpreter.SHUTDOWN {
			break
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/justsocialapps/holmes/analytics"
	"github.com/justsocialapps/holmes/assets"
	"github.com/justsocialapps/holmes/publisher"
	"github.com/justsocialapps/holmes/tracker"
	"gopkg.in/Shopify/sarama.v1"
)

const version string = "1.7.0-dev"

//go:generate scripts/prepare_assets.sh
//go:generate go run scripts/include_assets.go

func provideTrackingChannel(trackingChannel chan<- *tracker.TrackingObject, handler func(trackingChannel chan<- *tracker.TrackingObject, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		handler(trackingChannel, w, r)
	}
}

func startServer(host string, port *string) {
	listener, err := net.Listen("tcp", host+":"+*port)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Holmes running on " + host + ":" + *port)
	log.Println(assets.Bannertxt)

	err = http.Serve(listener, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	var protocol = flag.String("protocol", "https", "The protocol used to serve Holmes resources ('http' or 'https')")
	var host = flag.String("host", "localhost", "The host name used to reach Holmes")
	var proxyPort = flag.String("proxyPort", "3001", "The TCP port for reaching Holmes if Holmes is operated behind a reverse proxy.")
	var proxyPath = flag.String("proxyPath", "", "The base path for reaching Holmes if Holmes is operated behind a reverse proxy.")
	var listenPort = flag.String("listenPort", "3001", "The TCP port that Holmes listens on")
	var kafkaHost = flag.String("kafkaHost", "localhost:9092", "The Kafka host to consume messages from")
	var logfileName = flag.String("logfile", "", "The file to log messages to")
	var printVersion = flag.Bool("version", false, "Print Holmes version and exit")
	flag.Parse()

	if *printVersion {
		fmt.Println(version)
		return
	}

	var logFile *os.File
	if *logfileName == "" {
		logFile = os.Stdout
	} else {
		var err error
		logFile, err = os.OpenFile(*logfileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatal(err)
		}
	}
	log.SetOutput(logFile)
	sarama.Logger = log.New(logFile, "[Sarama] ", log.LstdFlags)

	baseURL := *protocol + "://" + *host
	if !(*protocol == "https" && *proxyPort == "443") && !(*protocol == "http" && *proxyPort == "80") {
		baseURL = baseURL + ":" + *proxyPort
	}
	baseURL = baseURL + *proxyPath

	trackingChannel := make(chan *tracker.TrackingObject, 10)
	http.HandleFunc("/track", provideTrackingChannel(trackingChannel, tracker.Track))
	http.HandleFunc("/analytics.js", analytics.Analytics(baseURL))
	go publisher.Publish(trackingChannel, kafkaHost, "tracking")

	startServer("localhost", listenPort)
}
<commit_msg>Bump version number to 1.7.0<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/justsocialapps/holmes/analytics"
	"github.com/justsocialapps/holmes/assets"
	"github.com/justsocialapps/holmes/publisher"
	"github.com/justsocialapps/holmes/tracker"
	"gopkg.in/Shopify/sarama.v1"
)

const version string = "1.7.0"

//go:generate scripts/prepare_assets.sh
//go:generate go run scripts/include_assets.go

func provideTrackingChannel(trackingChannel chan<- *tracker.TrackingObject, handler func(trackingChannel chan<- *tracker.TrackingObject, w http.ResponseWriter, r *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		handler(trackingChannel, w, r)
	}
}

func startServer(host string, port *string) {
	listener, err := net.Listen("tcp", host+":"+*port)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Holmes running on " + host + ":" + *port)
	log.Println(assets.Bannertxt)

	err = http.Serve(listener, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	var protocol = flag.String("protocol", "https", "The protocol used to serve Holmes resources ('http' or 'https')")
	var host = flag.String("host", "localhost", "The host name used to reach Holmes")
	var proxyPort = flag.String("proxyPort", "3001", "The TCP port for reaching Holmes if Holmes is operated behind a reverse proxy.")
	var proxyPath = flag.String("proxyPath", "", "The base path for reaching Holmes if Holmes is operated behind a reverse proxy.")
	var listenPort = flag.String("listenPort", "3001", "The TCP port that Holmes listens on")
	var kafkaHost = flag.String("kafkaHost", "localhost:9092", "The Kafka host to consume messages from")
	var logfileName = flag.String("logfile", "", "The file to log messages to")
	var printVersion = flag.Bool("version", false, "Print Holmes version and exit")
	flag.Parse()

	if *printVersion {
		fmt.Println(version)
		return
	}

	var logFile *os.File
	if *logfileName == "" {
		logFile = os.Stdout
	} else {
		var err error
		logFile, err = os.OpenFile(*logfileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
		if err != nil {
			log.Fatal(err)
		}
	}
	log.SetOutput(logFile)
	sarama.Logger = log.New(logFile, "[Sarama] ", log.LstdFlags)

	baseURL := *protocol + "://" + *host
	if !(*protocol == "https" && *proxyPort == "443") && !(*protocol == "http" && *proxyPort == "80") {
		baseURL = baseURL + ":" + *proxyPort
	}
	baseURL = baseURL + *proxyPath

	trackingChannel := make(chan *tracker.TrackingObject, 10)
	http.HandleFunc("/track", provideTrackingChannel(trackingChannel, tracker.Track))
	http.HandleFunc("/analytics.js", analytics.Analytics(baseURL))
	go publisher.Publish(trackingChannel, kafkaHost, "tracking")

	startServer("localhost", listenPort)
}
<|endoftext|>


<commit_before>package maps

import (
	"image"
	"io"

	"github.com/MJKWoolnough/minecraft/nbt"
)

func init() {
	image.RegisterFormat("minecraftmap", "\x0a\x00\x00\x0a\x00\x04data", Decode, Config)
}

func readData(r io.Reader) (nbt.Compound, error) {
	t, err := nbt.Decode(r)
	if err != nil {
		return nil, err
	}

	if t.TagID() != nbt.TagCompound {
		return nil, nbt.WrongTag{nbt.TagCompound, t.TagID()}
	}

	d := t.Data().(nbt.Compound).Get("data")
	if d.TagID() != nbt.TagCompound {
		return nil, nbt.WrongTag{nbt.TagCompound, d.TagID()}
	}
	return d.Data().(nbt.Compound), nil
}

func getDimensions(d nbt.Compound) image.Rectangle {
	var width, height int
	w := d.Get("width")
	if w.TagID() == nbt.TagShort {
		width = int(w.Data().(nbt.Short))
	}
	h := d.Get("height")
	if h.TagID() == nbt.TagShort {
		height = int(h.Data().(nbt.Short))
	}
	return image.Rectangle{
		image.Point{0, 0},
		image.Point{width, height},
	}
}

// Decode takes a reader for an uncompressed Minecraft map.
//
// Minecraft maps are gzip compressed, so the reader given to this func should
// be wrapped in gzip.NewReader.
func Decode(r io.Reader) (image.Image, error) {
	d, err := readData(r)
	if err != nil {
		return nil, err
	}

	c := d.Get("colors")
	if c.TagID() != nbt.TagByteArray {
		return nil, nbt.WrongTag{nbt.TagByteArray, c.TagID()}
	}

	rect := getDimensions(d)

	return &image.Paletted{
		Pix:     c.Data().(nbt.ByteArray).Bytes(),
		Stride:  rect.Max.X,
		Rect:    rect,
		Palette: palette,
	}, nil
}

type config struct {
	Data struct {
		Width  int16 `nbt:"width"`
		Height int16 `nbt:"height"`
	} `nbt:"data"`
}

// Config reader the configuration for an uncompressed Minecraft map.
//
// Minecraft maps are gzip compressed, so the reader given to this func should
// be wrapped in gzip.NewReader.
func Config(r io.Reader) (image.Config, error) {
	var c config
	_, err := nbt.RDecode(r, &c)
	if err != nil {
		return image.Config{}, err
	}
	return image.Config{
		ColorModel: palette,
		Width:      int(c.Data.Width),
		Height:     int(c.Data.Height),
	}, nil
}
<commit_msg>corrected NBT useage<commit_after>package maps

import (
	"image"
	"io"

	"github.com/MJKWoolnough/minecraft/nbt"
)

func init() {
	image.RegisterFormat("minecraftmap", "\x0a\x00\x00\x0a\x00\x04data", Decode, Config)
}

func readData(r io.Reader) (nbt.Compound, error) {
	t, err := nbt.Decode(r)
	if err != nil {
		return nil, err
	}

	if t.TagID() != nbt.TagCompound {
		return nil, nbt.WrongTag{nbt.TagCompound, t.TagID()}
	}

	d := t.Data().(nbt.Compound).Get("data")
	if d.TagID() != nbt.TagCompound {
		return nil, nbt.WrongTag{nbt.TagCompound, d.TagID()}
	}
	return d.Data().(nbt.Compound), nil
}

func getDimensions(d nbt.Compound) image.Rectangle {
	var width, height int
	w := d.Get("width")
	if w.TagID() == nbt.TagShort {
		width = int(w.Data().(nbt.Short))
	}
	h := d.Get("height")
	if h.TagID() == nbt.TagShort {
		height = int(h.Data().(nbt.Short))
	}
	return image.Rectangle{
		image.Point{0, 0},
		image.Point{width, height},
	}
}

// Decode takes a reader for an uncompressed Minecraft map.
//
// Minecraft maps are gzip compressed, so the reader given to this func should
// be wrapped in gzip.NewReader.
func Decode(r io.Reader) (image.Image, error) {
	d, err := readData(r)
	if err != nil {
		return nil, err
	}

	c := d.Get("colors")
	if c.TagID() != nbt.TagByteArray {
		return nil, nbt.WrongTag{nbt.TagByteArray, c.TagID()}
	}

	rect := getDimensions(d)

	return &image.Paletted{
		Pix:     c.Data().(nbt.ByteArray).Bytes(),
		Stride:  rect.Max.X,
		Rect:    rect,
		Palette: palette,
	}, nil
}

// Config reader the configuration for an uncompressed Minecraft map.
//
// Minecraft maps are gzip compressed, so the reader given to this func should
// be wrapped in gzip.NewReader.
func Config(r io.Reader) (image.Config, error) {
	d, err := readData(r)
	if err != nil {
		return image.Config{}, err
	}
	rect := getDimensions(d)
	return image.Config{
		ColorModel: palette,
		Width:      int(rect.Max.X),
		Height:     int(rect.Max.Y),
	}, nil
}
<|endoftext|>