<commit_before>package main

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

	//"github.com/hashicorp/serf/client"
	"github.com/codegangsta/cli"
	"github.com/hashicorp/serf/command"
	"github.com/hashicorp/serf/command/agent"
	"github.com/hashicorp/serf/serf"
)

var (
	defaultName, _ = os.Hostname()
	config         Config
)

func main() {

	app := cli.NewApp()
	app.Name = "serfbort"
	app.Usage = "deploy tool"
	app.Action = cli.ShowAppHelp
	//top level flags, common to all commands
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "rpc",
			Value: "localhost:7373",
			Usage: "Listen on the address for RPC requests (i.e. from deploy command)",
		},
		cli.StringFlag{
			Name:  "rpc-auth",
			Usage: "Auth token to use for RPC",
		},
		cli.StringFlag{
			Name:   "config",
			Usage:  "JSON config describing deploy targets, commands, etc",
			EnvVar: "SERFBORT_CONFIG",
		},
	}
	// subcommands
	app.Commands = []cli.Command{
		{
			Name: "master",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Value: defaultName,
					Usage: "Name to use in serf protocol",
				},
				cli.StringFlag{
					Name:  "master",
					Value: "localhost:7946",
					Usage: "Join the cluster by coordinating with this master",
				},
				cli.StringFlag{
					Name:  "listen",
					Value: "localhost:7946",
					Usage: "Listen on the address for serf communication",
				},
			},
			Usage:  "Run the serfbort master process",
			Action: StartMaster,
		},
		{
			Name:   "verify",
			Flags:  []cli.Flag{},
			Usage:  "Verify a deploy",
			Action: DoVerify,
		},
		{
			Name:   "deploy",
			Flags:  []cli.Flag{},
			Usage:  "Perform a deploy",
			Action: DoDeploy,
			Before: LoadConfig,
		},
		{
			Name: "agent",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "master",
					Value: "localhost:7946",
					Usage: "Join the cluster by coordinating with this master",
				},
				cli.StringFlag{
					Name:  "listen",
					Value: "localhost:7947",
					Usage: "Listen on the address for serf communication",
				},
				cli.StringFlag{
					Name:  "name",
					Value: defaultName,
					Usage: "Name to use in serf protocol",
				},
				cli.StringFlag{
					Name:  "tags-file",
					Usage: "Load tags for agent from file (json format)",
				},
			},
			Usage:  "Run the serfbort agent",
			Before: LoadConfig,
			Action: StartAgent,
		},
	}

	app.Run(os.Args)

}

func StartAgent(c *cli.Context) {
	//TODO make this work with authkeys
	//rpcAddress := c.GlobalString("rpc")
	//rpcAuthKey := c.GlobalString("rpc-auth")
	masterAddress := c.String("master")
	listenAddress := c.String("listen")

	serfConfig := serf.DefaultConfig()
	fields := strings.Split(listenAddress, ":")
	if len(fields) != 2 {
		log.Fatalf("listen requires host:port! %s is not valid", listenAddress)
	}
	bindAddr := fields[0]
	bindPort, err := strconv.Atoi(fields[1])
	if err != nil {
		log.Fatalf("Unable to parse %s into port", fields[1])
	}
	serfConfig.MemberlistConfig.BindAddr = bindAddr
	serfConfig.MemberlistConfig.BindPort = bindPort

	evtCh := make(chan serf.Event, 64)
	serfConfig.EventCh = evtCh

	if c.IsSet("tags-file") {
		tagsLoaded, err := loadTagsFromFile(c.String("tags-file"))
		if err != nil {
			log.Fatalf("Unable to load tags from file: %s", err)
		}
		serfConfig.Tags = tagsLoaded
	}
	if c.IsSet("name") {
		serfConfig.NodeName = c.String("name")
	}
	log.Printf("Starting agent with tags %v", serfConfig.Tags)
	//TODO pull this into the Agent type
	s, err := serf.Create(serfConfig)
	if err != nil {
		log.Fatalf("Error creating Serf: %s", err)
	}

	log.Printf("Joining cluster by way of %s", masterAddress)
	n, err := s.Join([]string{masterAddress}, true)
	if n > 0 {
		log.Printf("Cluster joined; %d nodes participating", n)
	}
	if err != nil {
		log.Fatalf("unable to join cluster: %s", err)
	}

	a := AgentEventHandler{s, evtCh}
	a.EventLoop()
}

func StartMaster(c *cli.Context) {
	rpcAddress := c.GlobalString("rpc")
	rpcAuthKey := c.GlobalString("rpc-auth")
	masterAddress := c.String("master")
	listenAddress := c.String("listen")

	fields := strings.Split(listenAddress, ":")
	if len(fields) != 2 {
		log.Fatalf("listen requires host:port! %s is not valid", listenAddress)
	}
	bindAddr := fields[0]
	bindPort, err := strconv.Atoi(fields[1])
	if err != nil {
		log.Fatalf("Unable to parse %s into port", fields[1])
	}
	serfConfig := serf.DefaultConfig()
	serfConfig.MemberlistConfig.BindAddr = bindAddr
	serfConfig.MemberlistConfig.BindPort = bindPort
	if c.IsSet("name") {
		serfConfig.NodeName = c.String("name")
	}

	log.Printf("Starting master on %s", listenAddress)
	log.Printf("Starting master RPC listener on %s", rpcAddress)
	//TODO pull this crap into the Master type
	logOutput := os.Stderr
	logWriter := agent.NewLogWriter(123)
	a, err := agent.Create(agent.DefaultConfig(), serfConfig, logWriter)
	if err != nil {
		log.Fatalf("Unable to create agent: %s", err)
	}

	//register event handlers
	a.RegisterEventHandler(MasterEventHandler{})

	if err := a.Start(); err != nil {
		log.Fatalf("Unable to start agent: %s", err)
	}

	log.Printf("Joining cluster by way of %s", masterAddress)
	n, err := a.Join([]string{masterAddress}, true)
	if n > 0 {
		log.Printf("Cluster joined; %d nodes participating", n)
	}
	if err != nil {
		log.Fatalf("unable to join cluster: %s", err)
	}

	members := a.Serf().Members()
	log.Printf("%d nodes currently in cluster:", len(members))
	for _, m := range members {
		log.Printf("  %s %s:%d %v %s", m.Name, m.Addr, m.Port, m.Tags, m.Status)
	}

	//TODO we should create an agent with agent.Create instead of this!
	//a := agent.Agent{}
	rpcListener, err := net.Listen("tcp", rpcAddress)
	if err != nil {
		log.Fatal("Error starting RPC listener: %s", err)
	}
	agent.NewAgentIPC(a, rpcAuthKey, rpcListener, logOutput, logWriter)
	select {}

}

func DoVerify(c *cli.Context) {
	panic("fuck implement me")
}

func DoDeploy(c *cli.Context) {
	rpcAddress := c.GlobalString("rpc")
	rpcAuthKey := c.GlobalString("rpc-auth")
	cmd := c.Command.Name
	args := c.Args()
	if len(args) < 1 {
		log.Fatalf("%s requires a deploy target", c.Command.Name)
	}
	target := args[0]
	args = args[1:]

	_, ok := config.Targets[target]
	if !ok {
		log.Fatal("Unable to find target %q in the config", target)
	}

	var payload string
	if len(args) > 0 {
		payload = args[0]
	}
	message := fmt.Sprintf("%s|%s", target, payload)
	//TODO use msgpack to write payload
	//TODO encode targeting info with payload (tags, host list, etc)

	log.Printf("Deploying %s with payload %q (message %q)", target, payload, message)

	rpcclient, err := command.RPCClient(rpcAddress, rpcAuthKey)
	if err != nil {
		log.Fatalf("Unable to connect to master at %s: %s", rpcAddress, err)
	}

	err = rpcclient.UserEvent(cmd, []byte(message), false)
	if err != nil {
		log.Fatal(err)
	}
	log.Print("OK")

}

// loads the config into a global variable
func LoadConfig(c *cli.Context) error {
	if !c.GlobalIsSet("config") {
		log.Fatalln("config is required")
	}
	configFile := c.GlobalString("config")
	cfg, err := loadConfigFromFile(configFile)
	if err != nil {
		//TODO this is dumb that returning an error just causes the command to not be run
		// it doesnt actually print any messages out
		log.Fatalf("Unable to load config: %s", err)
	}
	config = cfg
	log.Printf("Loaded %d targets from %s: %v", len(config.Targets), configFile, config.Targets)

	return err
}

/*
func leaveCluster() {
	//TODO this defer isnt running when ctrl-c'd
			go func() {
		    sig := <-sigChan
		        log.Printf("Cleaning up registered callback after signal %s\n", sig)
		                              os.Exit(0)
				log.Print("fuck")
				if s != nil {
					log.Print("Leaving cluster")
					err := s.Leave()
					if err != nil {
						log.Print(err)
						return
					}
					log.Print("Shutting down")
					err = s.Shutdown()
					if err != nil {
						log.Print(err)
						return
					}

				}
			}()
}
*/
<commit_msg>add ghetto status output<commit_after>package main

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

	//"github.com/hashicorp/serf/client"
	"github.com/codegangsta/cli"
	"github.com/hashicorp/serf/command"
	"github.com/hashicorp/serf/command/agent"
	"github.com/hashicorp/serf/serf"
)

var (
	defaultName, _ = os.Hostname()
	config         Config
)

const (
	//TODO read from build symbols?
	VERSION = "0.1.0"
)

func main() {

	app := cli.NewApp()
	app.Name = "serfbort"
	app.Usage = "deploy tool"
	app.Version = VERSION
	app.Action = cli.ShowAppHelp
	//top level flags, common to all commands
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "config",
			Usage:  "JSON config describing deploy targets, commands, etc",
			EnvVar: "SERFBORT_CONFIG",
		},
		cli.StringFlag{
			Name:  "rpc",
			Value: "localhost:7373",
			Usage: "Listen on the address for RPC requests (i.e. from deploy command)",
		},
		cli.StringFlag{
			Name:  "rpc-auth",
			Usage: "Auth token to use for RPC",
		},
	}
	// subcommands
	app.Commands = []cli.Command{
		{
			Name: "master",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "name",
					Value: defaultName,
					Usage: "Name to use in serf protocol",
				},
				cli.StringFlag{
					Name:  "master",
					Value: "localhost:7946",
					Usage: "Join the cluster by coordinating with this master",
				},
				cli.StringFlag{
					Name:  "listen",
					Value: "localhost:7946",
					Usage: "Listen on the address for serf communication",
				},
			},
			Usage:  "Run the serfbort master process",
			Action: StartMaster,
		},
		{
			Name: "agent",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "master",
					Value: "localhost:7946",
					Usage: "Join the cluster by coordinating with this master",
				},
				cli.StringFlag{
					Name:  "listen",
					Value: "localhost:7947",
					Usage: "Listen on the address for serf communication",
				},
				cli.StringFlag{
					Name:  "name",
					Value: defaultName,
					Usage: "Name to use in serf protocol",
				},
				cli.StringFlag{
					Name:  "tags-file",
					Usage: "Load tags for agent from file (json format)",
				},
			},
			Usage:  "Run the serfbort agent",
			Before: LoadConfig,
			Action: StartAgent,
		},

		{
			Name:   "deploy",
			Flags:  []cli.Flag{},
			Usage:  "Perform a deploy to a target",
			Action: DoDeploy,
			Before: LoadConfig,
		},
		{
			Name:   "verify",
			Flags:  []cli.Flag{},
			Usage:  "Verify a deploy target",
			Action: DoVerify,
		},

		{
			Name: "status",
			Flags: []cli.Flag{
				//match on hostname pattern
				//match on status
				//match on tags
				cli.StringSliceFlag{
					Name:  "tag",
					Usage: `Filter by requiring tag on agent (tag=value) (can be a regexp like "val.*"!)`,
				},
				cli.StringFlag{
					Name:  "name",
					Usage: `Filter by requiring name of agent to match (can be a regexp like "web-1.*"!)`,
				},
			},
			Usage:  "Check the status of all cluster members",
			Action: DoStatus,
		},
	}

	app.Run(os.Args)

}

