<commit_before>package action

import (
	"fmt"
	"os"
	"runtime"

	"github.com/fatih/color"
	"github.com/muesli/crunchy"
	"github.com/muesli/goprogressbar"
	"github.com/urfave/cli"
)

// auditedSecret with its name, content a warning message and a pipeline error.
type auditedSecret struct {
	name string

	// the secret's content as a string. Needed for checking for duplicates.
	content string

	// message to the user about some flaw in the secret
	message string

	// real error that something in the pipeline went wrong
	err error
}

// Audit validates passwords against common flaws
func (s *Action) Audit(c *cli.Context) error {
	t, err := s.Store.Tree()
	if err != nil {
		return err
	}
	list := t.List(0)

	fmt.Printf("Checking %d secrets. This may take some time ...\n", len(list))

	// Jobs are the secrets that still need auditing.
	jobs := make(chan string)

	// Secrets that have been audited.
	checked := make(chan auditedSecret)

	// Spawn workers that run the auditing of all secrets concurrently.
	validator := crunchy.NewValidator()
	for worker := 0; worker < runtime.NumCPU(); worker++ {
		go s.audit(validator, jobs, checked)
	}

	go func() {
		for _, secret := range list {
			jobs <- secret
		}
		close(jobs)
	}()

	duplicates := make(map[string][]string)
	messages := make(map[string][]string)

	bar := &goprogressbar.ProgressBar{
		Total: int64(len(list)),
		Width: 120,
	}

	i := 0
	for secret := range checked {
		duplicates[secret.content] = append(duplicates[secret.content], secret.name)

		if secret.message != "" {
			messages[secret.message] = append(messages[secret.message], secret.name)
		}

		i++
		bar.Current = int64(i)
		bar.Text = fmt.Sprintf("%d of %d secrets checked", bar.Current, bar.Total)
		bar.LazyPrint()

		if i == len(list) {
			break
		}
	}
	close(checked)
	fmt.Println("") // Print empty line after the progressbar.

	foundDuplicates := false
	for _, secrets := range duplicates {
		if len(secrets) > 1 {
			foundDuplicates = true

			fmt.Printf(color.CyanString("Detected a shared secret for:\n"))
			for _, secret := range secrets {
				fmt.Printf(color.CyanString("\t- %s\n", secret))
			}
		}
	}

	if !foundDuplicates {
		fmt.Println(color.GreenString("No shared secrets found."))
	}

	foundWeakPasswords := false
	for msg, secrets := range messages {
		foundWeakPasswords = true
		fmt.Printf(color.CyanString("%s:\n", msg))
		for _, secret := range secrets {
			fmt.Printf(color.CyanString("\t- %s\n", secret))
		}
	}

	if !foundWeakPasswords {
		fmt.Println(color.GreenString("No weak secrets detected."))
	}

	if foundWeakPasswords || foundDuplicates {
		os.Exit(1)
	}

	return nil
}

