<commit_before>// RIM - Remote Interfaces Monitor

/* Copyright (c) 2014 Andrea Masi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */

package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

var workers = runtime.NumCPU()

const (
	remoteCommand = `cat /proc/net/dev; echo ZZZ; sleep 1; cat /proc/net/dev;`
	separator     = "ZZZ\n"
)

// interfaceData models single interface' data for a given host
type interfaceData struct {
	host  string
	name  string
	rates map[string]uint64
	err   error
}

type jobResult struct {
	host string
	err  error
	// es: map[string]map[string]uint64{"eth0": map[string]uint64{"tx-Bps":12000, "rx-Bps":12000}}
	data map[string]map[string]uint64
}

type job struct {
	host            string
	sshClientConfig ssh.ClientConfig
	result          chan<- jobResult
}

// unpackJobResult reads data from a jobResult and unpack it into a slice of interfaceData, one for each interface.
func unpackJobResult(jr *jobResult) []interfaceData {
	data := []interfaceData{}
	if jr.err != nil {
		return []interfaceData{interfaceData{jr.host, "", nil, jr.err}}
	}
	for keyInterface, valueMap := range jr.data {
		i := interfaceData{jr.host, keyInterface, valueMap, nil}
		data = append(data, i)
	}
	return data
}

func sanitizeHost(s *string) {
	if !strings.Contains(*s, ":") {
		*s = fmt.Sprintf("%s:%d", *s, 22)
	}
}

func splitOnSpaces(s string) []string {
	// Remove leading a trailing white spaces that gives wrong results with regexp below
	trimmedS := strings.Trim(s, " ")
	return regexp.MustCompile(`\s+`).Split(trimmedS, -1)
}

// makeValueMap creates map with t2 or t1 values
func makeValueMap(data []string) map[string]uint64 {
	dataMap := make(map[string]uint64)
	for i, s := range data {
		// FIXME parse error
		converted, _ := strconv.ParseUint(s, 10, 64)
		switch i {
		case 0:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["rx-Bps"] = converted
		case 1:
			// here its not packets per second but absolute bytes at t2
			// however we'll store pps later
			dataMap["rx-pps"] = converted
		case 2:
			// here its not errors per second but absolute bytes at t2
			// however we'll store eps later
			dataMap["rx-eps"] = converted
		case 3:
			// here its not drop per second but absolute bytes at t2
			// however we'll store dps later
			dataMap["rx-dps"] = converted
		case 8:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["tx-Bps"] = converted
		case 9:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["tx-pps"] = converted
		case 10:
			// here its not errors per second but absolute bytes at t2
			// however we'll store eps later
			dataMap["tx-eps"] = converted
		case 11:
			// here its not drops per second but absolute bytes at t2
			// however we'll store dps later
			dataMap["tx-dps"] = converted
		}
	}
	return dataMap
}

// calculateRates uses t2 values stored in dataAtT2 by makeValueMap to calculate rates
func calculateRates(dataAtT2, dataAtT1 map[string]uint64) {
	for k, v := range dataAtT2 {
		// assuming that ΔT is always 1 second (sleep 1)
		dataAtT2[k] = v - dataAtT1[k]
	}
}

// parseOutput arranges RemoteCommand output and calculates rates
func parseOutput(out *bytes.Buffer, data map[string]map[string]uint64) error {
	outBytes := bytes.Split(out.Bytes(), []byte(separator))
	// Contains interfaces' value at t1
	outOne := outBytes[0]
	// Contains interfaces' value at t2
	outTwo := outBytes[1]
	scanner := bufio.NewScanner(bytes.NewBuffer(outTwo))
	for scanner.Scan() {
		s := scanner.Text()
		// Excludes titles
		if strings.Contains(s, "|") {
			continue
		}
		splittedRow := strings.Split(s, ":")
		// remove white spaces
		iface := strings.Replace(splittedRow[0], " ", "", -1)
		countersData := splitOnSpaces(splittedRow[1])
		debugPrintln("parsed data @ t2:", iface, countersData)
		data[iface] = makeValueMap(countersData)
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	scanner = bufio.NewScanner(bytes.NewBuffer(outOne))
	for scanner.Scan() {
		s := scanner.Text()
		// Excludes titles
		if strings.Contains(s, "|") {
			continue
		}
		splittedRow := strings.Split(s, ":")
		// remove white spaces
		iface := strings.Replace(splittedRow[0], " ", "", -1)
		countersData := splitOnSpaces(splittedRow[1])
		dataAtT1 := makeValueMap(countersData)
		debugPrintln("parsed data @ t1:", iface, countersData)
		calculateRates(data[iface], dataAtT1)
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func (j *job) getRemoteData() {
	var output bytes.Buffer
	destination := j.host
	sanitizeHost(&destination)
	conn, err := ssh.Dial("tcp", destination, &j.sshClientConfig)
	if err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	session, err := conn.NewSession()
	if err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	defer session.Close()
	session.Stdout = &output
	if err := session.Run(remoteCommand); err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	debugPrintln(output.String())
	data := make(map[string]map[string]uint64)
	if err := parseOutput(&output, data); err != nil {
		j.result <- jobResult{j.host, err, nil}
	}
	j.result <- jobResult{j.host, nil, data}
}

func createSSHConfig(user, passwd string) ssh.ClientConfig {
	sshAuthSock := os.Getenv("SSH_AUTH_SOCK")
	authMethods := []ssh.AuthMethod{ssh.Password(passwd)}
	if sshAuthSock != "" {
		debugPrintln("ssh-agent socket:", sshAuthSock)
		socket, err := net.Dial("unix", sshAuthSock)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		} else {
			agentClient := agent.NewClient(socket)
			authMethod := ssh.PublicKeysCallback(agentClient.Signers)
			authMethods = append(authMethods, authMethod)
			// FIXME works even without calling agent.ForwardToAgent()?
			debugPrintln("ssh-agent configured")
		}
	}
	return ssh.ClientConfig{
		User: user,
		Auth: authMethods,
	}
}

func populateQueue(jobs chan<- job, results chan<- jobResult, hosts []string, sshConfig ssh.ClientConfig) {
	for _, host := range hosts {
		jobs <- job{host, sshConfig, results}
	}
	close(jobs)
}

func evaluateQueue(jobs <-chan job) {
	for j := range jobs {
		j.getRemoteData()
	}
}

func parallelizeWorkers(jQueue chan job) {
	for i := 0; i < workers; i++ {
		go evaluateQueue(jQueue)
	}
}

func presentSingleResult(r *jobResult) {
	fmt.Printf("%20.20s%12.12s%8.8s%8.8s\n", "Host", "Interface", "RX-KBps", "TX-KBps")
	if r.err != nil {
		fmt.Println(r.host, r.err)
	} else {
		// k is remote interface
		// v is a map with rates
		for k, v := range r.data {
			fmt.Printf("%20.20s", r.host)
			fmt.Printf("%12.12s", k)
			fmt.Printf("%8d", uint64(v["rx-Bps"]/1024))
			fmt.Printf("%8d", uint64(v["tx-Bps"]/1024))
			fmt.Println("")
		}
	}
}

func printHead() {
	fmt.Printf(
		"%20s%12s%9s%9s%12s%12s%12s%12s%12s%12s\n",
		"Host",
		"Interface",
		"Rx-Kb/s",
		"Tx-Kb/s",
		"Rx-Pckts/s",
		"Tx-Pckts/s",
		"Rx-Drp/s",
		"Tx-Drp/s",
		"Rx-Err/s",
		"Tx-Err/s",
	)
}

func displayResults(results []interfaceData, noHead bool) {
	for i, r := range results {
		if i%40 == 0 && !noHead {
			printHead()
		}
		if r.err != nil {
			fmt.Fprintln(os.Stderr, "[ERROR]", r.host, r.err)
		} else {
			fmt.Printf("%20s", r.host)
			fmt.Printf("%12s", r.name)
			fmt.Printf("%9d", uint64(r.rates["rx-Bps"]*8/1024))
			fmt.Printf("%9d", uint64(r.rates["tx-Bps"]*8/1024))
			fmt.Printf("%12d", r.rates["rx-pps"])
			fmt.Printf("%12d", r.rates["tx-pps"])
			fmt.Printf("%12d", r.rates["rx-dps"])
			fmt.Printf("%12d", r.rates["tx-dps"])
			fmt.Printf("%12d", r.rates["rx-eps"])
			fmt.Printf("%12d", r.rates["tx-eps"])
			fmt.Println("")
		}
	}
}

func getHostsFromFile(path string) []string {
	// FIXME sanityze user input
	if path == "{filename}" {
		fmt.Fprintln(os.Stderr, "-f is mandatory")
		os.Exit(2)
	}
	bytes, err := ioutil.ReadFile(path)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error reading file", err)
		os.Exit(2)
	}
	hosts := strings.Split(string(bytes), "\n")
	// remove last empty element
	hosts = hosts[:len(hosts)-1]
	debugPrintln("Parsed hosts from file:", hosts)
	return hosts
}

func main() {
	jobsQueue := make(chan job, workers)
	resultQueue := make(chan jobResult, workers)
	hostsFileFlag := flag.String("f", "{filename}", " [FILE] file containing target hosts, one per line.")
	userFlag := flag.String("u", "root", "[USERNAME] ssh username.")
	passwdFlag := flag.String("p", "nopassword", "[PASSWORD] ssh password for remote hosts. Automatically use ssh-agent as fallback.")
	noHeadFlag := flag.Bool("n", false, "Do not show titles.")
	versionFlag := flag.Bool("v", false, "Show version and exit")
	flag.Parse()
	if *versionFlag {
		fmt.Println("RIM - Remote Interface Monitor v1.0.0")
		return
	}
	hosts := getHostsFromFile(*hostsFileFlag)
	sshConfig := createSSHConfig(*userFlag, *passwdFlag)
	resultCounts := 0
	interfacesData := make([]interfaceData, 0, len(hosts))
	runtime.GOMAXPROCS(workers)
	go populateQueue(jobsQueue, resultQueue, hosts, sshConfig)
	go parallelizeWorkers(jobsQueue)
	for {
		// FIXME make a case for timeout
		select {
		case jobResult := <-resultQueue:
			resultCounts++
			interfacesData = append(interfacesData, unpackJobResult(&jobResult)...)
			if resultCounts == len(hosts) {
				displayResults(interfacesData, *noHeadFlag)
				return
			}
		}
	}
}
<commit_msg>Read target hosts from command line<commit_after>// RIM - Remote Interfaces Monitor

/* Copyright (c) 2014 Andrea Masi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */

package main

import (
	"bufio"
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/agent"
)

var workers = runtime.NumCPU()

const (
	remoteCommand = `cat /proc/net/dev; echo ZZZ; sleep 1; cat /proc/net/dev;`
	separator     = "ZZZ\n"
)

// interfaceData models single interface' data for a given host
type interfaceData struct {
	host  string
	name  string
	rates map[string]uint64
	err   error
}

type jobResult struct {
	host string
	err  error
	// es: map[string]map[string]uint64{"eth0": map[string]uint64{"tx-Bps":12000, "rx-Bps":12000}}
	data map[string]map[string]uint64
}

type job struct {
	host            string
	sshClientConfig ssh.ClientConfig
	result          chan<- jobResult
}

// unpackJobResult reads data from a jobResult and unpack it into a slice of interfaceData, one for each interface.
func unpackJobResult(jr *jobResult) []interfaceData {
	data := []interfaceData{}
	if jr.err != nil {
		return []interfaceData{interfaceData{jr.host, "", nil, jr.err}}
	}
	for keyInterface, valueMap := range jr.data {
		i := interfaceData{jr.host, keyInterface, valueMap, nil}
		data = append(data, i)
	}
	return data
}

func sanitizeHost(s *string) {
	if !strings.Contains(*s, ":") {
		*s = fmt.Sprintf("%s:%d", *s, 22)
	}
}

func splitOnSpaces(s string) []string {
	// Remove leading a trailing white spaces that gives wrong results with regexp below
	trimmedS := strings.Trim(s, " ")
	return regexp.MustCompile(`\s+`).Split(trimmedS, -1)
}

// makeValueMap creates map with t2 or t1 values
func makeValueMap(data []string) map[string]uint64 {
	dataMap := make(map[string]uint64)
	for i, s := range data {
		// FIXME parse error
		converted, _ := strconv.ParseUint(s, 10, 64)
		switch i {
		case 0:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["rx-Bps"] = converted
		case 1:
			// here its not packets per second but absolute bytes at t2
			// however we'll store pps later
			dataMap["rx-pps"] = converted
		case 2:
			// here its not errors per second but absolute bytes at t2
			// however we'll store eps later
			dataMap["rx-eps"] = converted
		case 3:
			// here its not drop per second but absolute bytes at t2
			// however we'll store dps later
			dataMap["rx-dps"] = converted
		case 8:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["tx-Bps"] = converted
		case 9:
			// here its not bytes per second but absolute bytes at t2
			// however we'll store Bps later
			dataMap["tx-pps"] = converted
		case 10:
			// here its not errors per second but absolute bytes at t2
			// however we'll store eps later
			dataMap["tx-eps"] = converted
		case 11:
			// here its not drops per second but absolute bytes at t2
			// however we'll store dps later
			dataMap["tx-dps"] = converted
		}
	}
	return dataMap
}

// calculateRates uses t2 values stored in dataAtT2 by makeValueMap to calculate rates
func calculateRates(dataAtT2, dataAtT1 map[string]uint64) {
	for k, v := range dataAtT2 {
		// assuming that ΔT is always 1 second (sleep 1)
		dataAtT2[k] = v - dataAtT1[k]
	}
}

// parseOutput arranges RemoteCommand output and calculates rates
func parseOutput(out *bytes.Buffer, data map[string]map[string]uint64) error {
	outBytes := bytes.Split(out.Bytes(), []byte(separator))
	// Contains interfaces' value at t1
	outOne := outBytes[0]
	// Contains interfaces' value at t2
	outTwo := outBytes[1]
	scanner := bufio.NewScanner(bytes.NewBuffer(outTwo))
	for scanner.Scan() {
		s := scanner.Text()
		// Excludes titles
		if strings.Contains(s, "|") {
			continue
		}
		splittedRow := strings.Split(s, ":")
		// remove white spaces
		iface := strings.Replace(splittedRow[0], " ", "", -1)
		countersData := splitOnSpaces(splittedRow[1])
		debugPrintln("parsed data @ t2:", iface, countersData)
		data[iface] = makeValueMap(countersData)
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	scanner = bufio.NewScanner(bytes.NewBuffer(outOne))
	for scanner.Scan() {
		s := scanner.Text()
		// Excludes titles
		if strings.Contains(s, "|") {
			continue
		}
		splittedRow := strings.Split(s, ":")
		// remove white spaces
		iface := strings.Replace(splittedRow[0], " ", "", -1)
		countersData := splitOnSpaces(splittedRow[1])
		dataAtT1 := makeValueMap(countersData)
		debugPrintln("parsed data @ t1:", iface, countersData)
		calculateRates(data[iface], dataAtT1)
	}
	if err := scanner.Err(); err != nil {
		return err
	}
	return nil
}

func (j *job) getRemoteData() {
	var output bytes.Buffer
	destination := j.host
	sanitizeHost(&destination)
	conn, err := ssh.Dial("tcp", destination, &j.sshClientConfig)
	if err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	session, err := conn.NewSession()
	if err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	defer session.Close()
	session.Stdout = &output
	if err := session.Run(remoteCommand); err != nil {
		j.result <- jobResult{j.host, err, nil}
		return
	}
	debugPrintln(output.String())
	data := make(map[string]map[string]uint64)
	if err := parseOutput(&output, data); err != nil {
		j.result <- jobResult{j.host, err, nil}
	}
	j.result <- jobResult{j.host, nil, data}
}

func createSSHConfig(user, passwd string) ssh.ClientConfig {
	sshAuthSock := os.Getenv("SSH_AUTH_SOCK")
	authMethods := []ssh.AuthMethod{ssh.Password(passwd)}
	if sshAuthSock != "" {
		debugPrintln("ssh-agent socket:", sshAuthSock)
		socket, err := net.Dial("unix", sshAuthSock)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		} else {
			agentClient := agent.NewClient(socket)
			authMethod := ssh.PublicKeysCallback(agentClient.Signers)
			authMethods = append(authMethods, authMethod)
			// FIXME works even without calling agent.ForwardToAgent()?
			debugPrintln("ssh-agent configured")
		}
	}
	return ssh.ClientConfig{
		User: user,
		Auth: authMethods,
	}
}

func populateQueue(jobs chan<- job, results chan<- jobResult, hosts []string, sshConfig ssh.ClientConfig) {
	for _, host := range hosts {
		jobs <- job{host, sshConfig, results}
	}
	close(jobs)
}

func evaluateQueue(jobs <-chan job) {
	for j := range jobs {
		j.getRemoteData()
	}
}

func parallelizeWorkers(jQueue chan job) {
	for i := 0; i < workers; i++ {
		go evaluateQueue(jQueue)
	}
}

func presentSingleResult(r *jobResult) {
	fmt.Printf("%20.20s%12.12s%8.8s%8.8s\n", "Host", "Interface", "RX-KBps", "TX-KBps")
	if r.err != nil {
		fmt.Println(r.host, r.err)
	} else {
		// k is remote interface
		// v is a map with rates
		for k, v := range r.data {
			fmt.Printf("%20.20s", r.host)
			fmt.Printf("%12.12s", k)
			fmt.Printf("%8d", uint64(v["rx-Bps"]/1024))
			fmt.Printf("%8d", uint64(v["tx-Bps"]/1024))
			fmt.Println("")
		}
	}
}

func printHead() {
	fmt.Printf(
		"%20s%12s%9s%9s%12s%12s%12s%12s%12s%12s\n",
		"Host",
		"Interface",
		"Rx-Kb/s",
		"Tx-Kb/s",
		"Rx-Pckts/s",
		"Tx-Pckts/s",
		"Rx-Drp/s",
		"Tx-Drp/s",
		"Rx-Err/s",
		"Tx-Err/s",
	)
}

func displayResults(results []interfaceData, noHead bool) {
	for i, r := range results {
		if i%40 == 0 && !noHead {
			printHead()
		}
		if r.err != nil {
			fmt.Fprintln(os.Stderr, "[ERROR]", r.host, r.err)
		} else {
			fmt.Printf("%20s", r.host)
			fmt.Printf("%12s", r.name)
			fmt.Printf("%9d", uint64(r.rates["rx-Bps"]*8/1024))
			fmt.Printf("%9d", uint64(r.rates["tx-Bps"]*8/1024))
			fmt.Printf("%12d", r.rates["rx-pps"])
			fmt.Printf("%12d", r.rates["tx-pps"])
			fmt.Printf("%12d", r.rates["rx-dps"])
			fmt.Printf("%12d", r.rates["tx-dps"])
			fmt.Printf("%12d", r.rates["rx-eps"])
			fmt.Printf("%12d", r.rates["tx-eps"])
			fmt.Println("")
		}
	}
}

func getHostsFromFile(path string) []string {
	bytes := []byte{}
	err := errors.New("")
	if path == "{filename}" {
		bytes, err = ioutil.ReadAll(os.Stdin)
	} else {
		bytes, err = ioutil.ReadFile(path)
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error reading input", err)
		os.Exit(2)
	}
	hosts := strings.Split(string(bytes), "\n")
	// remove last empty element
	hosts = hosts[:len(hosts)-1]
	debugPrintln("Parsed hosts from file:", hosts)
	return hosts
}

func main() {
	jobsQueue := make(chan job, workers)
	resultQueue := make(chan jobResult, workers)
	hostsFileFlag := flag.String("f", "{filename}", " [FILE] file containing target hosts, one per line.")
	userFlag := flag.String("u", "root", "[USERNAME] ssh username.")
	passwdFlag := flag.String("p", "nopassword", "[PASSWORD] ssh password for remote hosts. Automatically use ssh-agent as fallback.")
	noHeadFlag := flag.Bool("n", false, "Do not show titles.")
	versionFlag := flag.Bool("v", false, "Show version and exit")
	flag.Parse()
	if *versionFlag {
		fmt.Println("RIM - Remote Interface Monitor v1.0.0")
		return
	}
	hosts := getHostsFromFile(*hostsFileFlag)
	sshConfig := createSSHConfig(*userFlag, *passwdFlag)
	resultCounts := 0
	interfacesData := make([]interfaceData, 0, len(hosts))
	runtime.GOMAXPROCS(workers)
	go populateQueue(jobsQueue, resultQueue, hosts, sshConfig)
	go parallelizeWorkers(jobsQueue)
	for {
		// FIXME make a case for timeout
		select {
		case jobResult := <-resultQueue:
			resultCounts++
			interfacesData = append(interfacesData, unpackJobResult(&jobResult)...)
			if resultCounts == len(hosts) {
				displayResults(interfacesData, *noHeadFlag)
				return
			}
		}
	}
}
<|endoftext|>


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

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"sync"
	"sync/atomic"

	"github.com/docker/docker/opts"
	"github.com/docker/docker/pkg/mflag"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env opts.ListOpts
}

