<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
	"github.com/iron-io/iron_go3/worker"
)

// Configuration set via HUD
type Config struct {
	MsgDuration     time.Duration   `json:"msgDuration,omitempty"`
	IterationSleep  time.Duration   `json:"iterationSleep,omitempty"`
	MaxDuration     time.Duration   `json:"maxDuration,omitempty"`
	MaxIterations   *int            `json:"maxIterations,omitempty"`
	BatchSize       int             `json:"batchSize,omitempty"`
	MaxEmptyResults *int            `json:"maxEmptyResults,omitempty"`
	DequeueWait     int             `json:"dequeueWait,omitempty"`
	QueueName       string          `json:"queueName"`
	Env             config.Settings `json:"env"`
}

func DefaultConfig() *Config {
	m := 0
	return &Config{
		MsgDuration:     1 * time.Second,
		IterationSleep:  20 * time.Millisecond,
		MaxDuration:     45 * time.Minute,
		BatchSize:       1,
		DequeueWait:     0,
		MaxEmptyResults: &m,
	}
}

func (c *Config) Valid() error {
	if len(c.Env.ProjectId) == 0 || len(c.Env.Token) == 0 {
		return errors.New(`Require queue project & token set in code config.`)
	}
	return nil
}

func main() {
	start := time.Now()

	// Parse config json and validate
	worker.ParseFlags()
	c := DefaultConfig()
	worker.ConfigFromJSON(c)
	if err := c.Valid(); err != nil {
		log.Fatal(err)
	}

	// Copy config, obfuscate token, and print for record
	copy := *c
	copy.Env.Token = obfuscate(copy.Env.Token)
	j, err := json.MarshalIndent(copy, "", "    ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(j))

	// Retrieve queue info
	s := config.ManualConfig("iron_mq", &c.Env)
	t := time.Now()
	q := mq.ConfigNew(c.QueueName, &s)
	info, err := q.Info()
	if err != nil {
		log.Fatal("Could not access queue info", err)
	}
	fmt.Printf("Queue has %d messages. (request took %v)\n", info.Size, time.Since(t))

	// Loop for multiple iterations of dequeuing & processing messages
	emptyResultCount := 0
	totalProcessedCount := 0
batchLoop:
	for x := 0; c.MaxIterations == nil || x < *c.MaxIterations; x++ {
		// Determine if we have time for another set of processing
		if time.Since(start) > c.MaxDuration {
			break
		}

		// If configured, sleep between iterations
		if x != 0 {
			fmt.Println("Sleeping", c.IterationSleep)
			time.Sleep(c.IterationSleep)
		}

		// Create a timeout that can accommodate the duration of the entire batch
		timeout := float64(c.BatchSize) * c.MsgDuration.Seconds() * 1.1 // give it an extra 10% time for safety

		// Reserve messages with given batch size, timeout, and longpoll time
		t = time.Now()
		msgs, err := q.LongPoll(c.BatchSize, int(timeout), c.DequeueWait, false)
		if err != nil {
			// Ideally, continue the loop and try again later. After a certain amount of time, do panic/Fatal
			log.Fatal(err)
		}
		fmt.Printf("Iteration %d: Requested %d, got %d (request took %v with a max wait of %ds)\n", x, c.BatchSize, len(msgs), time.Since(t), c.DequeueWait)

		// Handle case of zero messages
		if len(msgs) == 0 && c.MaxEmptyResults != nil {
			emptyResultCount++
			if emptyResultCount > *c.MaxEmptyResults {
				fmt.Println("Queue is empty - breaking work loop")
				break
			}
		} else {
			// Reset count if queue isn't empty
			emptyResultCount = 0
		}

		// Process each message
		for i, msg := range msgs {
			// Determine if we have time to process another message
			if time.Since(start) > c.MaxDuration+c.MsgDuration {
				fmt.Println("Not enough time to process message - breaking work loop")
				break batchLoop
			}

			// Simulate Message Processing
			time.Sleep(c.MsgDuration)
			fmt.Printf(" %d: %q\n", i, msg.Body)

			// Example case for error processing
			var processingError error
			if processingError != nil {
				// Move error to error queue
				// errorQueue.Push(msg)
			}

			totalProcessedCount++

			// Delete processed message from queue
			err = msg.Delete()
			if err != nil {
				fmt.Println("Could not delete msg:", msg.Body, err)
			}
		}
	}

	fmt.Printf("Worker ending after %s and processing %d messages", time.Since(start), totalProcessedCount)
}

func obfuscate(v string) string {
	r := []rune(v)
	for x := len(r) / 4; x < len(r); x++ {
		r[x] = '*'
	}
	return string(r)
}
<commit_msg>Fixed empty result max<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"time"

	"github.com/iron-io/iron_go3/config"
	"github.com/iron-io/iron_go3/mq"
	"github.com/iron-io/iron_go3/worker"
)

// Configuration set via HUD
type Config struct {
	MsgDuration     time.Duration   `json:"msgDuration,omitempty"`
	IterationSleep  time.Duration   `json:"iterationSleep,omitempty"`
	MaxDuration     time.Duration   `json:"maxDuration,omitempty"`
	MaxIterations   *int            `json:"maxIterations,omitempty"`
	BatchSize       int             `json:"batchSize,omitempty"`
	MaxEmptyResults *int            `json:"maxEmptyResults,omitempty"`
	DequeueWait     int             `json:"dequeueWait,omitempty"`
	QueueName       string          `json:"queueName"`
	Env             config.Settings `json:"env"`
}

func DefaultConfig() *Config {
	m := 0
	return &Config{
		MsgDuration:     1 * time.Second,
		IterationSleep:  20 * time.Millisecond,
		MaxDuration:     45 * time.Minute,
		BatchSize:       1,
		DequeueWait:     0,
		MaxEmptyResults: &m,
	}
}

func (c *Config) Valid() error {
	if len(c.Env.ProjectId) == 0 || len(c.Env.Token) == 0 {
		return errors.New(`Require queue project & token set in code config.`)
	}
	return nil
}

func main() {
	start := time.Now()

	// Parse config json and validate
	worker.ParseFlags()
	c := DefaultConfig()
	worker.ConfigFromJSON(c)
	if err := c.Valid(); err != nil {
		log.Fatal(err)
	}

	// Copy config, obfuscate token, and print for record
	copy := *c
	copy.Env.Token = obfuscate(copy.Env.Token)
	j, err := json.MarshalIndent(copy, "", "    ")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(j))

	// Retrieve queue info
	s := config.ManualConfig("iron_mq", &c.Env)
	t := time.Now()
	q := mq.ConfigNew(c.QueueName, &s)
	info, err := q.Info()
	if err != nil {
		log.Fatal("Could not access queue info", err)
	}
	fmt.Printf("Queue has %d messages. (request took %v)\n", info.Size, time.Since(t))

	// Loop for multiple iterations of dequeuing & processing messages
	emptyResultCount := 0
	totalProcessedCount := 0
batchLoop:
	for x := 0; c.MaxIterations == nil || x < *c.MaxIterations; x++ {
		// Determine if we have time for another set of processing
		if time.Since(start) > c.MaxDuration {
			break
		}

		// If configured, sleep between iterations
		if x != 0 {
			fmt.Println("Sleeping", c.IterationSleep)
			time.Sleep(c.IterationSleep)
		}

		// Create a timeout that can accommodate the duration of the entire batch
		timeout := float64(c.BatchSize) * c.MsgDuration.Seconds() * 1.1 // give it an extra 10% time for safety

		// Reserve messages with given batch size, timeout, and longpoll time
		t = time.Now()
		msgs, err := q.LongPoll(c.BatchSize, int(timeout), c.DequeueWait, false)
		if err != nil {
			// Ideally, continue the loop and try again later. After a certain amount of time, do panic/Fatal
			log.Fatal(err)
		}
		fmt.Printf("Iteration %d: Requested %d, got %d (request took %v with a max wait of %ds)\n", x, c.BatchSize, len(msgs), time.Since(t), c.DequeueWait)

		// Handle case of zero messages
		if len(msgs) == 0 && c.MaxEmptyResults != nil {
			emptyResultCount++
			if emptyResultCount >= *c.MaxEmptyResults {
				fmt.Println("Queue is empty - breaking work loop")
				break
			}
		} else {
			// Reset count if queue isn't empty
			emptyResultCount = 0
		}

		// Process each message
		for i, msg := range msgs {
			// Determine if we have time to process another message
			if time.Since(start) > c.MaxDuration+c.MsgDuration {
				fmt.Println("Not enough time to process message - breaking work loop")
				break batchLoop
			}

			// Simulate Message Processing
			time.Sleep(c.MsgDuration)
			fmt.Printf(" %d: %q\n", i, msg.Body)

			// Example case for error processing
			var processingError error
			if processingError != nil {
				// Move error to error queue
				// errorQueue.Push(msg)
			}

			totalProcessedCount++

			// Delete processed message from queue
			err = msg.Delete()
			if err != nil {
				fmt.Println("Could not delete msg:", msg.Body, err)
			}
		}
	}

	fmt.Printf("Worker ending after %s and processing %d messages", time.Since(start), totalProcessedCount)
}

func obfuscate(v string) string {
	r := []rune(v)
	for x := len(r) / 4; x < len(r); x++ {
		r[x] = '*'
	}
	return string(r)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"flag"
	"fmt"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/ec2"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	FILE_NAME = "/tmp/gopher_instances"
)

// Command Line Variables
var command string

// Flags Variables
var flagSet *flag.FlagSet

// Creation options
var instanceCount int
var instanceImage, instanceType, instanceRegionName, instanceLogin, instanceKey string

// Attack options
var numberOfRequests, concurrentRequests int
var options, url string

// EC2 Variables
var instanceRegion aws.Region

func init() {
	if len(os.Args) == 1 {
		command = "help"
	} else {
		command = os.Args[1]
	}

	flagSet = flag.NewFlagSet(command, flag.ExitOnError)

	// Creation options
	flagSet.IntVar(&instanceCount, "count", 5, "The number of gophers to call into action")
	flagSet.StringVar(&instanceRegionName, "region", "us-east-1", "The availability zone to start each gopher in (default: us-east-1d)")
	flagSet.StringVar(&instanceImage, "image", "ami-2bc99d42", "The image id to use for each gopher (default: ami-2bc99d42)")
	flagSet.StringVar(&instanceType, "type", "t1.micro", "The instance type to use for each gopher (default: t1.micro)")
	flagSet.StringVar(&instanceLogin, "login", "ubuntu", "The ssh username name to use to connect to the new servers (default: ubuntu).")
	flagSet.StringVar(&instanceKey, "key", "gophers", "The ssh key pair name to use to connect to the new gophers (default: gophers)")

	// Attack options
	flagSet.IntVar(&numberOfRequests, "requests", 5, "The number of requests to perform per gopher")
	flagSet.IntVar(&concurrentRequests, "concurrent", 1, "The number of concurrent requests to make per gopher")
	flagSet.StringVar(&url, "url", "", "The url to point the gophers towards when attacking")
	flagSet.StringVar(&options, "options", "", "Additional attack options (Not supported yet)")

	setupRegion()
}

func main() {
	if len(os.Args) <= 1 {
		flagSet.PrintDefaults()
	} else {
		flagSet.Parse(os.Args[2:])

	}

	switch command {
	case "help":
		printInstructions()
	case "up":
		up()
	case "down":
		down()
	case "attack":
		attack()
	case "report":
		report()
	default:
		flagSet.PrintDefaults()
	}
}