func (s *Action) audit(validator *crunchy.Validator, secrets <-chan string, checked chan<- auditedSecret) {
	for secret := range secrets {
		content, err := s.Store.GetFirstLine(secret)
		if err != nil {
			checked <- auditedSecret{name: secret, content: string(content), err: err}
			continue
		}

		if err := validator.Check(string(content)); err != nil {
			checked <- auditedSecret{name: secret, content: string(content), message: err.Error()}
			continue
		}

		checked <- auditedSecret{name: secret, content: string(content)}
	}
}
<commit_msg>Fixed handling decryption errors during audit (#249)<commit_after>package action

import (
	"fmt"
	"os"
	"runtime"

	"github.com/fatih/color"
	"github.com/muesli/crunchy"
	"github.com/muesli/goprogressbar"
	"github.com/urfave/cli"
)

// auditedSecret with its name, content a warning message and a pipeline error.
type auditedSecret struct {
	name string

	// the secret's content as a string. Needed for checking for duplicates.
	content string

	// message to the user about some flaw in the secret
	message string

	// real error that something in the pipeline went wrong
	err error
}

// Audit validates passwords against common flaws
func (s *Action) Audit(c *cli.Context) error {
	t, err := s.Store.Tree()
	if err != nil {
		return err
	}
	list := t.List(0)

	fmt.Printf("Checking %d secrets. This may take some time ...\n", len(list))

	// Jobs are the secrets that still need auditing.
	jobs := make(chan string)

	// Secrets that have been audited.
	checked := make(chan auditedSecret)

	// Spawn workers that run the auditing of all secrets concurrently.
	validator := crunchy.NewValidator()
	for worker := 0; worker < runtime.NumCPU(); worker++ {
		go s.audit(validator, jobs, checked)
	}

	go func() {
		for _, secret := range list {
			jobs <- secret
		}
		close(jobs)
	}()

	duplicates := make(map[string][]string)
	messages := make(map[string][]string)

	bar := &goprogressbar.ProgressBar{
		Total: int64(len(list)),
		Width: 120,
	}

	i := 0
	for secret := range checked {
		if secret.err == nil {
			duplicates[secret.content] = append(duplicates[secret.content], secret.name)
		}
		if secret.message != "" {
			messages[secret.message] = append(messages[secret.message], secret.name)
		}

		i++
		bar.Current = int64(i)
		bar.Text = fmt.Sprintf("%d of %d secrets checked", bar.Current, bar.Total)
		bar.LazyPrint()

		if i == len(list) {
			break
		}
	}
	close(checked)
	fmt.Println("") // Print empty line after the progressbar.

	foundDuplicates := false
	for _, secrets := range duplicates {
		if len(secrets) > 1 {
			foundDuplicates = true

			fmt.Printf(color.CyanString("Detected a shared secret for:\n"))
			for _, secret := range secrets {
				fmt.Printf(color.CyanString("\t- %s\n", secret))
			}
		}
	}

	if !foundDuplicates {
		fmt.Println(color.GreenString("No shared secrets found."))
	}

	foundWeakPasswords := false
	for msg, secrets := range messages {
		foundWeakPasswords = true
		fmt.Printf(color.CyanString("%s:\n", msg))
		for _, secret := range secrets {
			fmt.Printf(color.CyanString("\t- %s\n", secret))
		}
	}

	if !foundWeakPasswords {
		fmt.Println(color.GreenString("No weak secrets detected."))
	}

	if foundWeakPasswords || foundDuplicates {
		os.Exit(1)
	}

	return nil
}

func (s *Action) audit(validator *crunchy.Validator, secrets <-chan string, checked chan<- auditedSecret) {
	for secret := range secrets {
		content, err := s.Store.GetFirstLine(secret)
		if err != nil {
			checked <- auditedSecret{name: secret, content: string(content), err: err, message: err.Error()}
			continue
		}

		if err := validator.Check(string(content)); err != nil {
			checked <- auditedSecret{name: secret, content: string(content), message: err.Error()}
			continue
		}

		checked <- auditedSecret{name: secret, content: string(content)}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	flag "github.com/ogier/pflag"
	"github.com/flosch/pongo2"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/user"
	"strings"
	"sync"
)

func main() {
	flHost := flag.String("hosts", "", "hosts, support @filepath for loading hosts from file")
	flKey := flag.String("key", "", "private key")
	flUser := flag.String("user", "root", "remote user")
	flCmd := flag.String("cmd", "uname -a", "remote command")
	flPass := flag.String("pass", "", "optional user password")
	flVerbose := flag.Bool("verbose", false, "verbose mode (default false)")
	flReconnect := flag.Bool("reconnect", false, "reconnect on disconnected sessions (default false)")
	flag.Parse()
	if len(os.Args) == 1 {
		flag.PrintDefaults()
		return
	}
	hosts, err := parseHosts(*flHost)
	if err != nil {
		log.Printf("parse hosts err: %s", err)
		return
	}

	if *flVerbose {
		log.Printf("user: %s", *flUser)
		log.Printf("cmd: %s", *flCmd)
		log.Printf("hosts: %d", len(hosts))
	}

	privateKey, err := loadPrivateKey(*flKey)
	if err != nil {
		log.Fatalf("load private key err: %s", err)
		return
	}

	runCmdOnHosts(hosts, *flCmd, *flUser, *flPass, privateKey, *flReconnect, *flVerbose)
}

func runCmdOnHosts(hosts []string, cmd, defaultUser, defaultPass string, privateKey ssh.AuthMethod, reconnect, verbose bool) {
	wg := sync.WaitGroup{}
	wg.Add(len(hosts))
	for _, host := range hosts {
		go runCmdOnHost(host, cmd, defaultUser, defaultPass, privateKey, reconnect, verbose, &wg)
	}
	wg.Wait()
}

func runCmdOnHost(host string, cmd, defaultUser, defaultPass string, privateKey ssh.AuthMethod, reconnect, verbose bool, wg *sync.WaitGroup) {
	defer wg.Done()

	tpl, err := pongo2.FromString(cmd)
	if err != nil {
		log.Printf("cmd template err: %s", err)
		return
	}
	cmd, err = tpl.Execute(pongo2.Context{"host":host})
	if err != nil {
		log.Printf("cmd template err: %s", err)
		return
	}
	hostParsed, err := url.Parse(host)
	if err != nil {
		log.Printf("host %s parse failed: %s", host, err)
		return
	}
	var user string
	var pass string
	if hostParsed.Host == "" {
		hostParsed.Host = host
	}
	hostParts := strings.Split(hostParsed.Host, ":")
	if len(hostParts) == 1 {
		host = hostParts[0] + ":22"
	} else {
		host = hostParts[0] + ":" + hostParts[1]
	}
	if hostParsed.User != nil {
		user = hostParsed.User.Username()
		pass, _ = hostParsed.User.Password()
	}
	if user == "" {
		user = defaultUser
	}
	if pass == "" {
		pass = defaultPass
	}
	if verbose {
		log.Printf("connect to %s:%s@%s", user, pass, host)
	}
	clientConfig := ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			privateKey,
		},
	}
	if pass != "" {
		clientConfig.Auth = append([]ssh.AuthMethod{ssh.Password(pass)}, clientConfig.Auth...)
	}
	for {
		client, err := ssh.Dial("tcp", host, &clientConfig)
		if err != nil {
			log.Printf("connect to %s err: %s", host, err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		session, err := client.NewSession()
		if err != nil {
			log.Printf("session for %s failed: %s", host, err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		defer session.Close()
		stderr, err := session.StderrPipe()
		if err != nil {
			log.Printf("pipe stderr err: %s", err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		stdout, err := session.StdoutPipe()
		if err != nil {
			log.Printf("pipe stdout err: %s", err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		go io.Copy(&safeWriter{W: os.Stdout}, stdout)
		go io.Copy(&safeWriter{W: os.Stderr}, stderr)
		if err := session.Run(cmd); err != nil {
			log.Printf("failed execute on host %s: %s", host, err)
			if _, ok := err.(*ssh.ExitError); !ok && reconnect {
				continue
			}
			return
		}
		break
	}
}

type needReconnect struct {
	err error
}

type safeWriter struct {
	W     io.Writer
	mutex sync.Mutex
}

func (sw *safeWriter) Write(data []byte) (int, error) {
	sw.mutex.Lock()
	n, err := sw.W.Write(data)
	sw.mutex.Unlock()
	return n, err
}

func loadPrivateKey(keyPath string) (ssh.AuthMethod, error) {
	if keyPath == "" {
		return nil, fmt.Errorf("need private key")
	}
	if keyPath[:2] == "~/" {
		usr, _ := user.Current()
		keyPath = strings.Replace(keyPath, "~", usr.HomeDir, 1)
	}
	keyData, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	signer, err := ssh.ParsePrivateKey(keyData)
	if err != nil {
		return nil, err
	}
	return ssh.PublicKeys(signer), nil
}

func parseHosts(flagHost string) ([]string, error) {
	if strings.HasPrefix(flagHost, "@") {
		hostData, err := ioutil.ReadFile(flagHost[1:])
		if err != nil {
			return nil, err
		}
		return strings.Split(string(hostData), "\n"), nil
	}
	return strings.Split(flagHost, ","), nil
}
<commit_msg>fix resolve home dir<commit_after>package main

import (
	"fmt"
	flag "github.com/ogier/pflag"
	"github.com/flosch/pongo2"
	"golang.org/x/crypto/ssh"
	"io"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"os/user"
	"strings"
	"sync"
)

func main() {
	flHost := flag.String("hosts", "", "hosts, support @filepath for loading hosts from file")
	flKey := flag.String("key", "", "private key")
	flUser := flag.String("user", "root", "remote user")
	flCmd := flag.String("cmd", "uname -a", "remote command")
	flPass := flag.String("pass", "", "optional user password")
	flVerbose := flag.Bool("verbose", false, "verbose mode (default false)")
	flReconnect := flag.Bool("reconnect", false, "reconnect on disconnected sessions (default false)")
	flag.Parse()
	if len(os.Args) == 1 {
		flag.PrintDefaults()
		return
	}
	hosts, err := parseHosts(*flHost)
	if err != nil {
		log.Printf("parse hosts err: %s", err)
		return
	}

	if *flVerbose {
		log.Printf("user: %s", *flUser)
		log.Printf("cmd: %s", *flCmd)
		log.Printf("hosts: %d", len(hosts))
	}

	privateKey, err := loadPrivateKey(*flKey)
	if err != nil {
		log.Fatalf("load private key err: %s", err)
		return
	}

	runCmdOnHosts(hosts, *flCmd, *flUser, *flPass, privateKey, *flReconnect, *flVerbose)
}

func runCmdOnHosts(hosts []string, cmd, defaultUser, defaultPass string, privateKey ssh.AuthMethod, reconnect, verbose bool) {
	wg := sync.WaitGroup{}
	wg.Add(len(hosts))
	for _, host := range hosts {
		go runCmdOnHost(host, cmd, defaultUser, defaultPass, privateKey, reconnect, verbose, &wg)
	}
	wg.Wait()
}

func runCmdOnHost(host string, cmd, defaultUser, defaultPass string, privateKey ssh.AuthMethod, reconnect, verbose bool, wg *sync.WaitGroup) {
	defer wg.Done()

	tpl, err := pongo2.FromString(cmd)
	if err != nil {
		log.Printf("cmd template err: %s", err)
		return
	}
	cmd, err = tpl.Execute(pongo2.Context{"host":host})
	if err != nil {
		log.Printf("cmd template err: %s", err)
		return
	}
	hostParsed, err := url.Parse(host)
	if err != nil {
		log.Printf("host %s parse failed: %s", host, err)
		return
	}
	var user string
	var pass string
	if hostParsed.Host == "" {
		hostParsed.Host = host
	}
	hostParts := strings.Split(hostParsed.Host, ":")
	if len(hostParts) == 1 {
		host = hostParts[0] + ":22"
	} else {
		host = hostParts[0] + ":" + hostParts[1]
	}
	if hostParsed.User != nil {
		user = hostParsed.User.Username()
		pass, _ = hostParsed.User.Password()
	}
	if user == "" {
		user = defaultUser
	}
	if pass == "" {
		pass = defaultPass
	}
	if verbose {
		log.Printf("connect to %s:%s@%s", user, pass, host)
	}
	clientConfig := ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			privateKey,
		},
	}
	if pass != "" {
		clientConfig.Auth = append([]ssh.AuthMethod{ssh.Password(pass)}, clientConfig.Auth...)
	}
	for {
		client, err := ssh.Dial("tcp", host, &clientConfig)
		if err != nil {
			log.Printf("connect to %s err: %s", host, err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		session, err := client.NewSession()
		if err != nil {
			log.Printf("session for %s failed: %s", host, err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		defer session.Close()
		stderr, err := session.StderrPipe()
		if err != nil {
			log.Printf("pipe stderr err: %s", err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		stdout, err := session.StdoutPipe()
		if err != nil {
			log.Printf("pipe stdout err: %s", err)
			if reconnect {
				continue
			} else {
				return
			}
		}
		go io.Copy(&safeWriter{W: os.Stdout}, stdout)
		go io.Copy(&safeWriter{W: os.Stderr}, stderr)
		if err := session.Run(cmd); err != nil {
			log.Printf("failed execute on host %s: %s", host, err)
			if _, ok := err.(*ssh.ExitError); !ok && reconnect {
				continue
			}
			return
		}
		break
	}
}

type needReconnect struct {
	err error
}

type safeWriter struct {
	W     io.Writer
	mutex sync.Mutex
}

func (sw *safeWriter) Write(data []byte) (int, error) {
	sw.mutex.Lock()
	n, err := sw.W.Write(data)
	sw.mutex.Unlock()
	return n, err
}

func loadPrivateKey(keyPath string) (ssh.AuthMethod, error) {
	if keyPath == "" {
		return nil, fmt.Errorf("need private key")
	}
	keyPath = resolvePath(keyPath)
	keyData, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}
	signer, err := ssh.ParsePrivateKey(keyData)
	if err != nil {
		return nil, err
	}
	return ssh.PublicKeys(signer), nil
}

func resolvePath(path string) string {
	if path[:1] != "~" {
		return path
	}
	usr, _ := user.Current()
	return strings.Replace(path, "~", usr.HomeDir, 1)
}

func parseHosts(flagHost string) ([]string, error) {
	if strings.HasPrefix(flagHost, "@") {
		path := resolvePath(flagHost[1:])
		hostData, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, err
		}
		return strings.Split(string(hostData), "\n"), nil
	}
	return strings.Split(flagHost, ","), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"turnt-octo-hipster/max"
)

func main() {
	var sets int
	_, err := fmt.Scanf("%d", &sets)
	if err != nil {
		panic("could not read sets")
	}
	for ii := 0; ii < sets; ii++ {
		var col int
		_, err := fmt.Scanf("%d", &col)
		check(err, "could not read number of columns")
		var xx, yy []int
		for jj := 0; jj < col; jj++ {
			var val int
			_, err := fmt.Scanf("%d", &val)
			check(err, "could not read row")
			xx = append(xx, val)
		}
		for jj := 0; jj < col; jj++ {
			var val int
			_, err := fmt.Scanf("%d", &val)
			check(err, "could not read row")
			yy = append(yy, val)
		}
		fmt.Printf("The maximum distance is %v\n\n", max.MaximumDistance(xx, yy))
	}
}

func check(err error, str string) {
	if err != nil {
		panic(str)
	}
}
<commit_msg>missed one<commit_after>package main

import (
	"fmt"
	"turnt-octo-hipster/max"
)

func main() {
	var sets int
	_, err := fmt.Scanf("%d", &sets)
	check(err, "could not read sets")
	for ii := 0; ii < sets; ii++ {
		var col int
		_, err := fmt.Scanf("%d", &col)
		check(err, "could not read number of columns")
		var xx, yy []int
		for jj := 0; jj < col; jj++ {
			var val int
			_, err := fmt.Scanf("%d", &val)
			check(err, "could not read row")
			xx = append(xx, val)
		}
		for jj := 0; jj < col; jj++ {
			var val int
			_, err := fmt.Scanf("%d", &val)
			check(err, "could not read row")
			yy = append(yy, val)
		}
		fmt.Printf("The maximum distance is %v\n\n", max.MaximumDistance(xx, yy))
	}
}

func check(err error, str string) {
	if err != nil {
		panic(str)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"

	"code.cloudfoundry.org/cli/plugin"
	"code.cloudfoundry.org/cli/plugin/models"
	"github.com/bluemixgaragelondon/cf-blue-green-deploy/manifest"
)

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

func (p *CfPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	if len(args) > 0 && args[0] == "CLI-MESSAGE-UNINSTALL" {
		return
	}

	argsStruct := NewArgs(args)

	p.Connection = cliConnection

	defaultCfDomain, err := p.DefaultCfDomain()
	if err != nil {
		log.Fatalf("Failed to get default shared domain: %v", err)
	}

	p.Deployer.Setup(cliConnection)

	if argsStruct.AppName == "" {
		log.Fatal("App name was empty, must be provided.")
	}

	if !p.Deploy(defaultCfDomain, &manifest.FileManifestReader{}, argsStruct) {
		log.Fatal("Smoke tests failed")
	}
}

func (p *CfPlugin) Deploy(defaultCfDomain string, manifestReader manifest.ManifestReader, args Args) bool {
	appName := args.AppName

	p.Deployer.DeleteAllAppsExceptLiveApp(appName)
	liveAppName, liveAppRoutes := p.Deployer.LiveApp(appName)

	manifestScaleParameters := p.GetScaleFromManifest(appName, defaultCfDomain, manifestReader)

	newAppName := appName + "-new"

	// Add route so that we can run the smoke tests
	tempRoute := plugin_models.GetApp_RouteSummary{Host: newAppName, Domain: plugin_models.GetApp_DomainFields{Name: defaultCfDomain}}

	// If deploy is unsuccessful, p.ErrorFunc will be called which exits.
	p.Deployer.PushNewApp(newAppName, tempRoute, args.ManifestPath, manifestScaleParameters)

	promoteNewApp := true
	smokeTestScript := args.SmokeTestPath
	if smokeTestScript != "" {
		promoteNewApp = p.Deployer.RunSmokeTests(smokeTestScript, FQDN(tempRoute))
	}

	// TODO We're overloading 'new' here for both the staging app and the 'finished' app, which is confusing
	newAppRoutes := p.GetNewAppRoutes(args.AppName, defaultCfDomain, manifestReader, liveAppRoutes)

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

	if promoteNewApp {
		// If there is a live app, we want to disassociate the routes with the old version of the app
		// and instead update the routes to use the new version.
		if liveAppName != "" {
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(liveAppName, appName+"-old")
			p.Deployer.RenameApp(newAppName, appName)
			p.Deployer.UnmapRoutesFromApp(appName+"-old", liveAppRoutes...)
		} else {
			// If there is no live app, we only need to add our new routes.
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(newAppName, appName)
		}
		return true
	} else {
		// We don't want to promote. Instead mark it as failed.
		p.Deployer.RenameApp(newAppName, appName+"-failed")
		return false
	}
}

func (p *CfPlugin) GetNewAppRoutes(appName string, defaultCfDomain string, manifestReader manifest.ManifestReader, liveAppRoutes []plugin_models.GetApp_RouteSummary) []plugin_models.GetApp_RouteSummary {
	newAppRoutes := []plugin_models.GetApp_RouteSummary{}

	manifest, err := manifestReader.Read()
	if err != nil {
		// This error should be handled properly
		fmt.Println(err)
	}

	if manifest != nil {
		if appParams := manifest.GetAppParams(appName, defaultCfDomain); appParams != nil && appParams.Routes != nil {
			newAppRoutes = appParams.Routes
		}
	}

	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

	if len(uniqueRoutes) == 0 {
		uniqueRoutes = append(uniqueRoutes, plugin_models.GetApp_RouteSummary{Host: appName, Domain: plugin_models.GetApp_DomainFields{Name: defaultCfDomain}})
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetScaleFromManifest(appName string, defaultCfDomain string,
	manifestReader manifest.ManifestReader) (scaleParameters ScaleParameters) {
	manifest, err := manifestReader.Read()
	if err != nil {
		// TODO: Handle this error nicely
		fmt.Println(err)
	}
	if manifest != nil {
		manifestScaleParameters := manifest.GetAppParams(appName, defaultCfDomain)
		if manifestScaleParameters != nil {
			scaleParameters = ScaleParameters{
				Memory:        manifestScaleParameters.Memory,
				InstanceCount: manifestScaleParameters.InstanceCount,
				DiskQuota:     manifestScaleParameters.DiskQuota,
			}
		}
	}
	return
}

func (p *CfPlugin) UnionRouteLists(listA []plugin_models.GetApp_RouteSummary, listB []plugin_models.GetApp_RouteSummary) []plugin_models.GetApp_RouteSummary {
	duplicateList := append(listA, listB...)

	routesSet := make(map[plugin_models.GetApp_RouteSummary]struct{})

	for _, route := range duplicateList {
		routesSet[route] = struct{}{}
	}

	uniqueRoutes := []plugin_models.GetApp_RouteSummary{}
	for route := range routesSet {
		uniqueRoutes = append(uniqueRoutes, route)
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetMetadata() plugin.PluginMetadata {
	var major, minor, build int
	fmt.Sscanf(PluginVersion, "%d.%d.%d", &major, &minor, &build)

	return plugin.PluginMetadata{
		Name: "blue-green-deploy",
		Version: plugin.VersionType{
			Major: major,
			Minor: minor,
			Build: build,
		},
		Commands: []plugin.Command{
			{
				Name:     "blue-green-deploy",
				Alias:    "bgd",
				HelpText: "Zero-downtime deploys with smoke tests",
				UsageDetails: plugin.Usage{
					// TODO for manifests with multiple apps, a different smoke test is needed. The approach below would not work.
					// Perhaps we could name the smoke test in the manifest?
					Usage: "blue-green-deploy APP_NAME [--smoke-test TEST_SCRIPT] [-f MANIFEST_FILE]",
					Options: map[string]string{
						"smoke-test": "The test script to run.",
						"f":          "Path to manifest",
					},
				},
			},
		},
	}
}

func (p *CfPlugin) DefaultCfDomain() (domain string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", "/v2/shared_domains"); err != nil {
		return
	}

	response := struct {
		Resources []struct {
			Entity struct {
				Name string
			}
		}
	}{}

	var json_string string
	json_string = strings.Join(res, "\n")

	if err = json.Unmarshal([]byte(json_string), &response); err != nil {
		return
	}

	domain = response.Resources[0].Entity.Name
	return
}

func FQDN(r plugin_models.GetApp_RouteSummary) string {
	return fmt.Sprintf("%v.%v", r.Host, r.Domain.Name)
}

func main() {

	log.SetFlags(0)

	p := CfPlugin{
		Deployer: &BlueGreenDeploy{
			ErrorFunc: func(message string, err error) {
				log.Fatalf("%v - %v", message, err)
			},
			Out: os.Stdout,
		},
	}

	// TODO issue #24 - (Rufus) - not sure if I'm using the plugin correctly, but if I build (go build) and run without arguments
	// I expected to see available arguments but instead the code panics.
	plugin.Start(&p)
}
<commit_msg>Fixes #46 by passing -f path to manifest reader<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"

	"code.cloudfoundry.org/cli/plugin"
	"code.cloudfoundry.org/cli/plugin/models"
	"github.com/bluemixgaragelondon/cf-blue-green-deploy/manifest"
)

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

func (p *CfPlugin) Run(cliConnection plugin.CliConnection, args []string) {
	if len(args) > 0 && args[0] == "CLI-MESSAGE-UNINSTALL" {
		return
	}

	argsStruct := NewArgs(args)

	p.Connection = cliConnection

	defaultCfDomain, err := p.DefaultCfDomain()
	if err != nil {
		log.Fatalf("Failed to get default shared domain: %v", err)
	}

	p.Deployer.Setup(cliConnection)

	if argsStruct.AppName == "" {
		log.Fatal("App name was empty, must be provided.")
	}

	reader := manifest.FileManifestReader{argsStruct.ManifestPath}
	if !p.Deploy(defaultCfDomain, &reader, argsStruct) {
		log.Fatal("Smoke tests failed")
	}
}

func (p *CfPlugin) Deploy(defaultCfDomain string, manifestReader manifest.ManifestReader, args Args) bool {
	appName := args.AppName

	p.Deployer.DeleteAllAppsExceptLiveApp(appName)
	liveAppName, liveAppRoutes := p.Deployer.LiveApp(appName)

	manifestScaleParameters := p.GetScaleFromManifest(appName, defaultCfDomain, manifestReader)

	newAppName := appName + "-new"

	// Add route so that we can run the smoke tests
	tempRoute := plugin_models.GetApp_RouteSummary{Host: newAppName, Domain: plugin_models.GetApp_DomainFields{Name: defaultCfDomain}}

	// If deploy is unsuccessful, p.ErrorFunc will be called which exits.
	p.Deployer.PushNewApp(newAppName, tempRoute, args.ManifestPath, manifestScaleParameters)

	promoteNewApp := true
	smokeTestScript := args.SmokeTestPath
	if smokeTestScript != "" {
		promoteNewApp = p.Deployer.RunSmokeTests(smokeTestScript, FQDN(tempRoute))
	}

	// TODO We're overloading 'new' here for both the staging app and the 'finished' app, which is confusing
	newAppRoutes := p.GetNewAppRoutes(args.AppName, defaultCfDomain, manifestReader, liveAppRoutes)

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

	if promoteNewApp {
		// If there is a live app, we want to disassociate the routes with the old version of the app
		// and instead update the routes to use the new version.
		if liveAppName != "" {
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(liveAppName, appName+"-old")
			p.Deployer.RenameApp(newAppName, appName)
			p.Deployer.UnmapRoutesFromApp(appName+"-old", liveAppRoutes...)
		} else {
			// If there is no live app, we only need to add our new routes.
			p.Deployer.MapRoutesToApp(newAppName, newAppRoutes...)
			p.Deployer.RenameApp(newAppName, appName)
		}
		return true
	} else {
		// We don't want to promote. Instead mark it as failed.
		p.Deployer.RenameApp(newAppName, appName+"-failed")
		return false
	}
}

func (p *CfPlugin) GetNewAppRoutes(appName string, defaultCfDomain string, manifestReader manifest.ManifestReader, liveAppRoutes []plugin_models.GetApp_RouteSummary) []plugin_models.GetApp_RouteSummary {
	newAppRoutes := []plugin_models.GetApp_RouteSummary{}

	manifest, err := manifestReader.Read()
	if err != nil {
		// This error should be handled properly
		fmt.Println(err)
	}

	if manifest != nil {
		if appParams := manifest.GetAppParams(appName, defaultCfDomain); appParams != nil && appParams.Routes != nil {
			newAppRoutes = appParams.Routes
		}
	}

	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

	if len(uniqueRoutes) == 0 {
		uniqueRoutes = append(uniqueRoutes, plugin_models.GetApp_RouteSummary{Host: appName, Domain: plugin_models.GetApp_DomainFields{Name: defaultCfDomain}})
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetScaleFromManifest(appName string, defaultCfDomain string,
	manifestReader manifest.ManifestReader) (scaleParameters ScaleParameters) {
	manifest, err := manifestReader.Read()
	if err != nil {
		// TODO: Handle this error nicely
		fmt.Println(err)
	}
	if manifest != nil {
		manifestScaleParameters := manifest.GetAppParams(appName, defaultCfDomain)
		if manifestScaleParameters != nil {
			scaleParameters = ScaleParameters{
				Memory:        manifestScaleParameters.Memory,
				InstanceCount: manifestScaleParameters.InstanceCount,
				DiskQuota:     manifestScaleParameters.DiskQuota,
			}
		}
	}
	return
}

func (p *CfPlugin) UnionRouteLists(listA []plugin_models.GetApp_RouteSummary, listB []plugin_models.GetApp_RouteSummary) []plugin_models.GetApp_RouteSummary {
	duplicateList := append(listA, listB...)

	routesSet := make(map[plugin_models.GetApp_RouteSummary]struct{})

	for _, route := range duplicateList {
		routesSet[route] = struct{}{}
	}

	uniqueRoutes := []plugin_models.GetApp_RouteSummary{}
	for route := range routesSet {
		uniqueRoutes = append(uniqueRoutes, route)
	}
	return uniqueRoutes
}

func (p *CfPlugin) GetMetadata() plugin.PluginMetadata {
	var major, minor, build int
	fmt.Sscanf(PluginVersion, "%d.%d.%d", &major, &minor, &build)

	return plugin.PluginMetadata{
		Name: "blue-green-deploy",
		Version: plugin.VersionType{
			Major: major,
			Minor: minor,
			Build: build,
		},
		Commands: []plugin.Command{
			{
				Name:     "blue-green-deploy",
				Alias:    "bgd",
				HelpText: "Zero-downtime deploys with smoke tests",
				UsageDetails: plugin.Usage{
					// TODO for manifests with multiple apps, a different smoke test is needed. The approach below would not work.
					// Perhaps we could name the smoke test in the manifest?
					Usage: "blue-green-deploy APP_NAME [--smoke-test TEST_SCRIPT] [-f MANIFEST_FILE]",
					Options: map[string]string{
						"smoke-test": "The test script to run.",
						"f":          "Path to manifest",
					},
				},
			},
		},
	}
}

func (p *CfPlugin) DefaultCfDomain() (domain string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", "/v2/shared_domains"); err != nil {
		return
	}

	response := struct {
		Resources []struct {
			Entity struct {
				Name string
			}
		}
	}{}

	var json_string string
	json_string = strings.Join(res, "\n")

	if err = json.Unmarshal([]byte(json_string), &response); err != nil {
		return
	}

	domain = response.Resources[0].Entity.Name
	return
}

func FQDN(r plugin_models.GetApp_RouteSummary) string {
	return fmt.Sprintf("%v.%v", r.Host, r.Domain.Name)
}

func main() {

	log.SetFlags(0)

	p := CfPlugin{
		Deployer: &BlueGreenDeploy{
			ErrorFunc: func(message string, err error) {
				log.Fatalf("%v - %v", message, err)
			},
			Out: os.Stdout,
		},
	}

	// TODO issue #24 - (Rufus) - not sure if I'm using the plugin correctly, but if I build (go build) and run without arguments
	// I expected to see available arguments but instead the code panics.
	plugin.Start(&p)
}
<|endoftext|>


<commit_before>package main

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

	goyaml "gopkg.in/yaml.v2"
)

func main() {
	err := _main()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(2)
	}
	os.Exit(0)
}

func _main() error {
	var data interface{}
	input, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		return err
	}
	err = goyaml.Unmarshal(input, &data)
	if err != nil {
		return err
	}
	input = nil
	err = transformData(&data)
	if err != nil {
		return err
	}

	output, err := json.Marshal(data)
	if err != nil {
		return err
	}
	_, err = os.Stdout.Write(output)
	return err
}

func transformData(pIn *interface{}) (err error) {
	switch in := (*pIn).(type) {
	case map[interface{}]interface{}:
		m := make(map[string]interface{}, len(in))
		for k, v := range in {
			if err = transformData(&v); err != nil {
				return err
			}
			var sk string
			switch k.(type) {
			case string:
				sk = k.(string)
			case int:
				sk = strconv.Itoa(k.(int))
			default:
				return fmt.Errorf("type mismatch: expect map key string or int; got: %T", k)
			}
			m[sk] = v
		}
		*pIn = m
	case []interface{}:
		for i := len(in) - 1; i >= 0; i-- {
			if err = transformData(&in[i]); err != nil {
				return err
			}
		}
	}
	return nil
}
<commit_msg>move os.Stdin/os.Stdout out of the translation code<commit_after>package main

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

	goyaml "gopkg.in/yaml.v2"
)

func main() {
	err := translate(os.Stdin, os.Stdout)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(2)
	}
	os.Exit(0)
}

func translate(in io.Reader, out io.Writer) error {
	var data interface{}
	input, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}
	err = goyaml.Unmarshal(input, &data)
	if err != nil {
		return err
	}
	input = nil
	err = transformData(&data)
	if err != nil {
		return err
	}

	output, err := json.Marshal(data)
	if err != nil {
		return err
	}
	_, err = out.Write(output)
	return err
}

func transformData(pIn *interface{}) (err error) {
	switch in := (*pIn).(type) {
	case map[interface{}]interface{}:
		m := make(map[string]interface{}, len(in))
		for k, v := range in {
			if err = transformData(&v); err != nil {
				return err
			}
			var sk string
			switch k.(type) {
			case string:
				sk = k.(string)
			case int:
				sk = strconv.Itoa(k.(int))
			default:
				return fmt.Errorf("type mismatch: expect map key string or int; got: %T", k)
			}
			m[sk] = v
		}
		*pIn = m
	case []interface{}:
		for i := len(in) - 1; i >= 0; i-- {
			if err = transformData(&in[i]); err != nil {
				return err
			}
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/meatballhat/negroni-logrus"
	"gopkg.in/unrolled/render.v1"

	"github.com/alphagov/metadata-api/content_api"
	"github.com/alphagov/metadata-api/need_api"
)

var (
	appDomain = getEnvDefault("GOVUK_APP_DOMAIN", "alphagov.co.uk")
	port      = getEnvDefault("HTTP_PORT", "3000")

	contentAPI = "https://contentapi." + appDomain
	needAPI    = "https://need-api." + appDomain

	renderer = render.New(render.Options{})
)

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
	renderer.JSON(w, http.StatusOK, map[string]string{"status": "OK"})
}

func InfoHandler(contentAPI, needAPI string, config *Config) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var needs []*need_api.Need

		slug := r.URL.Path[len("/info"):]

		if len(slug) <= 1 || slug == "/" {
			renderError(w, http.StatusNotFound, "not found")
			return
		}

		artefact, err := content_api.FetchArtefact(contentAPI, config.BearerTokenContentAPI, slug)
		if err != nil {
			renderError(w, http.StatusInternalServerError, err.Error())
			return
		}

		for _, needID := range artefact.Details.NeedIDs {
			need, err := need_api.FetchNeed(needAPI, config.BearerTokenNeedAPI, needID)
			if err != nil {
				renderError(w, http.StatusInternalServerError, err.Error())
				return
			}
			needs = append(needs, need)
		}

		metadata := &Metadata{
			Artefact:     artefact,
			Needs:        needs,
			ResponseInfo: &ResponseInfo{Status: "ok"},
		}

		renderer.JSON(w, http.StatusOK, metadata)
	}
}

func main() {
	loggingMiddleware := negronilogrus.NewCustomMiddleware(
		logrus.InfoLevel, &logrus.JSONFormatter{}, "metadata-api")
	logging := loggingMiddleware.Logger

	config, err := ReadConfig("config.json")
	if err != nil {
		logging.Fatalln("Couldn't load configuration", err)
	}

	httpMux := http.NewServeMux()
	httpMux.HandleFunc("/healthcheck", HealthCheckHandler)
	httpMux.HandleFunc("/info/", InfoHandler(contentAPI, needAPI, config))

	middleware := negroni.New()
	middleware.Use(loggingMiddleware)
	middleware.UseHandler(httpMux)

	middleware.Run(":" + port)
}

func renderError(w http.ResponseWriter, status int, errorString string) {
	renderer.JSON(w, status, &Metadata{ResponseInfo: &ResponseInfo{Status: errorString}})
}

func getEnvDefault(key string, defaultVal string) string {
	val := os.Getenv(key)
	if val == "" {
		return defaultVal
	}

	return val
}
<commit_msg>Be specific about where the error was seen when exposing it<commit_after>package main

import (
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/meatballhat/negroni-logrus"
	"gopkg.in/unrolled/render.v1"

	"github.com/alphagov/metadata-api/content_api"
	"github.com/alphagov/metadata-api/need_api"
)

var (
	appDomain = getEnvDefault("GOVUK_APP_DOMAIN", "alphagov.co.uk")
	port      = getEnvDefault("HTTP_PORT", "3000")

	contentAPI = "https://contentapi." + appDomain
	needAPI    = "https://need-api." + appDomain

	renderer = render.New(render.Options{})
)

func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
	renderer.JSON(w, http.StatusOK, map[string]string{"status": "OK"})
}

func InfoHandler(contentAPI, needAPI string, config *Config) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var needs []*need_api.Need

		slug := r.URL.Path[len("/info"):]

		if len(slug) <= 1 || slug == "/" {
			renderError(w, http.StatusNotFound, "not found")
			return
		}

		artefact, err := content_api.FetchArtefact(contentAPI, config.BearerTokenContentAPI, slug)
		if err != nil {
			renderError(w, http.StatusInternalServerError, "Artefact: "+err.Error())
			return
		}

		for _, needID := range artefact.Details.NeedIDs {
			need, err := need_api.FetchNeed(needAPI, config.BearerTokenNeedAPI, needID)
			if err != nil {
				renderError(w, http.StatusInternalServerError, "Need: "+err.Error())
				return
			}
			needs = append(needs, need)
		}

		metadata := &Metadata{
			Artefact:     artefact,
			Needs:        needs,
			ResponseInfo: &ResponseInfo{Status: "ok"},
		}

		renderer.JSON(w, http.StatusOK, metadata)
	}
}

func main() {
	loggingMiddleware := negronilogrus.NewCustomMiddleware(
		logrus.InfoLevel, &logrus.JSONFormatter{}, "metadata-api")
	logging := loggingMiddleware.Logger

	config, err := ReadConfig("config.json")
	if err != nil {
		logging.Fatalln("Couldn't load configuration", err)
	}

	httpMux := http.NewServeMux()
	httpMux.HandleFunc("/healthcheck", HealthCheckHandler)
	httpMux.HandleFunc("/info/", InfoHandler(contentAPI, needAPI, config))

	middleware := negroni.New()
	middleware.Use(loggingMiddleware)
	middleware.UseHandler(httpMux)

	middleware.Run(":" + port)
}

func renderError(w http.ResponseWriter, status int, errorString string) {
	renderer.JSON(w, status, &Metadata{ResponseInfo: &ResponseInfo{Status: errorString}})
}

func getEnvDefault(key string, defaultVal string) string {
	val := os.Getenv(key)
	if val == "" {
		return defaultVal
	}

	return val
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"path"
	"strings"
	"time"
	"strconv"

	"github.com/gin-gonic/gin"
        "github.com/brandfolder/gin-gorelic"
)

// Logger is a simple log handler, out puts in the standard of apache access log common.
// See http://httpd.apache.org/docs/2.2/logs.html#accesslog
func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		ip, err := net.ResolveTCPAddr("tcp", c.Request.RemoteAddr)
		if err != nil {
			c.Abort()
		}

		// before request
		c.Next()
		// after request

		user := "-"
		if c.Request.URL.User != nil {
			user = c.Request.URL.User.Username()
		}

		latency := time.Since(t)

		// This is the format of Apache Log Common, with an additional field of latency
		fmt.Printf("%v - %v [%v] \"%v %v %v\" %v %v %v\n",
			ip.IP, user, t.Format(time.RFC3339), c.Request.Method, c.Request.URL.Path,
			c.Request.Proto, c.Writer.Status(), c.Request.ContentLength, latency)
	}
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func testRemoteTCPPort(address string) bool {
	_, err := net.DialTimeout("tcp", address, 3 * time.Second)
	if err != nil {
		return false
	}
	return true
}

func mainHandler(c *gin.Context) {
	fields := strings.Split(c.Params.ByName("field"), ".")
	ip, err := net.ResolveTCPAddr("tcp", c.Request.RemoteAddr)
	if err != nil {
		c.Abort()
	}

	cfIP := net.ParseIP(c.Request.Header.Get("CF-Connecting-IP"))
	if cfIP != nil {
		ip.IP = cfIP
	}

        if fields[0] == "porttest" {
		if len(fields) >= 2 {
			if port, err := strconv.Atoi(fields[1]); err == nil && port > 0 && port <= 65535 {
				c.String(200, fmt.Sprintln(testRemoteTCPPort(ip.IP.String() + ":" + fields[1])))
			} else {
				c.String(400, "Invalid Port Number")
			}
		} else {
			c.String(400, "Need Port")
		}
		return
        }

	c.Set("ip", ip.IP.String())
	c.Set("port", ip.Port)
	c.Set("ua", c.Request.UserAgent())
	c.Set("lang", c.Request.Header.Get("Accept-Language"))
	c.Set("encoding", c.Request.Header.Get("Accept-Encoding"))
	c.Set("method", c.Request.Method)
	c.Set("mime", c.Request.Header.Get("Accept"))
	c.Set("referer", c.Request.Header.Get("Referer"))
	c.Set("forwarded", c.Request.Header.Get("X-Forwarded-For"))
	c.Set("country_code", c.Request.Header.Get("CF-IPCountry"))

	ua := strings.Split(c.Request.UserAgent(), "/")

	// Only lookup hostname if the results are going to need it.
	if stringInSlice(fields[0], []string{"all", "host"}) || (fields[0] == "" && ua[0] != "curl") {
		hostnames, err := net.LookupAddr(ip.IP.String())
		if err != nil {
			c.Set("host", "")
		} else {
			c.Set("host", hostnames[0])
		}
	}

	wantsJSON := false
	if len(fields) >= 2 && fields[1] == "json" {
		wantsJSON = true
	}

	switch fields[0] {
	case "":
		//If the user is using curl, then we should just return the IP, else we show the home page.
		if ua[0] == "curl" {
			c.String(200, fmt.Sprintln(ip.IP))
		} else {
			c.HTML(200, "index.html", c.Keys)
		}
		return
	case "request":
		c.JSON(200, c.Request)
		return
	case "all":
		if wantsJSON {
			c.JSON(200, c.Keys)
		} else {
			c.String(200, "%v", c.Keys)
		}
		return
	}

	fieldResult, exists := c.Get(fields[0])
	if !exists {
		c.String(404, "Not Found")
		return
	}
	c.String(200, fmt.Sprintln(fieldResult))

}

// FileServer is a basic file serve handler, this is just here as an example.
// gin.Static() should be used instead
func FileServer(root string) gin.HandlerFunc {
	return func(c *gin.Context) {
		file := c.Params.ByName("file")
		if !strings.HasPrefix(file, "/") {
			file = "/" + file
		}
		http.ServeFile(c.Writer, c.Request, path.Join(root, path.Clean(file)))
	}
}

func main() {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(Logger())
	r.LoadHTMLGlob("templates/*")

	if NEWRELIC_LICENSE_KEY := os.Getenv("NEWRELIC_LICENSE_KEY"); NEWRELIC_LICENSE_KEY != "" {
		var NEWRELIC_APPLICATION_NAME string
		if NEWRELIC_APPLICATION_NAME = os.Getenv("NEWRELIC_APPLICATION_NAME"); NEWRELIC_APPLICATION_NAME == "" {
			NEWRELIC_APPLICATION_NAME = "ifconfig.io"
		}
		gorelic.InitNewrelicAgent(NEWRELIC_LICENSE_KEY, NEWRELIC_APPLICATION_NAME, true)
		r.Use(gorelic.Handler)
	}

	r.GET("/:field", mainHandler)
	r.GET("/", mainHandler)

	// Create a listener for FCGI
	fcgi_listen, err := net.Listen("tcp", "127.0.0.1:4000")
	if err != nil {
		panic(err)
	}
	errc := make(chan error)
	go func(errc chan error) {
		for err := range errc {
			panic(err)
		}
	}(errc)

	go func(errc chan error) {
		errc <- fcgi.Serve(fcgi_listen, r)
	}(errc)

	port := os.Getenv("PORT")
	host := os.Getenv("HOST")
	if port == "" {
		port = "8080"
	}
	errc <- r.Run(host + ":" + port)
}
<commit_msg>Add systemd socket support<commit_after>package main

import (
	"fmt"
	"net"
	"net/http"
	"net/http/fcgi"
	"os"
	"path"
	"strings"
	"time"
	"strconv"

	"github.com/gin-gonic/gin"
        "github.com/brandfolder/gin-gorelic"
        "github.com/coreos/go-systemd/activation"
)

// Logger is a simple log handler, out puts in the standard of apache access log common.
// See http://httpd.apache.org/docs/2.2/logs.html#accesslog
func Logger() gin.HandlerFunc {
	return func(c *gin.Context) {
		t := time.Now()
		ip, err := net.ResolveTCPAddr("tcp", c.Request.RemoteAddr)
		if err != nil {
			c.Abort()
		}

		// before request
		c.Next()
		// after request

		user := "-"
		if c.Request.URL.User != nil {
			user = c.Request.URL.User.Username()
		}

		latency := time.Since(t)

		// This is the format of Apache Log Common, with an additional field of latency
		fmt.Printf("%v - %v [%v] \"%v %v %v\" %v %v %v\n",
			ip.IP, user, t.Format(time.RFC3339), c.Request.Method, c.Request.URL.Path,
			c.Request.Proto, c.Writer.Status(), c.Request.ContentLength, latency)
	}
}

func stringInSlice(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}
	return false
}

func testRemoteTCPPort(address string) bool {
	_, err := net.DialTimeout("tcp", address, 3 * time.Second)
	if err != nil {
		return false
	}
	return true
}

func mainHandler(c *gin.Context) {
	fields := strings.Split(c.Params.ByName("field"), ".")
	ip, err := net.ResolveTCPAddr("tcp", c.Request.RemoteAddr)
	if err != nil {
		c.Abort()
	}

	cfIP := net.ParseIP(c.Request.Header.Get("CF-Connecting-IP"))
	if cfIP != nil {
		ip.IP = cfIP
	}

        if fields[0] == "porttest" {
		if len(fields) >= 2 {
			if port, err := strconv.Atoi(fields[1]); err == nil && port > 0 && port <= 65535 {
				c.String(200, fmt.Sprintln(testRemoteTCPPort(ip.IP.String() + ":" + fields[1])))
			} else {
				c.String(400, "Invalid Port Number")
			}
		} else {
			c.String(400, "Need Port")
		}
		return
        }

	c.Set("ip", ip.IP.String())
	c.Set("port", ip.Port)
	c.Set("ua", c.Request.UserAgent())
	c.Set("lang", c.Request.Header.Get("Accept-Language"))
	c.Set("encoding", c.Request.Header.Get("Accept-Encoding"))
	c.Set("method", c.Request.Method)
	c.Set("mime", c.Request.Header.Get("Accept"))
	c.Set("referer", c.Request.Header.Get("Referer"))
	c.Set("forwarded", c.Request.Header.Get("X-Forwarded-For"))
	c.Set("country_code", c.Request.Header.Get("CF-IPCountry"))

	ua := strings.Split(c.Request.UserAgent(), "/")

	// Only lookup hostname if the results are going to need it.
	if stringInSlice(fields[0], []string{"all", "host"}) || (fields[0] == "" && ua[0] != "curl") {
		hostnames, err := net.LookupAddr(ip.IP.String())
		if err != nil {
			c.Set("host", "")
		} else {
			c.Set("host", hostnames[0])
		}
	}

	wantsJSON := false
	if len(fields) >= 2 && fields[1] == "json" {
		wantsJSON = true
	}

	switch fields[0] {
	case "":
		//If the user is using curl, then we should just return the IP, else we show the home page.
		if ua[0] == "curl" {
			c.String(200, fmt.Sprintln(ip.IP))
		} else {
			c.HTML(200, "index.html", c.Keys)
		}
		return
	case "request":
		c.JSON(200, c.Request)
		return
	case "all":
		if wantsJSON {
			c.JSON(200, c.Keys)
		} else {
			c.String(200, "%v", c.Keys)
		}
		return
	}

	fieldResult, exists := c.Get(fields[0])
	if !exists {
		c.String(404, "Not Found")
		return
	}
	c.String(200, fmt.Sprintln(fieldResult))

}

// FileServer is a basic file serve handler, this is just here as an example.
// gin.Static() should be used instead
func FileServer(root string) gin.HandlerFunc {
	return func(c *gin.Context) {
		file := c.Params.ByName("file")
		if !strings.HasPrefix(file, "/") {
			file = "/" + file
		}
		http.ServeFile(c.Writer, c.Request, path.Join(root, path.Clean(file)))
	}
}

func main() {
	r := gin.New()
	r.Use(gin.Recovery())
	r.Use(Logger())
	r.LoadHTMLGlob("templates/*")

	if NEWRELIC_LICENSE_KEY := os.Getenv("NEWRELIC_LICENSE_KEY"); NEWRELIC_LICENSE_KEY != "" {
		var NEWRELIC_APPLICATION_NAME string
		if NEWRELIC_APPLICATION_NAME = os.Getenv("NEWRELIC_APPLICATION_NAME"); NEWRELIC_APPLICATION_NAME == "" {
			NEWRELIC_APPLICATION_NAME = "ifconfig.io"
		}
		gorelic.InitNewrelicAgent(NEWRELIC_LICENSE_KEY, NEWRELIC_APPLICATION_NAME, true)
		r.Use(gorelic.Handler)
	}

	r.GET("/:field", mainHandler)
	r.GET("/", mainHandler)

	// Create a listener for FCGI
	fcgi_listen, err := net.Listen("tcp", "127.0.0.1:4000")
	if err != nil {
		panic(err)
	}
	errc := make(chan error)
	go func(errc chan error) {
		for err := range errc {
			panic(err)
		}
	}(errc)

	go func(errc chan error) {
		errc <- fcgi.Serve(fcgi_listen, r)
	}(errc)

	// Listen on whatever systemd tells us to.
	listeners, err := activation.Listeners(true)
	if err != nil {
		fmt.Printf("Could not get systemd listerns with err %q", err)
	}
	for _, listener := range listeners {
		go func(errc chan error) {
			errc <- http.Serve(listener, r)
		}(errc)
	}

	port := os.Getenv("PORT")
	host := os.Getenv("HOST")
	if port == "" {
		port = "8080"
	}
	errc <- r.Run(host + ":" + port)
}
<|endoftext|>


<commit_before>package bench

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"sync"
	"time"
)

// Executes a benchmark. The context is used to cancel the benchmark at any
// given time.
func (b *Bench) Exec(ctx context.Context) error {
	client := b.getClient()
	remainingRequests := b.Requests
	t := time.Now()

	for remainingRequests > 0 {
		waitChannel := make(chan struct{})
		go b.runConcurrentJobs(ctx, waitChannel, client, &remainingRequests)
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-waitChannel:
			continue
		}
	}

	defer func() {
		b.Renderer.SetTotalDuration(time.Since(t))
	}()

	return nil
}