func StartAgent(c *cli.Context) {
	//TODO make this work with authkeys
	//rpcAddress := c.GlobalString("rpc")
	//rpcAuthKey := c.GlobalString("rpc-auth")
	masterAddress := c.String("master")
	listenAddress := c.String("listen")

	serfConfig := serf.DefaultConfig()
	fields := strings.Split(listenAddress, ":")
	if len(fields) != 2 {
		log.Fatalf("listen requires host:port! %s is not valid", listenAddress)
	}
	bindAddr := fields[0]
	bindPort, err := strconv.Atoi(fields[1])
	if err != nil {
		log.Fatalf("Unable to parse %s into port", fields[1])
	}
	serfConfig.MemberlistConfig.BindAddr = bindAddr
	serfConfig.MemberlistConfig.BindPort = bindPort

	evtCh := make(chan serf.Event, 64)
	serfConfig.EventCh = evtCh

	if c.IsSet("tags-file") {
		tagsLoaded, err := loadTagsFromFile(c.String("tags-file"))
		if err != nil {
			log.Fatalf("Unable to load tags from file: %s", err)
		}
		serfConfig.Tags = tagsLoaded
	}
	if c.IsSet("name") {
		serfConfig.NodeName = c.String("name")
	}
	log.Printf("Starting agent with tags %v", serfConfig.Tags)
	//TODO pull this into the Agent type
	s, err := serf.Create(serfConfig)
	if err != nil {
		log.Fatalf("Error creating Serf: %s", err)
	}

	log.Printf("Joining cluster by way of %s", masterAddress)
	n, err := s.Join([]string{masterAddress}, true)
	if n > 0 {
		log.Printf("Cluster joined; %d nodes participating", n)
	}
	if err != nil {
		log.Fatalf("unable to join cluster: %s", err)
	}

	a := AgentEventHandler{s, evtCh}
	a.EventLoop()
}

func StartMaster(c *cli.Context) {
	rpcAddress := c.GlobalString("rpc")
	rpcAuthKey := c.GlobalString("rpc-auth")
	masterAddress := c.String("master")
	listenAddress := c.String("listen")

	fields := strings.Split(listenAddress, ":")
	if len(fields) != 2 {
		log.Fatalf("listen requires host:port! %s is not valid", listenAddress)
	}
	bindAddr := fields[0]
	bindPort, err := strconv.Atoi(fields[1])
	if err != nil {
		log.Fatalf("Unable to parse %s into port", fields[1])
	}
	serfConfig := serf.DefaultConfig()
	serfConfig.MemberlistConfig.BindAddr = bindAddr
	serfConfig.MemberlistConfig.BindPort = bindPort
	if c.IsSet("name") {
		serfConfig.NodeName = c.String("name")
	}
	serfConfig.Tags = map[string]string{"master": "true"}

	log.Printf("Starting master on %s", listenAddress)
	log.Printf("Starting master RPC listener on %s", rpcAddress)
	//TODO pull this crap into the Master type
	logOutput := os.Stderr
	logWriter := agent.NewLogWriter(123)
	a, err := agent.Create(agent.DefaultConfig(), serfConfig, logWriter)
	if err != nil {
		log.Fatalf("Unable to create agent: %s", err)
	}

	//register event handlers
	a.RegisterEventHandler(MasterEventHandler{})

	if err := a.Start(); err != nil {
		log.Fatalf("Unable to start agent: %s", err)
	}

	log.Printf("Joining cluster by way of %s", masterAddress)
	n, err := a.Join([]string{masterAddress}, true)
	if n > 0 {
		log.Printf("Cluster joined; %d nodes participating", n)
	}
	if err != nil {
		log.Fatalf("unable to join cluster: %s", err)
	}

	members := a.Serf().Members()
	log.Printf("%d nodes currently in cluster:", len(members))
	for _, m := range members {
		log.Printf("  %s %s:%d %v %s", m.Name, m.Addr, m.Port, m.Tags, m.Status)
	}

	//TODO we should create an agent with agent.Create instead of this!
	//a := agent.Agent{}
	rpcListener, err := net.Listen("tcp", rpcAddress)
	if err != nil {
		log.Fatal("Error starting RPC listener: %s", err)
	}
	agent.NewAgentIPC(a, rpcAuthKey, rpcListener, logOutput, logWriter)
	select {}

}

func DoVerify(c *cli.Context) {
	panic("fuck implement me")
}

func DoStatus(c *cli.Context) {
	rpcAddress := c.GlobalString("rpc")
	rpcAuthKey := c.GlobalString("rpc-auth")
	statusFilter := ""
	nameFilter := c.String("name")
	tagsUnparsed := c.StringSlice("tag")
	tagsRequired := map[string]string{}
	for _, t := range tagsUnparsed {
		vals := strings.Split(t, "=")
		if len(vals) != 2 {
			log.Fatalf("tag must take parameters of the format tag=value! %s is fucked up", t)
		}
		tagsRequired[vals[0]] = vals[1]
	}

	log.Printf("Checking cluster status (tags: %v, name: %q)", tagsRequired, nameFilter)

	rpcclient, err := command.RPCClient(rpcAddress, rpcAuthKey)
	if err != nil {
		log.Fatalf("Unable to connect to RPC at %s: %s", rpcAddress, err)
	}
	defer rpcclient.Close()
	members, err := rpcclient.MembersFiltered(tagsRequired, statusFilter, nameFilter)
	if err != nil {
		log.Fatalf("Error retrieving members: %s", err)
	}

	fmt.Printf("%d nodes reporting\n", len(members))
	fmt.Printf("name\taddr\tport\ttags\tstatus\n")
	for _, member := range members {
		fmt.Printf("%s\t%s\t%d\t%v\t%s\n", member.Name, member.Addr, member.Port, member.Tags, member.Status)
	}

}

func DoDeploy(c *cli.Context) {
	rpcAddress := c.GlobalString("rpc")
	rpcAuthKey := c.GlobalString("rpc-auth")
	cmd := c.Command.Name
	args := c.Args()
	if len(args) < 1 {
		log.Fatalf("%s requires a deploy target", c.Command.Name)
	}
	target := args[0]
	args = args[1:]

	_, ok := config.Targets[target]
	if !ok {
		log.Fatal("Unable to find target %q in the config", target)
	}

	var payload string
	if len(args) > 0 {
		payload = args[0]
	}
	message := fmt.Sprintf("%s|%s", target, payload)
	//TODO use msgpack to write payload
	//TODO encode targeting info with payload (tags, host list, etc)

	log.Printf("Deploying %s with payload %q (message %q)", target, payload, message)

	rpcclient, err := command.RPCClient(rpcAddress, rpcAuthKey)
	if err != nil {
		log.Fatalf("Unable to connect to RPC at %s: %s", rpcAddress, err)
	}
	defer rpcclient.Close()

	err = rpcclient.UserEvent(cmd, []byte(message), false)
	if err != nil {
		log.Fatal(err)
	}
	log.Print("OK")

}

// loads the config into a global variable
func LoadConfig(c *cli.Context) error {
	if !c.GlobalIsSet("config") {
		log.Fatalln("config is required")
	}
	configFile := c.GlobalString("config")
	cfg, err := loadConfigFromFile(configFile)
	if err != nil {
		//TODO this is dumb that returning an error just causes the command to not be run
		// it doesnt actually print any messages out
		log.Fatalf("Unable to load config: %s", err)
	}
	config = cfg
	log.Printf("Loaded %d targets from %s: %v", len(config.Targets), configFile, config.Targets)

	return err
}

/*
func leaveCluster() {
	//TODO this defer isnt running when ctrl-c'd
			go func() {
		    sig := <-sigChan
		        log.Printf("Cleaning up registered callback after signal %s\n", sig)
		                              os.Exit(0)
				log.Print("fuck")
				if s != nil {
					log.Print("Leaving cluster")
					err := s.Leave()
					if err != nil {
						log.Print(err)
						return
					}
					log.Print("Shutting down")
					err = s.Shutdown()
					if err != nil {
						log.Print(err)
						return
					}

				}
			}()
}
*/
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"github.com/belogik/goes"
	"log"
	"net/http"
	"runtime"
	"strings"
)

func main() {

	maxProcs := runtime.NumCPU()
	runtime.GOMAXPROCS(maxProcs)

	var (
		es_host string
	)

	flag.StringVar(&es_host, "eshost", "localhost:9200", "HTTP host:port for ElasticSearch server")
	flag.Parse()

	es_host_and_port := strings.Split(es_host, ":")

	engine := goes.NewConnection(es_host_and_port[0], es_host_and_port[1])

	http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {

		q := r.URL.Query().Get("q")
		// fmt.Fprintf(w, "Search: %q", q)
		query := map[string]interface{}{
			"query": map[string]interface{}{
				"filtered": map[string]interface{}{
					"query": map[string]interface{}{
						"query_string": map[string]interface{}{
							"query":            q,
							"default_operator": "AND",
						},
					},
				},
			},
		}

		searchResults, err := engine.Search(query, []string{"products"}, []string{"product"})

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		json_data, err := json.Marshal(searchResults)

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(json_data)
	})

	log.Fatal(http.ListenAndServe(":3000", nil))
}
<commit_msg>Filter visible products only.<commit_after>package main

import (
	"encoding/json"
	"flag"
	"github.com/belogik/goes"
	"log"
	"net/http"
	"runtime"
	"strings"
)

func main() {

	maxProcs := runtime.NumCPU()
	runtime.GOMAXPROCS(maxProcs)

	var (
		es_host string
	)

	flag.StringVar(&es_host, "eshost", "localhost:9200", "HTTP host:port for ElasticSearch server")
	flag.Parse()

	es_host_and_port := strings.Split(es_host, ":")

	engine := goes.NewConnection(es_host_and_port[0], es_host_and_port[1])

	http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {

		q := r.URL.Query().Get("q")
		// fmt.Fprintf(w, "Search: %q", q)
		query := map[string]interface{}{
			"query": map[string]interface{}{
				"filtered": map[string]interface{}{
					"query": map[string]interface{}{
						"query_string": map[string]interface{}{
							"query":            q,
							"default_operator": "AND",
						},
					},
					"filter": map[string]interface{}{
						"and": []interface{}{
							map[string]interface{}{
								"term": map[string]interface{}{
									"status": []string{"visible"},
								},
							},
						},
					},
				},
			},
		}

		searchResults, err := engine.Search(query, []string{"products"}, []string{"product"})

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		json_data, err := json.Marshal(searchResults)

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		w.Write(json_data)
	})

	log.Fatal(http.ListenAndServe(":3000", nil))
}
<|endoftext|>


<commit_before>// Copyright 2015 Stuart Glenn, OMRF. All rights reserved.
// Use of this code is governed by a 3 clause BSD style license
// Full license details in LICENSE file distributed with this software

package main

import (
	"encoding/csv"
	"log"
	"os"

	"github.com/oklasoft/mmatcher/matcher"
)