func up() {
	fmt.Printf("Adding %v gopher(s) to your army.\n", instanceCount)

	if instanceCount <= 0 {
		fmt.Printf("You must declare a number of gophers greater than 0.")
		return
	}
	createInstances := ec2.RunInstances{
		MinCount:     instanceCount,
		MaxCount:     instanceCount,
		ImageId:      instanceImage,
		InstanceType: instanceType,
		KeyName:      instanceKey,
	}

	ec2Connection, err := ec2Connect()
	runInstancesResponse, err := ec2Connection.RunInstances(&createInstances)
	handleError(err)

	_, err = tagInstances(runInstancesResponse.Instances)
	handleError(err)

	instances, err := findInstances(0)
	handleError(err)

	notReadyInstancesCount := len(instances)
	for notReadyInstancesCount != 0 {
		time.Sleep(3 * time.Second)
		instances, err := findInstances(0)
		handleError(err)

		readyInstancesCount := notReadyInstancesCount - len(instances)

		for i := 0; i < readyInstancesCount; i++ {
			fmt.Printf(".")
		}

		notReadyInstancesCount = len(instances)
	}

	instances, err = findInstances(16)
	handleError(err)

	fmt.Println("\nArming your gophers with grenades, stand back!")

	setupResponseChannel := make(chan setupResponse)
	for _, instance := range instances {
		setupInstance(setupResponseChannel, instance.DNSName)
	}

	for i := 0; i < len(instances); i++ {
		resp := <-setupResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers were inbred, check your AWS account to make sure things haven't gone awry.")
			fmt.Printf("Message: (%v) %v\n", resp.host, resp.message)
			fmt.Printf("Error: (%v) %v\n", resp.host, resp.err)
		}
	}

	fmt.Printf("\n%v gophers are ready to invade!\n", len(instances))
}

func down() {
	fmt.Println("Your gopher army has been nuked from orbit.")

	instances, err := findInstances(-1)
	handleError(err)

	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	ec2Connection.TerminateInstances(instanceIds)
}

func attack() {
	fmt.Println("your gophers are on the move!")

	if url == "" {
		fmt.Println("You must provide a url to start the attack.")
		return
	}

	instances, err := findInstances(16)
	handleError(err)

	attackResponseChannel := make(chan benchmarkResponse)
	for _, instance := range instances {
		startAttack(attackResponseChannel, instance.DNSName)
	}

	var complete, failed int
	var totalTime, requestsPerSecond float32
	for i := 0; i < len(instances); i++ {
		resp := <-attackResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers started a civil war.")
		}

		complete += resp.Complete
		failed += resp.Failed
		requestsPerSecond += resp.RequestsPerSecond
		totalTime += resp.TimePerRequest * float32(resp.Complete+resp.Failed)
	}

	fmt.Println("Completed requests:", complete)
	fmt.Println("Failed requests:", failed)
	fmt.Println("Requests per second:", requestsPerSecond, "[#/sec] (mean)")
	fmt.Println("Time per request:", totalTime/float32(complete+failed), "[ms] (mean)")
}

func report() {
	fmt.Println("Who know where the gophers are?")

	instances, err := findInstances(-1)
	handleError(err)

	if len(instances) > 0 {
		fmt.Println("Name (DNS Name) - State")
		for _, instance := range instances {
			var instanceName string

			for _, tag := range instance.Tags {
				if tag.Key == "Name" {
					instanceName = tag.Value
				}
			}

			fmt.Printf("%s (%s) - %s\n", instanceName, instance.DNSName, instance.State.Name)
		}
	} else {
		fmt.Println("Your army has gone AWOL.  Better recruit some more!")
	}
}

func setupInstance(response chan setupResponse, host string) {
	go func() {
		setupResponse := setupResponse{host: host}

		var client *ssh.ClientConn
		for i := 0; client == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("Attempting to create and ssh connection to %s.\n", host)
			client, _ = sshClient(fmt.Sprintf("%s:22", host))
		}

		var session *ssh.Session
		for i := 0; session == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("creating the session: %v\n", client)
			session, _ = client.NewSession()
		}

		// fmt.Println("defering the session")
		defer session.Close()

		// fmt.Println("setting up the buffer")
		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer
		// fmt.Println("making the call")
		err := session.Run("sudo apt-get install apache2-utils -y")
		if err != nil {
			setupResponse.err = append(setupResponse.err, err)
		}

		setupResponse.message = outputBuffer.String()
		// fmt.Println("returning the response")
		response <- setupResponse
	}()
}