func (b *Bench) runConcurrentJobs(ctx context.Context, waitChannel chan struct{}, client *http.Client, remainingRequests *int) {
	wg := &sync.WaitGroup{}
	remainingConcurrent := b.Concurrency
	for remainingConcurrent > 0 && *remainingRequests > 0 {
		for _, url := range b.Urls {
			req := b.buildRequest(url)
			req = req.WithContext(ctx)
			wg.Add(1)
			go b.runBench(wg, client, req)
		}
		(*remainingRequests)--
		remainingConcurrent--
	}
	wg.Wait()
	close(waitChannel)
}

func (b *Bench) runBench(wg *sync.WaitGroup, client *http.Client, req *http.Request) {
	defer wg.Done()

	tr := time.Now()
	resp, err := client.Do(req)
	responseTime := time.Since(tr)
	reqUrl := req.URL.String()

	if err != nil {
		if err, ok := err.(*url.Error); ok && err.Timeout() {
			go b.Renderer.AddTimedoutResponse(reqUrl)
			return
		}

		go b.printVerbosityMessage(fmt.Sprintf("Error for %s: %v\n", reqUrl, err))
		go b.Renderer.AddFailedResponse(reqUrl)
		return
	}

	defer resp.Body.Close()

	go b.updateResult(reqUrl, resp, responseTime)
}