func main() {
	case_file, err := os.Open(os.Args[1])
	if nil != err {
		log.Fatal(err)
	}
	defer case_file.Close()

	cases, err := matcher.NewRecordsFromCSV(case_file)
	if nil != err {
		log.Fatal(err)
	}

	control_file, err := os.Open(os.Args[2])
	if nil != err {
		log.Fatal(err)
	}
	defer control_file.Close()

	controls, err := matcher.NewRecordsFromCSV(control_file)
	if nil != err {
		log.Fatal(err)
	}

	all_matches := matcher.NewMatchSet()

	positions := []int{0, 1, 2}
	ranges := []matcher.Atter{matcher.TextAtt{}, matcher.TextAtt{}, matcher.NumericAtt{5}}

	for _, r := range cases {
		spots := r.Matches(controls, positions, ranges...)
		for _, i := range spots {
			all_matches.AddPair(matcher.NewPair(r.ID, controls[i].ID))
		}
	}

	log.Print("First pass lookikng for matches found:", all_matches)

	opti := all_matches.QuantityOptimized()

	log.Print("After optimizing we got:", opti)

	out := csv.NewWriter(os.Stdout)
	out.Write([]string{"case", "control"})

	for _, r := range cases {
		m := opti.MatchesFor(r.ID)
		if 0 == len(m) {
			continue
		}
		out.Write([]string{r.ID, m[0]})
	}
	out.Flush()

}
<commit_msg>Flesh out main to be more generic, all opts from CLI<commit_after>// Copyright 2015 Stuart Glenn, OMRF. All rights reserved.
// Use of this code is governed by a 3 clause BSD style license
// Full license details in LICENSE file distributed with this software

package main

import (
	"encoding/csv"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/oklasoft/mmatcher/matcher"
)

func loadData(path string) matcher.Records {
	file, err := os.Open(path)
	if nil != err {
		log.Fatal(err)
	}
	defer file.Close()

	data, err := matcher.NewRecordsFromCSV(file)
	if nil != err {
		log.Fatal(err)
	}
	return data
}

func parseKeys(s string) ([]int, []matcher.Atter) {
	parts := strings.Split(s, ",")
	positions := make([]int, len(parts))
	ranges := make([]matcher.Atter, len(parts))
	for i, v := range parts {
		k := strings.Split(v, ":")
		p, err := strconv.ParseInt(k[0], 10, 32)
		if nil != err {
			log.Fatal(err)
		}
		positions[i] = int(p) - 1
		if len(k) > 1 {
			r, err := strconv.ParseFloat(k[1], 32)
			if nil != err {
				log.Fatal(err)
			}
			ranges[i] = matcher.NumericAtt{r}
		}
	}
	return positions, ranges
}

func main() {
	positions, ranges := parseKeys(os.Args[1])
	log.Print(positions)
	log.Print(ranges)
	cases := loadData(os.Args[2])
	controls := loadData(os.Args[3])

	all_matches := matcher.NewMatchSet()

	for _, r := range cases {
		spots := r.Matches(controls, positions, ranges...)
		for _, i := range spots {
			all_matches.AddPair(matcher.NewPair(r.ID, controls[i].ID))
		}
	}

	opti := all_matches.QuantityOptimized()

	out := csv.NewWriter(os.Stdout)
	out.Write([]string{"case", "control"})

	for _, r := range cases {
		m := opti.MatchesFor(r.ID)
		if 0 == len(m) {
			out.Write([]string{r.ID})
			continue
		}
		control := controls.Get(m[0])
		line := []string{r.ID, m[0]}
		for _, p := range positions {
			line = append(line, r.Atts[p].String(), control.Atts[p].String())
		}
		out.Write(line)
	}
	out.Flush()

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"reflect"
	"strings"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/handlers"
)

type server struct {
	tmpl *template.Template
}

type headInfo struct {
	Title   string
	Icon    string
	Request string
}

func main() {
	var err error

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	s := &server{}
	s.tmpl, err = parseTemplates("template", ".html")
	if err != nil {
		log.Fatal(err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/", s.indexHandler)
	mux.HandleFunc("/http-basics/", s.httpBasicsHandler("http-basics.html", "HTTP Basics", "fa-coffee"))
	mux.HandleFunc("/http-parse/", s.parseHandler)
	mux.HandleFunc("/http-query/", s.httpBasicsHandler("http-query.html", "HTTP Query", "fa-question"))
	mux.HandleFunc("/http-post/", s.httpPostHandler)
	mux.HandleFunc("/http-media/", s.httpMediaHandler)
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// f, err := os.Create("access.log")
	// if err != nil {
	// 	log.Fatal(err)
	// }
	logHandler := handlers.LoggingHandler(os.Stdout, mux)

	w, err := watchTemplate("template")
	defer w.Close()
	go s.reloadTemplate(w)

	log.Println("listening on :8080")
	log.Fatal(http.ListenAndServe(":8080", logHandler))
}

func writeError(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.WriteHeader(http.StatusInternalServerError)
	w.Write([]byte(msg))
}

func (s *server) execTemplate(w http.ResponseWriter, file string, data interface{}) {
	err := s.tmpl.ExecuteTemplate(w, file, data)
	if err != nil {
		log.Println("fail to execute template:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
}

func (s *server) reloadTemplate(w *fsnotify.Watcher) {
	for {
		select {
		case event := <-w.Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				tmpl, err := parseTemplates("template", ".html")
				if err != nil {
					log.Println("fail to load template:", err)
				}
				log.Println("template updated")
				s.tmpl = tmpl
			}
		case err := <-w.Errors:
			log.Println("fail to watch template:", err)
		}
	}
}

func (s *server) indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		s.notFoundHandler(w, r)
		return
	}
	d := &headInfo{
		Title: "AJAX Game",
		Icon:  "fa-gamepad",
	}
	s.execTemplate(w, "index.html", d)
}

func (s *server) httpBasicsHandler(file, title, icon string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		d := &headInfo{
			Title: title,
			Icon:  icon,
		}
		allow := []string{"Host"}
		tmp, err := dumpRequest(r, allow, true)
		if err != nil {
			log.Println("fail to dump request:", err)
			writeError(w, "Oops, something went wrong... ☹")
			return
		}
		d.Request = string(tmp)
		s.execTemplate(w, file, d)
	}
}

func (s *server) parseHandler(w http.ResponseWriter, r *http.Request) {

	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "fail to parse form: %q", err)
		return
	}

	netcatRequest := r.FormValue("request")
	if netcatRequest == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "POST variable request empty")
		return
	}

	exploded := strings.Split(netcatRequest, " ")
	method := exploded[0]

	if !strings.HasPrefix(exploded[2], "HTTP/1.0") && !strings.HasPrefix(exploded[2], "HTTP/1.1") {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Request must be HTTP/1.0 or HTTP/1.1")
		return
	}

	newr, err := http.NewRequest(method, "http://localhost:8080"+exploded[1], nil)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot create new request: %q", err)
		return
	}

	client := &http.Client{}
	resp, err := client.Do(newr)

	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "cannot client.Do: %q", err)
		return
	}
	defer resp.Body.Close()

	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "cannot read body: %q", err)
		return
	}

	w.WriteHeader(resp.StatusCode)
	w.Write(b)
}

func (s *server) httpPostHandler(w http.ResponseWriter, r *http.Request) {
	d := &struct {
		headInfo
		Error string
		Color string
		Name  string
	}{
		headInfo: headInfo{
			Title: "HTTP Post",
			Icon:  "fa-info",
		},
		Error: "Sorry, I am confuse... What is your favorite color again? Did we met before?",
	}
	badRequestHandler := s.badRequestHandler(d)

	q := r.URL.Query()
	d.Name = strings.Title(q.Get("name"))
	d.Color = q.Get("color")
	if d.Name == "" || d.Color == "" {
		badRequestHandler(w, r)
		return
	}

	tmp, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println("fail to dump request:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
	d.Request = string(tmp)
	s.execTemplate(w, "http-post.html", d)
}

func (s *server) httpMediaHandler(w http.ResponseWriter, r *http.Request) {
	d := &struct {
		headInfo
		Error    string
		Color    string
		Name     string
		KindWord string
		FunGauge string
	}{
		headInfo: headInfo{
			Title: "HTTP Media",
			Icon:  "fa-sun-o",
		},
		Error: "Something is not quite right... Do we know each other?",
	}
	badRequestHandler := s.badRequestHandler(d)

	tmp, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println("fail to dump request:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
	d.Request = string(tmp)

	err = r.ParseForm()
	if err != nil {
		badRequestHandler(w, r)
		return
	}
	d.Color = r.Form.Get("color")
	d.Name = strings.Title(r.Form.Get("name"))
	d.KindWord = r.Form.Get("kind-word")
	d.FunGauge = r.Form.Get("fun-gauge")
	if d.Color == "" || d.Name == "" || d.KindWord == "" || d.FunGauge == "" {
		badRequestHandler(w, r)
		return
	}

	s.execTemplate(w, "http-media.html", d)
}

func (s *server) notFoundHandler(w http.ResponseWriter, r *http.Request) {
	d := &headInfo{
		Title: "404 - Not Found",
		Icon:  "fa-eye",
	}
	w.WriteHeader(http.StatusNotFound)
	err := s.tmpl.ExecuteTemplate(w, "not-found.html", d)
	if err != nil {
		log.Println("fail to execute template:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
}

func (s *server) badRequestHandler(data interface{}) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		v := reflect.ValueOf(data)
		if v.Kind() == reflect.Ptr && !v.IsNil() && v.IsValid() {
			f := v.Elem().FieldByName("Icon")
			if f.IsValid() {
				f.SetString("fa-bug")
			}
		} else {
			log.Println("unexpected type for data (expects &struct{})")
		}

		w.WriteHeader(http.StatusBadRequest)
		err := s.tmpl.ExecuteTemplate(w, "bad-request.html", data)
		if err != nil {
			log.Println("fail to execute template:", err)
			writeError(w, "Oops, something went wrong... ☹")
			return
		}
	}
}
<commit_msg>Use 302 Redirect in http-parse<commit_after>package main

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

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/handlers"
)

type server struct {
	tmpl *template.Template
}

type headInfo struct {
	Title   string
	Icon    string
	Request string
}

func main() {
	var err error

	log.SetFlags(log.LstdFlags | log.Lshortfile)

	s := &server{}
	s.tmpl, err = parseTemplates("template", ".html")
	if err != nil {
		log.Fatal(err)
	}

	mux := http.NewServeMux()
	mux.HandleFunc("/", s.indexHandler)
	mux.HandleFunc("/http-basics/", s.httpBasicsHandler("http-basics.html", "HTTP Basics", "fa-coffee"))
	mux.HandleFunc("/http-parse/", s.parseHandler)
	mux.HandleFunc("/http-query/", s.httpBasicsHandler("http-query.html", "HTTP Query", "fa-question"))
	mux.HandleFunc("/http-post/", s.httpPostHandler)
	mux.HandleFunc("/http-media/", s.httpMediaHandler)
	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// f, err := os.Create("access.log")
	// if err != nil {
	// 	log.Fatal(err)
	// }
	logHandler := handlers.LoggingHandler(os.Stdout, mux)

	w, err := watchTemplate("template")
	defer w.Close()
	go s.reloadTemplate(w)

	log.Println("listening on :8080")
	log.Fatal(http.ListenAndServe(":8080", logHandler))
}

func writeError(w http.ResponseWriter, msg string) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.WriteHeader(http.StatusInternalServerError)
	w.Write([]byte(msg))
}

func (s *server) execTemplate(w http.ResponseWriter, file string, data interface{}) {
	err := s.tmpl.ExecuteTemplate(w, file, data)
	if err != nil {
		log.Println("fail to execute template:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
}

func (s *server) reloadTemplate(w *fsnotify.Watcher) {
	for {
		select {
		case event := <-w.Events:
			if event.Op&fsnotify.Write == fsnotify.Write {
				tmpl, err := parseTemplates("template", ".html")
				if err != nil {
					log.Println("fail to load template:", err)
				}
				log.Println("template updated")
				s.tmpl = tmpl
			}
		case err := <-w.Errors:
			log.Println("fail to watch template:", err)
		}
	}
}

func (s *server) indexHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		s.notFoundHandler(w, r)
		return
	}
	d := &headInfo{
		Title: "AJAX Game",
		Icon:  "fa-gamepad",
	}
	s.execTemplate(w, "index.html", d)
}