func startAttack(response chan benchmarkResponse, host string) {
	go func() {
		benchmarkResponse := benchmarkResponse{}

		client, err := sshClient(fmt.Sprintf("%s:22", host))
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		session, err := client.NewSession()
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		defer session.Close()

		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer

		benchmarkCommand := fmt.Sprintf("ab -r -n %v -c %v %v \"%v\"", numberOfRequests, concurrentRequests, options, url)
		err = session.Run(benchmarkCommand)
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		// fmt.Println(&outputBuffer)
		outputString := outputBuffer.String()

		for _, line := range strings.Split(outputString, "\n") {
			if strings.Contains(line, "Complete requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Complete, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Failed requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Failed, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Requests per second:") {
				re := regexp.MustCompile("Requests per second:\\s*(\\d+.\\d+)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.RequestsPerSecond = float32(valueFloat)
			}
			if strings.Contains(line, "Time per request:") && !strings.Contains(line, "across all concurrent requests") {
				re := regexp.MustCompile("Time per request:\\s*(\\d+.\\d+)\\s*\\[ms\\]\\s*\\(mean\\)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.TimePerRequest = float32(valueFloat)
			}
		}

		response <- benchmarkResponse
	}()
}

func printInstructions() {
	fmt.Println(`gophers COMMAND [options]

gophers with grenades

A utility for arming (creating) many gophers (small EC2 instances) to attack
(load test) targets (web applications).

commands:
  up      Start a batch of load testing servers.
  attack  Begin the attack on a specific url.
  down    Shutdown and deactivate the load testing servers.
  report  Report the status of the load testing servers.
    `)
}

func ec2Connect() (*ec2.EC2, error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return nil, err
	}

	ec2Connection := ec2.New(auth, aws.USEast)

	return ec2Connection, nil
}

func setupRegion() {
	instanceRegion = aws.Regions[instanceRegionName]
}

func getInstanceIds(instances []ec2.Instance) (instanceIds []string) {
	for _, instance := range instances {
		instanceIds = append(instanceIds, instance.InstanceId)
	}

	return instanceIds
}

func tagInstances(instances []ec2.Instance) (responses []*ec2.SimpleResp, err error) {
	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	if err != nil {
		return nil, err
	}

	for _, instance := range instances {
		nameTag := ec2.Tag{"Name", instance.InstanceId}
		gopherTag := ec2.Tag{"gopher", "true"}
		tags := []ec2.Tag{nameTag, gopherTag}

		response, err := ec2Connection.CreateTags(instanceIds, tags)
		if err != nil {
			return nil, err
		}

		responses = append(responses, response)
	}

	return responses, nil
}

func findInstances(statusCode int) (instances []ec2.Instance, err error) {
	filter := ec2.NewFilter()
	filter.Add("tag:gopher", "true")

	if statusCode != -1 {
		filter.Add("instance-state-code", strconv.Itoa(statusCode))
	}

	ec2Connection, err := ec2Connect()
	resp, err := ec2Connection.Instances(nil, filter)
	if err != nil {
		return nil, err
	}

	for _, reservation := range resp.Reservations {
		for _, instance := range reservation.Instances {
			instances = append(instances, instance)
		}
	}

	return instances, nil
}

func sshClient(host string) (*ssh.ClientConn, error) {
	var auths []ssh.ClientAuth

	keypath := getKeyPath()
	k := &keyring{}
	err := k.loadPEM(keypath)
	if err != nil {
		return nil, err
	}

	auths = append(auths, ssh.ClientAuthKeyring(k))

	config := &ssh.ClientConfig{
		User: "ubuntu",
		Auth: auths,
	}

	client, err := ssh.Dial("tcp", host, config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func getKeyPath() string {
	user, _ := user.Current()
	homeDirectory := user.HomeDir

	return filepath.Join(homeDirectory, ".ssh", fmt.Sprintf("%s.pem", instanceKey))
}

func handleError(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>Removed unused const that was going to be used to store data.<commit_after>package main

import (
	"bytes"
	"code.google.com/p/go.crypto/ssh"
	"flag"
	"fmt"
	"launchpad.net/goamz/aws"
	"launchpad.net/goamz/ec2"
	"os"
	"os/user"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// Command Line Variables
var command string

// Flags Variables
var flagSet *flag.FlagSet

// Creation options
var instanceCount int
var instanceImage, instanceType, instanceRegionName, instanceLogin, instanceKey string

// Attack options
var numberOfRequests, concurrentRequests int
var options, url string

// EC2 Variables
var instanceRegion aws.Region

func init() {
	if len(os.Args) == 1 {
		command = "help"
	} else {
		command = os.Args[1]
	}

	flagSet = flag.NewFlagSet(command, flag.ExitOnError)

	// Creation options
	flagSet.IntVar(&instanceCount, "count", 5, "The number of gophers to call into action")
	flagSet.StringVar(&instanceRegionName, "region", "us-east-1", "The availability zone to start each gopher in (default: us-east-1d)")
	flagSet.StringVar(&instanceImage, "image", "ami-2bc99d42", "The image id to use for each gopher (default: ami-2bc99d42)")
	flagSet.StringVar(&instanceType, "type", "t1.micro", "The instance type to use for each gopher (default: t1.micro)")
	flagSet.StringVar(&instanceLogin, "login", "ubuntu", "The ssh username name to use to connect to the new servers (default: ubuntu).")
	flagSet.StringVar(&instanceKey, "key", "gophers", "The ssh key pair name to use to connect to the new gophers (default: gophers)")

	// Attack options
	flagSet.IntVar(&numberOfRequests, "requests", 5, "The number of requests to perform per gopher")
	flagSet.IntVar(&concurrentRequests, "concurrent", 1, "The number of concurrent requests to make per gopher")
	flagSet.StringVar(&url, "url", "", "The url to point the gophers towards when attacking")
	flagSet.StringVar(&options, "options", "", "Additional attack options (Not supported yet)")

	setupRegion()
}

func main() {
	if len(os.Args) <= 1 {
		flagSet.PrintDefaults()
	} else {
		flagSet.Parse(os.Args[2:])

	}

	switch command {
	case "help":
		printInstructions()
	case "up":
		up()
	case "down":
		down()
	case "attack":
		attack()
	case "report":
		report()
	default:
		flagSet.PrintDefaults()
	}
}

func up() {
	fmt.Printf("Adding %v gopher(s) to your army.\n", instanceCount)

	if instanceCount <= 0 {
		fmt.Printf("You must declare a number of gophers greater than 0.")
		return
	}
	createInstances := ec2.RunInstances{
		MinCount:     instanceCount,
		MaxCount:     instanceCount,
		ImageId:      instanceImage,
		InstanceType: instanceType,
		KeyName:      instanceKey,
	}

	ec2Connection, err := ec2Connect()
	runInstancesResponse, err := ec2Connection.RunInstances(&createInstances)
	handleError(err)

	_, err = tagInstances(runInstancesResponse.Instances)
	handleError(err)

	instances, err := findInstances(0)
	handleError(err)

	notReadyInstancesCount := len(instances)
	for notReadyInstancesCount != 0 {
		time.Sleep(3 * time.Second)
		instances, err := findInstances(0)
		handleError(err)

		readyInstancesCount := notReadyInstancesCount - len(instances)

		for i := 0; i < readyInstancesCount; i++ {
			fmt.Printf(".")
		}

		notReadyInstancesCount = len(instances)
	}

	instances, err = findInstances(16)
	handleError(err)

	fmt.Println("\nArming your gophers with grenades, stand back!")

	setupResponseChannel := make(chan setupResponse)
	for _, instance := range instances {
		setupInstance(setupResponseChannel, instance.DNSName)
	}

	for i := 0; i < len(instances); i++ {
		resp := <-setupResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers were inbred, check your AWS account to make sure things haven't gone awry.")
			fmt.Printf("Message: (%v) %v\n", resp.host, resp.message)
			fmt.Printf("Error: (%v) %v\n", resp.host, resp.err)
		}
	}

	fmt.Printf("\n%v gophers are ready to invade!\n", len(instances))
}

func down() {
	fmt.Println("Your gopher army has been nuked from orbit.")

	instances, err := findInstances(-1)
	handleError(err)

	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	ec2Connection.TerminateInstances(instanceIds)
}

func attack() {
	fmt.Println("your gophers are on the move!")

	if url == "" {
		fmt.Println("You must provide a url to start the attack.")
		return
	}

	instances, err := findInstances(16)
	handleError(err)

	attackResponseChannel := make(chan benchmarkResponse)
	for _, instance := range instances {
		startAttack(attackResponseChannel, instance.DNSName)
	}

	var complete, failed int
	var totalTime, requestsPerSecond float32
	for i := 0; i < len(instances); i++ {
		resp := <-attackResponseChannel
		if resp.err != nil {
			fmt.Println("Looks like the gophers started a civil war.")
		}

		complete += resp.Complete
		failed += resp.Failed
		requestsPerSecond += resp.RequestsPerSecond
		totalTime += resp.TimePerRequest * float32(resp.Complete+resp.Failed)
	}

	fmt.Println("Completed requests:", complete)
	fmt.Println("Failed requests:", failed)
	fmt.Println("Requests per second:", requestsPerSecond, "[#/sec] (mean)")
	fmt.Println("Time per request:", totalTime/float32(complete+failed), "[ms] (mean)")
}

func report() {
	fmt.Println("Who know where the gophers are?")

	instances, err := findInstances(-1)
	handleError(err)

	if len(instances) > 0 {
		fmt.Println("Name (DNS Name) - State")
		for _, instance := range instances {
			var instanceName string

			for _, tag := range instance.Tags {
				if tag.Key == "Name" {
					instanceName = tag.Value
				}
			}

			fmt.Printf("%s (%s) - %s\n", instanceName, instance.DNSName, instance.State.Name)
		}
	} else {
		fmt.Println("Your army has gone AWOL.  Better recruit some more!")
	}
}

func setupInstance(response chan setupResponse, host string) {
	go func() {
		setupResponse := setupResponse{host: host}

		var client *ssh.ClientConn
		for i := 0; client == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("Attempting to create and ssh connection to %s.\n", host)
			client, _ = sshClient(fmt.Sprintf("%s:22", host))
		}

		var session *ssh.Session
		for i := 0; session == nil || i == 10; i++ {
			time.Sleep(2 * time.Second)
			// fmt.Printf("creating the session: %v\n", client)
			session, _ = client.NewSession()
		}

		// fmt.Println("defering the session")
		defer session.Close()

		// fmt.Println("setting up the buffer")
		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer
		// fmt.Println("making the call")
		err := session.Run("sudo apt-get install apache2-utils -y")
		if err != nil {
			setupResponse.err = append(setupResponse.err, err)
		}

		setupResponse.message = outputBuffer.String()
		// fmt.Println("returning the response")
		response <- setupResponse
	}()
}

func startAttack(response chan benchmarkResponse, host string) {
	go func() {
		benchmarkResponse := benchmarkResponse{}

		client, err := sshClient(fmt.Sprintf("%s:22", host))
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		session, err := client.NewSession()
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		defer session.Close()

		var outputBuffer bytes.Buffer
		session.Stdout = &outputBuffer

		benchmarkCommand := fmt.Sprintf("ab -r -n %v -c %v %v \"%v\"", numberOfRequests, concurrentRequests, options, url)
		err = session.Run(benchmarkCommand)
		if err != nil {
			benchmarkResponse.err = append(benchmarkResponse.err, err)
		}

		// fmt.Println(&outputBuffer)
		outputString := outputBuffer.String()

		for _, line := range strings.Split(outputString, "\n") {
			if strings.Contains(line, "Complete requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Complete, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Failed requests:") {
				value := strings.TrimSpace(strings.Split(line, ":")[1])
				benchmarkResponse.Failed, _ = strconv.Atoi(value)
			}
			if strings.Contains(line, "Requests per second:") {
				re := regexp.MustCompile("Requests per second:\\s*(\\d+.\\d+)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.RequestsPerSecond = float32(valueFloat)
			}
			if strings.Contains(line, "Time per request:") && !strings.Contains(line, "across all concurrent requests") {
				re := regexp.MustCompile("Time per request:\\s*(\\d+.\\d+)\\s*\\[ms\\]\\s*\\(mean\\)")
				value := re.FindStringSubmatch(line)[1]
				valueFloat, _ := strconv.ParseFloat(value, 32)
				benchmarkResponse.TimePerRequest = float32(valueFloat)
			}
		}

		response <- benchmarkResponse
	}()
}

func printInstructions() {
	fmt.Println(`gophers COMMAND [options]

gophers with grenades

A utility for arming (creating) many gophers (small EC2 instances) to attack
(load test) targets (web applications).

commands:
  up      Start a batch of load testing servers.
  attack  Begin the attack on a specific url.
  down    Shutdown and deactivate the load testing servers.
  report  Report the status of the load testing servers.
    `)
}

func ec2Connect() (*ec2.EC2, error) {
	auth, err := aws.EnvAuth()
	if err != nil {
		return nil, err
	}

	ec2Connection := ec2.New(auth, aws.USEast)

	return ec2Connection, nil
}

func setupRegion() {
	instanceRegion = aws.Regions[instanceRegionName]
}

func getInstanceIds(instances []ec2.Instance) (instanceIds []string) {
	for _, instance := range instances {
		instanceIds = append(instanceIds, instance.InstanceId)
	}

	return instanceIds
}

func tagInstances(instances []ec2.Instance) (responses []*ec2.SimpleResp, err error) {
	instanceIds := getInstanceIds(instances)

	ec2Connection, err := ec2Connect()
	if err != nil {
		return nil, err
	}

	for _, instance := range instances {
		nameTag := ec2.Tag{"Name", instance.InstanceId}
		gopherTag := ec2.Tag{"gopher", "true"}
		tags := []ec2.Tag{nameTag, gopherTag}

		response, err := ec2Connection.CreateTags(instanceIds, tags)
		if err != nil {
			return nil, err
		}

		responses = append(responses, response)
	}

	return responses, nil
}

func findInstances(statusCode int) (instances []ec2.Instance, err error) {
	filter := ec2.NewFilter()
	filter.Add("tag:gopher", "true")

	if statusCode != -1 {
		filter.Add("instance-state-code", strconv.Itoa(statusCode))
	}

	ec2Connection, err := ec2Connect()
	resp, err := ec2Connection.Instances(nil, filter)
	if err != nil {
		return nil, err
	}

	for _, reservation := range resp.Reservations {
		for _, instance := range reservation.Instances {
			instances = append(instances, instance)
		}
	}

	return instances, nil
}

func sshClient(host string) (*ssh.ClientConn, error) {
	var auths []ssh.ClientAuth

	keypath := getKeyPath()
	k := &keyring{}
	err := k.loadPEM(keypath)
	if err != nil {
		return nil, err
	}

	auths = append(auths, ssh.ClientAuthKeyring(k))

	config := &ssh.ClientConfig{
		User: "ubuntu",
		Auth: auths,
	}

	client, err := ssh.Dial("tcp", host, config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func getKeyPath() string {
	user, _ := user.Current()
	homeDirectory := user.HomeDir

	return filepath.Join(homeDirectory, ".ssh", fmt.Sprintf("%s.pem", instanceKey))
}

func handleError(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"

	_ "github.com/lib/pq"

	"github.com/fabric8-services/fabric8-tenant/app"
	"github.com/fabric8-services/fabric8-tenant/auth"
	"github.com/fabric8-services/fabric8-tenant/configuration"
	"github.com/fabric8-services/fabric8-tenant/controller"
	"github.com/fabric8-services/fabric8-tenant/jsonapi"
	"github.com/fabric8-services/fabric8-tenant/keycloak"
	"github.com/fabric8-services/fabric8-tenant/migration"
	"github.com/fabric8-services/fabric8-tenant/openshift"
	"github.com/fabric8-services/fabric8-tenant/tenant"
	witmiddleware "github.com/fabric8-services/fabric8-wit/goamiddleware"
	"github.com/fabric8-services/fabric8-wit/log"
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	goajwt "github.com/goadesign/goa/middleware/security/jwt"
	"github.com/jinzhu/gorm"
	"github.com/sirupsen/logrus"

	"fmt"

	goalogrus "github.com/goadesign/goa/logging/logrus"
	"github.com/spf13/viper"
)

func main() {

	viper.GetStringMapString("TEST")

	var migrateDB bool
	flag.BoolVar(&migrateDB, "migrateDatabase", false, "Migrates the database to the newest version and exits.")
	flag.Parse()

	// Initialized configuration
	config, err := configuration.GetData()
	if err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"err": err,
		}, "failed to setup the configuration")
	}

	// Initialized developer mode flag for the logger
	log.InitializeLogger(config.IsLogJSON(), config.GetLogLevel())

	db := connect(config)
	defer db.Close()
	migrate(db)

	// Nothing to here except exit, since the migration is already performed.
	if migrateDB {
		os.Exit(0)
	}

	serviceToken := config.GetOpenshiftServiceToken()
	if serviceToken == "" {
		if config.UseOpenshiftCurrentCluster() {
			file, err := ioutil.ReadFile("/run/secrets/kubernetes.io/serviceaccount/token")
			if err != nil {
				logrus.Panic(nil, map[string]interface{}{
					"err": err,
				}, "failed to read service account token")
			}
			serviceToken = strings.TrimSpace(string(file))
		} else {
			logrus.Panic(nil, map[string]interface{}{}, "missing service token")
		}
	}

	var tr *http.Transport
	if config.APIServerInsecureSkipTLSVerify() {
		tr = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	if config.GetOpenshiftCheVersion() != "" {
		log.Logger().Infof("Che Version: %s", config.GetOpenshiftCheVersion())
	}
	if config.GetOpenshiftJenkinsVersion() != "" {
		log.Logger().Infof("Jenkins Version: %s", config.GetOpenshiftJenkinsVersion())
	}
	if config.GetOpenshiftTeamVersion() != "" {
		log.Logger().Infof("Team Version: %s", config.GetOpenshiftTeamVersion())
	}
	if config.GetOpenshiftTemplateDir() != "" {
		log.Logger().Infof("Template Dir: %s", config.GetOpenshiftTemplateDir())
	}

	openshiftConfig := openshift.Config{
		MasterURL:      config.GetOpenshiftTenantMasterURL(),
		ConsoleURL:     config.GetConsoleURL(),
		Token:          serviceToken,
		HttpTransport:  tr,
		CheVersion:     config.GetOpenshiftCheVersion(),
		JenkinsVersion: config.GetOpenshiftJenkinsVersion(),
		TeamVersion:    config.GetOpenshiftTeamVersion(),
		TemplateDir:    config.GetOpenshiftTemplateDir(),
	}

	openshiftMasterUser, err := openshift.WhoAmI(openshiftConfig)
	if err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"err": err,
		}, "unknown master user based on service token")
	}
	openshiftConfig.MasterUser = openshiftMasterUser

	keycloakConfig := keycloak.Config{
		BaseURL: config.GetKeycloakURL(),
		Realm:   config.GetKeycloakRealm(),
		Broker:  config.GetKeycloakOpenshiftBroker(),
	}

	templateVars, err := config.GetTemplateValues()
	if err != nil {
		panic(err)
	}

	templateVars["KEYCLOAK_URL"] = ""
	templateVars["FABRIC8_CONSOLE_URL"] = openshiftConfig.ConsoleURL
	templateVars["KEYCLOAK_OSO_ENDPOINT"] = keycloakConfig.CustomBrokerTokenURL("openshift-v3")
	templateVars["KEYCLOAK_GITHUB_ENDPOINT"] = fmt.Sprintf("%s%s?for=https://github.com", config.GetAuthURL(), auth.RetrieveTokenPath())

	publicKeys, err := keycloak.GetPublicKeys(config.GetAuthURL())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err":    err,
			"target": config.GetAuthURL(),
		}, "failed to fetch public keys from token service")
	}

	// Create service
	service := goa.New("tenant")

	// Mount middleware
	service.WithLogger(goalogrus.New(log.Logger()))
	service.Use(middleware.RequestID())
	service.Use(gzip.Middleware(9))
	service.Use(jsonapi.ErrorHandler(service, true))
	service.Use(middleware.Recover())

	service.Use(witmiddleware.TokenContext(publicKeys, nil, app.NewJWTSecurity()))
	service.Use(log.LogRequest(config.IsDeveloperModeEnabled()))
	app.UseJWTMiddleware(service, goajwt.New(publicKeys, nil, app.NewJWTSecurity()))

	// Mount "status" controller
	statusCtrl := controller.NewStatusController(service, db)
	app.MountStatusController(service, statusCtrl)

	// Mount "tenant" controller
	witURL := config.GetWitURL()
	tenantCtrl := controller.NewTenantController(service, tenant.NewDBService(db), keycloakConfig, openshiftConfig, templateVars, witURL)
	app.MountTenantController(service, tenantCtrl)

	// Mount "tenantkube" controller
	tenanKubetCtrl := controller.NewTenantKubeController(service, tenant.NewDBService(db), keycloakConfig, openshiftConfig, templateVars)
	app.MountTenantKubeController(service, tenanKubetCtrl)

	// Mount "auth" controller
	authCtrl := controller.NewAuthController(service, tenant.NewDBService(db), keycloakConfig, openshiftConfig, templateVars)
	app.MountAuthController(service, authCtrl)

	log.Logger().Infoln("Git Commit SHA: ", controller.Commit)
	log.Logger().Infoln("UTC Build Time: ", controller.BuildTime)
	log.Logger().Infoln("UTC Start Time: ", controller.StartTime)
	log.Logger().Infoln("Dev mode:       ", config.IsDeveloperModeEnabled())
	log.Logger().Infoln("WIT URL:        ", witURL)

	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.Handle("/", service.Mux)

	// Start http
	if err := http.ListenAndServe(config.GetHTTPAddress(), nil); err != nil {
		log.Error(nil, map[string]interface{}{
			"addr": config.GetHTTPAddress(),
			"err":  err,
		}, "unable to connect to server")
		service.LogError("startup", "err", err)
	}
}