func main() {

	options := Options{
		env:     opts.NewListOpts(nil),
	}
	mflag.Var(&options.env, []string{"e", "-env"}, "Set environment variables")

	mflag.Parse()

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	go func() {
		defer dying.Fall()
		// Await Stdin closure, don't care about errors
		_, _ = io.Copy(ioutil.Discard, os.Stdin)
	}()

	go loop(&wg, &dying, options)

	<-dying.Barrier()
}

func makeEnv(opt opts.ListOpts) []string {
	var env []string
	for _, envVar := range opt.GetAll() {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

func loop(wg *sync.WaitGroup, dying *barrier.Barrier, options Options) {
	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)

	client, err := docker.NewClient("unix:///run/docker.sock")
	if err != nil {
		dying.Fall()
		log.Println(err)
		return
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	baseName := path.Base(wd)

	var i uint64
	getName := func() string {
		n := atomic.AddUint64(&i, 1)
		return fmt.Sprint(baseName, "_", n)
	}

	env := makeEnv(options.env)

	var liveMutex sync.Mutex
	var live *Container

	for {

		c := NewContainer(client, getName(), wg, dying)
		c.Env = env

		dying.Forward(&c.Closing)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			go func() {
				for err := range c.Errors {
					log.Println("BUG: Async container error:", err)
				}
			}()

			status, err := c.Run()
			if err != nil {
				log.Println(err)
				c.Failed.Fall()
				return
			}
			log.Println(c.Name, "exit:", status)
		}(c)

		go func(c *Container) {

			log.Println("Awaiting container fate:", c.Name)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				log.Println("(This should never happen?)")
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			liveMutex.Lock()
			defer liveMutex.Unlock()
			previousLive := live

			// Block main exit until the firewall rule has been removed
			wg.Add(1)

			target := c.container.NetworkSettings.PortMappingAPI()[0].PublicPort
			remove, err := ConfigureRedirect(5555, target)
			if err != nil {
				// Firewall rule didn't get applied.
				wg.Done()
				c.err(err)
				return
			}

			live = c
			if previousLive != nil {
				previousLive.Closing.Fall()
			}

			// Networking
			go func() {
				defer wg.Done()

				<-c.Closing.Barrier()
				remove()
			}()
		}(c)

		<-sig

		c.Superceded.Fall()

		log.Println("Signalled!")
	}
}
<commit_msg>Make async errors cause container teardown<commit_after>// Copyright 2014 The Hanoverd Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"
	"strings"
	"sync"
	"sync/atomic"

	"github.com/docker/docker/opts"
	"github.com/docker/docker/pkg/mflag"
	"github.com/fsouza/go-dockerclient"
	"github.com/pwaller/barrier"
)

// DockerErrorStatus returns the HTTP status code represented by `err` or Status
// OK if no error or 0 if err != nil and is not a docker error.
func DockerErrorStatus(err error) int {
	if err, ok := err.(*docker.Error); ok {
		return err.Status
	}
	if err == nil {
		return http.StatusOK
	}
	return 0
}

type Options struct {
	env opts.ListOpts
}

func main() {

	options := Options{
		env:     opts.NewListOpts(nil),
	}
	mflag.Var(&options.env, []string{"e", "-env"}, "Set environment variables")

	mflag.Parse()

	log.Println("Hanoverd")

	var wg sync.WaitGroup
	defer wg.Wait()

	// Fired when we're signalled to exit
	var dying barrier.Barrier
	defer dying.Fall()

	go func() {
		defer dying.Fall()
		// Await Stdin closure, don't care about errors
		_, _ = io.Copy(ioutil.Discard, os.Stdin)
	}()

	go loop(&wg, &dying, options)

	<-dying.Barrier()
}

func makeEnv(opt opts.ListOpts) []string {
	var env []string
	for _, envVar := range opt.GetAll() {
		if strings.Contains(envVar, "=") {
			env = append(env, envVar)
		} else {
			env = append(env, fmt.Sprint(envVar, "=", os.Getenv(envVar)))
		}
	}
	return env
}