func (s *server) httpBasicsHandler(file, title, icon string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		d := &headInfo{
			Title: title,
			Icon:  icon,
		}
		allow := []string{"Host"}
		tmp, err := dumpRequest(r, allow, true)
		if err != nil {
			log.Println("fail to dump request:", err)
			writeError(w, "Oops, something went wrong... ☹")
			return
		}
		d.Request = string(tmp)
		s.execTemplate(w, file, d)
	}
}

func (s *server) parseHandler(w http.ResponseWriter, r *http.Request) {

	err := r.ParseForm()
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "fail to parse form: %q", err)
		return
	}
	netcatRequest := r.FormValue("request")
	if netcatRequest == "" {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "POST variable request empty")
		return
	}

	exploded := strings.Split(netcatRequest, " ")

	if len(exploded) != 3 {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintf(w, "Wrong request...")
		return
	}

	method := exploded[0]
	page := exploded[1]
	version := exploded[2]

	if method != "GET" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		fmt.Fprintf(w, "Please use GET method")
		return
	}

	if !strings.HasPrefix(version, "HTTP/1.0") && !strings.HasPrefix(version, "HTTP/1.1") {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprintln(w, "Request must be HTTP/1.0 or HTTP/1.1")
		return
	}

	w.Header().Set("Location", page)
	w.WriteHeader(http.StatusFound)
}

func (s *server) httpPostHandler(w http.ResponseWriter, r *http.Request) {
	d := &struct {
		headInfo
		Error string
		Color string
		Name  string
	}{
		headInfo: headInfo{
			Title: "HTTP Post",
			Icon:  "fa-info",
		},
		Error: "Sorry, I am confuse... What is your favorite color again? Did we met before?",
	}
	badRequestHandler := s.badRequestHandler(d)

	q := r.URL.Query()
	d.Name = strings.Title(q.Get("name"))
	d.Color = q.Get("color")
	if d.Name == "" || d.Color == "" {
		badRequestHandler(w, r)
		return
	}

	tmp, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println("fail to dump request:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
	d.Request = string(tmp)
	s.execTemplate(w, "http-post.html", d)
}

func (s *server) httpMediaHandler(w http.ResponseWriter, r *http.Request) {
	d := &struct {
		headInfo
		Error    string
		Color    string
		Name     string
		KindWord string
		FunGauge string
	}{
		headInfo: headInfo{
			Title: "HTTP Media",
			Icon:  "fa-sun-o",
		},
		Error: "Something is not quite right... Do we know each other?",
	}
	badRequestHandler := s.badRequestHandler(d)

	tmp, err := httputil.DumpRequest(r, true)
	if err != nil {
		log.Println("fail to dump request:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
	d.Request = string(tmp)

	err = r.ParseForm()
	if err != nil {
		badRequestHandler(w, r)
		return
	}
	d.Color = r.Form.Get("color")
	d.Name = strings.Title(r.Form.Get("name"))
	d.KindWord = r.Form.Get("kind-word")
	d.FunGauge = r.Form.Get("fun-gauge")
	if d.Color == "" || d.Name == "" || d.KindWord == "" || d.FunGauge == "" {
		badRequestHandler(w, r)
		return
	}

	s.execTemplate(w, "http-media.html", d)
}

func (s *server) notFoundHandler(w http.ResponseWriter, r *http.Request) {
	d := &headInfo{
		Title: "404 - Not Found",
		Icon:  "fa-eye",
	}
	w.WriteHeader(http.StatusNotFound)
	err := s.tmpl.ExecuteTemplate(w, "not-found.html", d)
	if err != nil {
		log.Println("fail to execute template:", err)
		writeError(w, "Oops, something went wrong... ☹")
		return
	}
}

func (s *server) badRequestHandler(data interface{}) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		v := reflect.ValueOf(data)
		if v.Kind() == reflect.Ptr && !v.IsNil() && v.IsValid() {
			f := v.Elem().FieldByName("Icon")
			if f.IsValid() {
				f.SetString("fa-bug")
			}
		} else {
			log.Println("unexpected type for data (expects &struct{})")
		}

		w.WriteHeader(http.StatusBadRequest)
		err := s.tmpl.ExecuteTemplate(w, "bad-request.html", data)
		if err != nil {
			log.Println("fail to execute template:", err)
			writeError(w, "Oops, something went wrong... ☹")
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/spf13/cobra"
)

var (
	wholeDirectory bool
	recursive      bool
	json           bool
)

func main() {
	var cmd = &cobra.Command{
		Use:   "hasher",
		Short: "generate an hash from a file",
		Run: func(cmd *cobra.Command, args []string) {
			cmd.Help()
		},
	}

	var cmdSha256 = &cobra.Command{
		Use:   "sha256 [string to echo]",
		Short: "generates a SHA256 from a given file or directory",
		Run: func(cmd *cobra.Command, args []string) {
			files, _ := ioutil.ReadDir("./")
			for _, f := range files {
				fmt.Print(f.Name() + " : ")

				hasher := sha256.New()
				f, err := os.Open(f.Name())
				if err != nil {
					log.Fatal(err)
				}
				defer f.Close()
				if _, err := io.Copy(hasher, f); err != nil {
					log.Fatal(err)
				}

				fmt.Println(hex.EncodeToString(hasher.Sum(nil)))
			}
		},
	}

	cmd.Flags().BoolVarP(&wholeDirectory, "all", "a", false, "iterate all files in directory")
	cmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "iterate the directory recursively")
	cmd.Flags().BoolVarP(&json, "json", "j", true, "output in json format")
	cmd.AddCommand(cmdSha256)
	cmd.Execute()
}
<commit_msg>update main.go<commit_after>package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"

	"github.com/spf13/cobra"
)

var (
	recursive                         bool
	doMD5, doSHA1, doSHA256, doSHA512 bool
	hashes                            map[string]map[string]string
)

func main() {
	hashes = map[string]map[string]string{}

	var cmd = &cobra.Command{
		Use:   "hasher [file or directory]",
		Short: "generate an hash from a file and prints in json format",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				cmd.Help()
				return
			}

			file, err := os.Stat(args[0])

			if err != nil {
				log.Fatal(err)
			}

			if file.IsDir() {
				if recursive {
					filepath.Walk(args[0], func(path string, info os.FileInfo, err error) error {
						if err != nil {
							return err
						}

						if info.IsDir() {
							return nil
						}

						hashFile(path)
						return nil
					})
				} else {

				}
			} else {
				hashFile(args[0])
			}

			jsonContent, err := json.MarshalIndent(hashes, "", "\t")

			if err != nil {
				log.Fatal(err)
			}

			fmt.Println(string(jsonContent))
		},
	}

	cmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "iterate the directory recursively")

	cmd.Flags().BoolVarP(&doMD5, "md5", "", false, "get the MD5 hash")
	cmd.Flags().BoolVarP(&doSHA1, "sha1", "", false, "get the SHA1 hash")
	cmd.Flags().BoolVarP(&doSHA256, "sha256", "", false, "get the SHA256 hash")
	cmd.Flags().BoolVarP(&doSHA512, "sha512", "", false, "get the SHA512 hash")
	cmd.Execute()
}

func hashFile(path string) {
	hashes[path] = map[string]string{}

	file, err := ioutil.ReadFile(path)

	if err != nil {
		log.Fatal(err)
	}

	if doMD5 {
		hasher := md5.New()
		hasher.Write(file)
		hashes[path]["md5"] = hex.EncodeToString(hasher.Sum(nil))
	}

	if doSHA1 {
		hasher := sha1.New()
		hasher.Write(file)
		hashes[path]["sha1"] = hex.EncodeToString(hasher.Sum(nil))
	}

	if doSHA256 {
		hasher := sha256.New()
		hasher.Write(file)
		hashes[path]["sha256"] = hex.EncodeToString(hasher.Sum(nil))
	}

	if doSHA512 {
		hasher := sha512.New()
		hasher.Write(file)
		hashes[path]["sha512"] = hex.EncodeToString(hasher.Sum(nil))
	}
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "fmt"
    "time"
    "flag"
    "reflect"

    "k8s.io/client-go/rest"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/cache"
    "k8s.io/client-go/tools/clientcmd"
    core "k8s.io/client-go/pkg/api/v1"
    extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"

    "k8s.io/apimachinery/pkg/fields"
    "k8s.io/apimachinery/pkg/util/intstr"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

    log "github.com/Sirupsen/logrus"
)

var (
    //dns wildcard record for all applications created, should be like example.com
    wildcardRecord = os.Getenv("AUTO_INGRESS_SERVER_NAME")
    //namespace where auto-ingress will be activated
    namespace = os.Getenv("AUTO_INGRESS_NAMESPACE")
    //secret for ssl/tls of namespace where auto-ingress is running
    secret = os.Getenv("AUTO_INGRESS_SECRET")
    //read kubeconfig
    kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
)

func main() {
    flag.Parse()

    var err error
    var config *rest.Config

    //if kubeconfig is specified, use out-of-cluster
    if *kubeconfig != "" {
        config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
    } else {
        //get config when running inside Kubernetes
        config, err = rest.InClusterConfig()
    }

    if err != nil {
        log.Errorln(err.Error())
        return
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Errorln(err.Error())
        return
    }

    //map to keep track of which services have been already auto-ingressed
	var svcIngPair map[string]extensions.Ingress
    svcIngPair = make(map[string]extensions.Ingress)

    //get current ingresses on cluster
    log.Info("Initializing mapping between ingresses and services...")
	err = createIngressServiceMap(clientset, svcIngPair)
    if err != nil {
        log.Errorln(err.Error())
        return
    }

    log.Info("Initialized map: ", reflect.ValueOf(svcIngPair).MapKeys())

    //create a watch to listen for create/update/delete event on service
    //new created service will be auto-ingressed if it specifies label "autoingress: true"
    //deleted service will be remove the associated ingress if it specifies label "autoingress: true"
    watchlist := cache.NewListWatchFromClient(clientset.Core().RESTClient(), "services", namespace,
        fields.Everything())
    _, controller := cache.NewInformer(
        watchlist,
        &core.Service{},
        time.Second * 0,
        cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                svc := obj.(*core.Service)
                log.Info("Service added: ", svc.Name)
                lb := svc.Labels
                if _, found1 := svcIngPair[svc.Name]; !found1 {
                    if val, found2 := lb["auto-ingress/enabled"]; found2 {
                        if val == "enabled" {
                            newIng, err := createIngressForService(clientset, *svc)
                            if err != nil {
                                log.Errorln(err.Error())
                            } else {
                                log.Info("Created new ingress for service: ", svc.Name)
                                svcIngPair[svc.Name] = *newIng
                                log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                            }
                        }
                    }
                }
            },
            DeleteFunc: func(obj interface{}) {
                svc := obj.(*core.Service)
                log.Info("Service deleted: ", svc.Name)
				if ing, found := svcIngPair[svc.Name]; found {
					clientset.Ingresses(namespace).Delete(ing.Name, nil)
					log.Info("Deleted ingress for service: ", svc.Name)
                    delete(svcIngPair, svc.Name)
                    log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
				}
            },
            UpdateFunc:func(oldObj, newObj interface{}) {
                newSvc := newObj.(*core.Service)
                log.Info("Service changed: ", newSvc.Name)
                lb := newSvc.Labels
                if ing, found1 := svcIngPair[newSvc.Name]; found1 {
                    if val, found2 := lb["auto-ingress/enabled"]; !found2 {
                        clientset.Ingresses(namespace).Delete(ing.Name, nil)
                        log.Info("Deleted ingress for service: ", newSvc.Name)
                        delete(svcIngPair, newSvc.Name)
                        log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                    } else {
                        if val == "disabled" {
                            clientset.Ingresses(namespace).Delete(ing.Name, nil)
                            log.Info("Deleted ingress for service: ", newSvc.Name)
                            delete(svcIngPair, newSvc.Name)
                            log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                        }
                    }
                } else {
                    if val, found3 := lb["auto-ingress/enabled"]; found3 {
                        if val == "enabled" {
                            newIng, err := createIngressForService(clientset, *newSvc)
                            if err != nil {
                                log.Errorln(err.Error())
                            } else {
                                log.Info("created new ingress for service: ", newSvc.Name)
                                svcIngPair[newSvc.Name] = *newIng
                                log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                            }
                        }
                    }
                }
            },
        },
    )
    stop := make(chan struct{})
    go controller.Run(stop)
    for{
        time.Sleep(time.Second)
    }
}