func connect(config *configuration.Data) *gorm.DB {
	var err error
	var db *gorm.DB
	for {
		db, err = gorm.Open("postgres", config.GetPostgresConfigString())
		if err != nil {
			log.Logger().Errorf("ERROR: Unable to open connection to database %v", err)
			log.Logger().Infof("Retrying to connect in %v...", config.GetPostgresConnectionRetrySleep())
			time.Sleep(config.GetPostgresConnectionRetrySleep())
		} else {
			break
		}
	}

	if config.IsDeveloperModeEnabled() {
		db = db.Debug()
	}

	if config.GetPostgresConnectionMaxIdle() > 0 {
		log.Logger().Infof("Configured connection pool max idle %v", config.GetPostgresConnectionMaxIdle())
		db.DB().SetMaxIdleConns(config.GetPostgresConnectionMaxIdle())
	}
	if config.GetPostgresConnectionMaxOpen() > 0 {
		log.Logger().Infof("Configured connection pool max open %v", config.GetPostgresConnectionMaxOpen())
		db.DB().SetMaxOpenConns(config.GetPostgresConnectionMaxOpen())
	}
	return db
}

func migrate(db *gorm.DB) {
	// Migrate the schema
	err := migration.Migrate(db.DB())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": err,
		}, "failed migration")
	}
}
<commit_msg>Mount tenants REST endpoint (#437)<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"

	_ "github.com/lib/pq"

	"github.com/fabric8-services/fabric8-tenant/app"
	"github.com/fabric8-services/fabric8-tenant/auth"
	"github.com/fabric8-services/fabric8-tenant/configuration"
	"github.com/fabric8-services/fabric8-tenant/controller"
	"github.com/fabric8-services/fabric8-tenant/jsonapi"
	"github.com/fabric8-services/fabric8-tenant/keycloak"
	"github.com/fabric8-services/fabric8-tenant/migration"
	"github.com/fabric8-services/fabric8-tenant/openshift"
	"github.com/fabric8-services/fabric8-tenant/tenant"
	witmiddleware "github.com/fabric8-services/fabric8-wit/goamiddleware"
	"github.com/fabric8-services/fabric8-wit/log"
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	goajwt "github.com/goadesign/goa/middleware/security/jwt"
	"github.com/jinzhu/gorm"
	"github.com/sirupsen/logrus"

	"fmt"

	goalogrus "github.com/goadesign/goa/logging/logrus"
	"github.com/spf13/viper"
)

func main() {

	viper.GetStringMapString("TEST")

	var migrateDB bool
	flag.BoolVar(&migrateDB, "migrateDatabase", false, "Migrates the database to the newest version and exits.")
	flag.Parse()

	// Initialized configuration
	config, err := configuration.GetData()
	if err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"err": err,
		}, "failed to setup the configuration")
	}

	// Initialized developer mode flag for the logger
	log.InitializeLogger(config.IsLogJSON(), config.GetLogLevel())

	db := connect(config)
	defer db.Close()
	migrate(db)

	// Nothing to here except exit, since the migration is already performed.
	if migrateDB {
		os.Exit(0)
	}

	serviceToken := config.GetOpenshiftServiceToken()
	if serviceToken == "" {
		if config.UseOpenshiftCurrentCluster() {
			file, err := ioutil.ReadFile("/run/secrets/kubernetes.io/serviceaccount/token")
			if err != nil {
				logrus.Panic(nil, map[string]interface{}{
					"err": err,
				}, "failed to read service account token")
			}
			serviceToken = strings.TrimSpace(string(file))
		} else {
			logrus.Panic(nil, map[string]interface{}{}, "missing service token")
		}
	}

	var tr *http.Transport
	if config.APIServerInsecureSkipTLSVerify() {
		tr = &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
	}

	if config.GetOpenshiftCheVersion() != "" {
		log.Logger().Infof("Che Version: %s", config.GetOpenshiftCheVersion())
	}
	if config.GetOpenshiftJenkinsVersion() != "" {
		log.Logger().Infof("Jenkins Version: %s", config.GetOpenshiftJenkinsVersion())
	}
	if config.GetOpenshiftTeamVersion() != "" {
		log.Logger().Infof("Team Version: %s", config.GetOpenshiftTeamVersion())
	}
	if config.GetOpenshiftTemplateDir() != "" {
		log.Logger().Infof("Template Dir: %s", config.GetOpenshiftTemplateDir())
	}

	openshiftConfig := openshift.Config{
		MasterURL:      config.GetOpenshiftTenantMasterURL(),
		ConsoleURL:     config.GetConsoleURL(),
		Token:          serviceToken,
		HttpTransport:  tr,
		CheVersion:     config.GetOpenshiftCheVersion(),
		JenkinsVersion: config.GetOpenshiftJenkinsVersion(),
		TeamVersion:    config.GetOpenshiftTeamVersion(),
		TemplateDir:    config.GetOpenshiftTemplateDir(),
	}

	openshiftMasterUser, err := openshift.WhoAmI(openshiftConfig)
	if err != nil {
		logrus.Panic(nil, map[string]interface{}{
			"err": err,
		}, "unknown master user based on service token")
	}
	openshiftConfig.MasterUser = openshiftMasterUser

	keycloakConfig := keycloak.Config{
		BaseURL: config.GetKeycloakURL(),
		Realm:   config.GetKeycloakRealm(),
		Broker:  config.GetKeycloakOpenshiftBroker(),
	}

	templateVars, err := config.GetTemplateValues()
	if err != nil {
		panic(err)
	}

	templateVars["KEYCLOAK_URL"] = ""
	templateVars["FABRIC8_CONSOLE_URL"] = openshiftConfig.ConsoleURL
	templateVars["KEYCLOAK_OSO_ENDPOINT"] = keycloakConfig.CustomBrokerTokenURL("openshift-v3")
	templateVars["KEYCLOAK_GITHUB_ENDPOINT"] = fmt.Sprintf("%s%s?for=https://github.com", config.GetAuthURL(), auth.RetrieveTokenPath())

	publicKeys, err := keycloak.GetPublicKeys(config.GetAuthURL())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err":    err,
			"target": config.GetAuthURL(),
		}, "failed to fetch public keys from token service")
	}

	// Create service
	service := goa.New("tenant")

	// Mount middleware
	service.WithLogger(goalogrus.New(log.Logger()))
	service.Use(middleware.RequestID())
	service.Use(gzip.Middleware(9))
	service.Use(jsonapi.ErrorHandler(service, true))
	service.Use(middleware.Recover())

	service.Use(witmiddleware.TokenContext(publicKeys, nil, app.NewJWTSecurity()))
	service.Use(log.LogRequest(config.IsDeveloperModeEnabled()))
	app.UseJWTMiddleware(service, goajwt.New(publicKeys, nil, app.NewJWTSecurity()))

	// Mount "status" controller
	statusCtrl := controller.NewStatusController(service, db)
	app.MountStatusController(service, statusCtrl)

	// Mount "tenant" controller
	witURL := config.GetWitURL()
	tenantService := tenant.NewDBService(db)

	tenantCtrl := controller.NewTenantController(service, tenantService, keycloakConfig, openshiftConfig, templateVars, witURL)
	app.MountTenantController(service, tenantCtrl)

	tenantsCtrl := controller.NewTenantsController(service, tenantService)
	app.MountTenantsController(service, tenantsCtrl)

	// Mount "tenantkube" controller
	tenanKubetCtrl := controller.NewTenantKubeController(service, tenantService, keycloakConfig, openshiftConfig, templateVars)
	app.MountTenantKubeController(service, tenanKubetCtrl)

	// Mount "auth" controller
	authCtrl := controller.NewAuthController(service, tenantService, keycloakConfig, openshiftConfig, templateVars)
	app.MountAuthController(service, authCtrl)

	log.Logger().Infoln("Git Commit SHA: ", controller.Commit)
	log.Logger().Infoln("UTC Build Time: ", controller.BuildTime)
	log.Logger().Infoln("UTC Start Time: ", controller.StartTime)
	log.Logger().Infoln("Dev mode:       ", config.IsDeveloperModeEnabled())
	log.Logger().Infoln("WIT URL:        ", witURL)

	http.Handle("/favicon.ico", http.NotFoundHandler())
	http.Handle("/", service.Mux)

	// Start http
	if err := http.ListenAndServe(config.GetHTTPAddress(), nil); err != nil {
		log.Error(nil, map[string]interface{}{
			"addr": config.GetHTTPAddress(),
			"err":  err,
		}, "unable to connect to server")
		service.LogError("startup", "err", err)
	}
}