func (b *Bench) updateResult(reqUrl string, resp *http.Response, responseTime time.Duration) {
	b.Renderer.AddResponseTime(reqUrl, responseTime)
	b.Renderer.AddReceivedDataLength(reqUrl, resp.ContentLength)
	b.Renderer.AddResponseStatusCode(reqUrl, resp.StatusCode, b.isFailed(resp.StatusCode))
	b.printVerbosityMessage(fmt.Sprintf("Sent requests for %s in %v: %s\n", reqUrl, responseTime, http.StatusText(resp.StatusCode)))
}

func (b *Bench) printVerbosityMessage(msg string) {
	if b.VerbosityWriter != nil {
		b.VerbosityWriterLock.Lock()
		fmt.Fprint(b.VerbosityWriter, msg)
		b.VerbosityWriterLock.Unlock()
	}
}

func (b *Bench) isFailed(statusCode int) bool {
	for _, code := range b.SuccessStatusCodes {
		if statusCode == code {
			return false
		}
	}

	return true
}

func (b *Bench) getClient() *http.Client {
	tr := &http.Transport{
		Dial: b.getDial(),
	}

	if b.ResponseTimeout > 0 {
		tr.ResponseHeaderTimeout = b.ResponseTimeout
	}

	if b.Proxy != "" {
		p, _ := url.Parse(b.Proxy)
		tr.Proxy = http.ProxyURL(p)
	}

	return &http.Client{Transport: tr}
}