//create service map in the initial phase to check the current ingresses running on cluster
func createIngressServiceMap(clientset *kubernetes.Clientset, m map[string]extensions.Ingress) error {

	services, err := clientset.CoreV1().Services(namespace).List(metav1.ListOptions{})

    if err != nil {
        return err
    }

    ingresses, err:= clientset.ExtensionsV1beta1().Ingresses(namespace).List(metav1.ListOptions{})

    if err != nil {
        return err
    }

    for i:=0; i < len(ingresses.Items); i++ {
        rules := ingresses.Items[i].Spec.Rules
        for j:=0; j < len(rules); j++ {

            paths := rules[j].HTTP.Paths
            for k:=0; k < len(paths); k++ {
                svcName := paths[k].Backend.ServiceName
                if _, found := m[svcName]; !found {
                    m[svcName] = ingresses.Items[i]
                }
            }
        }
    }

	for i:=0; i < len(services.Items); i++ {
        if _, found1 := m[services.Items[i].GetName()]; !found1 {
            lb := services.Items[i].GetLabels()
            if val, found2 := lb["auto-ingress/enabled"]; found2 {
                if val == "enabled" {
                    newIng, err := createIngressForService(clientset, services.Items[i])
                    if err != nil {
                        return err
                    }
                    m[services.Items[i].GetName()] = *newIng
                }
            }
        }
    }

    return nil
}

//create an ingress for the associated service
func createIngressForService(clientset *kubernetes.Clientset, service core.Service) (*extensions.Ingress, error) {
	backend := createIngressBackend(service)

    ingressname := service.Name
    servername := ingressname + "." + wildcardRecord

    ingress := createIngress(ingressname, servername, backend)

    newIng, err := clientset.Ingresses(namespace).Create(ingress)

    return newIng, err
}

//create an ingress backend before putting it to the ingress
func createIngressBackend(service core.Service) extensions.IngressBackend {
    serviceName := service.GetName()
    if len(service.Spec.Ports) > 0 {
        var servicePort32 interface{}
        var servicePort int

        servicePort32 = service.Spec.Ports[0].Port
        servicePort32Tmp := servicePort32.(int32)

        servicePort = int(servicePort32Tmp)
        return extensions.IngressBackend {
            ServiceName: serviceName,
            ServicePort: intstr.FromInt(servicePort),
        }
    }

    return extensions.IngressBackend {}
}

//create ingress for associated service
func createIngress(ingressname string, servername string, backend extensions.IngressBackend) *extensions.Ingress {

    return &extensions.Ingress {
        ObjectMeta: metav1.ObjectMeta {
            Name: ingressname,
            Namespace: namespace,
        },
        Spec: extensions.IngressSpec {
            TLS: []extensions.IngressTLS{
                {
                    Hosts: []string{
                        servername,
                    },
                    SecretName: secret,

                },
            },
            Rules: []extensions.IngressRule {
                {
                    Host: servername,
                    IngressRuleValue: extensions.IngressRuleValue {
                        HTTP: &extensions.HTTPIngressRuleValue {
                        Paths: []extensions.HTTPIngressPath {
                            {
                                Path: "/",
                                Backend: backend,
                            },
                        },
                        },
                    },
                },
            },
        },
    }
}
<commit_msg>remove fmt<commit_after>package main

import (
    "os"
    "time"
    "flag"
    "reflect"

    "k8s.io/client-go/rest"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/cache"
    "k8s.io/client-go/tools/clientcmd"
    core "k8s.io/client-go/pkg/api/v1"
    extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"

    "k8s.io/apimachinery/pkg/fields"
    "k8s.io/apimachinery/pkg/util/intstr"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

    log "github.com/Sirupsen/logrus"
)

var (
    //dns wildcard record for all applications created, should be like example.com
    wildcardRecord = os.Getenv("AUTO_INGRESS_SERVER_NAME")
    //namespace where auto-ingress will be activated
    namespace = os.Getenv("AUTO_INGRESS_NAMESPACE")
    //secret for ssl/tls of namespace where auto-ingress is running
    secret = os.Getenv("AUTO_INGRESS_SECRET")
    //read kubeconfig
    kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
)

func main() {
    flag.Parse()

    var err error
    var config *rest.Config

    //if kubeconfig is specified, use out-of-cluster
    if *kubeconfig != "" {
        config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig)
    } else {
        //get config when running inside Kubernetes
        config, err = rest.InClusterConfig()
    }

    if err != nil {
        log.Errorln(err.Error())
        return
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Errorln(err.Error())
        return
    }

    //map to keep track of which services have been already auto-ingressed
	var svcIngPair map[string]extensions.Ingress
    svcIngPair = make(map[string]extensions.Ingress)

    //get current ingresses on cluster
    log.Info("Initializing mapping between ingresses and services...")
	err = createIngressServiceMap(clientset, svcIngPair)
    if err != nil {
        log.Errorln(err.Error())
        return
    }

    log.Info("Initialized map: ", reflect.ValueOf(svcIngPair).MapKeys())

    //create a watch to listen for create/update/delete event on service
    //new created service will be auto-ingressed if it specifies label "autoingress: true"
    //deleted service will be remove the associated ingress if it specifies label "autoingress: true"
    watchlist := cache.NewListWatchFromClient(clientset.Core().RESTClient(), "services", namespace,
        fields.Everything())
    _, controller := cache.NewInformer(
        watchlist,
        &core.Service{},
        time.Second * 0,
        cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                svc := obj.(*core.Service)
                log.Info("Service added: ", svc.Name)
                lb := svc.Labels
                if _, found1 := svcIngPair[svc.Name]; !found1 {
                    if val, found2 := lb["auto-ingress/enabled"]; found2 {
                        if val == "enabled" {
                            newIng, err := createIngressForService(clientset, *svc)
                            if err != nil {
                                log.Errorln(err.Error())
                            } else {
                                log.Info("Created new ingress for service: ", svc.Name)
                                svcIngPair[svc.Name] = *newIng
                                log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                            }
                        }
                    }
                }
            },
            DeleteFunc: func(obj interface{}) {
                svc := obj.(*core.Service)
                log.Info("Service deleted: ", svc.Name)
				if ing, found := svcIngPair[svc.Name]; found {
					clientset.Ingresses(namespace).Delete(ing.Name, nil)
					log.Info("Deleted ingress for service: ", svc.Name)
                    delete(svcIngPair, svc.Name)
                    log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
				}
            },
            UpdateFunc:func(oldObj, newObj interface{}) {
                newSvc := newObj.(*core.Service)
                log.Info("Service changed: ", newSvc.Name)
                lb := newSvc.Labels
                if ing, found1 := svcIngPair[newSvc.Name]; found1 {
                    if val, found2 := lb["auto-ingress/enabled"]; !found2 {
                        clientset.Ingresses(namespace).Delete(ing.Name, nil)
                        log.Info("Deleted ingress for service: ", newSvc.Name)
                        delete(svcIngPair, newSvc.Name)
                        log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                    } else {
                        if val == "disabled" {
                            clientset.Ingresses(namespace).Delete(ing.Name, nil)
                            log.Info("Deleted ingress for service: ", newSvc.Name)
                            delete(svcIngPair, newSvc.Name)
                            log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                        }
                    }
                } else {
                    if val, found3 := lb["auto-ingress/enabled"]; found3 {
                        if val == "enabled" {
                            newIng, err := createIngressForService(clientset, *newSvc)
                            if err != nil {
                                log.Errorln(err.Error())
                            } else {
                                log.Info("created new ingress for service: ", newSvc.Name)
                                svcIngPair[newSvc.Name] = *newIng
                                log.Info("Updated map: ", reflect.ValueOf(svcIngPair).MapKeys())
                            }
                        }
                    }
                }
            },
        },
    )
    stop := make(chan struct{})
    go controller.Run(stop)
    for{
        time.Sleep(time.Second)
    }
}

//create service map in the initial phase to check the current ingresses running on cluster
func createIngressServiceMap(clientset *kubernetes.Clientset, m map[string]extensions.Ingress) error {

	services, err := clientset.CoreV1().Services(namespace).List(metav1.ListOptions{})

    if err != nil {
        return err
    }

    ingresses, err:= clientset.ExtensionsV1beta1().Ingresses(namespace).List(metav1.ListOptions{})

    if err != nil {
        return err
    }

    for i:=0; i < len(ingresses.Items); i++ {
        rules := ingresses.Items[i].Spec.Rules
        for j:=0; j < len(rules); j++ {

            paths := rules[j].HTTP.Paths
            for k:=0; k < len(paths); k++ {
                svcName := paths[k].Backend.ServiceName
                if _, found := m[svcName]; !found {
                    m[svcName] = ingresses.Items[i]
                }
            }
        }
    }

	for i:=0; i < len(services.Items); i++ {
        if _, found1 := m[services.Items[i].GetName()]; !found1 {
            lb := services.Items[i].GetLabels()
            if val, found2 := lb["auto-ingress/enabled"]; found2 {
                if val == "enabled" {
                    newIng, err := createIngressForService(clientset, services.Items[i])
                    if err != nil {
                        return err
                    }
                    m[services.Items[i].GetName()] = *newIng
                }
            }
        }
    }

    return nil
}

//create an ingress for the associated service
func createIngressForService(clientset *kubernetes.Clientset, service core.Service) (*extensions.Ingress, error) {
	backend := createIngressBackend(service)

    ingressname := service.Name
    servername := ingressname + "." + wildcardRecord

    ingress := createIngress(ingressname, servername, backend)

    newIng, err := clientset.Ingresses(namespace).Create(ingress)

    return newIng, err
}

//create an ingress backend before putting it to the ingress
func createIngressBackend(service core.Service) extensions.IngressBackend {
    serviceName := service.GetName()
    if len(service.Spec.Ports) > 0 {
        var servicePort32 interface{}
        var servicePort int

        servicePort32 = service.Spec.Ports[0].Port
        servicePort32Tmp := servicePort32.(int32)

        servicePort = int(servicePort32Tmp)
        return extensions.IngressBackend {
            ServiceName: serviceName,
            ServicePort: intstr.FromInt(servicePort),
        }
    }

    return extensions.IngressBackend {}
}

//create ingress for associated service
func createIngress(ingressname string, servername string, backend extensions.IngressBackend) *extensions.Ingress {

    return &extensions.Ingress {
        ObjectMeta: metav1.ObjectMeta {
            Name: ingressname,
            Namespace: namespace,
        },
        Spec: extensions.IngressSpec {
            TLS: []extensions.IngressTLS{
                {
                    Hosts: []string{
                        servername,
                    },
                    SecretName: secret,

                },
            },
            Rules: []extensions.IngressRule {
                {
                    Host: servername,
                    IngressRuleValue: extensions.IngressRuleValue {
                        HTTP: &extensions.HTTPIngressRuleValue {
                        Paths: []extensions.HTTPIngressPath {
                            {
                                Path: "/",
                                Backend: backend,
                            },
                        },
                        },
                    },
                },
            },
        },
    }
}
<|endoftext|>


<commit_before>/*
Quick and simple monitoring system

Usage:
 jsonmon config.yml
 jsonmon -v # Prints version to stdout and exits

Environment:
 HOST
  - defaults to localhost
  - the JSON API network interface
 PORT
  - defaults to 3000
  - the JSON API port
*/
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