func connect(config *configuration.Data) *gorm.DB {
	var err error
	var db *gorm.DB
	for {
		db, err = gorm.Open("postgres", config.GetPostgresConfigString())
		if err != nil {
			log.Logger().Errorf("ERROR: Unable to open connection to database %v", err)
			log.Logger().Infof("Retrying to connect in %v...", config.GetPostgresConnectionRetrySleep())
			time.Sleep(config.GetPostgresConnectionRetrySleep())
		} else {
			break
		}
	}

	if config.IsDeveloperModeEnabled() {
		db = db.Debug()
	}

	if config.GetPostgresConnectionMaxIdle() > 0 {
		log.Logger().Infof("Configured connection pool max idle %v", config.GetPostgresConnectionMaxIdle())
		db.DB().SetMaxIdleConns(config.GetPostgresConnectionMaxIdle())
	}
	if config.GetPostgresConnectionMaxOpen() > 0 {
		log.Logger().Infof("Configured connection pool max open %v", config.GetPostgresConnectionMaxOpen())
		db.DB().SetMaxOpenConns(config.GetPostgresConnectionMaxOpen())
	}
	return db
}

func migrate(db *gorm.DB) {
	// Migrate the schema
	err := migration.Migrate(db.DB())
	if err != nil {
		log.Panic(nil, map[string]interface{}{
			"err": err,
		}, "failed migration")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"sync"
	"time"

	"gopkg.in/tylerb/graceful.v1"

	"github.com/honeybadger-io/honeybadger-go"
	"github.com/kiskolabs/heroku-cloudwatch-drain/logger"
	"github.com/kiskolabs/heroku-cloudwatch-drain/logparser"
	"github.com/newrelic/go-agent"
)

// App is a Heroku HTTPS log drain. It receives log batches as POST requests,
// parses them, and sends them to CloudWatch Logs.
type App struct {
	retention      int
	stripAnsiCodes bool
	user, pass     string
	parse          logparser.ParseFunc
	newrelic       newrelic.Application

	loggers map[string]logger.Logger
	mu      sync.Mutex // protects loggers
}

func main() {
	var bind, user, pass string
	var retention int
	var stripAnsiCodes bool

	flag.StringVar(&bind, "bind", ":8080", "address to bind to")
	flag.IntVar(&retention, "retention", 0, "log retention in days for new log groups")
	flag.StringVar(&user, "user", "", "username for HTTP basic auth")
	flag.StringVar(&pass, "pass", "", "password for HTTP basic auth")
	flag.BoolVar(&stripAnsiCodes, "strip-ansi-codes", false, "strip ANSI codes from log messages")
	flag.Parse()

	nrAppName := os.Getenv("NEW_RELIC_APP_NAME")
	if nrAppName == "" {
		nrAppName = "heroku-cloudwatch-drain"
	}

	nrLicense := os.Getenv("NEW_RELIC_LICENSE_KEY")
	nrConfig := newrelic.NewConfig(nrAppName, nrLicense)
	nrConfig.Enabled = (nrLicense != "")

	nrApp, err := newrelic.NewApplication(nrConfig)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	app := &App{
		retention:      retention,
		user:           user,
		pass:           pass,
		stripAnsiCodes: stripAnsiCodes,
		parse:          logparser.Parse,
		loggers:        make(map[string]logger.Logger),
		newrelic:       nrApp,
	}

	if honeybadger.Config.APIKey == "" {
		honeybadger.Configure(honeybadger.Configuration{Backend: honeybadger.NewNullBackend()})
	}

	mux := http.NewServeMux()
	mux.Handle(newrelic.WrapHandle(nrApp, "/", honeybadger.Handler(app)))
	err = graceful.RunWithErr(bind, 5*time.Second, mux)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	app.Stop()
}

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	appName := r.URL.Path[1:]

	honeybadger.SetContext(honeybadger.Context{
		"AppName": appName,
	})

	if appName == "" && r.Method == http.MethodGet {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
		return
	}

	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("The only accepted request method is POST"))
		return
	}

	if appName == "" {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Request path must specify the log group name"))
		return
	}

	user, pass, _ := r.BasicAuth()
	if user != app.user || pass != app.pass {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	txn, _ := w.(newrelic.Transaction)
	if txn != nil {
		if err := txn.AddAttribute("AppName", appName); nil != err {
			log.Printf("failed to add New Relic attribute for app %s: %s\n", appName, err)
		}
	}

	l, err := app.logger(appName)
	if err != nil {
		log.Printf("failed to create logger for app %s: %s\n", appName, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if err = app.processMessages(r.Body, l, txn); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		honeybadger.Notify(err)
		log.Println(err)
		return
	}

	w.WriteHeader(http.StatusAccepted)
}

// Stop all the loggers, flushing any pending requests.
func (app *App) Stop() {
	var wg sync.WaitGroup
	wg.Add(len(app.loggers))
	app.mu.Lock()
	defer app.mu.Unlock()
	for _, l := range app.loggers {
		go func(l logger.Logger) {
			l.Stop()
			wg.Done()
		}(l)
	}
	wg.Wait()
}

func (app *App) logger(appName string) (l logger.Logger, err error) {
	app.mu.Lock()
	defer app.mu.Unlock()
	l, ok := app.loggers[appName]
	if !ok {
		l, err = logger.NewCloudWatchLogger(appName, app.retention, app.newrelic)
		app.loggers[appName] = l
	}
	return l, err
}

func (app *App) processMessages(r io.Reader, l logger.Logger, txn newrelic.Transaction) error {
	if txn != nil {
		defer newrelic.StartSegment(txn, "processMessages").End()
	}
	buf := bufio.NewReader(r)
	eof := false
	for {
		b, err := buf.ReadBytes('\n')
		if err != nil {
			if err == io.EOF {
				eof = true
			} else {
				honeybadger.Notify(err)
				return fmt.Errorf("failed to scan request body: %s", err)
			}
		}
		if eof && len(b) == 0 {
			break
		}
		entry, err := app.parse(b)
		if err != nil {
			honeybadger.Notify(err)
			return fmt.Errorf("unable to parse message: %s, error: %s", string(b), err)
		}
		m := entry.Message
		if app.stripAnsiCodes {
			m = stripAnsi(m)
		}
		if !eof {
			m = m[:len(m)-1]
		}
		l.Log(entry.Time, m)
		if eof {
			break
		}
	}
	return nil
}

var ansiRegexp = regexp.MustCompile("\x1b[^m]*m")

func stripAnsi(s string) string {
	return ansiRegexp.ReplaceAllLiteralString(s, "")
}
<commit_msg>Improves the error grouping<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"sync"
	"time"

	"gopkg.in/tylerb/graceful.v1"

	"github.com/honeybadger-io/honeybadger-go"
	"github.com/kiskolabs/heroku-cloudwatch-drain/logger"
	"github.com/kiskolabs/heroku-cloudwatch-drain/logparser"
	"github.com/newrelic/go-agent"
)

// App is a Heroku HTTPS log drain. It receives log batches as POST requests,
// parses them, and sends them to CloudWatch Logs.
type App struct {
	retention      int
	stripAnsiCodes bool
	user, pass     string
	parse          logparser.ParseFunc
	newrelic       newrelic.Application

	loggers map[string]logger.Logger
	mu      sync.Mutex // protects loggers
}

func main() {
	var bind, user, pass string
	var retention int
	var stripAnsiCodes bool

	flag.StringVar(&bind, "bind", ":8080", "address to bind to")
	flag.IntVar(&retention, "retention", 0, "log retention in days for new log groups")
	flag.StringVar(&user, "user", "", "username for HTTP basic auth")
	flag.StringVar(&pass, "pass", "", "password for HTTP basic auth")
	flag.BoolVar(&stripAnsiCodes, "strip-ansi-codes", false, "strip ANSI codes from log messages")
	flag.Parse()

	nrAppName := os.Getenv("NEW_RELIC_APP_NAME")
	if nrAppName == "" {
		nrAppName = "heroku-cloudwatch-drain"
	}

	nrLicense := os.Getenv("NEW_RELIC_LICENSE_KEY")
	nrConfig := newrelic.NewConfig(nrAppName, nrLicense)
	nrConfig.Enabled = (nrLicense != "")

	nrApp, err := newrelic.NewApplication(nrConfig)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	app := &App{
		retention:      retention,
		user:           user,
		pass:           pass,
		stripAnsiCodes: stripAnsiCodes,
		parse:          logparser.Parse,
		loggers:        make(map[string]logger.Logger),
		newrelic:       nrApp,
	}

	if honeybadger.Config.APIKey == "" {
		honeybadger.Configure(honeybadger.Configuration{Backend: honeybadger.NewNullBackend()})
	}

	honeybadger.BeforeNotify(
		func(notice *honeybadger.Notice) error {
			if notice.ErrorClass == "errors.errorString" {
				notice.Fingerprint = notice.ErrorMessage
			}
			return nil
		},
	)

	mux := http.NewServeMux()
	mux.Handle(newrelic.WrapHandle(nrApp, "/", honeybadger.Handler(app)))
	err = graceful.RunWithErr(bind, 5*time.Second, mux)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	app.Stop()
}

func (app *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	appName := r.URL.Path[1:]

	honeybadger.SetContext(honeybadger.Context{
		"AppName": appName,
	})

	if appName == "" && r.Method == http.MethodGet {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
		return
	}

	if r.Method != http.MethodPost {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("The only accepted request method is POST"))
		return
	}

	if appName == "" {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Request path must specify the log group name"))
		return
	}

	user, pass, _ := r.BasicAuth()
	if user != app.user || pass != app.pass {
		w.WriteHeader(http.StatusForbidden)
		return
	}

	txn, _ := w.(newrelic.Transaction)
	if txn != nil {
		if err := txn.AddAttribute("AppName", appName); nil != err {
			log.Printf("failed to add New Relic attribute for app %s: %s\n", appName, err)
		}
	}

	l, err := app.logger(appName)
	if err != nil {
		log.Printf("failed to create logger for app %s: %s\n", appName, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	if err = app.processMessages(r.Body, l, txn); err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		honeybadger.Notify(err)
		log.Println(err)
		return
	}

	w.WriteHeader(http.StatusAccepted)
}

// Stop all the loggers, flushing any pending requests.
func (app *App) Stop() {
	var wg sync.WaitGroup
	wg.Add(len(app.loggers))
	app.mu.Lock()
	defer app.mu.Unlock()
	for _, l := range app.loggers {
		go func(l logger.Logger) {
			l.Stop()
			wg.Done()
		}(l)
	}
	wg.Wait()
}

func (app *App) logger(appName string) (l logger.Logger, err error) {
	app.mu.Lock()
	defer app.mu.Unlock()
	l, ok := app.loggers[appName]
	if !ok {
		l, err = logger.NewCloudWatchLogger(appName, app.retention, app.newrelic)
		app.loggers[appName] = l
	}
	return l, err
}