func (b *Bench) getDial() func(network, addr string) (net.Conn, error) {
	if b.ConnectionTimeout > 0 {
		return func(network, addr string) (net.Conn, error) {
			return net.DialTimeout(network, addr, b.ConnectionTimeout)
		}
	}

	return net.Dial
}

func (b *Bench) buildRequest(u *Url) *http.Request {
	req, err := newRequest(u)

	if err != nil {
		log.Fatalf("Could not create request for %s: %v", u, err)
	}

	if b.Auth != nil {
		req.SetBasicAuth(b.Auth.Username, b.Auth.Password)
	}

	if _, ok := b.Headers["User-Agent"]; !ok {
		req.Header.Add("User-Agent", "Gbench")
	}

	for key, value := range b.Headers {
		req.Header.Add(key, value)
	}

	if b.RawCookie != "" {
		req.Header.Add("Set-Cookie", b.RawCookie)
	}

	return req
}

func newRequest(u *Url) (*http.Request, error) {
	if u.Method == http.MethodGet || u.Method == http.MethodHead {
		return http.NewRequest(u.Method, u.Addr, nil)
	}

	values := url.Values{}

	for key, value := range u.Data {
		values.Add(key, value)
	}

	req, err := http.NewRequest(u.Method, u.Addr, bytes.NewBufferString(values.Encode()))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	return req, nil
}
<commit_msg>Fix race condition in go routines<commit_after>package bench

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"sync"
	"time"
)

// Executes a benchmark. The context is used to cancel the benchmark at any
// given time.
func (b *Bench) Exec(ctx context.Context) error {
	client := b.getClient()
	remainingRequests := b.Requests
	t := time.Now()

	for remainingRequests > 0 {
		waitChannel := make(chan struct{})
		go b.runConcurrentJobs(ctx, waitChannel, client, &remainingRequests)
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-waitChannel:
			continue
		}
	}

	defer func() {
		b.Renderer.SetTotalDuration(time.Since(t))
	}()

	return nil
}

func (b *Bench) runConcurrentJobs(ctx context.Context, waitChannel chan struct{}, client *http.Client, remainingRequests *int) {
	wg := &sync.WaitGroup{}
	remainingConcurrent := b.Concurrency
	for remainingConcurrent > 0 && *remainingRequests > 0 {
		for _, url := range b.Urls {
			req := b.buildRequest(url)
			req = req.WithContext(ctx)
			wg.Add(1)
			go b.runBench(wg, client, req)
		}
		(*remainingRequests)--
		remainingConcurrent--
	}
	wg.Wait()
	close(waitChannel)
}

func (b *Bench) runBench(wg *sync.WaitGroup, client *http.Client, req *http.Request) {
	defer wg.Done()

	tr := time.Now()
	resp, err := client.Do(req)
	responseTime := time.Since(tr)
	reqUrl := req.URL.String()

	if err != nil {
		if err, ok := err.(*url.Error); ok && err.Timeout() {
			b.printVerbosityMessage(fmt.Sprintf("Timed out request for %s: %v\n", reqUrl, err))
			b.Renderer.AddTimedoutResponse(reqUrl)
			return
		}

		b.printVerbosityMessage(fmt.Sprintf("Error for %s: %v\n", reqUrl, err))
		b.Renderer.AddFailedResponse(reqUrl)
		return
	}

	defer resp.Body.Close()

	b.Renderer.AddResponseTime(reqUrl, responseTime)
	b.Renderer.AddReceivedDataLength(reqUrl, resp.ContentLength)
	b.Renderer.AddResponseStatusCode(reqUrl, resp.StatusCode, b.isFailed(resp.StatusCode))
	b.printVerbosityMessage(fmt.Sprintf("Sent requests for %s in %v: %s\n", reqUrl, responseTime, http.StatusText(resp.StatusCode)))
}

func (b *Bench) printVerbosityMessage(msg string) {
	if b.VerbosityWriter != nil {
		b.VerbosityWriterLock.Lock()
		defer b.VerbosityWriterLock.Unlock()
		fmt.Fprint(b.VerbosityWriter, msg)
	}
}

func (b *Bench) isFailed(statusCode int) bool {
	for _, code := range b.SuccessStatusCodes {
		if statusCode == code {
			return false
		}
	}

	return true
}

func (b *Bench) getClient() *http.Client {
	tr := &http.Transport{
		Dial: b.getDial(),
	}

	if b.ResponseTimeout > 0 {
		tr.ResponseHeaderTimeout = b.ResponseTimeout
	}

	if b.Proxy != "" {
		p, _ := url.Parse(b.Proxy)
		tr.Proxy = http.ProxyURL(p)
	}

	return &http.Client{Transport: tr}
}

func (b *Bench) getDial() func(network, addr string) (net.Conn, error) {
	if b.ConnectionTimeout > 0 {
		return func(network, addr string) (net.Conn, error) {
			return net.DialTimeout(network, addr, b.ConnectionTimeout)
		}
	}

	return net.Dial
}

func (b *Bench) buildRequest(u *Url) *http.Request {
	req, err := newRequest(u)

	if err != nil {
		log.Fatalf("Could not create request for %s: %v", u, err)
	}

	if b.Auth != nil {
		req.SetBasicAuth(b.Auth.Username, b.Auth.Password)
	}

	if _, ok := b.Headers["User-Agent"]; !ok {
		req.Header.Add("User-Agent", "Gbench")
	}

	for key, value := range b.Headers {
		req.Header.Add(key, value)
	}

	if b.RawCookie != "" {
		req.Header.Add("Set-Cookie", b.RawCookie)
	}

	return req
}