// Application version.
const Version = "1.3.1"

// This one is for internal use.
type ver struct {
	App  string `json:"jsonmon"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

var version ver

// Check details.
type Check struct {
	Name   string      `json:"name,omitempty" yaml:"name"`
	Web    string      `json:"web,omitempty" yaml:"web"`
	Shell  string      `json:"shell,omitempty" yaml:"shell"`
	Match  string      `json:"-" yaml:"match"`
	Return int         `json:"-" yaml:"return"`
	Notify interface{} `json:"-" yaml:"notify"`
	Alert  interface{} `json:"-" yaml:"alert"`
	Tries  int         `json:"-" yaml:"tries"`
	Repeat int         `json:"-" yaml:"repeat"`
	Failed bool        `json:"failed" yaml:"-"`
	Since  string      `json:"since,omitempty" yaml:"-"`
}

// Global checks list. Need to share it with workers and Web UI.
var checks []Check

// Global last modified date for HTTP caching.
var modified string

// Construct the last modified string.
func etag() {
	modified = "W/\"" + strconv.FormatInt(time.Now().UnixNano(), 10) + "\""
}

// The main loop.
func main() {
	// Parse CLI args.
	usage := "Usage: " + path.Base(os.Args[0]) + " config.yml\n" +
		"Docs:  https://github.com/chillum/jsonmon/wiki"
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(1)
	}
	// -v for version.
	version.App = Version
	version.Go = runtime.Version()
	version.Os = runtime.GOOS
	version.Arch = runtime.GOARCH
	switch os.Args[1] {
	case "-h":
		fallthrough
	case "-help":
		fallthrough
	case "--help":
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(0)
	case "-v":
		fallthrough
	case "-version":
		fallthrough
	case "--version":
		json, _ := json.Marshal(&version)
		fmt.Println(string(json))
		os.Exit(0)
	}
	// Tune concurrency.
	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}
	// Read config file or exit with error.
	config, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>")
		fmt.Fprintln(os.Stderr, err)
		os.Exit(3)
	}
	err = yaml.Unmarshal(config, &checks)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>")
		fmt.Fprintln(os.Stderr, "invalid", os.Args[1])
		os.Exit(3)
	}
	// Exit with return code 0 on kill.
	done := make(chan os.Signal, 1)
	signal.Notify(done, syscall.SIGTERM)
	go func() {
		<-done
		os.Exit(0)
	}()
	// Run checks.
	etag()
	for i := range checks {
		go worker(&checks[i])
	}
	// Launch the JSON API.
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "3000"
	}
	http.HandleFunc("/version", getVersion)
	http.HandleFunc("/", getChecks)
	err = http.ListenAndServe(host+":"+port, nil)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>")
		fmt.Fprintln(os.Stderr, err)
	}
	os.Exit(4)
}

// Background worker.
func worker(check *Check) {
	for {
		if check.Repeat == 0 { // Set default timeout.
			check.Repeat = 30
		}
		if check.Tries == 0 { // Default to 1 attempt.
			check.Tries = 1
		}
		if check.Web != "" {
			web(check)
		}
		if check.Shell != "" {
			shell(check)
		}
		time.Sleep(time.Second * time.Duration(check.Repeat))
	}
}

// Shell worker.
func shell(check *Check) {
	// Set check's display name.
	var name string
	if check.Name != "" {
		name = check.Name
	} else {
		name = check.Shell
	}
	// Execute with shell in N attemps.
	var out []byte
	var err error
	for i := 0; i < check.Tries; i++ {
		out, err = exec.Command("/bin/sh", "-c", check.Shell).CombinedOutput()
		if err == nil {
			if check.Match != "" { // Match regexp.
				var regex *regexp.Regexp
				regex, err = regexp.Compile(check.Match)
				if err == nil && !regex.Match(out) {
					err = errors.New("Expected:\n" + check.Match + "\n\nGot:\n" + string(out))
				}
			}
			break
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			check.Failed = false
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			notify(check.Notify, "Fixed: "+name, nil)
			alert(check, &name, nil)
		}
	} else {
		if !check.Failed {
			check.Failed = true
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			msg := string(out) + err.Error()
			notify(check.Notify, "Failed: "+name, &msg)
			alert(check, &name, &msg)
		}
	}
}

// Web worker.
func web(check *Check) {
	// Set check's display name.
	var name string
	if check.Name != "" {
		name = check.Name
	} else {
		name = check.Web
	}
	if check.Return == 0 { // Successful HTTP return code is 200.
		check.Return = 200
	}
	// Get the URL in N attempts.
	var err error
	for i := 0; i < check.Tries; i++ {
		err = fetch(check.Web, check.Match, check.Return)
		if err == nil {
			break
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			check.Failed = false
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			notify(check.Notify, "Fixed: "+name, nil)
			alert(check, &name, nil)

		}
	} else {
		if !check.Failed {
			check.Failed = true
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			msg := err.Error()
			notify(check.Notify, "Failed: "+name, &msg)
			alert(check, &name, &msg)
		}
	}
}

// Check HTTP redirects.
func redirect(req *http.Request, via []*http.Request) error {
	// When redirects number > 10 probably there's a problem.
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	// Redirects don't get User-Agent.
	req.Header.Set("User-Agent", "jsonmon")
	return nil
}

// The actual HTTP GET.
func fetch(url string, match string, code int) error {
	var err error
	var resp *http.Response
	var req *http.Request
	client := &http.Client{}
	client.CheckRedirect = redirect
	req, err = http.NewRequest("GET", url, nil)
	if err == nil {
		req.Header.Set("User-Agent", "jsonmon")
		resp, err = client.Do(req)
		if err == nil {
			if resp.StatusCode != code { // Check status code.
				err = errors.New(url + " returned " + strconv.Itoa(resp.StatusCode))
			} else { // Match regexp.
				if resp != nil && match != "" {
					var regex *regexp.Regexp
					regex, err = regexp.Compile(match)
					if err == nil {
						var body []byte
						body, _ = ioutil.ReadAll(resp.Body)
						if !regex.Match(body) {
							err = errors.New("Expected:\n" + match + "\n\nGot:\n" + string(body))
						}
					}
				}
			}
		}
	}
	if resp != nil {
		resp.Body.Close()
	}
	return err
}

// Logs and mail alerting.
func notify(mail interface{}, subject string, message *string) {
	// Log the alerts.
	fmt.Print("<5>")
	fmt.Println(subject)
	if message != nil {
		fmt.Println(*message)
	}
	// Mail the alerts.
	if mail != nil {
		// Make the message.
		var rcpt string
		var ok bool
		if rcpt, ok = mail.(string); !ok {
			for i, v := range mail.([]interface{}) {
				if i != 0 {
					rcpt += ", "
				}
				rcpt += v.(string)
			}
		}
		msg := "To: " + rcpt + "\nSubject: " + subject + "\nX-Mailer: jsonmon\n\n"
		if message != nil {
			msg += *message
		}
		msg += "\n.\n"
		// And send it.
		sendmail := exec.Command("/usr/sbin/sendmail", "-t")
		stdin, _ := sendmail.StdinPipe()
		err := sendmail.Start()
		if err != nil {
			fmt.Fprint(os.Stderr, "<3>")
			fmt.Fprintln(os.Stderr, err)
		}
		io.WriteString(stdin, msg)
		sendmail.Wait()
	}
}

// Executes callback. Passes args: true/false, check's name, message.
func alert(check *Check, name *string, msg *string) {
	if check.Alert != nil {
		plugin, ok := check.Alert.(string)
		if ok { // check.Alert is a string.
			out, err := exec.Command(plugin, strconv.FormatBool(check.Failed), *name, *msg).CombinedOutput()
			if err != nil {
				fmt.Fprint(os.Stderr, "<3>", plugin, " failed\n")
				fmt.Fprint(os.Stderr, string(out))
				fmt.Fprintln(os.Stderr, err.Error())
			}
		} else { // check.Alert is a list.
			for _, i := range check.Alert.([]interface{}) {
				out, err := exec.Command(i.(string), strconv.FormatBool(check.Failed), *name, *msg).CombinedOutput()
				if err != nil {
					fmt.Fprint(os.Stderr, "<3>", i.(string), " failed\n")
					fmt.Fprint(os.Stderr, string(out))
					fmt.Fprintln(os.Stderr, err.Error())
				}
			}
		}
	}
}

// Display checks' details.
func getChecks(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" { // Serve for root page only, 404 otherwise.
		w.Header().Set("Server", "jsonmon")
		http.NotFound(w, r)
		return
	}
	displayJSON(w, r, &checks)
}

// Display application version.
func getVersion(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &version)
}

// Output JSON.
func displayJSON(w http.ResponseWriter, r *http.Request, data interface{}) {
	h := w.Header()
	h.Set("Server", "jsonmon")
	if r.Header.Get("If-None-Match") == modified {
		delete(h, "Content-Type")
		delete(h, "Content-Length")
		w.WriteHeader(http.StatusNotModified)
	} else {
		h.Set("Cache-Control", "no-cache")
		h.Set("ETag", modified)
		h.Set("Access-Control-Allow-Origin", "*")
		h.Set("Content-Type", "application/json; charset=utf-8")
		json, _ := json.MarshalIndent(&data, "", "  ")
		w.Write(json)
		fmt.Fprintln(w, "") // Trailing newline.
	}
}
<commit_msg>serialize logs (regression in v1.3.1)<commit_after>/*
Quick and simple monitoring system

Usage:
 jsonmon config.yml
 jsonmon -v # Prints version to stdout and exits

Environment:
 HOST
  - defaults to localhost
  - the JSON API network interface
 PORT
  - defaults to 3000
  - the JSON API port
*/
package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"syscall"
	"time"
)

// Application version.
const Version = "1.3.2"

// This one is for internal use.
type ver struct {
	App  string `json:"jsonmon"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

var version ver

// Check details.
type Check struct {
	Name   string      `json:"name,omitempty" yaml:"name"`
	Web    string      `json:"web,omitempty" yaml:"web"`
	Shell  string      `json:"shell,omitempty" yaml:"shell"`
	Match  string      `json:"-" yaml:"match"`
	Return int         `json:"-" yaml:"return"`
	Notify interface{} `json:"-" yaml:"notify"`
	Alert  interface{} `json:"-" yaml:"alert"`
	Tries  int         `json:"-" yaml:"tries"`
	Repeat int         `json:"-" yaml:"repeat"`
	Failed bool        `json:"failed" yaml:"-"`
	Since  string      `json:"since,omitempty" yaml:"-"`
}

// Global checks list. Need to share it with workers and Web UI.
var checks []Check

// Global last modified date for HTTP caching.
var modified string

// Construct the last modified string.
func etag() {
	modified = "W/\"" + strconv.FormatInt(time.Now().UnixNano(), 10) + "\""
}

// The main loop.
func main() {
	// Parse CLI args.
	usage := "Usage: " + path.Base(os.Args[0]) + " config.yml\n" +
		"Docs:  https://github.com/chillum/jsonmon/wiki"
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(1)
	}
	// -v for version.
	version.App = Version
	version.Go = runtime.Version()
	version.Os = runtime.GOOS
	version.Arch = runtime.GOARCH
	switch os.Args[1] {
	case "-h":
		fallthrough
	case "-help":
		fallthrough
	case "--help":
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(0)
	case "-v":
		fallthrough
	case "-version":
		fallthrough
	case "--version":
		json, _ := json.Marshal(&version)
		fmt.Println(string(json))
		os.Exit(0)
	}
	// Tune concurrency.
	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}
	// Read config file or exit with error.
	config, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", err, "\n")
		os.Exit(3)
	}
	err = yaml.Unmarshal(config, &checks)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", "invalid ", os.Args[1], "\n")
		os.Exit(3)
	}
	// Exit with return code 0 on kill.
	done := make(chan os.Signal, 1)
	signal.Notify(done, syscall.SIGTERM)
	go func() {
		<-done
		os.Exit(0)
	}()
	// Run checks.
	etag()
	for i := range checks {
		go worker(&checks[i])
	}
	// Launch the JSON API.
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "3000"
	}
	http.HandleFunc("/version", getVersion)
	http.HandleFunc("/", getChecks)
	err = http.ListenAndServe(host+":"+port, nil)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2> ", err, "\n")
	}
	os.Exit(4)
}