func (app *App) processMessages(r io.Reader, l logger.Logger, txn newrelic.Transaction) error {
	if txn != nil {
		defer newrelic.StartSegment(txn, "processMessages").End()
	}
	buf := bufio.NewReader(r)
	eof := false
	for {
		b, err := buf.ReadBytes('\n')
		if err != nil {
			if err == io.EOF {
				eof = true
			} else {
				honeybadger.Notify(err)
				return fmt.Errorf("failed to scan request body: %s", err)
			}
		}
		if eof && len(b) == 0 {
			break
		}
		entry, err := app.parse(b)
		if err != nil {
			honeybadger.Notify(err)
			return fmt.Errorf("unable to parse message: %s, error: %s", string(b), err)
		}
		m := entry.Message
		if app.stripAnsiCodes {
			m = stripAnsi(m)
		}
		if !eof {
			m = m[:len(m)-1]
		}
		l.Log(entry.Time, m)
		if eof {
			break
		}
	}
	return nil
}

var ansiRegexp = regexp.MustCompile("\x1b[^m]*m")

func stripAnsi(s string) string {
	return ansiRegexp.ReplaceAllLiteralString(s, "")
}
<|endoftext|>


<commit_before>//Pholcus幽灵蛛是一款Go语言编写的爬虫软件框架（含GUI界面），
//优雅的爬虫规则、可控的高并发、任意的批量任务、多种输出方式、大量Demo，并且考虑了支持分布式布局。
package main

import (
	"github.com/henrylee2cn/pholcus/pholcus/gui"
)

func main() {
	gui.Run()
}
<commit_msg>添加项目注释性简介<commit_after>//Pholcus幽灵蛛是一款Go语言编写的爬虫软件框架（含GUI界面），
//优雅的爬虫规则、可控的高并发、任意的批量任务、多种输出方式、大量Demo，并且考虑了支持分布式布局。
//（官方QQ群：Go大数据 42731170，欢迎加入我们的讨论）
package main

import (
	"github.com/henrylee2cn/pholcus/pholcus/gui"
)

func main() {
	gui.Run()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/kataras/iris"

	"googlemaps.github.io/maps"
)

const (
	mapsQPSLimit             = 10
	nearbySearchRadiusMeters = 100
)

func main() {
	// Environment validation. We would like to fail fast.
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT env var is mandatory")
	}

	gMapsKey := os.Getenv("GOOGLE_MAPS_KEY")
	if gMapsKey == "" {
		log.Fatal("$GOOGLE_MAPS_KEY env var is mandatory")
	}

	gMapsClient, err := maps.NewClient(maps.WithAPIKey(gMapsKey), maps.WithRateLimit(mapsQPSLimit))
	if err != nil {
		log.Fatalf("Error creating google maps client: %q", err)
	}

	app := iris.New()
	apiV1 := app.Party("api/v1")
	{
		apiV1.Get("/place", func(ctx *iris.Context) {
			lat, err := strconv.ParseFloat(ctx.URLParam("lat"), 64)
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.HTML(http.StatusBadRequest, "Invalid lat param")
				return
			}
			lng, err := strconv.ParseFloat(ctx.URLParam("lng"), 64)
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.HTML(http.StatusBadRequest, "Invalid lng param")
				return
			}
			resp, err := gMapsClient.NearbySearch(context.Background(), &maps.NearbySearchRequest{
				Location: &maps.LatLng{
					Lat: lat,
					Lng: lng,
				},
				Radius: nearbySearchRadiusMeters,
			})
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.SetStatusCode(http.StatusInternalServerError)
				return
			}
			ctx.SetContentType("application/json")
			ctx.JSON(http.StatusOK, resp)
		})
	}
	app.Listen(":" + port)
}
<commit_msg>Redirecting / to github.com/acessoatodos<commit_after>package main

import (
	"context"
	"log"
	"os"
	"strconv"

	"github.com/kataras/iris"

	"googlemaps.github.io/maps"
)

const (
	mapsQPSLimit             = 10
	nearbySearchRadiusMeters = 100
)

func main() {
	// Environment validation. We would like to fail fast.
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT env var is mandatory")
	}

	gMapsKey := os.Getenv("GOOGLE_MAPS_KEY")
	if gMapsKey == "" {
		log.Fatal("$GOOGLE_MAPS_KEY env var is mandatory")
	}

	gMapsClient, err := maps.NewClient(maps.WithAPIKey(gMapsKey), maps.WithRateLimit(mapsQPSLimit))
	if err != nil {
		log.Fatalf("Error creating google maps client: %q", err)
	}

	app := iris.New()

	// Redirecting to github for now.
	app.Get("/", func(ctx *iris.Context) {
		ctx.Redirect("//github.com/danielfireman/acessoatodos", iris.StatusTemporaryRedirect)
	})

	apiV1 := app.Party("api/v1")
	{
		apiV1.Get("/place", func(ctx *iris.Context) {
			lat, err := strconv.ParseFloat(ctx.URLParam("lat"), 64)
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.HTML(iris.StatusBadRequest, "Invalid lat param")
				return
			}
			lng, err := strconv.ParseFloat(ctx.URLParam("lng"), 64)
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.HTML(iris.StatusBadRequest, "Invalid lng param")
				return
			}
			resp, err := gMapsClient.NearbySearch(context.Background(), &maps.NearbySearchRequest{
				Location: &maps.LatLng{
					Lat: lat,
					Lng: lng,
				},
				Radius: nearbySearchRadiusMeters,
			})
			if err != nil {
				ctx.Logger().Printf("Error processing request: %q", err)
				ctx.SetStatusCode(iris.StatusInternalServerError)
				return
			}
			ctx.SetContentType("application/json")
			ctx.JSON(iris.StatusOK, resp)
		})
	}
	app.Listen(":" + port)
}
<|endoftext|>


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

// Package main contains an App Engine that serves vanity URLs for a git repo.
package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"

	"google.golang.org/appengine"

	"io/ioutil"

	"gopkg.in/yaml.v2"
)

type ypkg struct {
	Repo    string `yaml:"repo,omitempty"`
	Display string `yaml:"display,omitempty"`
}

var m map[string]ypkg

func init() {
	vanity, err := ioutil.ReadFile("./vanity.yaml")
	if err != nil {
		log.Fatal(err)
	}
	if err := yaml.Unmarshal(vanity, &m); err != nil {
		log.Fatal(err)
	}
	for _, e := range m {
		if e.Display != "" {
			continue
		}
		if strings.Contains(e.Repo, "github.com") {
			e.Display = fmt.Sprintf("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}", e.Repo, e.Repo, e.Repo)
		}
	}
	http.HandleFunc("/", handle)
}

func handle(w http.ResponseWriter, r *http.Request) {
	current := r.URL.Path
	p, ok := m[current]
	if !ok {
		http.NotFound(w, r)
		return
	}

	host := appengine.DefaultVersionHostname(appengine.NewContext(r))
	if err := vanityTmpl.Execute(w, struct {
		Import  string
		Repo    string
		Display string
	}{
		Import:  host + current,
		Repo:    p.Repo,
		Display: p.Display,
	}); err != nil {
		http.Error(w, "cannot render the page", http.StatusInternalServerError)
	}
}

var vanityTmpl, _ = template.New("vanity").Parse(`<!DOCTYPE html>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="{{.Import}} git {{.Repo}}">
<meta name="go-source" content="{{.Import}} {{.Display}}">
<meta http-equiv="refresh" content="0; url=https://godoc.org/{{.Import}}">

Nothing to see here; see the package on godoc.

`)

func mustLoad(key string, value *string) {
	v := os.Getenv(key)
	if v == "" {
		log.Fatalf("missing %v env variable", key)
	}
	*value = v
}
<commit_msg>fix package godoc to mention it supports multiple repos<commit_after>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main contains an App Engine that serves vanity URLs for git repos.
package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"

	"google.golang.org/appengine"

	"io/ioutil"

	"gopkg.in/yaml.v2"
)

type ypkg struct {
	Repo    string `yaml:"repo,omitempty"`
	Display string `yaml:"display,omitempty"`
}

var m map[string]ypkg

func init() {
	vanity, err := ioutil.ReadFile("./vanity.yaml")
	if err != nil {
		log.Fatal(err)
	}
	if err := yaml.Unmarshal(vanity, &m); err != nil {
		log.Fatal(err)
	}
	for _, e := range m {
		if e.Display != "" {
			continue
		}
		if strings.Contains(e.Repo, "github.com") {
			e.Display = fmt.Sprintf("%v %v/tree/master{/dir} %v/blob/master{/dir}/{file}#L{line}", e.Repo, e.Repo, e.Repo)
		}
	}
	http.HandleFunc("/", handle)
}

func handle(w http.ResponseWriter, r *http.Request) {
	current := r.URL.Path
	p, ok := m[current]
	if !ok {
		http.NotFound(w, r)
		return
	}

	host := appengine.DefaultVersionHostname(appengine.NewContext(r))
	if err := vanityTmpl.Execute(w, struct {
		Import  string
		Repo    string
		Display string
	}{
		Import:  host + current,
		Repo:    p.Repo,
		Display: p.Display,
	}); err != nil {
		http.Error(w, "cannot render the page", http.StatusInternalServerError)
	}
}

var vanityTmpl, _ = template.New("vanity").Parse(`<!DOCTYPE html>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="{{.Import}} git {{.Repo}}">
<meta name="go-source" content="{{.Import}} {{.Display}}">
<meta http-equiv="refresh" content="0; url=https://godoc.org/{{.Import}}">

Nothing to see here; see the package on godoc.

`)