func loop(wg *sync.WaitGroup, dying *barrier.Barrier, options Options) {
	sig := make(chan os.Signal)
	signal.Notify(sig, os.Interrupt)

	client, err := docker.NewClient("unix:///run/docker.sock")
	if err != nil {
		dying.Fall()
		log.Println(err)
		return
	}

	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	baseName := path.Base(wd)

	var i uint64
	getName := func() string {
		n := atomic.AddUint64(&i, 1)
		return fmt.Sprint(baseName, "_", n)
	}

	env := makeEnv(options.env)

	var liveMutex sync.Mutex
	var live *Container

	for {

		c := NewContainer(client, getName(), wg, dying)
		c.Env = env

		// Global exit should cause container exit
		dying.Forward(&c.Closing)

		wg.Add(1)
		go func(c *Container) {
			defer wg.Done()

			go func() {
				for err := range c.Errors {
					log.Println("BUG: Async container error:", err)
					// TODO(pwaller): If this case is hit we might not want to
					// tear the container down really.
					c.Failed.Fall()
					c.Closing.Fall()
				}
			}()

			status, err := c.Run()
			if err != nil {
				log.Println(err)
				c.Failed.Fall()
				return
			}
			log.Println(c.Name, "exit:", status)
		}(c)

		go func(c *Container) {

			log.Println("Awaiting container fate:", c.Name)
			select {
			case <-c.Failed.Barrier():
				log.Println("Container failed before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Superceded.Barrier():
				log.Println("Container superceded before going live:", c.Name)
				c.Closing.Fall()
				return
			case <-c.Closing.Barrier():
				log.Println("Container closed before going live:", c.Name)
				log.Println("(This should never happen?)")
				return

			case <-c.Ready.Barrier():
			}

			log.Println("Container going live:", c.Name)

			liveMutex.Lock()
			defer liveMutex.Unlock()
			previousLive := live

			// Block main exit until the firewall rule has been removed
			wg.Add(1)

			target := c.container.NetworkSettings.PortMappingAPI()[0].PublicPort
			remove, err := ConfigureRedirect(5555, target)
			if err != nil {
				// Firewall rule didn't get applied.
				wg.Done()
				c.err(err)
				return
			}

			live = c
			if previousLive != nil {
				previousLive.Closing.Fall()
			}

			// Networking
			go func() {
				defer wg.Done()

				<-c.Closing.Barrier()
				remove()
			}()
		}(c)

		<-sig

		c.Superceded.Fall()

		log.Println("Signalled!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	_ "net/http/pprof"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/neo-utils-go"
	"github.com/Financial-Times/subjects-rw-neo4j/subjects"
	log "github.com/Sirupsen/logrus"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
	"strconv"
)

func init() {
	log.SetFormatter(new(log.JSONFormatter))
}

func main() {
	app := cli.App("subjetcs-rw-neo4j", "A RESTful API for managing Subjects in neo4j")
	neoURL := stringEnv("NEO_URL", "http://localhost:7474/db/data") //"neo4j endpoint URL"
	port := intEnv("PORT", 8080)                                    //"Port to listen on"
	batchSize := intEnv("BATCH_SIZE", 1024)                         //"Maximum number of statements to execute per batch"
	graphiteTCPAddress := stringEnv("GRAPHITE_TCP_ADDRESS", "")     //"Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally)"
	graphitePrefix := stringEnv("GRAPHITE_PREFIX", "")              //"Prefix to use. Should start with content, include the environment, and the host name. e.g. coco.pre-prod.subjects-rw-neo4j.1"
	logMetrics := boolEnv("LOG_METRICS", false)                     //"Whether to log metrics. Set to true if running locally and you want metrics output"

	app.Action = func() {
		db, err := neoism.Connect(neoURL)
		if err != nil {
			log.Errorf("Could not connect to neo4j, error=[%s]\n", err)
		}

		batchRunner := neoutils.NewBatchCypherRunner(neoutils.StringerDb{db}, batchSize)
		subjectsDriver := subjects.NewCypherSubjectsService(batchRunner, db)

		baseftrwapp.OutputMetricsIfRequired(graphiteTCPAddress, graphitePrefix, logMetrics)

		engs := map[string]baseftrwapp.Service{
			"subjects": subjectsDriver,
		}

		var checks []v1a.Check
		for _, e := range engs {
			checks = append(checks, makeCheck(e, batchRunner))
		}

		baseftrwapp.RunServer(engs,
			v1a.Handler("ft-subjects_rw_neo4j ServiceModule", "Writes 'subjects' to Neo4j, usually as part of a bulk upload done on a schedule", checks...),
			port, "subjects-rw-neo4j", "local")
	}

	app.Run(os.Args)
}

func makeCheck(service baseftrwapp.Service, cr neoutils.CypherRunner) v1a.Check {
	return v1a.Check{
		BusinessImpact:   "Cannot read/write subjects via this writer",
		Name:             "Check connectivity to Neo4j - neoUrl is a parameter in hieradata for this service",
		PanicGuide:       "TODO - write panic guide",
		Severity:         1,
		TechnicalSummary: fmt.Sprintf("Cannot connect to Neo4j instance %s with at least one subject loaded in it", cr),
		Checker:          func() (string, error) { return "", service.Check() },
	}
}

func stringEnv(key string, def string) string {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	return v
}

func intEnv(key string, def int) int {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	i, err := strconv.Atoi(v)
	if err != nil {
		log.Errorf("Could not convert %s:\"%s\" to int. Using default value: %d", key, v, def)
	}
	return i
}

func boolEnv(key string, def bool) bool {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	b, err := strconv.ParseBool(v)
	if err != nil {
		log.Errorf("Could not convert %s:\"%s\" to int. Using default value: %d", key, v, def)
	}
	return b
}
<commit_msg>Support both flags and envs<commit_after>package main

import (
	"fmt"
	_ "net/http/pprof"
	"os"

	"github.com/Financial-Times/base-ft-rw-app-go"
	"github.com/Financial-Times/go-fthealth/v1a"
	"github.com/Financial-Times/neo-utils-go"
	"github.com/Financial-Times/subjects-rw-neo4j/subjects"
	log "github.com/Sirupsen/logrus"
	"github.com/jawher/mow.cli"
	"github.com/jmcvetta/neoism"
)

func init() {
	log.SetFormatter(new(log.JSONFormatter))
}

func main() {
	app := cli.App("subjetcs-rw-neo4j", "A RESTful API for managing Subjects in neo4j")
	neoURL := app.String(cli.StringOpt{
		Name:   "neo-url",
		Value:  "http://localhost:7474/db/data",
		Desc:   "neo4j endpoint URL",
		EnvVar: "NEO_URL",
	})
	graphiteTCPAddress := app.String(cli.StringOpt{
		Name:   "graphite-tcp-address",
		Value:  "",
		Desc:   "Graphite TCP address, e.g. graphite.ft.com:2003. Leave as default if you do NOT want to output to graphite (e.g. if running locally",
		EnvVar: "GRAPHITE_TCP_ADDRESS",
	})
	graphitePrefix := app.String(cli.StringOpt{
		Name:   "graphite-prefix",
		Value:  "",
		Desc:   "Prefix to use. Should start with content, include the environment, and the host name. e.g. coco.pre-prod.subjects-rw-neo4j.1",
		EnvVar: "GRAPHITE_PREFIX",
	})
	port := app.Int(cli.IntOpt{
		Name:   "port",
		Value:  8080,
		Desc:   "Port to listen on",
		EnvVar: "PORT",
	})
	batchSize := app.Int(cli.IntOpt{
		Name:   "batch-size",
		Value:  1024,
		Desc:   "Maximum number of statements to execute per batch",
		EnvVar: "BATCH_SIZE",
	})
	logMetrics := app.Bool(cli.BoolOpt{
		Name:   "log-metrics",
		Value:  false,
		Desc:   "Whether to log metrics. Set to true if running locally and you want metrics output",
		EnvVar: "LOG_METRICS",
	})

	app.Action = func() {
		db, err := neoism.Connect(*neoURL)
		if err != nil {
			log.Errorf("Could not connect to neo4j, error=[%s]\n", err)
		}

		batchRunner := neoutils.NewBatchCypherRunner(neoutils.StringerDb{db}, *batchSize)
		subjectsDriver := subjects.NewCypherSubjectsService(batchRunner, db)

		baseftrwapp.OutputMetricsIfRequired(*graphiteTCPAddress, *graphitePrefix, *logMetrics)

		engs := map[string]baseftrwapp.Service{
			"subjects": subjectsDriver,
		}

		var checks []v1a.Check
		for _, e := range engs {
			checks = append(checks, makeCheck(e, batchRunner))
		}

		baseftrwapp.RunServer(engs,
			v1a.Handler("ft-subjects_rw_neo4j ServiceModule", "Writes 'subjects' to Neo4j, usually as part of a bulk upload done on a schedule", checks...),
			*port, "subjects-rw-neo4j", "local")
	}

	app.Run(os.Args)
}

func makeCheck(service baseftrwapp.Service, cr neoutils.CypherRunner) v1a.Check {
	return v1a.Check{
		BusinessImpact:   "Cannot read/write subjects via this writer",
		Name:             "Check connectivity to Neo4j - neoUrl is a parameter in hieradata for this service",
		PanicGuide:       "TODO - write panic guide",
		Severity:         1,
		TechnicalSummary: fmt.Sprintf("Cannot connect to Neo4j instance %s with at least one subject loaded in it", cr),
		Checker:          func() (string, error) { return "", service.Check() },
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-tools/go-xamarin/builder"
	"github.com/bitrise-tools/go-xamarin/buildtool"
	"github.com/bitrise-tools/go-xamarin/constants"
	"github.com/bitrise-tools/go-xamarin/project"
)

func exportEnvironmentWithEnvman(keyStr, valueStr string) error {
	cmd := cmdex.NewCommand("envman", "add", "--key", keyStr)
	cmd.SetStdin(strings.NewReader(valueStr))
	return cmd.Run()
}

func exportArtifactDir(pth, deployDir, envKey string) error {
	base := filepath.Base(pth)
	deployPth := filepath.Join(deployDir, base)

	if err := cmdex.CopyDir(pth, deployPth, false); err != nil {
		return fmt.Errorf("Failed to move artifact (%s) to (%s)", pth, deployPth)
	}

	if err := exportEnvironmentWithEnvman(envKey, deployPth); err != nil {
		return fmt.Errorf("Failed to export artifact path (%s) into (%s)", deployPth, envKey)
	}

	log.Done("artifact path (%s) is available in (%s) environment variable", deployPth, envKey)

	return nil
}

func exportArtifactFile(pth, deployDir, envKey string) error {
	base := filepath.Base(pth)
	deployPth := filepath.Join(deployDir, base)

	if err := cmdex.CopyFile(pth, deployPth); err != nil {
		return fmt.Errorf("Failed to move artifact (%s) to (%s)", pth, deployPth)
	}

	if err := exportEnvironmentWithEnvman(envKey, deployPth); err != nil {
		return fmt.Errorf("Failed to export artifact path (%s) into (%s)", deployPth, envKey)
	}

	log.Done("artifact path (%s) is available in (%s) environment variable", deployPth, envKey)

	return nil
}

// ConfigsModel ...
type ConfigsModel struct {
	XamarinSolution      string
	XamarinConfiguration string
	XamarinPlatform      string
	ProjectTypeWhitelist string
	ForceMDTool          string

	// Other configs
	DeployDir string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		XamarinSolution:      os.Getenv("xamarin_solution"),
		XamarinConfiguration: os.Getenv("xamarin_configuration"),
		XamarinPlatform:      os.Getenv("xamarin_platform"),
		ProjectTypeWhitelist: os.Getenv("project_type_whitelist"),
		ForceMDTool:          os.Getenv("force_mdtool"),

		DeployDir: os.Getenv("BITRISE_DEPLOY_DIR"),
	}
}

func (configs ConfigsModel) print() {
	log.Info("Configs:")
	log.Detail("- XamarinSolution: %s", configs.XamarinSolution)
	log.Detail("- XamarinConfiguration: %s", configs.XamarinConfiguration)
	log.Detail("- XamarinPlatform: %s", configs.XamarinPlatform)
	log.Detail("- ProjectTypeWhitelist: %s", configs.ProjectTypeWhitelist)
	log.Detail("- ForceMDTool: %s", configs.ForceMDTool)
	fmt.Println()

	log.Detail("- DeployDir: %s", configs.DeployDir)
}

func (configs ConfigsModel) validate() error {
	// required
	if configs.XamarinSolution == "" {
		return errors.New("No XamarinSolution parameter specified!")
	}
	if exist, err := pathutil.IsPathExists(configs.XamarinSolution); err != nil {
		return fmt.Errorf("Failed to check if XamarinSolution exist at: %s, error: %s", configs.XamarinSolution, err)
	} else if !exist {
		return fmt.Errorf("XamarinSolution not exist at: %s", configs.XamarinSolution)
	}

	if configs.XamarinConfiguration == "" {
		return errors.New("No XamarinConfiguration parameter specified!")
	}

	if configs.XamarinPlatform == "" {
		return errors.New("No XamarinPlatform parameter specified!")
	}

	return nil
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		fmt.Println()
		log.Error("Issue with input: %s", err)
		fmt.Println()

		os.Exit(1)
	}

	// parse project type filters
	projectTypeWhitelist := []constants.ProjectType{}
	if len(configs.ProjectTypeWhitelist) > 0 {
		split := strings.Split(configs.ProjectTypeWhitelist, ",")
		for _, item := range split {
			item := strings.TrimSpace(item)
			projectType, err := constants.ParseProjectType(item)
			if err != nil {
				log.Error("Failed to parse project type (%s), error: %s", item, err)
				os.Exit(1)
			}
			projectTypeWhitelist = append(projectTypeWhitelist, projectType)
		}
	}
	// ---

	// build
	fmt.Println()
	log.Info("Building all projects in solution: %s", configs.XamarinSolution)

	builder, err := builder.New(configs.XamarinSolution, projectTypeWhitelist, (configs.ForceMDTool == "yes"))
	if err != nil {
		log.Error("Failed to create xamarin builder, error: %s", err)
		os.Exit(1)
	}

	callback := func(project project.Model, command buildtool.PrintableCommand) {
		fmt.Println()
		log.Info("Building project: %s", project.Name)
		log.Done("$ %s", command.PrintableCommand())
		fmt.Println()
	}

	if err := builder.BuildAllProjects(configs.XamarinConfiguration, configs.XamarinPlatform, callback); err != nil {
		log.Error("Build failed, error: %s", err)
		os.Exit(1)
	}

	output, err := builder.CollectOutput(configs.XamarinConfiguration, configs.XamarinPlatform)
	if err != nil {
		log.Error("Failed to collect generated outputs, error: %s", err)
		os.Exit(1)
	}
	// ---

	// export outputs
	fmt.Println()
	log.Info("Exporting generated outputs...")

	for projectType, outputMap := range output {
		fmt.Println()
		log.Info("%s outputs:", projectType)

		switch projectType {
		case constants.ProjectTypeIos:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg iOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_IOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			ipaPth, ok := outputMap[constants.OutputTypeIPA]
			if ok {
				log.Detail("exporintg iOS ipa: %s", ipaPth)
				if err := exportArtifactFile(ipaPth, configs.DeployDir, "BITRISE_IOS_IPA_PATH"); err != nil {
					log.Error("Failed to export ipa, error: %s", err)
					os.Exit(1)
				}
			}
			dsymPth, ok := outputMap[constants.OutputTypeDSYM]
			if ok {
				log.Detail("exporintg iOS dSYM: %s", dsymPth)
				if err := exportArtifactFile(dsymPth, configs.DeployDir, "BITRISE_IOS_DSYM_PATH"); err != nil {
					log.Error("Failed to export dsym, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeAndroid:
			apkPth, ok := outputMap[constants.OutputTypeAPK]
			if ok {
				log.Detail("exporintg apk: %s", apkPth)
				if err := exportArtifactFile(apkPth, configs.DeployDir, "BITRISE_APK_PATH"); err != nil {
					log.Error("Failed to export apk, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeMac:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg macOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_MACOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			appPth, ok := outputMap[constants.OutputTypeAPP]
			if ok {
				log.Detail("exporintg macOS app: %s", appPth)
				if err := exportArtifactDir(appPth, configs.DeployDir, "BITRISE_MACOS_APP_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			pkgPth, ok := outputMap[constants.OutputTypePKG]
			if ok {
				log.Detail("exporintg macOS pkg: %s", pkgPth)
				if err := exportArtifactFile(pkgPth, configs.DeployDir, "BITRISE_MACOS_PKG_PATH"); err != nil {
					log.Error("Failed to export pkg, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeTVOs:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg tvOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_TVOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			ipaPth, ok := outputMap[constants.OutputTypeIPA]
			if ok {
				log.Detail("exporintg tvOS ipa: %s", ipaPth)
				if err := exportArtifactFile(ipaPth, configs.DeployDir, "BITRISE_TVOS_IPA_PATH"); err != nil {
					log.Error("Failed to export ipa, error: %s", err)
					os.Exit(1)
				}
			}
			dsymPth, ok := outputMap[constants.OutputTypeDSYM]
			if ok {
				log.Detail("exporintg tvOS dSYM: %s", dsymPth)
				if err := exportArtifactFile(dsymPth, configs.DeployDir, "BITRISE_TVOS_DSYM_PATH"); err != nil {
					log.Error("Failed to export dsym, error: %s", err)
					os.Exit(1)
				}
			}
		}
	}
	// ---
}
<commit_msg>zip dsym<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-tools/go-xamarin/builder"
	"github.com/bitrise-tools/go-xamarin/buildtool"
	"github.com/bitrise-tools/go-xamarin/constants"
	"github.com/bitrise-tools/go-xamarin/project"
)

func exportEnvironmentWithEnvman(keyStr, valueStr string) error {
	cmd := cmdex.NewCommand("envman", "add", "--key", keyStr)
	cmd.SetStdin(strings.NewReader(valueStr))
	return cmd.Run()
}

func exportZipedArtifactDir(pth, deployDir, envKey string) error {
	parentDir := filepath.Dir(pth)
	dirName := filepath.Base(pth)
	deployPth := filepath.Join(deployDir, dirName+".zip")
	cmd := cmdex.NewCommand("/usr/bin/zip", "-rTy", deployPth, dirName)
	cmd.SetDir(parentDir)
	out, err := cmd.RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return fmt.Errorf("Failed to zip dir: %s, output: %s, error: %s", pth, out, err)
	}

	if err := exportEnvironmentWithEnvman(envKey, deployPth); err != nil {
		return fmt.Errorf("Failed to export artifact path (%s) into (%s)", deployPth, envKey)
	}

	log.Done("artifact path (%s) is available in (%s) environment variable", deployPth, envKey)

	return nil
}

func exportArtifactDir(pth, deployDir, envKey string) error {
	base := filepath.Base(pth)
	deployPth := filepath.Join(deployDir, base)

	if err := cmdex.CopyDir(pth, deployPth, false); err != nil {
		return fmt.Errorf("Failed to move artifact (%s) to (%s)", pth, deployPth)
	}

	if err := exportEnvironmentWithEnvman(envKey, deployPth); err != nil {
		return fmt.Errorf("Failed to export artifact path (%s) into (%s)", deployPth, envKey)
	}

	log.Done("artifact path (%s) is available in (%s) environment variable", deployPth, envKey)

	return nil
}

func exportArtifactFile(pth, deployDir, envKey string) error {
	base := filepath.Base(pth)
	deployPth := filepath.Join(deployDir, base)

	if err := cmdex.CopyFile(pth, deployPth); err != nil {
		return fmt.Errorf("Failed to move artifact (%s) to (%s)", pth, deployPth)
	}

	if err := exportEnvironmentWithEnvman(envKey, deployPth); err != nil {
		return fmt.Errorf("Failed to export artifact path (%s) into (%s)", deployPth, envKey)
	}

	log.Done("artifact path (%s) is available in (%s) environment variable", deployPth, envKey)

	return nil
}

// ConfigsModel ...
type ConfigsModel struct {
	XamarinSolution      string
	XamarinConfiguration string
	XamarinPlatform      string
	ProjectTypeWhitelist string
	ForceMDTool          string

	// Other configs
	DeployDir string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		XamarinSolution:      os.Getenv("xamarin_solution"),
		XamarinConfiguration: os.Getenv("xamarin_configuration"),
		XamarinPlatform:      os.Getenv("xamarin_platform"),
		ProjectTypeWhitelist: os.Getenv("project_type_whitelist"),
		ForceMDTool:          os.Getenv("force_mdtool"),

		DeployDir: os.Getenv("BITRISE_DEPLOY_DIR"),
	}
}

func (configs ConfigsModel) print() {
	log.Info("Configs:")
	log.Detail("- XamarinSolution: %s", configs.XamarinSolution)
	log.Detail("- XamarinConfiguration: %s", configs.XamarinConfiguration)
	log.Detail("- XamarinPlatform: %s", configs.XamarinPlatform)
	log.Detail("- ProjectTypeWhitelist: %s", configs.ProjectTypeWhitelist)
	log.Detail("- ForceMDTool: %s", configs.ForceMDTool)
	fmt.Println()

	log.Detail("- DeployDir: %s", configs.DeployDir)
}

func (configs ConfigsModel) validate() error {
	// required
	if configs.XamarinSolution == "" {
		return errors.New("No XamarinSolution parameter specified!")
	}
	if exist, err := pathutil.IsPathExists(configs.XamarinSolution); err != nil {
		return fmt.Errorf("Failed to check if XamarinSolution exist at: %s, error: %s", configs.XamarinSolution, err)
	} else if !exist {
		return fmt.Errorf("XamarinSolution not exist at: %s", configs.XamarinSolution)
	}

	if configs.XamarinConfiguration == "" {
		return errors.New("No XamarinConfiguration parameter specified!")
	}

	if configs.XamarinPlatform == "" {
		return errors.New("No XamarinPlatform parameter specified!")
	}

	return nil
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		fmt.Println()
		log.Error("Issue with input: %s", err)
		fmt.Println()

		os.Exit(1)
	}

	// parse project type filters
	projectTypeWhitelist := []constants.ProjectType{}
	if len(configs.ProjectTypeWhitelist) > 0 {
		split := strings.Split(configs.ProjectTypeWhitelist, ",")
		for _, item := range split {
			item := strings.TrimSpace(item)
			projectType, err := constants.ParseProjectType(item)
			if err != nil {
				log.Error("Failed to parse project type (%s), error: %s", item, err)
				os.Exit(1)
			}
			projectTypeWhitelist = append(projectTypeWhitelist, projectType)
		}
	}
	// ---

	// build
	fmt.Println()
	log.Info("Building all projects in solution: %s", configs.XamarinSolution)

	builder, err := builder.New(configs.XamarinSolution, projectTypeWhitelist, (configs.ForceMDTool == "yes"))
	if err != nil {
		log.Error("Failed to create xamarin builder, error: %s", err)
		os.Exit(1)
	}

	callback := func(project project.Model, command buildtool.PrintableCommand) {
		fmt.Println()
		log.Info("Building project: %s", project.Name)
		log.Done("$ %s", command.PrintableCommand())
		fmt.Println()
	}

	if err := builder.BuildAllProjects(configs.XamarinConfiguration, configs.XamarinPlatform, callback); err != nil {
		log.Error("Build failed, error: %s", err)
		os.Exit(1)
	}

	output, err := builder.CollectOutput(configs.XamarinConfiguration, configs.XamarinPlatform)
	if err != nil {
		log.Error("Failed to collect generated outputs, error: %s", err)
		os.Exit(1)
	}
	// ---

	// export outputs
	fmt.Println()
	log.Info("Exporting generated outputs...")

	for projectType, outputMap := range output {
		fmt.Println()
		log.Info("%s outputs:", projectType)

		switch projectType {
		case constants.ProjectTypeIos:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg iOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_IOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			ipaPth, ok := outputMap[constants.OutputTypeIPA]
			if ok {
				log.Detail("exporintg iOS ipa: %s", ipaPth)
				if err := exportArtifactFile(ipaPth, configs.DeployDir, "BITRISE_IOS_IPA_PATH"); err != nil {
					log.Error("Failed to export ipa, error: %s", err)
					os.Exit(1)
				}
			}
			dsymPth, ok := outputMap[constants.OutputTypeDSYM]
			if ok {
				log.Detail("exporintg iOS dSYM: %s", dsymPth)
				if err := exportZipedArtifactDir(dsymPth, configs.DeployDir, "BITRISE_IOS_DSYM_PATH"); err != nil {
					log.Error("Failed to export dsym, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeAndroid:
			apkPth, ok := outputMap[constants.OutputTypeAPK]
			if ok {
				log.Detail("exporintg apk: %s", apkPth)
				if err := exportArtifactFile(apkPth, configs.DeployDir, "BITRISE_APK_PATH"); err != nil {
					log.Error("Failed to export apk, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeMac:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg macOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_MACOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			appPth, ok := outputMap[constants.OutputTypeAPP]
			if ok {
				log.Detail("exporintg macOS app: %s", appPth)
				if err := exportArtifactDir(appPth, configs.DeployDir, "BITRISE_MACOS_APP_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			pkgPth, ok := outputMap[constants.OutputTypePKG]
			if ok {
				log.Detail("exporintg macOS pkg: %s", pkgPth)
				if err := exportArtifactFile(pkgPth, configs.DeployDir, "BITRISE_MACOS_PKG_PATH"); err != nil {
					log.Error("Failed to export pkg, error: %s", err)
					os.Exit(1)
				}
			}
		case constants.ProjectTypeTVOs:
			xcarchivePth, ok := outputMap[constants.OutputTypeXCArchive]
			if ok {
				log.Detail("exporintg tvOS xcarchive: %s", xcarchivePth)
				if err := exportArtifactDir(xcarchivePth, configs.DeployDir, "BITRISE_TVOS_XCARCHIVE_PATH"); err != nil {
					log.Error("Failed to export xcarchive, error: %s", err)
					os.Exit(1)
				}
			}
			ipaPth, ok := outputMap[constants.OutputTypeIPA]
			if ok {
				log.Detail("exporintg tvOS ipa: %s", ipaPth)
				if err := exportArtifactFile(ipaPth, configs.DeployDir, "BITRISE_TVOS_IPA_PATH"); err != nil {
					log.Error("Failed to export ipa, error: %s", err)
					os.Exit(1)
				}
			}
			dsymPth, ok := outputMap[constants.OutputTypeDSYM]
			if ok {
				log.Detail("exporintg tvOS dSYM: %s", dsymPth)
				if err := exportZipedArtifactDir(dsymPth, configs.DeployDir, "BITRISE_TVOS_DSYM_PATH"); err != nil {
					log.Error("Failed to export dsym, error: %s", err)
					os.Exit(1)
				}
			}
		}
	}
	// ---
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"
	"time"
)

var replace = map[string]func(){
	"nnf":       nnf,
	"nnl":       nnl,
	"dbg":       dbg,
	"openFile":  openFile,
	"readFile":  readFile,
	"getURL":    getURL,
	"reqStdin":  reqStdin,
	"goMain":    goMain,
	"tempFile":  tempFile,
	"serveHTTP": serveHTTP,
	"pymain":    pyMain,
	"html5":     html5,
	"now":       now,
	"ubb":       bash,
	"ubp":       python,
	"gomain":    goMain,
	"flagsh":    flagsh,
	"dummyType": dummyType,
	"jm":        jsonMarshal,
	"ju":        jsonUnmarshal,
	"rb":        readBody,
	"watcher":   watcher,
}

var update = map[string]func(string){
	"fpl(":  fpl,
	"lpf(":  lpf,
	"lpl(":  lpl,
	"fpf(":  fpf,
	"hfunc": hfunc,
	"ow:":   pyOpenWrite,
	"ul":    ul,
}

var modify = map[string]func(string){
	"_ctx,": contextArg,}
func main() {
	if os.Getenv("shortcuts") == "off" {
		return
	}

	stat, err := os.Stdin.Stat()
	if err != nil {
		log.Fatal(err)
	}
	if stat.Mode()&os.ModeCharDevice != 0 {
		log.Fatal("please pipe in some data")
	}

	s := bufio.NewScanner(os.Stdin)
	var lastBlank bool

	for s.Scan() {
		line := s.Text()
		trim := strings.TrimSpace(line)

		if f, found := replace[trim]; found {
			f()
			continue
		}

		var replaced bool
		for pre , f := range update {
			if strings.HasPrefix(trim, pre) {
				f(line)
				replaced = true
				break
			}

		}

		for pre, f := range modify {
			if strings.Contains(line, pre) {
				f(line)
				replaced = true
				break
			}
		}

		if replaced {
			continue
		}

		if strings.TrimSpace(line) == "" {
			if lastBlank {
				continue
			}
			lastBlank = true
		} else {
			lastBlank = false
		}
		fmt.Println(line)
	}
}

func nnf() {
	fmt.Println(`if err != nil{
	 log.Fatalf("Failed to do something: %s\n", err)
	 }`)
}

func nnl() {
	fmt.Println(`if err != nil{
	 log.Printf("Failed to do something: %s\n", err)
	 }`)
}

func dbg() {
	weekday := string([]rune(time.Now().Weekday().String())[0])
	day := time.Now().Day()
	fmt.Printf(`log.Printf("%s%d %%v", x)\n`, weekday, day)
}

func lpf(line string) {
	fmt.Println(strings.Replace(line, "lpf(", "log.Printf(", 1))
}

func fpf(line string) {
	fmt.Println(strings.Replace(line, "fpf(", "fmt.Printf(", 1))
}

func lpl(line string) {
	fmt.Println(strings.Replace(line, "lpl(", "log.Println(", 1))
}

func fpl(line string) {
	fmt.Println(strings.Replace(line, "fpl(", "fmt.Println(", 1))
}

func goMain() {
	fmt.Println(`package main

import (
    "fmt"
)

func main() {
    fmt.Println("gopher")
}
`)
}

func serveHTTP() {
	fmt.Println(`package main

import (
    "fmt"
	 "net/http"
)

func main() {
    http.HandleFunc("/", index)
	 http.ListenAndServe(":8080", nil)
}

func index(w http.ResponseWriter, r *http.Request){
	 fmt.Fprintf(w, "hello")
}
`)
}

func pyMain() {
	fmt.Println(`#!/usr/bin/env python3
"""
You should probably write something here.
"""

def main():
    """
    Do the thing.
    """
    print("python")

if __name__ == '__main__':
    main()
`)
}

func html5() {
	fmt.Println(`<!DOCTYPE html>

		 <meta charset="UTF-8">
		 <title>title</title>
        <link rel="stylesheet" href="https://aoeus.com/milligram.min.css" type="text/css">
		 <meta name="viewport" content="width-device-width, initial-scale=1">

topic

content

`)
}

func hfunc(line string) {
	parts := strings.Split(line, " ")
	name := "index"
	if len(parts) > 1 {
		name = parts[1]
	}
	fmt.Printf(`func %s(w http.ResponseWriter, r *http.Request){
	 }`, name)
}

func pyOpenWrite(line string) {
	l := len(line) - len(strings.TrimLeft(line, " "))
	pad := strings.Repeat(" ", l)
	lines := []string{
		`with open("out.txt", "wb") as raw:`,
		`    raw.write("{0}\n".format(msg))`,
	}

	for _, line = range lines {
		fmt.Printf("%s%s\n", pad, line)
	}

}

func contextArg(line string) {
	strings.Replace(line, "_ctx,", "ctx context.Context,", 1)
    fmt.Printf("%s", line)
}

func ul(line string) {
	trim := strings.TrimSpace(line)
	margin := len(line) - len(strings.TrimLeft(trim, " \t"))
	padding := strings.Repeat(" ", margin)
	fmt.Printf(padding)
	fmt.Println("
")
	for i := 0; i < 3; i++ {
		fmt.Printf(padding)
		fmt.Println("\t
")
		fmt.Printf(padding)
		fmt.Println("\t\tthing")
		fmt.Printf(padding)
		fmt.Println("\t
")
	}
	fmt.Printf(padding)
	fmt.Println("
")

}

func openFile() {
	fmt.Println(`f, err := os.Open(filename)
	 if err != nil {
		 log.Printf("Unable to open %q: %s\n", filename, err)
	 }
	 defer f.Close()`)
}

func readFile() {
	fmt.Println(`b, err := ioutil.ReadFile(filename)
	 if err != nil {
		 log.Printf("Unable to open %q: %s\n", filename, err)
	 }`)
}

func getURL() {
	fmt.Println(`resp, err := http.Get(link)
	 if err != nil {
		 log.Printf("Unable to fetch %q: %s\n", link, err)
		 return
	 }
	 defer resp.Body.Close()
	 b, err := ioutil.ReadAll(resp.Body)
	 if err != nil {
		 log.Printf("Unable to read response from  %q: %s\n", link, err)
		 return
	 }
	 `)
}

func reqStdin() {
	fmt.Println(`stat, err := os.Stdin.Stat()
	 if err != nil {
		 log.Fatal(err)
	 }
	 if stat.Mode()&os.ModeCharDevice != 0 {
		 log.Fatal("please pipe in some data")
	 }`)
}

func tempFile() {
	fmt.Println(`t, err := ioutil.TempFile("", "temp")
if err != nil{
	 log.Fatalf("Unable to create temp file: %s\n", err)
}
fmt.Printf("Created temp file %q\n", t.Name())
defer t.Close()
`)
}

func now() {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}

func bash() {
	fmt.Println("#!/usr/bin/env bash")
}

func python() {
	fmt.Println("#!/usr/bin/env python")
}

func flagsh() {

	fmt.Println(`#!/usr/bin/env bash

flag=$(mktemp)
touch $flag

while true; do
sleep 5
    find . -mmin -1 -name '*.go' 2>>/dev/null | while read file; do
        if [[ "$file" -nt $flag ]]; then
            if [[ "$file" == "$flag" ]]; then
                continue
            fi
            echo "$file was updated"
            touch $flag
        fi
    done
done
`)
}

func dummyType() {
	fmt.Println(`type dummy struct {
    thing string
    size int
    color string
}
`)
}
func jsonMarshal() {
	fmt.Println(`b, err := json.Marshal(x)
    if err != nil{
        log.Fatalf("Failed to do something: %s\n", err)
	 } `)
}

func jsonUnmarshal() {
	fmt.Println(`var x thing
err = json.Unmarshal(b, &x)
return x, err
`)
}

func readBody() {
	fmt.Println(`b, err := ioutil.ReadAll(r.Body)
	 if err != nil {
		 return err
	 }
	 defer r.Body.Close()`)
}

func watcher() {
	fmt.Println(`#!/usr/bin/env bash

bin=monkey
flag=$(mktemp)
code=main.go

function cleanup() {
    pkill $bin
    rm -f $bin
    rm -f $flag
    exit
}

trap cleanup SIGINT SIGTERM

while true
do
    if [ ! "$code" -nt $flag ]; then
        sleep 5
        continue
    fi
    go build -o $bin $code || { touch $flag; continue; }
    pkill $bin
    ./$bin &
    sleep 1
    ./tests.sh
    touch $flag
    sleep 15
done`)
}

<commit_msg>fix ctx replacement issue<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strings"
	"time"
)

var replace = map[string]func(){
	"nnf":       nnf,
	"nnl":       nnl,
	"dbg":       dbg,
	"openFile":  openFile,
	"readFile":  readFile,
	"getURL":    getURL,
	"reqStdin":  reqStdin,
	"goMain":    goMain,
	"tempFile":  tempFile,
	"serveHTTP": serveHTTP,
	"pymain":    pyMain,
	"html5":     html5,
	"now":       now,
	"ubb":       bash,
	"ubp":       python,
	"gomain":    goMain,
	"flagsh":    flagsh,
	"dummyType": dummyType,
	"jm":        jsonMarshal,
	"ju":        jsonUnmarshal,
	"rb":        readBody,
	"watcher":   watcher,
}

var update = map[string]func(string){
	"fpl(":  fpl,
	"lpf(":  lpf,
	"lpl(":  lpl,
	"fpf(":  fpf,
	"hfunc": hfunc,
	"ow:":   pyOpenWrite,
	"ul":    ul,
}

var modify = map[string]func(string){
	"_ctx,": contextArg,}
func main() {
	if os.Getenv("shortcuts") == "off" {
		return
	}

	stat, err := os.Stdin.Stat()
	if err != nil {
		log.Fatal(err)
	}
	if stat.Mode()&os.ModeCharDevice != 0 {
		log.Fatal("please pipe in some data")
	}

	s := bufio.NewScanner(os.Stdin)
	var lastBlank bool

	for s.Scan() {
		line := s.Text()
		trim := strings.TrimSpace(line)

		if f, found := replace[trim]; found {
			f()
			continue
		}

		var replaced bool
		for pre , f := range update {
			if strings.HasPrefix(trim, pre) {
				f(line)
				replaced = true
				break
			}

		}

		for pre, f := range modify {
			if strings.Contains(line, pre) {
				f(line)
				replaced = true
				break
			}
		}

		if replaced {
			continue
		}

		if strings.TrimSpace(line) == "" {
			if lastBlank {
				continue
			}
			lastBlank = true
		} else {
			lastBlank = false
		}
		fmt.Println(line)
	}
}

func nnf() {
	fmt.Println(`if err != nil{
	 log.Fatalf("Failed to do something: %s\n", err)
	 }`)
}

func nnl() {
	fmt.Println(`if err != nil{
	 log.Printf("Failed to do something: %s\n", err)
	 }`)
}

func dbg() {
	weekday := string([]rune(time.Now().Weekday().String())[0])
	day := time.Now().Day()
	fmt.Printf(`log.Printf("%s%d %%v", x)\n`, weekday, day)
}

func lpf(line string) {
	fmt.Println(strings.Replace(line, "lpf(", "log.Printf(", 1))
}

func fpf(line string) {
	fmt.Println(strings.Replace(line, "fpf(", "fmt.Printf(", 1))
}

func lpl(line string) {
	fmt.Println(strings.Replace(line, "lpl(", "log.Println(", 1))
}

func fpl(line string) {
	fmt.Println(strings.Replace(line, "fpl(", "fmt.Println(", 1))
}

func goMain() {
	fmt.Println(`package main

import (
    "fmt"
)

func main() {
    fmt.Println("gopher")
}
`)
}

func serveHTTP() {
	fmt.Println(`package main

import (
    "fmt"
	 "net/http"
)

func main() {
    http.HandleFunc("/", index)
	 http.ListenAndServe(":8080", nil)
}

func index(w http.ResponseWriter, r *http.Request){
	 fmt.Fprintf(w, "hello")
}
`)
}

func pyMain() {
	fmt.Println(`#!/usr/bin/env python3
"""
You should probably write something here.
"""

def main():
    """
    Do the thing.
    """
    print("python")

if __name__ == '__main__':
    main()
`)
}

func html5() {
	fmt.Println(`<!DOCTYPE html>

		 <meta charset="UTF-8">
		 <title>title</title>
        <link rel="stylesheet" href="https://aoeus.com/milligram.min.css" type="text/css">
		 <meta name="viewport" content="width-device-width, initial-scale=1">

topic

content

`)
}

func hfunc(line string) {
	parts := strings.Split(line, " ")
	name := "index"
	if len(parts) > 1 {
		name = parts[1]
	}
	fmt.Printf(`func %s(w http.ResponseWriter, r *http.Request){
	 }`, name)
}

func pyOpenWrite(line string) {
	l := len(line) - len(strings.TrimLeft(line, " "))
	pad := strings.Repeat(" ", l)
	lines := []string{
		`with open("out.txt", "wb") as raw:`,
		`    raw.write("{0}\n".format(msg))`,
	}

	for _, line = range lines {
		fmt.Printf("%s%s\n", pad, line)
	}

}

func contextArg(line string) {
	line = strings.Replace(line, "_ctx,", "ctx context.Context,", 1)
    fmt.Printf("%s\n", line)
}

func ul(line string) {
	trim := strings.TrimSpace(line)
	margin := len(line) - len(strings.TrimLeft(trim, " \t"))
	padding := strings.Repeat(" ", margin)
	fmt.Printf(padding)
	fmt.Println("
")
	for i := 0; i < 3; i++ {
		fmt.Printf(padding)
		fmt.Println("\t
")
		fmt.Printf(padding)
		fmt.Println("\t\tthing")
		fmt.Printf(padding)
		fmt.Println("\t
")
	}
	fmt.Printf(padding)
	fmt.Println("
")

}

func openFile() {
	fmt.Println(`f, err := os.Open(filename)
	 if err != nil {
		 log.Printf("Unable to open %q: %s\n", filename, err)
	 }
	 defer f.Close()`)
}

func readFile() {
	fmt.Println(`b, err := ioutil.ReadFile(filename)
	 if err != nil {
		 log.Printf("Unable to open %q: %s\n", filename, err)
	 }`)
}

func getURL() {
	fmt.Println(`resp, err := http.Get(link)
	 if err != nil {
		 log.Printf("Unable to fetch %q: %s\n", link, err)
		 return
	 }
	 defer resp.Body.Close()
	 b, err := ioutil.ReadAll(resp.Body)
	 if err != nil {
		 log.Printf("Unable to read response from  %q: %s\n", link, err)
		 return
	 }
	 `)
}

func reqStdin() {
	fmt.Println(`stat, err := os.Stdin.Stat()
	 if err != nil {
		 log.Fatal(err)
	 }
	 if stat.Mode()&os.ModeCharDevice != 0 {
		 log.Fatal("please pipe in some data")
	 }`)
}

func tempFile() {
	fmt.Println(`t, err := ioutil.TempFile("", "temp")
if err != nil{
	 log.Fatalf("Unable to create temp file: %s\n", err)
}
fmt.Printf("Created temp file %q\n", t.Name())
defer t.Close()
`)
}

func now() {
	fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}

func bash() {
	fmt.Println("#!/usr/bin/env bash")
}

func python() {
	fmt.Println("#!/usr/bin/env python")
}

func flagsh() {

	fmt.Println(`#!/usr/bin/env bash

flag=$(mktemp)
touch $flag

while true; do
sleep 5
    find . -mmin -1 -name '*.go' 2>>/dev/null | while read file; do
        if [[ "$file" -nt $flag ]]; then
            if [[ "$file" == "$flag" ]]; then
                continue
            fi
            echo "$file was updated"
            touch $flag
        fi
    done
done
`)
}

func dummyType() {
	fmt.Println(`type dummy struct {
    thing string
    size int
    color string
}
`)
}
func jsonMarshal() {
	fmt.Println(`b, err := json.Marshal(x)
    if err != nil{
        log.Fatalf("Failed to do something: %s\n", err)
	 } `)
}

func jsonUnmarshal() {
	fmt.Println(`var x thing
err = json.Unmarshal(b, &x)
return x, err
`)
}

func readBody() {
	fmt.Println(`b, err := ioutil.ReadAll(r.Body)
	 if err != nil {
		 return err
	 }
	 defer r.Body.Close()`)
}

func watcher() {
	fmt.Println(`#!/usr/bin/env bash

bin=monkey
flag=$(mktemp)
code=main.go

function cleanup() {
    pkill $bin
    rm -f $bin
    rm -f $flag
    exit
}

trap cleanup SIGINT SIGTERM

while true
do
    if [ ! "$code" -nt $flag ]; then
        sleep 5
        continue
    fi
    go build -o $bin $code || { touch $flag; continue; }
    pkill $bin
    ./$bin &
    sleep 1
    ./tests.sh
    touch $flag
    sleep 15
done`)
}

<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/miekg/dns"
	"github.com/zettio/weavedns/server"
	"log"
	"net"
	"time"
)

var zone = new(weavedns.ZoneDb)

func makeDNSReply(r *dns.Msg, name string, addr net.IP) *dns.Msg {
	m := new(dns.Msg)
	m.SetReply(r)
	hdr := dns.RR_Header{Name: name, Rrtype: dns.TypeA,
		Class: dns.ClassINET, Ttl: 3600}
	a := &dns.A{hdr, addr}
	m.Answer = append(m.Answer, a)
	return m
}

var mdnsClient *weavedns.MDNSClient

func handleMDNS(w dns.ResponseWriter, r *dns.Msg) {
	log.Println("MDNS received:", r)
	// Here we have to handle both requests incoming, responses to queries
	// we sent out, and responses to queries that other nodes sent
	if len(r.Answer) > 0 {
		mdnsClient.ResponseCallback(r)
	} else if len(r.Question) > 0 {
		q := r.Question[0]
		ip, err := zone.MatchLocal(q.Name)
		if err == nil {
			m := makeDNSReply(r, q.Name, net.ParseIP(ip))
			mdnsClient.SendResponse(m)
		} else if mdnsClient.IsInflightQuery(r) {
			// ignore this - it's our own query received via multicast
		} else {
			log.Printf("Failed MDNS lookup for %s", q.Name)
		}
	}
}

func handleLocal(w dns.ResponseWriter, r *dns.Msg) {
	log.Printf("Received message: %s", r)
	q := r.Question[0]
	ip, err := zone.MatchLocal(q.Name)
	if err == nil {
		m := makeDNSReply(r, q.Name, net.ParseIP(ip))
		w.WriteMsg(m)
	} else {
		log.Printf("Failed lookup for %s; sending mDNS query", q.Name)
		// We don't know the answer; see if someone else does
		channel := make(chan *weavedns.ResponseA, 4)
		go func() {
			for resp := range channel {
				log.Printf("Got address response %s to query %s addr %s", resp.Name, q.Name, resp.Addr)
				m := makeDNSReply(r, resp.Name, resp.Addr)
				w.WriteMsg(m)
			}
			// FIXME: need to add a time-out either here or in mdnsClient
		}()
		mdnsClient.SendQuery(q.Name, dns.TypeA, channel)
	}
	return
}

func ensureInterface(ifaceName string, wait int) (iface *net.Interface, err error) {
	iface, err = findInterface(ifaceName)
	if err == nil || wait == 0 {
		return
	}
	log.Println("Waiting for interface", ifaceName, "to come up")
	for ; err != nil && wait > 0; wait -= 1 {
		time.Sleep(1 * time.Second)
		iface, err = findInterface(ifaceName)
	}
	if err == nil {
		log.Println("Interface", ifaceName, "is up")
	}
	return
}

func findInterface(ifaceName string) (iface *net.Interface, err error) {
	iface, err = net.InterfaceByName(ifaceName)
	if err != nil {
		return iface, fmt.Errorf("Unable to find interface %s", ifaceName)
	}
	if 0 == (net.FlagUp & iface.Flags) {
		return iface, fmt.Errorf("Interface %s is not up", ifaceName)
	}
	return
}

func main() {
	var (
		ifaceName string
		dnsPort   int
		wait      int
	)

	flag.StringVar(&ifaceName, "iface", "", "name of interface to use for multicast")
	flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0)")
	flag.IntVar(&dnsPort, "dnsport", 53, "port to listen to dns requests (defaults to 53)")
	flag.Parse()

	var iface *net.Interface = nil
	if ifaceName != "" {
		var err error
		iface, err = ensureInterface(ifaceName, wait)
		if err != nil {
			log.Fatal(err)
		}
	}

	LocalServeMux := dns.NewServeMux()
	LocalServeMux.HandleFunc("local", handleLocal)
	go weavedns.ListenHttp(zone)

	MDNSServeMux := dns.NewServeMux()
	MDNSServeMux.HandleFunc("local", handleMDNS)

	conn, err := weavedns.LinkLocalMulticastListener(iface)
	if err != nil {
		log.Fatal(err)
	}
	mdnsClient, err = weavedns.NewMDNSClient()
	if err != nil {
		log.Fatal(err)
	}
	mdnsClient.Start()

	go dns.ActivateAndServe(nil, conn, MDNSServeMux)

	address := fmt.Sprintf(":%d", dnsPort)
	err = dns.ListenAndServe(address, "udp", LocalServeMux)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Tidy up<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/miekg/dns"
	"github.com/zettio/weavedns/server"
	"log"
	"net"
	"time"
)

var zone = new(weavedns.ZoneDb)

func makeDNSReply(r *dns.Msg, name string, addr net.IP) *dns.Msg {
	m := new(dns.Msg)
	m.SetReply(r)
	hdr := dns.RR_Header{Name: name, Rrtype: dns.TypeA,
		Class: dns.ClassINET, Ttl: 3600}
	a := &dns.A{hdr, addr}
	m.Answer = append(m.Answer, a)
	return m
}

var mdnsClient *weavedns.MDNSClient

func handleMDNS(w dns.ResponseWriter, r *dns.Msg) {
	// Here we have to handle both requests incoming, responses to queries
	// we sent out, and responses to queries that other nodes sent
	if len(r.Answer) > 0 {
		mdnsClient.ResponseCallback(r)
	} else if len(r.Question) > 0 {
		q := r.Question[0]
		ip, err := zone.MatchLocal(q.Name)
		if err == nil {
			m := makeDNSReply(r, q.Name, net.ParseIP(ip))
			mdnsClient.SendResponse(m)
		} else if mdnsClient.IsInflightQuery(r) {
			// ignore this - it's our own query received via multicast
		} else {
			log.Printf("Failed MDNS lookup for %s", q.Name)
		}
	}
}

func handleLocal(w dns.ResponseWriter, r *dns.Msg) {
	q := r.Question[0]
	ip, err := zone.MatchLocal(q.Name)
	if err == nil {
		m := makeDNSReply(r, q.Name, net.ParseIP(ip))
		w.WriteMsg(m)
	} else {
		log.Printf("Failed lookup for %s; sending mDNS query", q.Name)
		// We don't know the answer; see if someone else does
		channel := make(chan *weavedns.ResponseA, 4)
		go func() {
			// Loop terminates when channel is closed by MDNSClient on timeout
			for resp := range channel {
				log.Printf("Got address response %s to query %s addr %s", resp.Name, q.Name, resp.Addr)
				m := makeDNSReply(r, resp.Name, resp.Addr)
				w.WriteMsg(m)
			}
		}()
		mdnsClient.SendQuery(q.Name, dns.TypeA, channel)
	}
	return
}

func ensureInterface(ifaceName string, wait int) (iface *net.Interface, err error) {
	iface, err = findInterface(ifaceName)
	if err == nil || wait == 0 {
		return
	}
	log.Println("Waiting for interface", ifaceName, "to come up")
	for ; err != nil && wait > 0; wait -= 1 {
		time.Sleep(1 * time.Second)
		iface, err = findInterface(ifaceName)
	}
	if err == nil {
		log.Println("Interface", ifaceName, "is up")
	}
	return
}

func findInterface(ifaceName string) (iface *net.Interface, err error) {
	iface, err = net.InterfaceByName(ifaceName)
	if err != nil {
		return iface, fmt.Errorf("Unable to find interface %s", ifaceName)
	}
	if 0 == (net.FlagUp & iface.Flags) {
		return iface, fmt.Errorf("Interface %s is not up", ifaceName)
	}
	return
}

func main() {
	var (
		ifaceName string
		dnsPort   int
		wait      int
	)

	flag.StringVar(&ifaceName, "iface", "", "name of interface to use for multicast")
	flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0)")
	flag.IntVar(&dnsPort, "dnsport", 53, "port to listen to dns requests (defaults to 53)")
	flag.Parse()

	var iface *net.Interface = nil
	if ifaceName != "" {
		var err error
		iface, err = ensureInterface(ifaceName, wait)
		if err != nil {
			log.Fatal(err)
		}
	}

	LocalServeMux := dns.NewServeMux()
	LocalServeMux.HandleFunc("local", handleLocal)
	go weavedns.ListenHttp(zone)

	MDNSServeMux := dns.NewServeMux()
	MDNSServeMux.HandleFunc("local", handleMDNS)

	conn, err := weavedns.LinkLocalMulticastListener(iface)
	if err != nil {
		log.Fatal(err)
	}
	mdnsClient, err = weavedns.NewMDNSClient()
	if err != nil {
		log.Fatal(err)
	}
	mdnsClient.Start()

	go dns.ActivateAndServe(nil, conn, MDNSServeMux)

	address := fmt.Sprintf(":%d", dnsPort)
	err = dns.ListenAndServe(address, "udp", LocalServeMux)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	spipe "github.com/s1kx/spipe/lib"
	"log"
	"os"
	"strconv"
)

func main() {
	// Start options
	var (
		listenHost = flag.String("i", "0.0.0.0", "Listening interface IP address")
		sourcePort = flag.Uint("s", 0, "Outbound source port number")
		network    = flag.String("net", "tcp", "Network type (tcp, tcp4, tcp6)")
	)
	flag.Parse()

	// Check if all mandatory arguments were supplied
	if flag.NArg() < 3 {
		fmt.Println("spipe [options] <listen port> <remote host> <remote port>")
		fmt.Println("")
		flag.PrintDefaults()
		fmt.Println("")
		fmt.Println("Example: spipe -i 127.0.0.1 80 example.com 80")
		os.Exit(1)
	}

	// Read mandatory arguments
	listenPort, err := strconv.Atoi(flag.Arg(0))
	if err != nil || listenPort < 1 || listenPort > 65535 {
		log.Fatalf("Invalid listening port: %s\n", flag.Arg(0))
	}
	remoteHost := flag.Arg(1)
	remotePort, err := strconv.Atoi(flag.Arg(2))
	if err != nil || remotePort < 1 || remotePort > 65535 {
		log.Fatalf("Invalid remote port: %s\n", flag.Arg(0))
	}

	// Start listener and pipe connections
	pipe := &spipe.Pipe{*network, *listenHost, uint(listenPort), remoteHost, uint(remotePort), *sourcePort}
	pipe.Start()
}
<commit_msg>Fix error output<commit_after>package main

import (
	"flag"
	"fmt"
	spipe "github.com/s1kx/spipe/lib"
	"log"
	"os"
	"strconv"
)

func main() {
	// Start options
	var (
		listenHost = flag.String("i", "0.0.0.0", "Listening interface IP address")
		sourcePort = flag.Uint("s", 0, "Outbound source port number")
		network    = flag.String("net", "tcp", "Network type (tcp, tcp4, tcp6)")
	)
	flag.Parse()

	// Check if all mandatory arguments were supplied
	if flag.NArg() < 3 {
		fmt.Println("spipe [options] <listen port> <remote host> <remote port>")
		fmt.Println("")
		flag.PrintDefaults()
		fmt.Println("")
		fmt.Println("Example: spipe -i 127.0.0.1 80 example.com 80")
		os.Exit(1)
	}

	// Read mandatory arguments
	listenPort, err := strconv.Atoi(flag.Arg(0))
	if err != nil || listenPort < 1 || listenPort > 65535 {
		log.Fatalf("Invalid listening port: %s\n", flag.Arg(0))
	}
	remoteHost := flag.Arg(1)
	remotePort, err := strconv.Atoi(flag.Arg(2))
	if err != nil || remotePort < 1 || remotePort > 65535 {
		log.Fatalf("Invalid remote port: %s\n", flag.Arg(2))
	}

	// Start listener and pipe connections
	pipe := &spipe.Pipe{*network, *listenHost, uint(listenPort), remoteHost, uint(remotePort), *sourcePort}
	pipe.Start()
}
<|endoftext|>


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

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/tsuru/tsuru-client/tsuru/admin"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/provision"
	_ "github.com/tsuru/tsuru/provision/docker"
)

const (
	version = "1.0.0"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header, nil)
	m.RegisterRemoved("log-remove", "This action is no longer supported.")
	m.RegisterDeprecated(&admin.AddPoolToSchedulerCmd{}, "docker-pool-add")
	m.Register(&updatePoolToSchedulerCmd{})
	m.RegisterDeprecated(&removePoolFromSchedulerCmd{}, "docker-pool-remove")
	m.RegisterDeprecated(addTeamsToPoolCmd{}, "docker-pool-teams-add")
	m.RegisterDeprecated(removeTeamsFromPoolCmd{}, "docker-pool-teams-remove")
	m.RegisterDeprecated(&admin.AddNodeCmd{}, "docker-node-add")
	m.RegisterDeprecated(&admin.RemoveNodeCmd{}, "docker-node-remove")
	m.RegisterDeprecated(&admin.UpdateNodeCmd{}, "docker-node-update")
	m.RegisterDeprecated(&admin.ListNodesCmd{}, "docker-node-list")
	registerProvisionersCommands(m)
	registerMigrated := func(cmd string, newCmd string) {
		if newCmd == "" {
			newCmd = cmd
		}
		m.RegisterRemoved(cmd, fmt.Sprintf("You should use `tsuru %s` instead.", newCmd))
	}
	registerMigrated("app-shell", "")
	registerMigrated("platform-update", "")
	registerMigrated("platform-remove", "")
	registerMigrated("machine-list", "")
	registerMigrated("machine-destroy", "")
	registerMigrated("app-unlock", "")
	registerMigrated("plan-create", "")
	registerMigrated("plan-remove", "")
	registerMigrated("router-list", "")
	registerMigrated("user-list", "")
	registerMigrated("pool-list", "")
	registerMigrated("app-routes-rebuild", "")
	registerMigrated("platform-add", "")
	registerMigrated("machine-template-list", "")
	registerMigrated("machine-template-add", "")
	registerMigrated("machine-template-remove", "")
	registerMigrated("machine-template-update", "")
	registerMigrated("user-quota-view", "")
	registerMigrated("user-quota-change", "")
	registerMigrated("app-quota-view", "")
	registerMigrated("app-quota-change", "")
	registerMigrated("view-user-quota", "user-quota-view")
	registerMigrated("change-user-quota", "user-quota-change")
	registerMigrated("view-app-quota", "app-quota-view")
	registerMigrated("change-app-quota", "app-quota-change")
	return m
}

func registerProvisionersCommands(m *cmd.Manager) {
	provisioners, err := provision.Registry()
	if err != nil {
		log.Fatalf("unable to load provisioners: %s", err)
	}
	for _, p := range provisioners {
		if c, ok := p.(cmd.AdminCommandable); ok {
			commands := c.AdminCommands()
			for _, cmd := range commands {
				name := cmd.Info().Name
				m.RegisterRemoved(name, fmt.Sprintf("You should use `tsuru %s` instead.", name))
			}
		}
	}
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>register migration of docker-node-* cmds<commit_after>// Copyright 2016 tsuru-admin authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/provision"
	_ "github.com/tsuru/tsuru/provision/docker"
)

const (
	version = "1.0.0"
	header  = "Supported-Tsuru-Admin"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header, nil)
	m.RegisterRemoved("log-remove", "This action is no longer supported.")
	m.Register(&updatePoolToSchedulerCmd{})
	m.RegisterDeprecated(&removePoolFromSchedulerCmd{}, "docker-pool-remove")
	m.RegisterDeprecated(addTeamsToPoolCmd{}, "docker-pool-teams-add")
	m.RegisterDeprecated(removeTeamsFromPoolCmd{}, "docker-pool-teams-remove")
	registerProvisionersCommands(m)
	registerMigrated := func(cmd string, newCmd string) {
		if newCmd == "" {
			newCmd = cmd
		}
		m.RegisterRemoved(cmd, fmt.Sprintf("You should use `tsuru %s` instead.", newCmd))
	}
	registerMigrated("app-shell", "")
	registerMigrated("platform-update", "")
	registerMigrated("platform-remove", "")
	registerMigrated("machine-list", "")
	registerMigrated("machine-destroy", "")
	registerMigrated("app-unlock", "")
	registerMigrated("plan-create", "")
	registerMigrated("plan-remove", "")
	registerMigrated("router-list", "")
	registerMigrated("user-list", "")
	registerMigrated("pool-list", "")
	registerMigrated("app-routes-rebuild", "")
	registerMigrated("platform-add", "")
	registerMigrated("machine-template-list", "")
	registerMigrated("machine-template-add", "")
	registerMigrated("machine-template-remove", "")
	registerMigrated("machine-template-update", "")
	registerMigrated("user-quota-view", "")
	registerMigrated("user-quota-change", "")
	registerMigrated("app-quota-view", "")
	registerMigrated("app-quota-change", "")
	registerMigrated("view-user-quota", "user-quota-view")
	registerMigrated("change-user-quota", "user-quota-change")
	registerMigrated("view-app-quota", "app-quota-view")
	registerMigrated("change-app-quota", "app-quota-change")
	registerMigrated("docker-node-add", "node-add")
	registerMigrated("docker-node-remove", "node-remove")
	registerMigrated("docker-node-update", "node-update")
	registerMigrated("docker-node-list", "node-list")
	registerMigrated("docker-pool-add", "pool-add")
	registerMigrated("pool-add", "")
	return m
}

func registerProvisionersCommands(m *cmd.Manager) {
	provisioners, err := provision.Registry()
	if err != nil {
		log.Fatalf("unable to load provisioners: %s", err)
	}
	for _, p := range provisioners {
		if c, ok := p.(cmd.AdminCommandable); ok {
			commands := c.AdminCommands()
			for _, cmd := range commands {
				name := cmd.Info().Name
				m.RegisterRemoved(name, fmt.Sprintf("You should use `tsuru %s` instead.", name))
			}
		}
	}
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/vially/volumectl/pulseaudio"
)

func main() {
	pa := pulseaudio.New()

	app := cli.NewApp()
	app.Name = "volumectl"
	app.Usage = "Control volume from the command line"
	app.Version = "0.0.4"
	app.Commands = []cli.Command{
		{
			Name:  "up",
			Usage: "increase volume (with 2%)",
			Action: func(c *cli.Context) {
				pa.IncreaseVolume()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "down",
			Usage: "decrease volume (with 2%)",
			Action: func(c *cli.Context) {
				pa.DecreaseVolume()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "mute",
			Usage: "mute volume",
			Action: func(c *cli.Context) {
				pa.SetMute(true)
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "unmute",
			Usage: "unmute volume",
			Action: func(c *cli.Context) {
				pa.SetMute(false)
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "toggle",
			Usage: "toggle mute",
			Action: func(c *cli.Context) {
				pa.ToggleMute()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "set",
			Usage: "set volume to a specific value",
			Action: func(c *cli.Context) {
				pa.SetVolume(c.Args().First())
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
	}
	app.Action = func(c *cli.Context) {
		mute := "[on]"
		if pa.Muted {
			mute = "[off]"
		}
		fmt.Println("Volume:", strconv.Itoa(pa.Volume)+"%", mute)
	}

	app.Run(os.Args)
}
<commit_msg>Bump version to v0.0.5<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
	"github.com/vially/volumectl/pulseaudio"
)

func main() {
	pa := pulseaudio.New()

	app := cli.NewApp()
	app.Name = "volumectl"
	app.Usage = "Control volume from the command line"
	app.Version = "0.0.5"
	app.Commands = []cli.Command{
		{
			Name:  "up",
			Usage: "increase volume (with 2%)",
			Action: func(c *cli.Context) {
				pa.IncreaseVolume()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "down",
			Usage: "decrease volume (with 2%)",
			Action: func(c *cli.Context) {
				pa.DecreaseVolume()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "mute",
			Usage: "mute volume",
			Action: func(c *cli.Context) {
				pa.SetMute(true)
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "unmute",
			Usage: "unmute volume",
			Action: func(c *cli.Context) {
				pa.SetMute(false)
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "toggle",
			Usage: "toggle mute",
			Action: func(c *cli.Context) {
				pa.ToggleMute()
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
		{
			Name:  "set",
			Usage: "set volume to a specific value",
			Action: func(c *cli.Context) {
				pa.SetVolume(c.Args().First())
				showVolumeNotification(pa.Volume, pa.Muted)
			},
		},
	}
	app.Action = func(c *cli.Context) {
		mute := "[on]"
		if pa.Muted {
			mute = "[off]"
		}
		fmt.Println("Volume:", strconv.Itoa(pa.Volume)+"%", mute)
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"time"
)

const (
	// Frequency of the save tick. Any planes last seen older than this are saved and removed from active
	savePeriod time.Duration = time.Minute * 1
)

var (
	// Command line flags
	addr        string
	port        uint
	verbose     bool
	veryVerbose bool
)

var (
	planeCache = make(map[uint]*Plane)
)

func init() {
	flag.StringVar(&addr, "a", "localhost:30003", "Address and port to connect to for input.")
	flag.UintVar(&port, "p", 8888, "Port to bind output webserver.")
	flag.BoolVar(&verbose, "v", false, "Enable verbose message logging. This will list contents of received messages.")
	flag.BoolVar(&veryVerbose, "vv", false, "Enable very verbose message logging. This will list raw received messages. Requires verbose flag")
}

func main() {
	flag.Parse()

	msgs := make(chan *message, 50)
	cmds := make(chan *BoardCmd)
	sigint := make(chan os.Signal, 1)
	signal.Notify(sigint, os.Interrupt)

	if verbose {
		fmt.Println("Initalizing databases")
	}
	err := init_db()
	if err != nil {
		fmt.Fprintf(os.Stderr, "errors setting up database: %v", err)
		os.Exit(1)
	}

	json := StartServer(cmds)
	tick := time.NewTicker(savePeriod)

	go connect(msgs)

	for {
		select {
		case m := <-msgs:
			pl, _ := getPlaneByIcao(m.icao)
			if _, ok := planeCache[m.icao]; !ok {
				planeCache[m.icao] = pl
			}
			updatePlane(m, pl)
		case cmd := <-cmds:
			json <- handleCommand(cmd)
		case t := <-tick.C:
			saveData(t)
		case <-sigint:
			saveData(time.Time{})
			err = close_db()
			tick.Stop()
			close(cmds)
			cmds = nil
			close(json)
			close(msgs)
			msgs = nil
			os.Exit(0)
		}
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "error closing database: %#v", err)
	}
	os.Exit(0)
}

func getPlaneByIcao(icao uint) (*Plane, error) {
	pl, ok := planeCache[icao]
	var err error
	if !ok {
		pl, err = LoadPlane(icao)
		if err != nil && err != planeNotFound {
			fmt.Fprintf(os.Stderr, "error loading from database: %v\n", err)
			pl = &Plane{Icao: icao}
		}
		if err != nil {
			return pl, planeNotFound
		}
	}

	return pl, nil
}

func handleCommand(cmd *BoardCmd) string {
	switch cmd.Cmd {
	case GetCurrent:
		return currentPlanes(cmd.Since)
	case GetAll:
		return getAllPlanes(cmd.Since)
	case GetPlane:
		return detailedPlane(cmd.Icao)
	case GetLocations:
		return getPlaneLocations(cmd.Icao, cmd.Since)
	default:
		fmt.Fprintf(os.Stderr, "unknown board command: %v", cmd.Cmd)
		return ""
	}
}

func saveData(t time.Time) {
	if len(planeCache) == 0 {
		return
	}

	var toSave []*Plane

	var zero time.Time
	if t == zero { // Save all planes if time 0. Probably an interrupt received.
		i := 0
		toSave = make([]*Plane, len(planeCache))
		for icao, pl := range planeCache {
			toSave[i] = pl
			delete(planeCache, icao)
			i++
		}
	} else {
		period := t.Add(-savePeriod)

		for icao, pl := range planeCache {
			if period.After(pl.LastSeen) {
				toSave = append(toSave, pl)
				delete(planeCache, icao)
			}
		}
	}

	if len(toSave) == 0 {
		return
	}

	err := SavePlanes(toSave)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error saving planes to database: %v\n", err)
	}
}
<commit_msg>Run db save in a goroutine.<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"time"
)

const (
	// Frequency of the save tick. Any planes last seen older than this are saved and removed from active
	savePeriod time.Duration = time.Minute * 1
)

var (
	// Command line flags
	addr        string
	port        uint
	verbose     bool
	veryVerbose bool
)

var (
	planeCache = make(map[uint]*Plane)
)

func init() {
	flag.StringVar(&addr, "a", "localhost:30003", "Address and port to connect to for input.")
	flag.UintVar(&port, "p", 8888, "Port to bind output webserver.")
	flag.BoolVar(&verbose, "v", false, "Enable verbose message logging. This will list contents of received messages.")
	flag.BoolVar(&veryVerbose, "vv", false, "Enable very verbose message logging. This will list raw received messages. Requires verbose flag")
}

func main() {
	flag.Parse()

	msgs := make(chan *message, 50)
	cmds := make(chan *BoardCmd)
	sigint := make(chan os.Signal, 1)
	signal.Notify(sigint, os.Interrupt)

	if verbose {
		fmt.Println("Initalizing databases")
	}
	err := init_db()
	if err != nil {
		fmt.Fprintf(os.Stderr, "errors setting up database: %v", err)
		os.Exit(1)
	}

	json := StartServer(cmds)
	tick := time.NewTicker(savePeriod)

	go connect(msgs)

	for {
		select {
		case m := <-msgs:
			pl, _ := getPlaneByIcao(m.icao)
			if _, ok := planeCache[m.icao]; !ok {
				planeCache[m.icao] = pl
			}
			updatePlane(m, pl)
		case cmd := <-cmds:
			json <- handleCommand(cmd)
		case t := <-tick.C:
			saveData(t)
		case <-sigint:
			saveData(time.Time{})
			err = close_db()
			tick.Stop()
			close(cmds)
			cmds = nil
			close(json)
			close(msgs)
			msgs = nil
			os.Exit(0)
		}
	}

	if err != nil {
		fmt.Fprintf(os.Stderr, "error closing database: %#v", err)
	}
	os.Exit(0)
}

func getPlaneByIcao(icao uint) (*Plane, error) {
	pl, ok := planeCache[icao]
	var err error
	if !ok {
		pl, err = LoadPlane(icao)
		if err != nil && err != planeNotFound {
			fmt.Fprintf(os.Stderr, "error loading from database: %v\n", err)
			pl = &Plane{Icao: icao}
		}
		if err != nil {
			return pl, planeNotFound
		}
	}

	return pl, nil
}

func handleCommand(cmd *BoardCmd) string {
	switch cmd.Cmd {
	case GetCurrent:
		return currentPlanes(cmd.Since)
	case GetAll:
		return getAllPlanes(cmd.Since)
	case GetPlane:
		return detailedPlane(cmd.Icao)
	case GetLocations:
		return getPlaneLocations(cmd.Icao, cmd.Since)
	default:
		fmt.Fprintf(os.Stderr, "unknown board command: %v", cmd.Cmd)
		return ""
	}
}

func saveData(t time.Time) {
	if len(planeCache) == 0 {
		return
	}

	var toSave []*Plane

	var zero time.Time
	if t == zero { // Save all planes if time 0. Probably an interrupt received.
		i := 0
		toSave = make([]*Plane, len(planeCache))
		for icao, pl := range planeCache {
			toSave[i] = pl
			delete(planeCache, icao)
			i++
		}
	} else {
		period := t.Add(-savePeriod)

		for icao, pl := range planeCache {
			if period.After(pl.LastSeen) {
				toSave = append(toSave, pl)
				delete(planeCache, icao)
			}
		}
	}

	if len(toSave) == 0 {
		return
	}

	if t != zeroTime {
		go SavePlanes(toSave)
	}
	err := SavePlanes(toSave)
	if err != nil {
		fmt.Fprintf(os.Stderr, "error saving planes to database: %v\n", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"encoding/json"
	"io/ioutil"
	"strings"
	"strconv"
	"net/http"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/dghubble/sling"
	"github.com/mitchellh/go-homedir"
)

var (
	modeCategory = kingpin.Command("mode", "Get Hoverfly's current mode")
	modeCommand = modeCategory.Command("status", "Get Hoverfly's current mode").Default()
	simulateCommand = modeCategory.Command("simulate", "Set Hoverfly to simulate mode")
	captureCommand = modeCategory.Command("capture", "Set Hoverfly to capture mode")
	modifyCommand = modeCategory.Command("modify", "Set Hoverfly to modify mode")
	synthesizeCommand = modeCategory.Command("synthesize", "Set Hoverfly to synthesize mode")

	startCommand = kingpin.Command("start", "Start a local instance of Hoverfly")
)

type ApiStateResponse struct {
	Mode string        `json:"mode"`
	Destination string `json"destination"`
}

func main() {
	hoverflyDirectory := createHomeDirectory()

	switch kingpin.Parse() {
		case modeCommand.FullCommand():
			modeHandler()
		case simulateCommand.FullCommand():
			simulateHandler()
		case captureCommand.FullCommand():
			captureHandler()
		case modifyCommand.FullCommand():
			modifyHandler()
		case synthesizeCommand.FullCommand():
			synthesizeHandler()
		case startCommand.FullCommand():
			startHandler(hoverflyDirectory)

	}
}

func createHomeDirectory() string {
	homeDirectory, _ := homedir.Dir()
	hoverflyDirectory := filepath.Join(homeDirectory, "/.hoverfly")

	if _, err := os.Stat(hoverflyDirectory); err != nil {
    		if os.IsNotExist(err) {
        		os.Mkdir(hoverflyDirectory, 0777)
    		}
	}

	return hoverflyDirectory
}

func modeHandler() {
	response := getHoverflyMode()
	fmt.Println("Hoverfly is currently set to " + response.Mode + " mode")
}

func simulateHandler() {
	response := setHoverflyMode("simulate")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to simulate mode")
}

func captureHandler() {
	response := setHoverflyMode("capture")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to capture mode")
}

func modifyHandler() {
	response := setHoverflyMode("modify")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to modify mode")
}

func synthesizeHandler() {
	response := setHoverflyMode("synthesize")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to synthesize mode")
}

func startHandler(hoverflyDirectory string) {
	hoverflyPidFile := filepath.Join(hoverflyDirectory, "hoverfly.pid")

	if _, err := os.Stat(hoverflyPidFile); err != nil {
                if os.IsNotExist(err) {
			cmd := exec.Command("/Users/benjih/Downloads/hoverfly/hoverfly_v0.5.17_OSX_amd64")
			cmd.Start()
			ioutil.WriteFile(hoverflyPidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
			fmt.Println("Hoverfly is now running")
                }
        }
}

func getHoverflyMode() (ApiStateResponse) {
	request, _ := sling.New().Get("http://localhost:8888/api/state").Request()
	response, _ := http.DefaultClient.Do(request)
	defer response.Body.Close()

	body, _ := ioutil.ReadAll(response.Body)
	var jsonResponse ApiStateResponse
	json.Unmarshal(body, &jsonResponse)
	return jsonResponse
}

func setHoverflyMode(mode string) (*http.Response) {
	request, _ := sling.New().Post("http://localhost:8888/api/state").Body(strings.NewReader(`{"mode":"` + mode + `"}`)).Request()
	response, _ := http.DefaultClient.Do(request)
	return response
}
<commit_msg>Can now stop a running Hoverfly, but you seem to have to stop it twice.<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"encoding/json"
	"io/ioutil"
	"strings"
	"strconv"
	"net/http"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/dghubble/sling"
	"github.com/mitchellh/go-homedir"
)

var (
	modeCategory = kingpin.Command("mode", "Get Hoverfly's current mode")
	modeCommand = modeCategory.Command("status", "Get Hoverfly's current mode").Default()
	simulateCommand = modeCategory.Command("simulate", "Set Hoverfly to simulate mode")
	captureCommand = modeCategory.Command("capture", "Set Hoverfly to capture mode")
	modifyCommand = modeCategory.Command("modify", "Set Hoverfly to modify mode")
	synthesizeCommand = modeCategory.Command("synthesize", "Set Hoverfly to synthesize mode")

	startCommand = kingpin.Command("start", "Start a local instance of Hoverfly")
	stopCommand = kingpin.Command("stop", "Stop a local instance of Hoverfly")
)

type ApiStateResponse struct {
	Mode string        `json:"mode"`
	Destination string `json"destination"`
}

func main() {
	hoverflyDirectory := createHomeDirectory()

	switch kingpin.Parse() {
		case modeCommand.FullCommand():
			modeHandler()
		case simulateCommand.FullCommand():
			simulateHandler()
		case captureCommand.FullCommand():
			captureHandler()
		case modifyCommand.FullCommand():
			modifyHandler()
		case synthesizeCommand.FullCommand():
			synthesizeHandler()
		case startCommand.FullCommand():
			startHandler(hoverflyDirectory)
		case stopCommand.FullCommand():
			stopHandler(hoverflyDirectory)

	}
}

func createHomeDirectory() string {
	homeDirectory, _ := homedir.Dir()
	hoverflyDirectory := filepath.Join(homeDirectory, "/.hoverfly")

	if _, err := os.Stat(hoverflyDirectory); err != nil {
    		if os.IsNotExist(err) {
        		os.Mkdir(hoverflyDirectory, 0777)
    		}
	}

	return hoverflyDirectory
}

func modeHandler() {
	response := getHoverflyMode()
	fmt.Println("Hoverfly is currently set to " + response.Mode + " mode")
}

func simulateHandler() {
	response := setHoverflyMode("simulate")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to simulate mode")
}

func captureHandler() {
	response := setHoverflyMode("capture")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to capture mode")
}

func modifyHandler() {
	response := setHoverflyMode("modify")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to modify mode")
}

func synthesizeHandler() {
	response := setHoverflyMode("synthesize")
	defer response.Body.Close()
	fmt.Println("Hoverfly set to synthesize mode")
}

func startHandler(hoverflyDirectory string) {
	hoverflyPidFile := filepath.Join(hoverflyDirectory, "hoverfly.pid")

	if _, err := os.Stat(hoverflyPidFile); err != nil {
                if os.IsNotExist(err) {
			cmd := exec.Command("/Users/benjih/Downloads/hoverfly/hoverfly_v0.5.17_OSX_amd64")
			cmd.Start()
			ioutil.WriteFile(hoverflyPidFile, []byte(strconv.Itoa(cmd.Process.Pid)), 0644)
			fmt.Println("Hoverfly is now running")
                }
        }
}

func stopHandler(hoverflyDirectory string) {
	hoverflyPidFile := filepath.Join(hoverflyDirectory, "hoverfly.pid")
	pidFileData, _ := ioutil.ReadFile(hoverflyPidFile)
	pid, _ := strconv.Atoi(string(pidFileData))
	hoverflyProcess := os.Process{Pid: pid}
	err := hoverflyProcess.Kill()
	if err != nil {
		fmt.Println("Hoverfly has been killed")
		os.Remove(hoverflyPidFile)
	} else {
		fmt.Println(err.Error())
		fmt.Println("Failed to kill Hoverfly")
		fmt.Printf("Pid: %#v", pid)
	}
}

func getHoverflyMode() (ApiStateResponse) {
	request, _ := sling.New().Get("http://localhost:8888/api/state").Request()
	response, _ := http.DefaultClient.Do(request)
	defer response.Body.Close()

	body, _ := ioutil.ReadAll(response.Body)
	var jsonResponse ApiStateResponse
	json.Unmarshal(body, &jsonResponse)
	return jsonResponse
}

func setHoverflyMode(mode string) (*http.Response) {
	request, _ := sling.New().Post("http://localhost:8888/api/state").Body(strings.NewReader(`{"mode":"` + mode + `"}`)).Request()
	response, _ := http.DefaultClient.Do(request)
	return response
}
<|endoftext|>