// Background worker.
func worker(check *Check) {
	for {
		if check.Repeat == 0 { // Set default timeout.
			check.Repeat = 30
		}
		if check.Tries == 0 { // Default to 1 attempt.
			check.Tries = 1
		}
		if check.Web != "" {
			web(check)
		}
		if check.Shell != "" {
			shell(check)
		}
		time.Sleep(time.Second * time.Duration(check.Repeat))
	}
}

// Shell worker.
func shell(check *Check) {
	// Set check's display name.
	var name string
	if check.Name != "" {
		name = check.Name
	} else {
		name = check.Shell
	}
	// Execute with shell in N attemps.
	var out []byte
	var err error
	for i := 0; i < check.Tries; i++ {
		out, err = exec.Command("/bin/sh", "-c", check.Shell).CombinedOutput()
		if err == nil {
			if check.Match != "" { // Match regexp.
				var regex *regexp.Regexp
				regex, err = regexp.Compile(check.Match)
				if err == nil && !regex.Match(out) {
					err = errors.New("Expected:\n" + check.Match + "\n\nGot:\n" + string(out))
				}
			}
			break
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			check.Failed = false
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			notify(check.Notify, "Fixed: "+name, nil)
			alert(check, &name, nil)
		}
	} else {
		if !check.Failed {
			check.Failed = true
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			msg := string(out) + err.Error()
			notify(check.Notify, "Failed: "+name, &msg)
			alert(check, &name, &msg)
		}
	}
}

// Web worker.
func web(check *Check) {
	// Set check's display name.
	var name string
	if check.Name != "" {
		name = check.Name
	} else {
		name = check.Web
	}
	if check.Return == 0 { // Successful HTTP return code is 200.
		check.Return = 200
	}
	// Get the URL in N attempts.
	var err error
	for i := 0; i < check.Tries; i++ {
		err = fetch(check.Web, check.Match, check.Return)
		if err == nil {
			break
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			check.Failed = false
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			notify(check.Notify, "Fixed: "+name, nil)
			alert(check, &name, nil)

		}
	} else {
		if !check.Failed {
			check.Failed = true
			check.Since = time.Now().Format(time.RFC3339)
			etag()
			msg := err.Error()
			notify(check.Notify, "Failed: "+name, &msg)
			alert(check, &name, &msg)
		}
	}
}

// Check HTTP redirects.
func redirect(req *http.Request, via []*http.Request) error {
	// When redirects number > 10 probably there's a problem.
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	// Redirects don't get User-Agent.
	req.Header.Set("User-Agent", "jsonmon")
	return nil
}

// The actual HTTP GET.
func fetch(url string, match string, code int) error {
	var err error
	var resp *http.Response
	var req *http.Request
	client := &http.Client{}
	client.CheckRedirect = redirect
	req, err = http.NewRequest("GET", url, nil)
	if err == nil {
		req.Header.Set("User-Agent", "jsonmon")
		resp, err = client.Do(req)
		if err == nil {
			if resp.StatusCode != code { // Check status code.
				err = errors.New(url + " returned " + strconv.Itoa(resp.StatusCode))
			} else { // Match regexp.
				if resp != nil && match != "" {
					var regex *regexp.Regexp
					regex, err = regexp.Compile(match)
					if err == nil {
						var body []byte
						body, _ = ioutil.ReadAll(resp.Body)
						if !regex.Match(body) {
							err = errors.New("Expected:\n" + match + "\n\nGot:\n" + string(body))
						}
					}
				}
			}
		}
	}
	if resp != nil {
		resp.Body.Close()
	}
	return err
}

// Logs and mail alerting.
func notify(mail interface{}, subject string, message *string) {
	// Log the alerts.
	if message == nil {
		fmt.Print("<5>", subject, "\n")
	} else {
		fmt.Print("<5>", subject, "\n", *message, "\n")
	}
	// Mail the alerts.
	if mail != nil {
		// Make the message.
		var rcpt string
		var ok bool
		if rcpt, ok = mail.(string); !ok {
			for i, v := range mail.([]interface{}) {
				if i != 0 {
					rcpt += ", "
				}
				rcpt += v.(string)
			}
		}
		msg := "To: " + rcpt + "\nSubject: " + subject + "\nX-Mailer: jsonmon\n\n"
		if message != nil {
			msg += *message
		}
		msg += "\n.\n"
		// And send it.
		sendmail := exec.Command("/usr/sbin/sendmail", "-t")
		stdin, _ := sendmail.StdinPipe()
		err := sendmail.Start()
		if err != nil {
			fmt.Fprint(os.Stderr, "<3>", err, "\n")
		}
		io.WriteString(stdin, msg)
		sendmail.Wait()
	}
}

// Executes callback. Passes args: true/false, check's name, message.
func alert(check *Check, name *string, msg *string) {
	if check.Alert != nil {
		plugin, ok := check.Alert.(string)
		if ok { // check.Alert is a string.
			out, err := exec.Command(plugin, strconv.FormatBool(check.Failed), *name, *msg).CombinedOutput()
			if err != nil {
				fmt.Fprint(os.Stderr, "<3>", plugin, " failed\n", string(out), err.Error(), "\n")
			}
		} else { // check.Alert is a list.
			for _, i := range check.Alert.([]interface{}) {
				out, err := exec.Command(i.(string), strconv.FormatBool(check.Failed), *name, *msg).CombinedOutput()
				if err != nil {
					fmt.Fprint(os.Stderr, "<3>", i, " failed\n", string(out), err.Error(), "\n")
				}
			}
		}
	}
}

// Display checks' details.
func getChecks(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" { // Serve for root page only, 404 otherwise.
		w.Header().Set("Server", "jsonmon")
		http.NotFound(w, r)
		return
	}
	displayJSON(w, r, &checks)
}

// Display application version.
func getVersion(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &version)
}

// Output JSON.
func displayJSON(w http.ResponseWriter, r *http.Request, data interface{}) {
	h := w.Header()
	h.Set("Server", "jsonmon")
	if r.Header.Get("If-None-Match") == modified {
		delete(h, "Content-Type")
		delete(h, "Content-Length")
		w.WriteHeader(http.StatusNotModified)
	} else {
		h.Set("Cache-Control", "no-cache")
		h.Set("ETag", modified)
		h.Set("Access-Control-Allow-Origin", "*")
		h.Set("Content-Type", "application/json; charset=utf-8")
		json, _ := json.MarshalIndent(&data, "", "  ")
		w.Write(json)
		fmt.Fprintln(w, "") // Trailing newline.
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/ogier/pflag"
)

var (
	name    = "prod"
	version = "0.0.0"

	flagset   = pflag.NewFlagSet(name, pflag.ContinueOnError)
	isHelp    = flagset.BoolP("help", "h", false, "")
	isVersion = flagset.BoolP("version", "", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... [FILE]...
Output direct product of lines of each files.

Options:
      --help                display this help text and exit
      --version             display version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintf(os.Stderr, "%s\n", version)
}

func printErr(err interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", name)
}

func main() {
	flagset.SetOutput(ioutil.Discard)
	if err := flagset.Parse(os.Args[1:]); err != nil {
		printErr(err)
		os.Exit(2)
	}
	if *isHelp {
		printUsage()
		os.Exit(0)
	}
	if *isVersion {
		printVersion()
		os.Exit(0)
	}

	var a [][]string
	if flagset.NArg() < 1 {
		a = append(a, make([]string, 0, 64))

		b := bufio.NewScanner(os.Stdin)
		for b.Scan() {
			a[0] = append(a[0], b.Text())
		}
		if err := b.Err(); err != nil {
			printErr(err)
			os.Exit(1)
		}
	} else {
		for i, arg := range flagset.Args() {
			a = append(a, make([]string, 0, 64))

			f, err := os.Open(arg)
			if err != nil {
				printErr(err)
				os.Exit(1)
			}
			defer f.Close()

			b := bufio.NewScanner(f)
			for b.Scan() {
				a[i] = append(a[i], b.Text())
			}
			if err = b.Err(); err != nil {
				printErr(err)
				os.Exit(1)
			}
		}
	}

	ss := make([]string, len(a))
	for indexes := range Product(a) {
		for i, index := range indexes {
			ss[i] = a[i][index]
		}
		fmt.Println(strings.Join(ss, "\t"))
	}
}
<commit_msg>Refactor main<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"

	"github.com/ogier/pflag"
)

var (
	name    = "prod"
	version = "0.0.0"

	flagset   = pflag.NewFlagSet(name, pflag.ContinueOnError)
	isHelp    = flagset.BoolP("help", "h", false, "")
	isVersion = flagset.BoolP("version", "", false, "")
)

func printUsage() {
	fmt.Fprintf(os.Stderr, `
Usage: %s [OPTION]... [FILE]...
Output direct product of lines of each files.

Options:
      --help                display this help text and exit
      --version             display version information and exit
`[1:], name)
}

func printVersion() {
	fmt.Fprintf(os.Stderr, "%s\n", version)
}

func printErr(err interface{}) {
	fmt.Fprintf(os.Stderr, "%s: %s\n", name, err)
}

func guideToHelp() {
	fmt.Fprintf(os.Stderr, "Try '%s --help' for more information.\n", name)
}

func main() {
	flagset.SetOutput(ioutil.Discard)
	if err := flagset.Parse(os.Args[1:]); err != nil {
		printErr(err)
		os.Exit(2)
	}
	if *isHelp {
		printUsage()
		os.Exit(0)
	}
	if *isVersion {
		printVersion()
		os.Exit(0)
	}

	var rs []io.Reader
	if flagset.NArg() == 0 {
		rs = append(rs, os.Stdin)
	} else {
		for _, arg := range flagset.Args() {
			f, err := os.Open(arg)
			if err != nil {
				printErr(err)
				os.Exit(1)
			}
			defer f.Close()
			rs = append(rs, f)
		}
	}

	var aa [][]string
	for _, r := range rs {
		a := make([]string, 0, 64)
		b := bufio.NewScanner(r)
		for b.Scan() {
			a = append(a, b.Text())
		}
		if err := b.Err(); err != nil {
			printErr(err)
			os.Exit(1)
		}
		aa = append(aa, a)
	}

	ss := make([]string, len(aa))
	for indexes := range Product(aa) {
		for i, index := range indexes {
			ss[i] = aa[i][index]
		}
		fmt.Println(strings.Join(ss, "\t"))
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Jeff Nickoloff. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package main

import (
	"archive/tar"
	"bufio"
	"io"
	"log"
	"os"
	path "path/filepath"
	"strings"
)

func main() {
	// buffered read tar from stdin into buffer
	// until reached EOF write buffer to stdout
	// write header for target file to stdout
	// read, buffer, and write target file to stdout

	log.SetOutput(os.Stderr)

	if len(os.Args) != 2 {
		log.Fatal(`requires one argument - relative name of the file to be included in the tar stream`)
	}
	fn := os.Args[1]

	// Learn something about the file
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	if path.IsAbs(fn) {
		fn, err = path.Rel(cwd, fn)
		if err != nil {
			log.Fatal(err)
		}
	}
	if strings.Index(fn, `..`) == 0 {
		log.Fatal(`The target file cannot be added from outside the context of the CWD`)
	}

	fi, err := os.Stat(fn)
	if err != nil {
		log.Fatal(err)
	}

	// Start pipeing the tar

	r := bufio.NewReader(os.Stdin)
	tin := tar.NewReader(r)
	tw := tar.NewWriter(os.Stdout)

	for {
		h, err := tin.Next()
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			log.Fatalln(err)
		}

		// Just a file, write it to stdout
		if err := tw.WriteHeader(h); err != nil {
			log.Fatalln(err)
		}
		if _, err := io.Copy(tw, tin); err != nil {
			log.Fatal(err)
		}
	}
	// Reached the end of the tar stream

	// Build the tar header
	head := &tar.Header{
		Name: fn,
		Mode: int64(fi.Mode()),
		Size: fi.Size(),
	}

	// Write the header
	if err = tw.WriteHeader(head); err != nil {
		log.Fatal(err)
	}

	// Open the target file, write a header, write the file, close everything
	fh, err := os.Open(fn)
	if err != nil {
		log.Fatal(err)
	}
	defer fh.Close()

	if _, err := io.Copy(tw, fh); err != nil {
		log.Fatal(err)
	}
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}
}

<commit_msg>Prevent appending non-regular files.<commit_after>// Copyright 2017 Jeff Nickoloff. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package main

import (
	"archive/tar"
	"bufio"
	"io"
	"log"
	"os"
	path "path/filepath"
	"strings"
)

func main() {
	// buffered read tar from stdin into buffer
	// until reached EOF write buffer to stdout
	// write header for target file to stdout
	// read, buffer, and write target file to stdout

	log.SetOutput(os.Stderr)

	if len(os.Args) != 2 {
		log.Fatal(`requires one argument - relative name of the file to be included in the tar stream`)
	}
	fn := os.Args[1]

	// Learn something about the file
	cwd, err := os.Getwd()
	if err != nil {
		log.Fatal(err)
	}

	if path.IsAbs(fn) {
		fn, err = path.Rel(cwd, fn)
		if err != nil {
			log.Fatal(err)
		}
	}
	if strings.Index(fn, `..`) == 0 {
		log.Fatal(`The target file cannot be added from outside the context of the CWD`)
	}

	fi, err := os.Stat(fn)
	if err != nil {
		log.Fatal(err)
	}

	if !fi.Mode().IsRegular() {
		log.Fatal(`Target file is not regular.`)
	}

	// Start pipeing the tar

	r := bufio.NewReader(os.Stdin)
	tin := tar.NewReader(r)
	tw := tar.NewWriter(os.Stdout)

	for {
		h, err := tin.Next()
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			log.Fatalln(err)
		}

		// Just a file, write it to stdout
		if err := tw.WriteHeader(h); err != nil {
			log.Fatalln(err)
		}
		if _, err := io.Copy(tw, tin); err != nil {
			log.Fatal(err)
		}
	}
	// Reached the end of the tar stream

	// Build the tar header
	head := &tar.Header{
		Name: fn,
		Mode: int64(fi.Mode()),
		Size: fi.Size(),
	}

	// Write the header
	if err = tw.WriteHeader(head); err != nil {
		log.Fatal(err)
	}

	// Open the target file, write a header, write the file, close everything
	fh, err := os.Open(fn)
	if err != nil {
		log.Fatal(err)
	}
	defer fh.Close()

	if _, err := io.Copy(tw, fh); err != nil {
		log.Fatal(err)
	}
	if err := tw.Close(); err != nil {
		log.Fatalln(err)
	}
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"unicode"

	"github.com/drone/drone-go/drone"
	"github.com/drone/drone-go/plugin"
	"github.com/drone/drone-go/template"
)