func mustLoad(key string, value *string) {
	v := os.Getenv(key)
	if v == "" {
		log.Fatalf("missing %v env variable", key)
	}
	*value = v
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin")
	for query.Next() {
		var id, title, hash, paste, delkey string
		err := query.Scan(&id, &title, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format(time.RFC3339)
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format(time.RFC3339)
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format(time.RFC3339)
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format(time.RFC3339)
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format(time.RFC3339)
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format(time.RFC3339)
		break

	default:
		expiryTime = now.Format(time.RFC3339)
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	if expiry > time.Now().Format(time.RFC3339) {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	if lang == "" {
		p := &Page{
			Title:    title,
			Body:     []byte(s),
			Raw:      link,
			Home:     ADDRESS,
			Download: download,
			Clone:    clone,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, download, link, clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>Add some temps prints for debugging<commit_after>package main

import (
	"crypto/sha1"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"html"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/dchest/uniuri"
	"github.com/ewhal/pygments"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
)

const (
	ADDRESS  = "http://localhost:9900"
	LENGTH   = 6
	PORT     = ":9900"
	USERNAME = ""
	PASS     = ""
	NAME     = ""
	DATABASE = USERNAME + ":" + PASS + "@/" + NAME + "?charset=utf8"
)

type Response struct {
	ID     string `json:"id"`
	TITLE  string `json:"title"`
	HASH   string `json:"hash"`
	URL    string `json:"url"`
	SIZE   int    `json:"size"`
	DELKEY string `json:"delkey"`
}

type Page struct {
	Title    string
	Body     []byte
	Raw      string
	Home     string
	Download string
	Clone    string
}

func check(err error) {
	if err != nil {
		fmt.Println(err)
	}
}

func generateName() string {
	s := uniuri.NewLen(LENGTH)
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	query, err := db.Query("select id from pastebin")
	for query.Next() {
		var id string
		err := query.Scan(&id)
		if err != nil {

		}
		if id == s {
			generateName()
		}
	}
	db.Close()

	return s

}
func hash(paste string) string {
	hasher := sha1.New()

	hasher.Write([]byte(paste))
	sha := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
	return sha
}

func save(raw string, lang string, title string, expiry string) []string {
	db, err := sql.Open("mysql", DATABASE)
	check(err)

	sha := hash(raw)
	query, err := db.Query("select id, title, hash, data, delkey from pastebin")
	for query.Next() {
		var id, title, hash, paste, delkey string
		err := query.Scan(&id, &title, &hash, &paste, &delkey)
		check(err)
		if hash == sha {
			url := ADDRESS + "/p/" + id
			return []string{id, title, hash, url, paste, delkey}
		}
	}
	id := generateName()
	var url string
	if lang == "" {
		url = ADDRESS + "/p/" + id
	} else {
		url = ADDRESS + "/p/" + id + "/" + lang
	}
	now := time.Now()
	var expiryTime string

	switch expiry {
	case "5 minutes":
		expiryTime = now.Add(time.Minute * 5).Format(time.RFC3339)
		break

	case "1 hour":
		expiryTime = now.Add(time.Hour + 1).Format(time.RFC3339)
		break

	case "1 day":
		expiryTime = now.Add(time.Hour * 24 * 1).Format(time.RFC3339)
		break

	case "1 week":
		expiryTime = now.Add(time.Hour * 24 * 7).Format(time.RFC3339)
		break

	case "1 month":
		expiryTime = now.Add(time.Hour * 24 * 30).Format(time.RFC3339)
		break

	case "1 year":
		expiryTime = now.Add(time.Hour * 24 * 365).Format(time.RFC3339)
		break

	default:
		expiryTime = now.Format(time.RFC3339)
		break

	}
	delKey := uniuri.NewLen(40)
	paste := html.EscapeString(raw)

	stmt, err := db.Prepare("INSERT INTO pastebin(id, title, hash, data, delkey, expiry) values(?,?,?,?,?,?)")
	check(err)
	if title == "" {
		_, err = stmt.Exec(id, id, sha, paste, delKey, expiryTime)
		check(err)
	} else {
		_, err = stmt.Exec(id, html.EscapeString(title), sha, paste, delKey, expiryTime)
		check(err)
	}
	db.Close()
	return []string{id, title, sha, url, paste, delKey}
}

func delHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	delkey := vars["delKey"]

	db, err := sql.Open("mysql", DATABASE)
	check(err)

	stmt, err := db.Prepare("delete from pastebin where delkey=?")
	check(err)

	res, err := stmt.Exec(html.EscapeString(delkey))
	check(err)

	_, err = res.RowsAffected()
	if err == sql.ErrNoRows {
		io.WriteString(w, "Error invalid paste")
	} else {
		io.WriteString(w, paste+" deleted")
	}
	db.Close()

}
func saveHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	output := vars["output"]
	switch r.Method {
	case "POST":
		paste := r.FormValue("p")
		lang := r.FormValue("lang")
		title := r.FormValue("title")
		expiry := r.FormValue("expiry")
		if paste == "" {
			http.Error(w, "Empty paste", 500)
			return
		}
		values := save(paste, lang, title, expiry)
		b := &Response{
			ID:     values[0],
			TITLE:  values[1],
			HASH:   values[2],
			URL:    values[3],
			SIZE:   len(values[4]),
			DELKEY: values[5],
		}

		switch output {
		case "json":

			w.Header().Set("Content-Type", "application/json")
			err := json.NewEncoder(w).Encode(b)

			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		case "xml":
			x, err := xml.MarshalIndent(b, "", "  ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			w.Header().Set("Content-Type", "application/xml")
			w.Write(x)

		case "html":
			w.Header().Set("Content-Type", "text/html")
			io.WriteString(w, "
URL: "+b.URL+"
")
			io.WriteString(w, "
Delete Key: "+b.DELKEY+"
")

		case "redirect":
			http.Redirect(w, r, b.URL, 301)

		default:
			w.Header().Set("Content-Type", "plain/text")
			io.WriteString(w, b.URL+"\n")
			io.WriteString(w, "delete key: "+b.DELKEY+"\n")
		}
	}

}

func highlight(s string, lang string) (string, error) {

	highlight, err := pygments.Highlight(html.UnescapeString(s), html.EscapeString(lang), "html", "style=autumn,linenos=True, lineanchors=True,anchorlinenos=True,noclasses=True,", "utf-8")
	if err != nil {
		return "", err
	}
	return highlight, nil

}

func getPaste(paste string, lang string) (string, string) {
	param1 := html.EscapeString(paste)
	db, err := sql.Open("mysql", DATABASE)
	var title, s string
	var expiry string
	err = db.QueryRow("select title, data, expiry from pastebin where id=?", param1).Scan(&title, &s, &expiry)
	check(err)
	fmt.Println(expiry)
	fmt.Println(time.Now().Format(time.RFC3339))
	fmt.Println(expiry > time.Now().Format(time.RFC3339))
	if expiry > time.Now().Format(time.RFC3339) {
		stmt, err := db.Prepare("delete from pastebin where id=?")
		check(err)
		_, err = stmt.Exec(param1)
		check(err)
		return "Error invalid paste", ""
	}
	db.Close()

	if err == sql.ErrNoRows {
		return "Error invalid paste", ""
	} else {
		if lang == "" {
			return html.UnescapeString(s), html.UnescapeString(title)
		} else {
			high, err := highlight(s, lang)
			check(err)
			return high, html.UnescapeString(title)

		}
	}

}

var templates = template.Must(template.ParseFiles("assets/paste.html", "assets/index.html", "assets/clone.html"))
var syntax, _ = ioutil.ReadFile("assets/syntax.html")

func pasteHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	lang := vars["lang"]
	s, title := getPaste(paste, lang)
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	if lang == "" {
		p := &Page{
			Title:    title,
			Body:     []byte(s),
			Raw:      link,
			Home:     ADDRESS,
			Download: download,
			Clone:    clone,
		}
		err := templates.ExecuteTemplate(w, "paste.html", p)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}

	} else {
		fmt.Fprintf(w, string(syntax), paste, paste, s, ADDRESS, download, link, clone)

	}
}

func cloneHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, title := getPaste(paste, "")
	link := ADDRESS + "/raw/" + paste
	download := ADDRESS + "/download/" + paste
	clone := ADDRESS + "/clone/" + paste
	p := &Page{
		Title:    title,
		Body:     []byte(s),
		Raw:      link,
		Home:     ADDRESS,
		Download: download,
		Clone:    clone,
	}
	err := templates.ExecuteTemplate(w, "clone.html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
func downloadHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	w.Header().Set("Content-Disposition", "attachment; filename="+paste)
	w.Header().Set("Content-Type", r.Header.Get("Content-Type"))
	io.WriteString(w, s)

}
func rawHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	paste := vars["pasteId"]
	s, _ := getPaste(paste, "")
	io.WriteString(w, s)

}

func main() {
	router := mux.NewRouter()
	router.HandleFunc("/p/{pasteId}", pasteHandler)
	router.HandleFunc("/raw/{pasteId}", rawHandler)
	router.HandleFunc("/p/{pasteId}/{lang}", pasteHandler)
	router.HandleFunc("/clone/{pasteId}", cloneHandler)
	router.HandleFunc("/download/{pasteId}", downloadHandler)
	router.HandleFunc("/save", saveHandler)
	router.HandleFunc("/save/{output}", saveHandler)
	router.HandleFunc("/del/{pasteId}/{delKey}", delHandler)
	router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("assets/"))))
	err := http.ListenAndServe(PORT, router)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/armatys/android-tools/strings/crowdin"
	"github.com/armatys/android-tools/strings/validator"
	"os"
)

// The action name to perform.
var actionNameArg string

// The path to the Android's "res" directory.
var projectResDirArg string

// The base locale used for comparison and validation of other locale strings.
var baseLocaleArg string

// The name of the xml file with string resources.
var stringsFileNameArg string

// Flag that specifies it the string validator should show strings that exist in base resources, but not in other resources.
var showMissingArg bool

// Path to a file with configuration for accessing crowdin.
// The file should contain a JSON object like this: {"Key": "api_key", "ProjectName": "the-project-name"}
var crowdinConfigFileArg string

var (
	actionNameValidate      = "validate"
	actionNameCrowdinUpdate = "crowdin-update"
	actionNameCrowdinExport = "crowdin-export"
	supportedActionNames    = []string{actionNameValidate, actionNameCrowdinUpdate}
)

func init() {
	flag.StringVar(&actionNameArg, "action", actionNameValidate, fmt.Sprintf("Action to perform, one of %v.", supportedActionNames))
	flag.StringVar(&projectResDirArg, "resdir", "", "(required) The path to the 'res' directory of your Android project.")
	flag.StringVar(&baseLocaleArg, "baselocale", "", "The base locale used for validation of other locale strings (e.g. 'en' or 'en-rGB').")
	flag.StringVar(&stringsFileNameArg, "filename", "strings.xml", "(required) The name of the xml file with XML string resources.")
	flag.BoolVar(&showMissingArg, "missing", false, "If true shows the missing translations.")
	flag.StringVar(&crowdinConfigFileArg, "crowdin-conf", "", "The path to a file with a JSON configuration for accessing Crowdin service. The JSON should look like {\"Key\": \"api_key\", \"ProjectName\": \"the-project-name\"}")
}

func main() {
	flag.Parse()
	if !isActionSupported(actionNameArg) {
		fmt.Printf("Action '%s' is not supported.\n", actionNameArg)
		os.Exit(-1)
	}
	if actionNameArg == actionNameValidate {
		validateStrings()
	} else if actionNameArg == actionNameCrowdinUpdate {
		crowdinUpdate()
	} else if actionNameArg == actionNameCrowdinExport {
		crowdinExport()
	}
}

func validateStrings() {
	if !(len(projectResDirArg) > 0 && len(stringsFileNameArg) > 0) {
		flag.Usage()
		os.Exit(-1)
	}

	var errorList []error = validator.Validate(projectResDirArg, baseLocaleArg, stringsFileNameArg, showMissingArg)
	errorCount := 0

	if len(errorList) > 0 {
		for _, e := range errorList {
			errorCount += 1
			fmt.Printf("[%d] %s\n", errorCount, e.Error())
		}
	}

	if errorCount > 0 {
		fmt.Printf("Found %d errors.\n", errorCount)
	} else {
		fmt.Println("No errors found.")
	}
	os.Exit(errorCount)
}

func crowdinUpdate() {
	if !(len(projectResDirArg) > 0 && len(stringsFileNameArg) > 0) {
		flag.Usage()
		os.Exit(-1)
	}
	config, err := loadCrowdinConf()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}
	if err := crowdin.UpdateStrings(config, projectResDirArg, stringsFileNameArg); err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	} else {
		fmt.Println("Strings have been updated.")
		os.Exit(0)
	}
}

func crowdinExport() {
	config, err := loadCrowdinConf()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}
	if resp, err := crowdin.ExportStrings(config); err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	} else {
		fmt.Println(resp)
		os.Exit(0)
	}
}

func loadCrowdinConf() (*crowdin.CrowdinConfig, error) {
	if len(crowdinConfigFileArg) == 0 {
		return nil, errors.New("The path to Crowdin configuration file is required.")
	}
	file, err := os.Open(crowdinConfigFileArg)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	var config crowdin.CrowdinConfig
	decoder := json.NewDecoder(file)
	if err := decoder.Decode(&config); err != nil {
		return nil, err
	}
	return &config, nil
}