func newRequest(u *Url) (*http.Request, error) {
	if u.Method == http.MethodGet || u.Method == http.MethodHead {
		return http.NewRequest(u.Method, u.Addr, nil)
	}

	values := url.Values{}

	for key, value := range u.Data {
		values.Add(key, value)
	}

	req, err := http.NewRequest(u.Method, u.Addr, bytes.NewBufferString(values.Encode()))

	if err != nil {
		return nil, err
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	return req, nil
}
<|endoftext|>


<commit_before>package nats

import (
	"io"
	"net"
	"testing"
	"bytes"
	"time"
)

type FakeAddr int

func (fa FakeAddr) Network() string {
	panic("FakeAddr#Network")
}

func (fa FakeAddr) String() string {
	panic("FakeAddr#String")
}

type FakeConnection struct {
	rin  *io.PipeReader
	win  *io.PipeWriter
	rout *io.PipeReader
	wout *io.PipeWriter
}

func NewFakeConnection() *FakeConnection {
	var fc FakeConnection

	fc.rin, fc.wout = io.Pipe()
	fc.rout, fc.win = io.Pipe()

	return &fc
}

func (fc *FakeConnection) Read(b []byte) (n int, err error) {
	return fc.rin.Read(b)
}

func (fc *FakeConnection) Write(b []byte) (n int, err error) {
	return fc.win.Write(b)
}

func (fc *FakeConnection) TestRead(t *testing.T, b string) bool {
	var err error

	var buf []byte
	var n int

	buf = make([]byte, len(b))
	n, err = fc.rout.Read(buf)

	if err != nil {
		t.Errorf("\nerror: %#v\n", err)
		return false
	}

	var expected []byte = []byte(b)
	var actual []byte = bytes.ToLower(buf[0:n])
	if !bytes.Equal(expected, actual) {
		t.Errorf("\nexpected: %#v\ngot: %#v\n", string(expected), string(actual))
		return false
	}

	return true
}

func (fc *FakeConnection) TestWrite(t *testing.T, b string) bool {
	var err error

	_, err = fc.wout.Write([]byte(b))

	if err != nil {
		t.Errorf("\nerror: %#v\n", err)
		return false
	}

	return true
}

func (fc *FakeConnection) Close() error {
	var err error

	err = fc.rin.Close()
	if err != nil {
		panic(err)
	}

	err = fc.win.Close()
	if err != nil {
		panic(err)
	}

	err = fc.rout.Close()
	if err != nil {
		panic(err)
	}

	err = fc.wout.Close()
	if err != nil {
		panic(err)
	}

	return nil
}

func (fc *FakeConnection) LocalAddr() net.Addr {
	var fa FakeAddr
	return fa
}

func (fc *FakeConnection) RemoteAddr() net.Addr {
	var fa FakeAddr
	return fa
}

func (fc *FakeConnection) SetDeadline(t time.Time) error {
	return nil
}

func (fc *FakeConnection) SetReadDeadline(t time.Time) error {
	return nil
}

func (fc *FakeConnection) SetWriteDeadline(t time.Time) error {
	return nil
}

func TestConnectionPongOnPing(t *testing.T) {
	var c = NewConnection()
	var fc = NewFakeConnection()
	var done = make(chan bool)
	var ok bool

	go func() {
		c.Run(fc)
		done <- true
	}()

	// Write PING
	ok = fc.TestWrite(t, "ping\r\n")
	if !ok {
		return
	}

	// Read PONG
	ok = fc.TestRead(t, "pong\r\n")
	if !ok {
		return
	}

	// Close connection
	fc.Close()

	// Wait for goroutine
	<-done
}
<commit_msg>Helper methods for connection start/stop<commit_after>package nats

import (
	"io"
	"net"
	"testing"
	"bytes"
	"time"
)

type FakeAddr int

func (fa FakeAddr) Network() string {
	panic("FakeAddr#Network")
}

func (fa FakeAddr) String() string {
	panic("FakeAddr#String")
}

type FakeConnection struct {
	rin  *io.PipeReader
	win  *io.PipeWriter
	rout *io.PipeReader
	wout *io.PipeWriter
}

func NewFakeConnection() *FakeConnection {
	var fc FakeConnection

	fc.rin, fc.wout = io.Pipe()
	fc.rout, fc.win = io.Pipe()

	return &fc
}

func (fc *FakeConnection) Read(b []byte) (n int, err error) {
	return fc.rin.Read(b)
}

func (fc *FakeConnection) Write(b []byte) (n int, err error) {
	return fc.win.Write(b)
}

func (fc *FakeConnection) TestRead(t *testing.T, b string) bool {
	var err error

	var buf []byte
	var n int

	buf = make([]byte, len(b))
	n, err = fc.rout.Read(buf)

	if err != nil {
		t.Errorf("\nerror: %#v\n", err)
		return false
	}

	var expected []byte = []byte(b)
	var actual []byte = bytes.ToLower(buf[0:n])
	if !bytes.Equal(expected, actual) {
		t.Errorf("\nexpected: %#v\ngot: %#v\n", string(expected), string(actual))
		return false
	}

	return true
}

func (fc *FakeConnection) TestWrite(t *testing.T, b string) bool {
	var err error

	_, err = fc.wout.Write([]byte(b))

	if err != nil {
		t.Errorf("\nerror: %#v\n", err)
		return false
	}

	return true
}

func (fc *FakeConnection) Close() error {
	var err error

	err = fc.rin.Close()
	if err != nil {
		panic(err)
	}

	err = fc.win.Close()
	if err != nil {
		panic(err)
	}

	err = fc.rout.Close()
	if err != nil {
		panic(err)
	}

	err = fc.wout.Close()
	if err != nil {
		panic(err)
	}

	return nil
}

func (fc *FakeConnection) LocalAddr() net.Addr {
	var fa FakeAddr
	return fa
}

func (fc *FakeConnection) RemoteAddr() net.Addr {
	var fa FakeAddr
	return fa
}

func (fc *FakeConnection) SetDeadline(t time.Time) error {
	return nil
}

func (fc *FakeConnection) SetReadDeadline(t time.Time) error {
	return nil
}

func (fc *FakeConnection) SetWriteDeadline(t time.Time) error {
	return nil
}

type testConnection struct {
	c    *Connection
	fc   *FakeConnection
	done chan bool
}

func (self *testConnection) start() {
	self.c = NewConnection()
	self.fc = NewFakeConnection()
	self.done = make(chan bool)

	go func() {
		self.c.Run(self.fc)
		self.done <- true
	}()
}

func (self *testConnection) stop() {
	// Close connection
	self.fc.Close()

	// Wait for goroutine
	<-self.done
}

func startTestConnection() *testConnection {
	var tc = new(testConnection)
	tc.start()
	return tc
}

func TestConnectionPongOnPing(t *testing.T) {
	var tc = startTestConnection()
	var ok bool

	// Write PING
	ok = tc.fc.TestWrite(t, "ping\r\n")
	if !ok {
		return
	}

	// Read PONG
	ok = tc.fc.TestRead(t, "pong\r\n")
	if !ok {
		return
	}

	tc.stop()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"mime"
	"os"
	"path/filepath"
	"strings"

	"github.com/drone/drone-go/plugin"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

type AWS struct {
	client *s3.S3
	bucket *s3.Bucket
	remote []string
	local  []string
	vargs  PluginArgs
}

type StringMap struct {
	parts map[string]string
}

func (e *StringMap) UnmarshalJSON(b []byte) error {
	if len(b) == 0 {
		return nil
	}

	p := map[string]string{}
	if err := json.Unmarshal(b, &p); err != nil {
		var s string
		if err := json.Unmarshal(b, &s); err != nil {
			return err
		}
		p["_string_"] = s
	}

	e.parts = p
	return nil
}

func (e *StringMap) IsEmpty() bool {
	if e == nil || len(e.parts) == 0 {
		return true
	}

	return false
}

func (e *StringMap) IsString() bool {
	if e.IsEmpty() || len(e.parts) != 1 {
		return false
	}

	_, ok := e.parts["_string_"]
	return ok
}

func (e *StringMap) String() string {
	if e.IsEmpty() || !e.IsString() {
		return ""
	}

	return e.parts["_string_"]
}

func (e *StringMap) Map() map[string]string {
	if e.IsEmpty() || e.IsString() {
		return map[string]string{}
	}

	return e.parts
}

type PluginArgs struct {
	Key         string    `json:"access_key"`
	Secret      string    `json:"secret_key"`
	Bucket      string    `json:"bucket"`
	Region      string    `json:"region"`
	Source      string    `json:"source"`
	Target      string    `json:"target"`
	Delete      bool      `json:"delete"`
	Access      StringMap `json:"acl"`
	ContentType StringMap `json:"content_type"`
}

func NewClient(vargs PluginArgs) AWS {
	auth := aws.Auth{AccessKey: vargs.Key, SecretKey: vargs.Secret}
	region := aws.Regions[vargs.Region]
	client := s3.New(auth, region)
	bucket := client.Bucket(vargs.Bucket)
	remote := make([]string, 1, 1)
	local := make([]string, 1, 1)

	aws := AWS{client, bucket, remote, local, vargs}
	return aws
}

func (aws *AWS) visit(path string, info os.FileInfo, err error) error {
	if path == "." {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	aws.local = append(aws.local, path)
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	defer file.Close()

	var access s3.ACL
	if aws.vargs.Access.IsString() {
		access = s3.ACL(aws.vargs.Access.String())
	} else if !aws.vargs.Access.IsEmpty() {
		accessMap := aws.vargs.Access.Map()
		for pattern := range accessMap {
			if match, _ := filepath.Match(pattern, path); match == true {
				access = s3.ACL(accessMap[pattern])
				break
			}
		}
	}

	if access == "" {
		access = s3.ACL("private")
	}

	fileExt := filepath.Ext(path)
	var contentType string
	if aws.vargs.ContentType.IsString() {
		contentType = aws.vargs.ContentType.String()
	} else if !aws.vargs.ContentType.IsEmpty() {
		contentMap := aws.vargs.ContentType.Map()
		for patternExt := range contentMap {
			if patternExt == fileExt {
				contentType = contentMap[patternExt]
				break
			}
		}
	}

	if contentType == "" {
		contentType = mime.TypeByExtension(fileExt)
	}

	fmt.Printf("Uploading %s with Content-Type %s and permissions %s\n", path, contentType, access)
	err = aws.bucket.PutReader(path, file, info.Size(), contentType, access)
	if err != nil {
		return err
	}

	return nil
}

func (aws *AWS) List(path string) (*s3.ListResp, error) {
	return aws.bucket.List(path, "", "", 10000)
}

func (aws *AWS) Cleanup() error {
	for _, remote := range aws.remote {
		found := false
		for _, local := range aws.local {
			if local == remote {
				found = true
				break
			}
		}

		if !found {
			fmt.Println("Removing remote file ", remote)
			err := aws.bucket.Del(remote)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func main() {
	vargs := PluginArgs{}

	plugin.Param("vargs", &vargs)
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if len(vargs.Key) == 0 || len(vargs.Secret) == 0 || len(vargs.Bucket) == 0 {
		return
	}

	if len(vargs.Region) == 0 {
		vargs.Region = "us-east-1"
	}

	if len(vargs.Source) == 0 {
		vargs.Source = "."
	}

	if strings.HasPrefix(vargs.Target, "/") {
		vargs.Target = vargs.Target[1:]
	}

	if vargs.Target != "" && !strings.HasSuffix(vargs.Target, "/") {
		vargs.Target = fmt.Sprintf("%s/", vargs.Target)
	}

	client := NewClient(vargs)

	resp, err := client.List(vargs.Target)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, item := range resp.Contents {
		client.remote = append(client.remote, item.Key)
	}

	err = filepath.Walk(vargs.Source, client.visit)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if vargs.Delete {
		err = client.Cleanup()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<commit_msg>handle errors<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"mime"
	"os"
	"path/filepath"
	"strings"

	"github.com/drone/drone-go/plugin"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/s3"
)

type AWS struct {
	client *s3.S3
	bucket *s3.Bucket
	remote []string
	local  []string
	vargs  PluginArgs
}

type StringMap struct {
	parts map[string]string
}

func (e *StringMap) UnmarshalJSON(b []byte) error {
	if len(b) == 0 {
		return nil
	}

	p := map[string]string{}
	if err := json.Unmarshal(b, &p); err != nil {
		var s string
		if err := json.Unmarshal(b, &s); err != nil {
			return err
		}
		p["_string_"] = s
	}

	e.parts = p
	return nil
}

func (e *StringMap) IsEmpty() bool {
	if e == nil || len(e.parts) == 0 {
		return true
	}

	return false
}

func (e *StringMap) IsString() bool {
	if e.IsEmpty() || len(e.parts) != 1 {
		return false
	}

	_, ok := e.parts["_string_"]
	return ok
}

func (e *StringMap) String() string {
	if e.IsEmpty() || !e.IsString() {
		return ""
	}

	return e.parts["_string_"]
}

func (e *StringMap) Map() map[string]string {
	if e.IsEmpty() || e.IsString() {
		return map[string]string{}
	}

	return e.parts
}

type PluginArgs struct {
	Key         string    `json:"access_key"`
	Secret      string    `json:"secret_key"`
	Bucket      string    `json:"bucket"`
	Region      string    `json:"region"`
	Source      string    `json:"source"`
	Target      string    `json:"target"`
	Delete      bool      `json:"delete"`
	Access      StringMap `json:"acl"`
	ContentType StringMap `json:"content_type"`
}

func NewClient(vargs PluginArgs) AWS {
	auth := aws.Auth{AccessKey: vargs.Key, SecretKey: vargs.Secret}
	region := aws.Regions[vargs.Region]
	client := s3.New(auth, region)
	bucket := client.Bucket(vargs.Bucket)
	remote := make([]string, 1, 1)
	local := make([]string, 1, 1)

	aws := AWS{client, bucket, remote, local, vargs}
	return aws
}

func (aws *AWS) visit(path string, info os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if path == "." {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	aws.local = append(aws.local, path)
	file, err := os.Open(path)
	if err != nil {
		return err
	}

	defer file.Close()

	var access s3.ACL
	if aws.vargs.Access.IsString() {
		access = s3.ACL(aws.vargs.Access.String())
	} else if !aws.vargs.Access.IsEmpty() {
		accessMap := aws.vargs.Access.Map()
		for pattern := range accessMap {
			if match, _ := filepath.Match(pattern, path); match == true {
				access = s3.ACL(accessMap[pattern])
				break
			}
		}
	}

	if access == "" {
		access = s3.ACL("private")
	}

	fileExt := filepath.Ext(path)
	var contentType string
	if aws.vargs.ContentType.IsString() {
		contentType = aws.vargs.ContentType.String()
	} else if !aws.vargs.ContentType.IsEmpty() {
		contentMap := aws.vargs.ContentType.Map()
		for patternExt := range contentMap {
			if patternExt == fileExt {
				contentType = contentMap[patternExt]
				break
			}
		}
	}

	if contentType == "" {
		contentType = mime.TypeByExtension(fileExt)
	}

	fmt.Printf("Uploading %s with Content-Type %s and permissions %s\n", path, contentType, access)
	err = aws.bucket.PutReader(path, file, info.Size(), contentType, access)
	if err != nil {
		return err
	}

	return nil
}

func (aws *AWS) List(path string) (*s3.ListResp, error) {
	return aws.bucket.List(path, "", "", 10000)
}

func (aws *AWS) Cleanup() error {
	for _, remote := range aws.remote {
		found := false
		for _, local := range aws.local {
			if local == remote {
				found = true
				break
			}
		}

		if !found {
			fmt.Println("Removing remote file ", remote)
			err := aws.bucket.Del(remote)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func main() {
	vargs := PluginArgs{}

	plugin.Param("vargs", &vargs)
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if len(vargs.Key) == 0 || len(vargs.Secret) == 0 || len(vargs.Bucket) == 0 {
		return
	}

	if len(vargs.Region) == 0 {
		vargs.Region = "us-east-1"
	}

	if len(vargs.Source) == 0 {
		vargs.Source = "."
	}

	if strings.HasPrefix(vargs.Target, "/") {
		vargs.Target = vargs.Target[1:]
	}

	if vargs.Target != "" && !strings.HasSuffix(vargs.Target, "/") {
		vargs.Target = fmt.Sprintf("%s/", vargs.Target)
	}

	client := NewClient(vargs)

	resp, err := client.List(vargs.Target)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	for _, item := range resp.Contents {
		client.remote = append(client.remote, item.Key)
	}

	err = filepath.Walk(vargs.Source, client.visit)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if vargs.Delete {
		err = client.Cleanup()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	slowhttp "github.com/Clever/go-bench/slowhttp"
	"os"
	"github.com/stretchr/testify/assert"
	"testing"
	"strings"
)

func assertNoError(err error, t *testing.T) {
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
}

func TestPlayback_1(t *testing.T) {
	p, err := os.Open("test/testdata1")
	assertNoError(err, t)

	l, err := slowhttp.StartServer()
	assertNoError(err, t)

	parseAndReplay(p, "http://127.0.0.1:8653", 1)
	l.Close()
}

const rootURL = "http://127.0.0.1:8653"
const verb = "GET"
const path = "/test/path"
const delay = 0
const extra = ""
func TestEventToRequestWithEmptyAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "", nil)
}

func TestEventToRequestWithBasicAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "Basic XXXX", []string{"Basic XXXX"})
}

func TestEventToRequestWithBearerAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "Bearer YYYY", []string{"Bearer YYYY"})
}

func assertRequestMatchesExpected(t *testing.T, benchAuthParam string, expectedAuthHeader []string) {
	requestEvent := RequestEvent{verb, path, benchAuthParam, delay, extra}
	httpRequest := eventToRequest(rootURL, requestEvent)
	assert.Equal(t, verb, httpRequest.Method, "Wrong HTTP method")
	host := strings.Replace(rootURL, "http://", "", -1)
	assert.Equal(t, host, httpRequest.Host, "Wrong root URL")
	assert.Equal(t, path, httpRequest.URL.Path, "Wrong request path")
	assert.Equal(t, expectedAuthHeader, httpRequest.Header["Authorization"], "Wrong authentication header")
}<commit_msg>Moves constants inside the only func that uses them in bench_test (and adds newline at EOF)<commit_after>package main

import (
	slowhttp "github.com/Clever/go-bench/slowhttp"
	"os"
	"github.com/stretchr/testify/assert"
	"testing"
	"strings"
)

func assertNoError(err error, t *testing.T) {
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
}

func TestPlayback_1(t *testing.T) {
	p, err := os.Open("test/testdata1")
	assertNoError(err, t)

	l, err := slowhttp.StartServer()
	assertNoError(err, t)

	parseAndReplay(p, "http://127.0.0.1:8653", 1)
	l.Close()
}

func TestEventToRequestWithEmptyAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "", nil)
}

func TestEventToRequestWithBasicAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "Basic XXXX", []string{"Basic XXXX"})
}

func TestEventToRequestWithBearerAuthHeader(t *testing.T) {
	assertRequestMatchesExpected(t, "Bearer YYYY", []string{"Bearer YYYY"})
}

func assertRequestMatchesExpected(t *testing.T, benchAuthParam string, expectedAuthHeader []string) {
	const rootURL = "http://127.0.0.1:8653"
	const verb = "GET"
	const path = "/test/path"
	const delay = 0
	const extra = ""

	requestEvent := RequestEvent{verb, path, benchAuthParam, delay, extra}
	httpRequest := eventToRequest(rootURL, requestEvent)
	assert.Equal(t, verb, httpRequest.Method, "Wrong HTTP method")
	host := strings.Replace(rootURL, "http://", "", -1)
	assert.Equal(t, host, httpRequest.Host, "Wrong root URL")
	assert.Equal(t, path, httpRequest.URL.Path, "Wrong request path")
	assert.Equal(t, expectedAuthHeader, httpRequest.Header["Authorization"], "Wrong authentication header")
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/google/go-github/github"
    "fmt"
    "github.com/bndr/gojenkins"
    "github.com/xoom/stash"
    "net/url"
    "strings"
    "bytes"
    "launchpad.net/xmlpath"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "sort"
    "time"
    "log"
    "html/template"
    "os"
    "bufio"
)

type Jenkins struct {
    Name     string
    Url      string
    Username string
    Password string
}

type Github struct {
    Organization string
    Username     string
    Password     string
}

type Stash struct {
    Prefix   string
    Url      string
    Username string
    Password string
}

type Configuration struct {
    Jenkins []Jenkins
    Github  []Github
    Stash   []Stash
}

type Job struct {
    JenkinsName string
    Name        string
    Url         string
    ScmUrl      string
}

type GitRepository struct {
    Project string
    ProjectUrl string
    Name    string
    Url     string
    ScmUrls []string
    Jobs    []Job
}

type ByProjectAndName []GitRepository

func (a ByProjectAndName) Len() int { return len(a) }
func (a ByProjectAndName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByProjectAndName) Less(i, j int) bool { return a[i].Project + a[i].Name < a[j].Project + a[j].Name}

func main() {

    fmt.Printf("Loading configuration...\n")
    configuration, err := readConfiguration();
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    fmt.Printf("Finished loading configuration.\n")

    var allJobs []Job
    var allRepos[]GitRepository

    for _, jenkins := range configuration.Jenkins {
        fmt.Printf("Loading jobs from %v...\n", jenkins.Name)
        resultJobs, err := jenkinsParser(jenkins.Name, jenkins.Url, jenkins.Username, jenkins.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading jobs from %v\n", jenkins.Name)
        allJobs = append(allJobs, resultJobs...)
    }

    for _, github := range configuration.Github {
        fmt.Printf("Loading repos from %v...\n", github.Organization)
        resultRepos, err := githubParser(github.Organization, github.Username, github.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading repos from %v\n", github.Organization)
        allRepos = append(allRepos, resultRepos...)
    }

    for _, stash := range configuration.Stash {
        fmt.Printf("Loading repos from %v...\n", stash.Url)
        resultRepos, err := stashParser(stash.Url, stash.Prefix, stash.Username, stash.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading repos with project prefixed with %v,  from %v", stash.Prefix, stash.Url)
        allRepos = append(allRepos, resultRepos...)
    }

    sort.Sort(ByProjectAndName((allRepos)))

    attachJobsToRepos(allRepos, allJobs)

    printResultsAsText(allRepos)

    printResultsAsHtml(allRepos, configuration)

}

func printResultsAsText(allRepos []GitRepository) {
    for _, repo := range allRepos {
        if (len(repo.Jobs) > 0) {
            jobsAsStrings := ""
            for _, job := range repo.Jobs {
                if (len(jobsAsStrings) > 0) {
                    jobsAsStrings += " and "
                }
                jobsAsStrings += job.Name + " at " + job.Url
            }
            fmt.Printf("%v/%v is built by %v \n", repo.Project, repo.Name, jobsAsStrings)
        } else {
            fmt.Printf("%v/%v is an orphan repo\n", repo.Project, repo.Name)
        }
    }
}

func printResultsAsHtml(allRepos []GitRepository, configuration Configuration) {
    currentTime := time.Now().Format(time.RFC3339)

    check := func(err error) {
        if err != nil {
            log.Fatal(err)
        }
    }
    t, err := template.ParseFiles("./template.html")

    type ConfigElement struct {
        Name    string
        Url string
    }
    configElements := []ConfigElement{}

    for _, jenkins := range configuration.Jenkins {
        configElements = append(configElements, ConfigElement{jenkins.Username + " @ " + jenkins.Name, jenkins.Url})
    }
    for _, github := range configuration.Github {
        configElements = append(configElements, ConfigElement{github.Organization, "https://github.com/" + github.Organization })
    }
    for _, stash := range configuration.Stash {
        configElements = append(configElements, ConfigElement{stash.Prefix, stash.Url})
    }

    for _, repo := range allRepos {
        if (len(repo.Jobs) > 0) {
            jobsAsStrings := ""
            for _, job := range repo.Jobs {
                if (len(jobsAsStrings) > 0) {
                    jobsAsStrings += " and "
                }
                jobsAsStrings += job.Name + " at " + job.Url
            }
        }
    }

    data := struct {
        Title          string
        Date           string
        ConfigElements []ConfigElement
        ReposAndJobs   []GitRepository

    }{
        Title: "GitXJenkins report",
        Date: currentTime,
        ConfigElements: configElements,
        ReposAndJobs: allRepos,
    }

    f, err := os.Create("output.html")
    check(err)
    defer f.Close()

    w := bufio.NewWriter(f)
    err = t.Execute(w, data)
    check(err)

    w.Flush()

}

func attachJobsToRepos(allRepos []GitRepository, allJobs []Job) {
    for i, repo := range allRepos {
        for _, job := range allJobs {
            for _, repoScmUrl := range repo.ScmUrls {
                if (job.ScmUrl == repoScmUrl) {
                    allRepos[i].Jobs = append(allRepos[i].Jobs, job)
                }
            }
        }
    }
}

func jenkinsParser(jenkinsName string, jenkinsURL string, username string, password string) ([]Job, error) {

    var resultJobs []Job

    jenkins, err := gojenkins.CreateJenkins(jenkinsURL, username, password).Init()
    if err != nil {
        return nil, err
    }

    jobs, err := jenkins.GetAllJobs();
    if err != nil {
        return nil, err
    }

    path := xmlpath.MustCompile("//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url")

    for _, job := range jobs {
        jobConfig, err := job.GetConfig();
        if err != nil {
            fmt.Printf("error: %v", err)
            continue
        }

        b := bytes.NewBufferString(jobConfig)

        root, err := xmlpath.Parse(b)
        if err != nil {
            fmt.Printf("error: %v", err)
            continue
        }
        if scmUrl, ok := path.String(root); ok {
            resultJobs = append(resultJobs, Job{JenkinsName: jenkinsName, Name:job.GetName(), Url:job.GetDetails().URL, ScmUrl:scmUrl})
        }
    }
    return resultJobs, nil
}

func stashParser(stashBaseUrl string, projectPrefix string, username string, password string) ([]GitRepository, error) {

    var resultGitRepositories []GitRepository

    stashUrl, err := url.Parse(stashBaseUrl)
    if err != nil {
        return resultGitRepositories, err
    }
    stashClient := stash.NewClient(username, password, stashUrl)
    repository, err := stashClient.GetRepositories()
    if err != nil {
        return resultGitRepositories, err
    }
    for _, element := range repository {
        if ( strings.HasPrefix(element.Project.Key, projectPrefix)) {
            var urls []string
            urls = append(urls, element.SshUrl())
            repoUrl := stashBaseUrl + "/projects/" + element.Project.Key + "/repos/" + element.Name + "/browse"
            resultGitRepositories = append(resultGitRepositories, GitRepository{Project: element.Project.Key, Name: element.Name, Url: repoUrl, ScmUrls:urls})
        }
    }
    return resultGitRepositories, nil
}

func githubParser(githubOrganization string, username string, password string) ([]GitRepository, error) {
    var resultGitRepositories []GitRepository

    client := github.NewClient(nil)
    orgs, _, _ := client.Repositories.List(githubOrganization, nil)

    for _, element := range orgs {
        var urls []string
        urls = append(urls, *element.GitURL)
        urls = append(urls, *element.CloneURL)
        url := strings.Replace(*element.URL, "api.", "", -1)
        url = strings.Replace(url, "repos/", "", -1)
        resultGitRepositories = append(resultGitRepositories, GitRepository{Project:githubOrganization, ProjectUrl:"https://github.com/" + githubOrganization, Name:*element.Name, Url:url, ScmUrls:urls})
    }
    return resultGitRepositories, nil
}

func readConfiguration() (Configuration, error) {
    t := Configuration{}
    dat, err := ioutil.ReadFile("config.yml")
    if err != nil {
        return t, err
    }
    err = yaml.Unmarshal(dat, &t)
    if err != nil {
        return t, err
    }
    return t, nil
}<commit_msg>fail fast if jenkins url / credentials is / are not correct<commit_after>package main

import (
    "github.com/google/go-github/github"
    "fmt"
    "github.com/bndr/gojenkins"
    "github.com/xoom/stash"
    "net/url"
    "strings"
    "bytes"
    "launchpad.net/xmlpath"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "sort"
    "time"
    "log"
    "html/template"
    "os"
    "bufio"
)

type Jenkins struct {
    Name     string
    Url      string
    Username string
    Password string
}

type Github struct {
    Organization string
    Username     string
    Password     string
}

type Stash struct {
    Prefix   string
    Url      string
    Username string
    Password string
}

type Configuration struct {
    Jenkins []Jenkins
    Github  []Github
    Stash   []Stash
}

type Job struct {
    JenkinsName string
    Name        string
    Url         string
    ScmUrl      string
}

type GitRepository struct {
    Project string
    ProjectUrl string
    Name    string
    Url     string
    ScmUrls []string
    Jobs    []Job
}

type ByProjectAndName []GitRepository

func (a ByProjectAndName) Len() int { return len(a) }
func (a ByProjectAndName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByProjectAndName) Less(i, j int) bool { return a[i].Project + a[i].Name < a[j].Project + a[j].Name}

func main() {

    fmt.Printf("Loading configuration...\n")
    configuration, err := readConfiguration();
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    fmt.Printf("Finished loading configuration.\n")

    var allJobs []Job
    var allRepos[]GitRepository

    for _, jenkins := range configuration.Jenkins {
        fmt.Printf("Loading jobs from %v...\n", jenkins.Name)
        resultJobs, err := jenkinsParser(jenkins.Name, jenkins.Url, jenkins.Username, jenkins.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading jobs from %v\n", jenkins.Name)
        allJobs = append(allJobs, resultJobs...)
    }

    for _, github := range configuration.Github {
        fmt.Printf("Loading repos from %v...\n", github.Organization)
        resultRepos, err := githubParser(github.Organization, github.Username, github.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading repos from %v\n", github.Organization)
        allRepos = append(allRepos, resultRepos...)
    }

    for _, stash := range configuration.Stash {
        fmt.Printf("Loading repos from %v...\n", stash.Url)
        resultRepos, err := stashParser(stash.Url, stash.Prefix, stash.Username, stash.Password)
        if err != nil {
            fmt.Printf("error: %v", err)
            return
        }
        fmt.Printf("Finished loading repos with project prefixed with %v,  from %v", stash.Prefix, stash.Url)
        allRepos = append(allRepos, resultRepos...)
    }

    sort.Sort(ByProjectAndName((allRepos)))

    attachJobsToRepos(allRepos, allJobs)

    printResultsAsText(allRepos)

    printResultsAsHtml(allRepos, configuration)

}

func printResultsAsText(allRepos []GitRepository) {
    for _, repo := range allRepos {
        if (len(repo.Jobs) > 0) {
            jobsAsStrings := ""
            for _, job := range repo.Jobs {
                if (len(jobsAsStrings) > 0) {
                    jobsAsStrings += " and "
                }
                jobsAsStrings += job.Name + " at " + job.Url
            }
            fmt.Printf("%v/%v is built by %v \n", repo.Project, repo.Name, jobsAsStrings)
        } else {
            fmt.Printf("%v/%v is an orphan repo\n", repo.Project, repo.Name)
        }
    }
}

func printResultsAsHtml(allRepos []GitRepository, configuration Configuration) {
    currentTime := time.Now().Format(time.RFC3339)

    check := func(err error) {
        if err != nil {
            log.Fatal(err)
        }
    }
    t, err := template.ParseFiles("./template.html")

    type ConfigElement struct {
        Name    string
        Url string
    }
    configElements := []ConfigElement{}

    for _, jenkins := range configuration.Jenkins {
        configElements = append(configElements, ConfigElement{jenkins.Username + " @ " + jenkins.Name, jenkins.Url})
    }
    for _, github := range configuration.Github {
        configElements = append(configElements, ConfigElement{github.Organization, "https://github.com/" + github.Organization })
    }
    for _, stash := range configuration.Stash {
        configElements = append(configElements, ConfigElement{stash.Prefix, stash.Url})
    }

    for _, repo := range allRepos {
        if (len(repo.Jobs) > 0) {
            jobsAsStrings := ""
            for _, job := range repo.Jobs {
                if (len(jobsAsStrings) > 0) {
                    jobsAsStrings += " and "
                }
                jobsAsStrings += job.Name + " at " + job.Url
            }
        }
    }

    data := struct {
        Title          string
        Date           string
        ConfigElements []ConfigElement
        ReposAndJobs   []GitRepository

    }{
        Title: "GitXJenkins report",
        Date: currentTime,
        ConfigElements: configElements,
        ReposAndJobs: allRepos,
    }

    f, err := os.Create("output.html")
    check(err)
    defer f.Close()

    w := bufio.NewWriter(f)
    err = t.Execute(w, data)
    check(err)

    w.Flush()

}

func attachJobsToRepos(allRepos []GitRepository, allJobs []Job) {
    for i, repo := range allRepos {
        for _, job := range allJobs {
            for _, repoScmUrl := range repo.ScmUrls {
                if (job.ScmUrl == repoScmUrl) {
                    allRepos[i].Jobs = append(allRepos[i].Jobs, job)
                }
            }
        }
    }
}

func jenkinsParser(jenkinsName string, jenkinsURL string, username string, password string) ([]Job, error) {

    var resultJobs []Job

    jenkins, err := gojenkins.CreateJenkins(jenkinsURL, username, password).Init()
    if err != nil {
        return nil, err
    }

    status, err := jenkins.Poll();
    if(status != 200) {
        log.Fatalf("Jenkins replied with status %v ; check your credentials for %v", status, jenkinsURL)
        return nil, err
    }

    jobs, err := jenkins.GetAllJobs();
    if err != nil {
        return nil, err
    }

    path := xmlpath.MustCompile("//scm/userRemoteConfigs/hudson.plugins.git.UserRemoteConfig/url")

    for _, job := range jobs {
        jobConfig, err := job.GetConfig();
        if err != nil {
            fmt.Printf("error: %v", err)
            continue
        }

        b := bytes.NewBufferString(jobConfig)

        root, err := xmlpath.Parse(b)
        if err != nil {
            fmt.Printf("error: %v", err)
            continue
        }
        if scmUrl, ok := path.String(root); ok {
            resultJobs = append(resultJobs, Job{JenkinsName: jenkinsName, Name:job.GetName(), Url:job.GetDetails().URL, ScmUrl:scmUrl})
        }
    }
    return resultJobs, nil
}

func stashParser(stashBaseUrl string, projectPrefix string, username string, password string) ([]GitRepository, error) {

    var resultGitRepositories []GitRepository

    stashUrl, err := url.Parse(stashBaseUrl)
    if err != nil {
        return resultGitRepositories, err
    }
    stashClient := stash.NewClient(username, password, stashUrl)
    repository, err := stashClient.GetRepositories()
    if err != nil {
        return resultGitRepositories, err
    }
    for _, element := range repository {
        if ( strings.HasPrefix(element.Project.Key, projectPrefix)) {
            var urls []string
            urls = append(urls, element.SshUrl())
            repoUrl := stashBaseUrl + "/projects/" + element.Project.Key + "/repos/" + element.Name + "/browse"
            resultGitRepositories = append(resultGitRepositories, GitRepository{Project: element.Project.Key, Name: element.Name, Url: repoUrl, ScmUrls:urls})
        }
    }
    return resultGitRepositories, nil
}

func githubParser(githubOrganization string, username string, password string) ([]GitRepository, error) {
    var resultGitRepositories []GitRepository

    client := github.NewClient(nil)
    orgs, _, _ := client.Repositories.List(githubOrganization, nil)

    for _, element := range orgs {
        var urls []string
        urls = append(urls, *element.GitURL)
        urls = append(urls, *element.CloneURL)
        url := strings.Replace(*element.URL, "api.", "", -1)
        url = strings.Replace(url, "repos/", "", -1)
        resultGitRepositories = append(resultGitRepositories, GitRepository{Project:githubOrganization, ProjectUrl:"https://github.com/" + githubOrganization, Name:*element.Name, Url:url, ScmUrls:urls})
    }
    return resultGitRepositories, nil
}

func readConfiguration() (Configuration, error) {
    t := Configuration{}
    dat, err := ioutil.ReadFile("config.yml")
    if err != nil {
        return t, err
    }
    err = yaml.Unmarshal(dat, &t)
    if err != nil {
        return t, err
    }
    return t, nil
}<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"github.com/gorilla/mux"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
)

type Certificates struct {
	CertFile string
	KeyFile  string
}

func listenAndServeTLSSNI(srv *http.Server, certs []Certificates) error {
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}
	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error

	config.Certificates = make([]tls.Certificate, len(certs))
	for i, v := range certs {
		config.Certificates[i], err = tls.LoadX509KeyPair(v.CertFile, v.KeyFile)
		if err != nil {
			return err
		}
	}

	config.BuildNameToCertificate()

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(conn, config)
	return srv.Serve(tlsListener)
}

func proxy3000() *httputil.ReverseProxy {
	remote3000, err3000 := url.Parse("http://lvh.me:3000")
	if err3000 != nil {
		panic(err3000)
	}

	return httputil.NewSingleHostReverseProxy(remote3000)
}

func proxy3001() *httputil.ReverseProxy {
	remote3001, err3001 := url.Parse("http://lvh.me:3001")
	if err3001 != nil {
		panic(err3001)
	}

	return httputil.NewSingleHostReverseProxy(remote3001)
}

func certManaboInfo() Certificates {
	return Certificates{
		CertFile: "ssl/manabo-info/fullchain.pem",
		KeyFile:  "ssl/manabo-info/privkey.pem",
	}
}

func certBoardManaboInfo() Certificates {
	return Certificates{
		CertFile: "ssl/board-manabo-info/fullchain.pem",
		KeyFile:  "ssl/board-manabo-info/privkey.pem",
	}
}

func main() {
	var certs []Certificates

	certs = append(certs, certManaboInfo())
	certs = append(certs, certBoardManaboInfo())

	route := mux.NewRouter()
	route.Host("manabo.info").PathPrefix("/").Handler(proxy3000())
	route.Host("board.manabo.info").PathPrefix("/").Handler(proxy3001())

	httpsServer := &http.Server{
		Addr:    ":443",
		Handler: route,
	}

	fmt.Println("Listening on port 443...")
	err := listenAndServeTLSSNI(httpsServer, certs)
	if err != nil {
		fmt.Printf("err: %s", err)
	}
}
<commit_msg>use zgok library<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/srtkkou/zgok"
	"io/ioutil"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"os"
)

type Certificates struct {
	CertFile string
	KeyFile  string
}

func loadX509KeyPair(certFile, keyFile string) (tls.Certificate, error) {
	certPEMBlock, err := readFromZfs(certFile)
	if err != nil {
		return tls.Certificate{}, err
	}
	keyPEMBlock, err := readFromZfs(keyFile)
	if err != nil {
		return tls.Certificate{}, err
	}
	return tls.X509KeyPair(certPEMBlock, keyPEMBlock)
}

func readFromZfs(filePath string) ([]byte, error) {
	zfs, _ := zgok.RestoreFileSystem(os.Args[0])
	if zfs != nil {
		// 本番環境
		return zfs.ReadFile(filePath)
	} else {
		// 開発環境
		return ioutil.ReadFile(filePath)
	}
}

func listenAndServeTLSSNI(srv *http.Server, certs []Certificates) error {
	addr := srv.Addr
	if addr == "" {
		addr = ":https"
	}
	config := &tls.Config{}
	if srv.TLSConfig != nil {
		*config = *srv.TLSConfig
	}
	if config.NextProtos == nil {
		config.NextProtos = []string{"http/1.1"}
	}

	var err error

	config.Certificates = make([]tls.Certificate, len(certs))
	for i, v := range certs {
		config.Certificates[i], err = loadX509KeyPair(v.CertFile, v.KeyFile)
		if err != nil {
			return err
		}
	}

	config.BuildNameToCertificate()

	conn, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}

	tlsListener := tls.NewListener(conn, config)
	return srv.Serve(tlsListener)
}

func proxy3000() *httputil.ReverseProxy {
	remote3000, err3000 := url.Parse("http://lvh.me:3000")
	if err3000 != nil {
		panic(err3000)
	}

	return httputil.NewSingleHostReverseProxy(remote3000)
}

func proxy3001() *httputil.ReverseProxy {
	remote3001, err3001 := url.Parse("http://lvh.me:3001")
	if err3001 != nil {
		panic(err3001)
	}

	return httputil.NewSingleHostReverseProxy(remote3001)
}

func certManaboInfo() Certificates {
	return Certificates{
		CertFile: "ssl/manabo-info/fullchain.pem",
		KeyFile:  "ssl/manabo-info/privkey.pem",
	}
}

func certBoardManaboInfo() Certificates {
	return Certificates{
		CertFile: "ssl/board-manabo-info/fullchain.pem",
		KeyFile:  "ssl/board-manabo-info/privkey.pem",
	}
}

func main() {
	var certs []Certificates

	certs = append(certs, certManaboInfo())
	certs = append(certs, certBoardManaboInfo())

	route := mux.NewRouter()
	route.Host("manabo.info").PathPrefix("/").Handler(proxy3000())
	route.Host("board.manabo.info").PathPrefix("/").Handler(proxy3001())

	httpsServer := &http.Server{
		Addr:    ":443",
		Handler: route,
	}

	fmt.Println("Listening on port 443...")
	err := listenAndServeTLSSNI(httpsServer, certs)
	if err != nil {
		fmt.Printf("err: %s", err)
	}
}
<|endoftext|>