// HipChat represents the settings needed to send a HipChat notification.
type HipChat struct {
	Notify   bool            `json:"notify"`
	From     string          `json:"from"`
	Room     drone.StringInt `json:"room_id_or_name"`
	Token    string          `json:"auth_token"`
	Template string          `json:"template"`
}

func main() {

	// plugin settings
	repo := drone.Repo{}
	build := drone.Build{}
	system := drone.System{}
	vargs := HipChat{}

	// set plugin parameters
	plugin.Param("build", &build)
	plugin.Param("repo", &repo)
	plugin.Param("system", &system)
	plugin.Param("vargs", &vargs)

	// parse the parameters
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// create the HipChat client
	client := NewClient(vargs.Room.String(), vargs.Token)

	// determine notification template
	if len(vargs.Template) == 0 {
		vargs.Template = "{{ uppercasefirst build.status }} {{ repo.owner }}/{{ repo.name }}#{{ truncate build.commit 8 }} ({{ build.branch }}) by {{ build.author }} in {{ duration build.started_at build.finished_at }}
 - {{ build.message }}"
	}

	// build the HipChat message
	msg := Message{
		From:    vargs.From,
		Notify:  vargs.Notify,
		Color:   Color(&build),
		Message: BuildMessage(&repo, &build, &system, vargs.Template),
	}

	// sends the HipChat message
	if err := client.Send(&msg); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// BuildMessage takes a number of drone parameters and builds a message.
func BuildMessage(repo *drone.Repo, build *drone.Build, sys *drone.System, tmpl string) string {

	// data for custom template rendering, if we need it
	payload := &drone.Payload{
		Build:  build,
		Repo:   repo,
		System: sys,
	}

	// render template
	msg, err := template.RenderTrim(tmpl, payload)
	if err != nil {
		return err.Error()
	}

	fmt.Println(msg)

	return msg
}

// Color takes a *plugin.Build object and determines the appropriate
// notification/message color.
func Color(build *drone.Build) string {
	switch build.Status {
	case drone.StatusSuccess:
		return "green"
	case drone.StatusFailure, drone.StatusError, drone.StatusKilled:
		return "red"
	default:
		return "yellow"
	}
}

// FirstRuneToUpper takes a string and capitalizes the first letter.
func FirstRuneToUpper(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	s = string(a)
	return s
}
<commit_msg>updating sys to system<commit_after>package main

import (
	"fmt"
	"os"
	"unicode"

	"github.com/drone/drone-go/drone"
	"github.com/drone/drone-go/plugin"
	"github.com/drone/drone-go/template"
)

// HipChat represents the settings needed to send a HipChat notification.
type HipChat struct {
	Notify   bool            `json:"notify"`
	From     string          `json:"from"`
	Room     drone.StringInt `json:"room_id_or_name"`
	Token    string          `json:"auth_token"`
	Template string          `json:"template"`
}

func main() {

	// plugin settings
	repo := drone.Repo{}
	build := drone.Build{}
	system := drone.System{}
	vargs := HipChat{}

	// set plugin parameters
	plugin.Param("build", &build)
	plugin.Param("repo", &repo)
	plugin.Param("system", &system)
	plugin.Param("vargs", &vargs)

	// parse the parameters
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// create the HipChat client
	client := NewClient(vargs.Room.String(), vargs.Token)

	// determine notification template
	if len(vargs.Template) == 0 {
		vargs.Template = "{{ uppercasefirst build.status }} {{ repo.owner }}/{{ repo.name }}#{{ truncate build.commit 8 }} ({{ build.branch }}) by {{ build.author }} in {{ duration build.started_at build.finished_at }}
 - {{ build.message }}"
	}

	// build the HipChat message
	msg := Message{
		From:    vargs.From,
		Notify:  vargs.Notify,
		Color:   Color(&build),
		Message: BuildMessage(&repo, &build, &system, vargs.Template),
	}

	// sends the HipChat message
	if err := client.Send(&msg); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// BuildMessage takes a number of drone parameters and builds a message.
func BuildMessage(repo *drone.Repo, build *drone.Build, sys *drone.System, tmpl string) string {

	// data for custom template rendering, if we need it
	payload := &drone.Payload{
		Build:  build,
		Repo:   repo,
		System: sys,
	}

	// render template
	msg, err := template.RenderTrim(tmpl, payload)
	if err != nil {
		return err.Error()
	}

	return msg
}

// Color takes a *plugin.Build object and determines the appropriate
// notification/message color.
func Color(build *drone.Build) string {
	switch build.Status {
	case drone.StatusSuccess:
		return "green"
	case drone.StatusFailure, drone.StatusError, drone.StatusKilled:
		return "red"
	default:
		return "yellow"
	}
}

// FirstRuneToUpper takes a string and capitalizes the first letter.
func FirstRuneToUpper(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	s = string(a)
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/caelifer/dups/finder"
)

// Internal constant to control number of Worker threads in balancer's worker pool
const workerPoolMultiplier = 2 // Use twice the available cores

// Flags
var (
	cpuprofile      = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile      = flag.String("memprofile", "", "write memory profile to file")
	maxWorkerNumber = flag.Int("jobs", runtime.NumCPU()*workerPoolMultiplier, "Number of parallel jobs")
	output          = flag.String("output", "-", "write output to a file. Default: STDOUT")
	stats           = flag.Bool("stats", false, "display runtime statistics on STDERR")
)

// Start of execution
func main() {
	// First parse flags
	flag.Parse()

	// Prep runtime to use the maxWorkerNumber real threads
	runtime.GOMAXPROCS(*maxWorkerNumber)

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		defer func() {
			pprof.WriteHeapProfile(f)
			f.Close()
		}()
	}

	// Process command line params
	paths := flag.Args()

	if len(paths) == 0 {
		// Default is current directory
		paths = []string{"."}
	}

	// Get output writer
	out, err := getOutput(*output)
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	// Trace time spent
	t1 := time.Now()

	// Find all dups and report to output
	find := finder.NewFinder(*maxWorkerNumber)
	for d := range find.AllDups(paths) {
		fmt.Fprintln(out, d)
	}

	// Update stats
	find.SetTimeSpent(time.Since(t1))

	if *stats {
		log.Println(find.Stats())
	}
}

func getOutput(path string) (io.WriteCloser, error) {
	switch path {
	case "-":
		return os.Stdout, nil // default
	default:
		return os.OpenFile(*output, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	}
}
<commit_msg>Rename jobs flag variable<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"runtime/pprof"
	"time"

	"github.com/caelifer/dups/finder"
)

// Internal constant to control number of Worker threads in balancer's worker pool
const workerPoolMultiplier = 2 // Use twice the available cores

// Flags
var (
	cpuprofile  = flag.String("cpuprofile", "", "write cpu profile to file")
	memprofile  = flag.String("memprofile", "", "write memory profile to file")
	workerCount = flag.Int("jobs", runtime.NumCPU()*workerPoolMultiplier, "Number of parallel jobs")
	output      = flag.String("output", "-", "write output to a file. Default: STDOUT")
	stats       = flag.Bool("stats", false, "display runtime statistics on STDERR")
)

// Start of execution
func main() {
	// First parse flags
	flag.Parse()

	// Prep runtime to use the workerCount real threads
	runtime.GOMAXPROCS(*workerCount)

	// CPU profile
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	// Memory profile
	if *memprofile != "" {
		f, err := os.Create(*memprofile)
		if err != nil {
			log.Fatal(err)
		}
		defer func() {
			pprof.WriteHeapProfile(f)
			f.Close()
		}()
	}

	// Process command line params
	paths := flag.Args()
	if len(paths) == 0 {
		// Default is current directory
		paths = []string{"."}
	}

	// Get output writer
	out, err := getOutput(*output)
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	// Trace time spent
	t1 := time.Now()

	// Find all dups and report to output
	find := finder.NewFinder(*workerCount)
	for d := range find.AllDups(paths) {
		fmt.Fprintln(out, d)
	}

	// Update stats
	find.SetTimeSpent(time.Since(t1))

	// Display runtime stats if requested
	if *stats {
		log.Println(find.Stats())
	}
}

// Get output handle
func getOutput(path string) (io.WriteCloser, error) {
	switch path {
	case "-":
		return os.Stdout, nil // default
	default:
		return os.OpenFile(*output, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
	}
}
<|endoftext|>