// Returns true if the `actionName` is supported by this tool.
func isActionSupported(actionName string) bool {
	for _, name := range supportedActionNames {
		if name == actionName {
			return true
		}
	}
	return false
}
<commit_msg>Enable crowdin-export action<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/armatys/android-tools/strings/crowdin"
	"github.com/armatys/android-tools/strings/validator"
	"os"
)

// The action name to perform.
var actionNameArg string

// The path to the Android's "res" directory.
var projectResDirArg string

// The base locale used for comparison and validation of other locale strings.
var baseLocaleArg string

// The name of the xml file with string resources.
var stringsFileNameArg string

// Flag that specifies it the string validator should show strings that exist in base resources, but not in other resources.
var showMissingArg bool

// Path to a file with configuration for accessing crowdin.
// The file should contain a JSON object like this: {"Key": "api_key", "ProjectName": "the-project-name"}
var crowdinConfigFileArg string

var (
	actionNameValidate      = "validate"
	actionNameCrowdinUpdate = "crowdin-update"
	actionNameCrowdinExport = "crowdin-export"
	supportedActionNames    = []string{actionNameValidate, actionNameCrowdinUpdate, actionNameCrowdinExport}
)

func init() {
	flag.StringVar(&actionNameArg, "action", actionNameValidate, fmt.Sprintf("Action to perform, one of %v.", supportedActionNames))
	flag.StringVar(&projectResDirArg, "resdir", "", "The path to the 'res' directory of your Android project (required for 'validate' and 'crowdin-update').")
	flag.StringVar(&baseLocaleArg, "baselocale", "", "The base locale used for validation of other locale strings (e.g. 'en' or 'en-rGB').")
	flag.StringVar(&stringsFileNameArg, "filename", "strings.xml", "The name of the xml file with XML string resources (required for 'validate' and 'crowdin-update').")
	flag.BoolVar(&showMissingArg, "missing", false, "If true shows the missing translations (use with 'validate').")
	flag.StringVar(&crowdinConfigFileArg, "crowdin-conf", "", "The path to a file with a JSON configuration for accessing Crowdin service (required for 'crowdin-*'). The JSON should look like {\"Key\": \"api_key\", \"ProjectName\": \"the-project-name\"}")
}

func main() {
	flag.Parse()
	if !isActionSupported(actionNameArg) {
		fmt.Printf("Action '%s' is not supported.\n", actionNameArg)
		os.Exit(-1)
	}
	if actionNameArg == actionNameValidate {
		validateStrings()
	} else if actionNameArg == actionNameCrowdinUpdate {
		crowdinUpdate()
	} else if actionNameArg == actionNameCrowdinExport {
		crowdinExport()
	}
}

func validateStrings() {
	if !(len(projectResDirArg) > 0 && len(stringsFileNameArg) > 0) {
		flag.Usage()
		os.Exit(-1)
	}

	var errorList []error = validator.Validate(projectResDirArg, baseLocaleArg, stringsFileNameArg, showMissingArg)
	errorCount := 0

	if len(errorList) > 0 {
		for _, e := range errorList {
			errorCount += 1
			fmt.Printf("[%d] %s\n", errorCount, e.Error())
		}
	}

	if errorCount > 0 {
		fmt.Printf("Found %d errors.\n", errorCount)
	} else {
		fmt.Println("No errors found.")
	}
	os.Exit(errorCount)
}

func crowdinUpdate() {
	if !(len(projectResDirArg) > 0 && len(stringsFileNameArg) > 0) {
		flag.Usage()
		os.Exit(-1)
	}
	config, err := loadCrowdinConf()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}
	if err := crowdin.UpdateStrings(config, projectResDirArg, stringsFileNameArg); err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	} else {
		fmt.Println("Strings have been updated.")
		os.Exit(0)
	}
}

func crowdinExport() {
	config, err := loadCrowdinConf()
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	}
	if resp, err := crowdin.ExportStrings(config); err != nil {
		fmt.Println(err.Error())
		os.Exit(-1)
	} else {
		fmt.Println(resp)
		os.Exit(0)
	}
}

func loadCrowdinConf() (*crowdin.CrowdinConfig, error) {
	if len(crowdinConfigFileArg) == 0 {
		return nil, errors.New("The path to Crowdin configuration file is required.")
	}
	file, err := os.Open(crowdinConfigFileArg)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	var config crowdin.CrowdinConfig
	decoder := json.NewDecoder(file)
	if err := decoder.Decode(&config); err != nil {
		return nil, err
	}
	return &config, nil
}

// Returns true if the `actionName` is supported by this tool.
func isActionSupported(actionName string) bool {
	for _, name := range supportedActionNames {
		if name == actionName {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"sync"
	//"os"
	//"unsafe"
)

// #cgo CFLAGS: -I/usr/share/R/include -I/usr/share/R
// #cgo LDFLAGS: -L/usr/lib/R -lR
// #include <stdlib.h>
// #include <Rembedded.h>
// #include <Rinterface.h>
// #include <R_ext/RStartup.h>
import "C"

type RSession struct {
	Stdin chan interface{}
	Stout chan interface{}
}

func NewRSession() *RSession {
	in := make(chan interface{})
	out := make(chan interface{})
	rs := &RSession{in, out}
	go rs.start()
	return rs
}

func (rs *RSession) R_ShowMessage() {
}

func (rs *RSession) R_Busy() {
}

func (rs *RSession) R_ReadConsole() {
}

func (rs *RSession) R_WriteConsole() {
}

func (rs *RSession) R_WriteConsoleEx() {
}

func (rs *RSession) R_ResetConsole() {
}

func (rs *RSession) R_FlushConsole() {
}

func (rs *RSession) R_ClearErrConsole() {
}

func (rs *RSession) R_ShowFiles() {
}

func (rs *RSession) R_ChooseFile() {
}

func (rs *RSession) R_EditFile() {
}

func (rs *RSession) R_EditFiles() {
}

func (rs *RSession) R_loadhistory() {
}

func (rs *RSession) R_savehistory() {
}

func (rs *RSession) R_addhistory() {
}

func (rs *RSession) R_Suicide() {
}

func (rs *RSession) start() {
	argc := C.int(1)
	argv := make([]*C.char, 7)
	argv[0] = C.CString("rgo")
	argv[1] = C.CString("--gui=none")
	argv[2] = C.CString("--no-save")
	argv[3] = C.CString("--no-readline")
	argv[4] = C.CString("--vanilla")
	argv[5] = C.CString("--slave")
	argv[6] = C.CString("--silent")

	//_ := os.Getenv("R_HOME") or C.get_R_HOME()
	C.Rf_initEmbeddedR(argc, &argv[0])

	C.R_ReplDLLinit()
	//C.Rf_mainloop()
	for {
		//if C.R_ReplDLLdo1() <= 0 {
		//	break
		//}
	}

}

// for reference:
// https://github.com/eddelbuettel/rinside/blob/master/src/RInside.cpp

//# Go string to C string; result must be freed with C.free
//# func C.CString(string) *C.char
//# C string to Go string
//# func C.GoString(*C.char) string
//# C string, length to Go string
//# func C.GoStringN(*C.char, C.int) string
//#	C pointer, length to Go []byte
//#	func C.GoBytes(unsafe.Pointer, C.int) []byte

func main() {
	fmt.Println("Yes we are inside of Go")
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0
	for i < 1 {
		NewRSession()
		i++
	}
	wg.Wait()
}
<commit_msg>add r callbacks<commit_after>package main

import (
	"fmt"
	"sync"
	//"os"
	//"unsafe"
)

// #cgo CFLAGS: -I/usr/share/R/include -I/usr/share/R
// #cgo LDFLAGS: -L/usr/lib/R -lR
// #include <stdlib.h>
// #include <Rembedded.h>
// #include <Rinterface.h>
import "C"

type RSession struct {
	Stdin chan interface{}
	Stout chan interface{}
}

func NewRSession() *RSession {
	in := make(chan interface{})
	out := make(chan interface{})
	rs := &RSession{in, out}
	go rs.start()
	return rs
}

func (rs *RSession) R_ShowMessage() {
}

//export R_Busy
func R_Busy(which C.int) {
	print("Busy?")
	//print(int(which))
}

//export R_ShowMessage
func R_ShowMessage(msg C.char) {
	print("go callback")
	print(msg)
}

//export R_ReadConsole
func R_ReadConsole(prompt *C.char, buf C.char, buflen C.int, hist C.int) C.int {
	print("READ ME!")
	prompt = C.CString("FOO> ")
	return C.int(0)
}

//export R_WriteConsole
func R_WriteConsole(buf C.char, buflen C.int) {
	print("WRITE ME!")
	print(C.GoString(&buf))
}

//export R_WriteConsoleEx
func R_WriteConsoleEx(buf C.char, buflen, otype C.int) {
	print("WRITE ME!")
}

//export R_ResetConsole
func R_ResetConsole() {
	print("RESET!!!")
}

//export R_FlushConsole
func R_FlushConsole() {
	print("FLUSH!")
}

//export R_ClearErrConsole
func R_ClearErrConsole() {
	print("CLEAR!")
}

//export R_ShowFiles
func R_ShowFiles(nfile C.int, file unsafe.Pointer, headers unsafe.Pointer, wtitle C.CString, del C.Rboolean, pager C.CString) {
}

//export R_ChooseFile
func R_ChooseFile(newFile C.int, buf C.CString, buflen C.int) C.int {
	return C.int(0)
}

//export R_EditFiles
func R_EditFiles(buf C.CString) C.int {
	return C.int(0)
}

//export R_loadhistory
func R_loadhistory(call, op, args, env C.SEXP) C.SEXP {
	print("loadhistory is not implemented")
	return C.R_NilValue
}

//export R_savehistory
func R_savehistory(call, op, args, env C.SEXP) C.SEXP {
	print("loadhistory is not implemented")
	return C.R_NilValue
}

//export R_addhistory
func R_addhistory(call, op, args, env C.SEXP) C.SEXP {
	print("loadhistory is not implemented")
	return C.R_NilValue
}

/*
//rexport R_Suicide
func R_Suicide(msg *unsafe.Pointer) {
}
*/

func (rs *RSession) start() {
	argc := C.int(1)
	argv := make([]*C.char, 7)
	argv[0] = C.CString("rgo")
	argv[1] = C.CString("--gui=none")
	argv[2] = C.CString("--no-save")
	argv[3] = C.CString("--no-readline")
	argv[4] = C.CString("--vanilla")
	argv[5] = C.CString("--slave")
	argv[6] = C.CString("--silent")

	//_ := os.Getenv("R_HOME") or C.get_R_HOME()
	C.Rf_initEmbeddedR(argc, &argv[0])

	C.R_ReplDLLinit()
	//C.Rf_mainloop()
	for {
		if C.R_ReplDLLdo1() <= 0 {
			break
		}
	}

}

// for reference:
// https://github.com/eddelbuettel/rinside/blob/master/src/RInside.cpp

//# Go string to C string; result must be freed with C.free
//# func C.CString(string) *C.char
//# C string to Go string
//# func C.GoString(*C.char) string
//# C string, length to Go string
//# func C.GoStringN(*C.char, C.int) string
//#	C pointer, length to Go []byte
//#	func C.GoBytes(unsafe.Pointer, C.int) []byte

func main() {
	fmt.Println("Yes we are inside of Go")
	var wg sync.WaitGroup
	wg.Add(1)
	i := 0
	for i < 1 {
		NewRSession()
		i++
	}
	wg.Wait()
}
<|endoftext|>