<commit_before>package main

import (
	"expvar"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/marpaia/graphite-golang"
)

// https://godoc.org/github.com/garyburd/redigo/redis#Pool
func newPool(port string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     4,
		IdleTimeout: 60 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", ":"+port)
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

// fqdn with underscores
func HostnameGraphite() string {
	hostname, _ := os.Hostname()
	return strings.Replace(hostname, ".", "_", -1)
}

func keyspaceEnable(pool *redis.Pool) {
	c := pool.Get()
	defer c.Close()

	// check if notify-keyspace-events are enabled
	notify, err := redis.StringMap(c.Do("CONFIG", "GET", "notify-keyspace-events"))
	if err != nil {
		log.Println(err)
		return
	}
	for _, v := range notify {
		config := keyspaceConfigRegex.FindString(v)
		if config != "" {
			// already enabled, we can listen for the LIST events
			log.Println("LIST events notifications already enabled")
		} else {
			// enable LIST events without replacing the existing config (if any)
			log.Println("Enabling LIST events notifications")
			if v == "" {
				_, err := redis.String(c.Do("CONFIG", "SET", "notify-keyspace-events", "lK"))
				if err != nil {
					log.Println(err)
					return
				}
			} else {
				// do not override the existing config
				_, err := redis.String(c.Do("CONFIG", "SET", "notify-keyspace-events", v+"lK"))
				if err != nil {
					log.Println(err)
					return
				}
			}
		}
	}
}

func instanceAlive(pool *redis.Pool) bool {
	c := pool.Get()
	defer c.Close()
	_, err := c.Do("PING")
	if err != nil {
		return false
	}
	return true
}

func instanceIsMaster(pool *redis.Pool, port string) {
	c := pool.Get()
	//defer c.Close()

	for {
		master, err := redis.StringMap(c.Do("CONFIG", "GET", "slaveof"))
		if err != nil {
			log.Println(err)
			// Retry connection to Redis until it is back
			defer c.Close()
			time.Sleep(time.Second * 1)
			c = pool.Get()
			continue
		}
		for _, value := range master {
			if value == "" {
				log.Printf("instance on port %s is a master\n", port)
			} else {
				log.Printf("instance on port %s is a slave of %s\n", port, value)
			}
		}
		time.Sleep(time.Second * 5)
	}
}

func queueStats(port string) {
	// connect to redis
	pool := newPool(port)
	c := pool.Get()
	if !instanceAlive(pool) {
		log.Printf("error: no redis instance listening on port %s, aborting\n", port)
		return
	}

	go keyspaceEnable(pool)

	// subscribe to the keyspace notifications
	c.Send("PSUBSCRIBE", "__keyspace*")
	c.Flush()
	// ignore first message received when subscribing
	c.Receive()

	// wait for published notifications
	for {
		reply, err := redis.StringMap(c.Receive())
		if err != nil {
			log.Println(err)

			// Retry connection to Redis until it is back
			defer c.Close()
			log.Printf("connection to redis lost. retry in 1s\n")
			time.Sleep(time.Second * 1)
			c = pool.Get()
			go keyspaceEnable(pool)
			c.Send("PSUBSCRIBE", "*")
			c.Flush()
			c.Receive()
			continue
		}
		// match for a LIST keyspace event
		for k, v := range reply {
			operation := listOperationsRegex.FindString(v)
			queue := keyspaceRegex.FindStringSubmatch(k)
			if len(queue) == 2 && operation != "" {
				//log.Printf("%s on %s queue\n", operation, queue[1])
				Stats.Add(fmt.Sprintf("%s.%s.%s", port, queue[1], operation), 1)
			}
		}
	}
}

var Stats = expvar.NewMap("stats").Init()
var listOperationsRegex = regexp.MustCompile("^(lpush|lpushx|rpush|rpushx|lpop|blpop|rpop|brpop)$")
var keyspaceRegex = regexp.MustCompile("^__keyspace.*__:(?P<queue_name>.*)$")
var keyspaceConfigRegex = regexp.MustCompile("^(AK.*|.*l.*K.*)$")
var ports redisPorts
var graph *graphite.Graphite

func main() {
	flag.Var(&ports, "ports", "comma-separated list of redis ports")
	graphiteHost := flag.String("graphite-host", "localhost", "graphite hostname")
	graphitePort := flag.Int("graphite-port", 2003, "graphite port")
	interval := flag.Int("interval", 60, "interval for sending graphite metrics")
	simulate := flag.Bool("simulate", false, "simulate sending to graphite via stdout")
	flag.Parse()

	// flag checks
	if len(ports) == 0 {
		log.Println("no redis instances defined, aborting")
		return
	}

	if *simulate {
		graph = graphite.NewGraphiteNop(*graphiteHost, *graphitePort)
	} else {
		var err error
		graph, err = graphite.NewGraphite(*graphiteHost, *graphitePort)
		if err != nil {
			log.Println(err)
			return
		}
	}
	hostname := HostnameGraphite()
	ticker := time.NewTicker(time.Second * time.Duration(*interval)).C

	for _, port := range ports {
		log.Println("spawning collector for port ", port)
		go queueStats(port)
	}

	sig := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-sig
		done <- true
	}()

	for {
		select {
		case <-ticker:
			Stats.Do(func(kv expvar.KeyValue) {
				graph.SimpleSend(fmt.Sprintf("scouter.%s.%s", hostname, kv.Key), kv.Value.String())
			})
		case <-done:
			log.Println("user aborted")
			return
		}
	}
}
<commit_msg>Added some small features<commit_after>package main

import (
	"expvar"
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/garyburd/redigo/redis"
	"github.com/marpaia/graphite-golang"
)

// https://godoc.org/github.com/garyburd/redigo/redis#Pool
func newPool(port string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     4,
		IdleTimeout: 60 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", ":"+port)
			if err != nil {
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

// fqdn with underscores
func HostnameGraphite() string {
	hostname, _ := os.Hostname()
	return strings.Replace(hostname, ".", "_", -1)
}

func keyspaceEnable(pool *redis.Pool, port string) {
	c := pool.Get()
	defer c.Close()

	// check if notify-keyspace-events are enabled
	notify, err := redis.StringMap(c.Do("CONFIG", "GET", "notify-keyspace-events"))
	if err != nil {
		log.Println(err)
		return
	}

	for _, v := range notify {
		config := keyspaceConfigRegex.FindString(v)
		if config != "" {
			// already enabled, we can listen for the LIST events
			log.Printf("[%s] LIST events notifications already enabled\n", port)
		} else {
			// enable LIST events without replacing the existing config (if any)
			log.Printf("[%s] Enabling LIST events notifications\n", port)
			if v == "" {
				log.Printf("[%s] There was no previous notify-keyspace-events config\n", port)
				_, err := redis.String(c.Do("CONFIG", "SET", "notify-keyspace-events", "lK"))
				if err != nil {
					log.Println(err)
					return
				}
			} else {
				// do not override the existing config
				log.Printf("[%s] Found previous notify-keyspace-events config, appending LIST events notifications\n", port)
				_, err := redis.String(c.Do("CONFIG", "SET", "notify-keyspace-events", v+"lK"))
				if err != nil {
					log.Println(err)
					return
				}
			}
		}
	}
}

func instanceAlive(pool *redis.Pool) bool {
	c := pool.Get()
	defer c.Close()
	_, err := c.Do("PING")
	if err != nil {
		return false
	}
	return true
}

func instanceIsMaster(pool *redis.Pool, port string) {
	c := pool.Get()

	for {
		master, err := redis.StringMap(c.Do("CONFIG", "GET", "slaveof"))
		if err != nil {
			log.Println(err)
			// Retry connection to Redis until it is back
			defer c.Close()
			time.Sleep(time.Second * 1)
			c = pool.Get()
			continue
		}
		for _, value := range master {
			if value == "" {
				chans[port] <- true
			} else {
				chans[port] <- false
			}
		}
		time.Sleep(time.Second * 5)
	}
}

func queueStats(port string) {
	// connect to redis
	pool := newPool(port)
	c := pool.Get()
	if !instanceAlive(pool) {
		log.Printf("error: no redis instance listening on port %s, aborting\n", port)
		return
	}

	// subscribe to the keyspace notifications
	c.Send("PSUBSCRIBE", "__keyspace*")
	c.Flush()
	// ignore first message received when subscribing
	c.Receive()

	go instanceIsMaster(pool, port)
	go keyspaceEnable(pool, port)

	fetchStats := true

	for {
		select {
		case fetchStats = <-chans[port]:
		default:
			if fetchStats {
				reply, err := redis.StringMap(c.Receive())
				if err != nil {
					// Retry connection to Redis until it is back
					defer c.Close()
					log.Printf("connection to redis lost. retry in 1s\n")
					time.Sleep(time.Second * 1)
					c = pool.Get()
					go keyspaceEnable(pool, port)
					c.Send("PSUBSCRIBE", "*")
					c.Flush()
					c.Receive()
					continue
				}
				// match for a LIST keyspace event
				for k, v := range reply {
					operation := listOperationsRegex.FindString(v)
					queue := keyspaceRegex.FindStringSubmatch(k)
					if len(queue) == 2 && operation != "" {
						Stats.Add(fmt.Sprintf("%s.%s.%s", port, queue[1], operation), 1)
					}
				}
			} else {
				// nothing to do. instance is a slave
				time.Sleep(time.Second * 1)
			}

		}
	}
}

var Stats = expvar.NewMap("stats").Init()
var listOperationsRegex = regexp.MustCompile("^(lpush|lpushx|rpush|rpushx|lpop|blpop|rpop|brpop)$")
var keyspaceRegex = regexp.MustCompile("^__keyspace.*__:(?P<queue_name>.*)$")
var keyspaceConfigRegex = regexp.MustCompile("^(AK.*|.*l.*K.*)$")
var ports redisPorts
var graph *graphite.Graphite
var chans = make(map[string](chan bool))

func main() {
	flag.Var(&ports, "ports", "comma-separated list of redis ports")
	graphiteHost := flag.String("graphite-host", "localhost", "graphite hostname")
	graphitePort := flag.Int("graphite-port", 2003, "graphite port")
	interval := flag.Int("interval", 60, "interval for sending graphite metrics")
	simulate := flag.Bool("simulate", false, "simulate sending to graphite via stdout")
	flag.Parse()

	// flag checks
	if len(ports) == 0 {
		log.Println("no redis instances defined, aborting")
		return
	}

	if *simulate {
		graph = graphite.NewGraphiteNop(*graphiteHost, *graphitePort)
	} else {
		var err error
		graph, err = graphite.NewGraphite(*graphiteHost, *graphitePort)
		if err != nil {
			log.Println(err)
			return
		}
	}
	hostname := HostnameGraphite()
	ticker := time.NewTicker(time.Second * time.Duration(*interval)).C

	for _, port := range ports {
		chans[port] = make(chan bool)
		log.Println("spawning collector for port ", port)
		go queueStats(port)
	}

	sig := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

	go func() {
		<-sig
		done <- true
	}()

	for {
		select {
		case <-ticker:
			Stats.Do(func(kv expvar.KeyValue) {
				graph.SimpleSend(fmt.Sprintf("scouter.%s.%s", hostname, kv.Key), kv.Value.String())
			})
		case <-done:
			log.Println("user aborted")
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/url"
	"os"
	"os/signal"
	"syscall"

	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/garden-windows/backend"
	"github.com/cloudfoundry-incubator/garden-windows/dotnet"
	"github.com/cloudfoundry-incubator/garden/server"
	"github.com/pivotal-golang/lager"
)

var containerGraceTime = flag.Duration(
	"containerGraceTime",
	0,
	"time after which to destroy idle containers",
)
var containerizerURL = flag.String(
	"containerizerURL",
	"http://127.0.0.1",
	"URL for the Containerizer container server",
)

func main() {
	defaultListNetwork := "unix"
	defaultListAddr := "/tmp/garden.sock"
	if os.Getenv("PORT") != "" {
		defaultListNetwork = "tcp"
		defaultListAddr = "0.0.0.0:" + os.Getenv("PORT")
	}
	var listenNetwork = flag.String(
		"listenNetwork",
		defaultListNetwork,
		"how to listen on the address (unix, tcp, etc.)",
	)
	var listenAddr = flag.String(
		"listenAddr",
		defaultListAddr,
		"address to listen on",
	)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger, _ := cf_lager.New("garden-windows")

	url, err := url.Parse(*containerizerURL)
	if err != nil {
		logger.Fatal("Could not parse containerizer url", err, lager.Data{
			"containerizerURL": containerizerURL,
		})
	}
	client := dotnet.NewClient(logger, url)
	netBackend, err := backend.NewDotNetBackend(client, logger)
	if err != nil {
		logger.Fatal("Server Failed to Start", err)
		os.Exit(1)
	}

	gardenServer := server.New(*listenNetwork, *listenAddr, *containerGraceTime, netBackend, logger)
	err = gardenServer.Start()
	if err != nil {
		logger.Fatal("Server Failed to Start", err)
		os.Exit(1)
	}

	logger.Info("started", lager.Data{
		"network": *listenNetwork,
		"addr":    *listenAddr,
	})

	signals := make(chan os.Signal, 1)

	go func() {
		<-signals
		gardenServer.Stop()
		os.Exit(0)
	}()

	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	select {}
}
<commit_msg>Add dropsonde logging<commit_after>package main

import (
	"flag"
	"net/url"
	"os"
	"os/signal"
	"syscall"

	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/garden-windows/backend"
	"github.com/cloudfoundry-incubator/garden-windows/dotnet"
	"github.com/cloudfoundry-incubator/garden/server"
	"github.com/cloudfoundry/dropsonde"
	"github.com/pivotal-golang/lager"
)

var containerGraceTime = flag.Duration(
	"containerGraceTime",
	0,
	"time after which to destroy idle containers",
)
var containerizerURL = flag.String(
	"containerizerURL",
	"http://127.0.0.1",
	"URL for the Containerizer container server",
)

var dropsondeOrigin = flag.String(
	"dropsondeOrigin",
	"garden-windows",
	"Origin identifier for dropsonde-emitted metrics.",
)

var dropsondeDestination = flag.String(
	"dropsondeDestination",
	"localhost:3457",
	"Destination for dropsonde-emitted metrics.",
)

func initializeDropsonde(logger lager.Logger) {
	err := dropsonde.Initialize(*dropsondeDestination, *dropsondeOrigin)
	if err != nil {
		logger.Error("failed to initialize dropsonde: %v", err)
	}
}

func main() {
	defaultListNetwork := "unix"
	defaultListAddr := "/tmp/garden.sock"
	if os.Getenv("PORT") != "" {
		defaultListNetwork = "tcp"
		defaultListAddr = "0.0.0.0:" + os.Getenv("PORT")
	}
	var listenNetwork = flag.String(
		"listenNetwork",
		defaultListNetwork,
		"how to listen on the address (unix, tcp, etc.)",
	)
	var listenAddr = flag.String(
		"listenAddr",
		defaultListAddr,
		"address to listen on",
	)
	cf_lager.AddFlags(flag.CommandLine)
	flag.Parse()

	logger, _ := cf_lager.New("garden-windows")

	initializeDropsonde(logger)

	url, err := url.Parse(*containerizerURL)
	if err != nil {
		logger.Fatal("Could not parse containerizer url", err, lager.Data{
			"containerizerURL": containerizerURL,
		})
	}
	client := dotnet.NewClient(logger, url)
	netBackend, err := backend.NewDotNetBackend(client, logger)
	if err != nil {
		logger.Fatal("Server Failed to Start", err)
		os.Exit(1)
	}

	gardenServer := server.New(*listenNetwork, *listenAddr, *containerGraceTime, netBackend, logger)
	err = gardenServer.Start()
	if err != nil {
		logger.Fatal("Server Failed to Start", err)
		os.Exit(1)
	}

	logger.Info("started", lager.Data{
		"network": *listenNetwork,
		"addr":    *listenAddr,
	})

	signals := make(chan os.Signal, 1)

	go func() {
		<-signals
		gardenServer.Stop()
		os.Exit(0)
	}()

	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"

	"github.com/jessevdk/go-flags"
	"github.com/yuya-takeyama/argf"
)

func usage() {
	os.Stderr.WriteString(`
Usage: csvp [OPTION]... [FILE]...
Print selected parts of CSV from each FILE to standard output.

Options:
  -i, --indexes=LIST
                 select only these indexes
  -h, --headers=LIST
                 select only these headers
  -t, --tsv
                 equivalent to -d'\t'
  -d, --delimiter=DELIM
                 use DELIM instead of comma for field delimiter
  -D, --output-delimiter=STRING
                 use STRING as the output delimiter (default: \t)
  --help
                 display this help text and exit
  --version
                 output version information and exit
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.7.0
`[1:])
}

type Option struct {
	IndexesList     string `short:"i" long:"indexes"`
	HeadersList     string `short:"h" long:"headers"`
	IsTSV           bool   `short:"t" long:"tsv"`
	Delimiter       string `short:"d" long:"delimiter" default:","`
	OutputDelimiter string `short:"D" long:"output-delimiter" default:"\t"`
	IsHelp          bool   `          long:"help"`
	IsVersion       bool   `          long:"version"`
	Files           []string
}

func parseOption(args []string) (opt *Option, err error) {
	opt = &Option{}
	flag := flags.NewParser(opt, flags.PassDoubleDash)

	opt.Files, err = flag.ParseArgs(args)
	if err != nil {
		return nil, err
	}
	return opt, nil
}

func toDelimiter(s string) (r rune, err error) {
	s, err = strconv.Unquote(`"` + s + `"`)
	if err != nil {
		return 0, err
	}

	runes := []rune(s)
	if len(runes) != 1 {
		return 0, fmt.Errorf("the delimiter must be a single character")
	}
	return runes[0], nil
}

func newCSVScannerFromOption(opt *Option) (c *CSVScanner, err error) {
	var selector Selector
	switch {
	case opt.IndexesList != "" && opt.HeadersList != "":
		return nil, fmt.Errorf("only one type of list may be specified")
	case opt.IndexesList != "":
		selector = NewIndexes(opt.IndexesList)
	case opt.HeadersList != "":
		selector = NewHeaders(opt.HeadersList)
	default:
		selector = NewAll()
	}

	reader, err := argf.From(opt.Files)
	if err != nil {
		return nil, err
	}

	c = NewCSVScanner(selector, reader)
	c.SetOutputDelimiter(opt.OutputDelimiter)
	switch {
	case opt.IsTSV:
		c.SetDelimiter('\t')
	default:
		delimiter, err := toDelimiter(opt.Delimiter)
		if err != nil {
			return nil, err
		}
		c.SetDelimiter(delimiter)
	}
	return c, nil
}

func do(c *CSVScanner) error {
	for c.Scan() {
		fmt.Println(c.Text())
	}
	return c.Err()
}

func printErr(err error) {
	fmt.Fprintln(os.Stderr, "cspv:", err)
}

func guideToHelp() {
	os.Stderr.WriteString(`
Try 'cspv --help' for more information.
`[1:])
}

func _main() int {
	opt, err := parseOption(os.Args[1:])
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	switch {
	case opt.IsHelp:
		usage()
		return 0
	case opt.IsVersion:
		version()
		return 0
	}

	c, err := newCSVScannerFromOption(opt)
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	if err = do(c); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<commit_msg>Use pflag<commit_after>package main

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

	"github.com/ogier/pflag"
	"github.com/yuya-takeyama/argf"
)

func usage() {
	os.Stderr.WriteString(`
Usage: csvp [OPTION]... [FILE]...
Print selected parts of CSV from each FILE to standard output.

Options:
  -i, --indexes=LIST
                 select only these indexes
  -h, --headers=LIST
                 select only these headers
  -t, --tsv
                 equivalent to -d'\t'
  -d, --delimiter=DELIM
                 use DELIM instead of comma for field delimiter
  -D, --output-delimiter=STRING
                 use STRING as the output delimiter (default: \t)
  --help
                 display this help text and exit
  --version
                 output version information and exit
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.7.0
`[1:])
}

type Option struct {
	IndexesList     string
	HeadersList     string
	IsTSV           bool
	Delimiter       string
	OutputDelimiter string
	IsHelp          bool
	IsVersion       bool
	Files           []string
}

func parseOption(args []string) (opt *Option, err error) {
	flag := pflag.NewFlagSet("csvp", pflag.ContinueOnError)
	flag.SetOutput(ioutil.Discard)

	opt = &Option{}
	flag.StringVarP(&opt.IndexesList, "indexes", "i", "", "")
	flag.StringVarP(&opt.HeadersList, "headers", "h", "", "")
	flag.BoolVarP(&opt.IsTSV, "tsv", "t", false, "")
	flag.StringVarP(&opt.Delimiter, "delimiter", "d", ",", "")
	flag.StringVarP(&opt.OutputDelimiter, "output-delimiter", "D", "\t", "")
	flag.BoolVarP(&opt.IsHelp, "help", "", false, "")
	flag.BoolVarP(&opt.IsVersion, "version", "", false, "")

	if err = flag.Parse(args); err != nil {
		return opt, err
	}

	opt.Files = flag.Args()
	return opt, nil
}

func toDelimiter(s string) (r rune, err error) {
	s, err = strconv.Unquote(`"` + s + `"`)
	if err != nil {
		return 0, err
	}

	runes := []rune(s)
	if len(runes) != 1 {
		return 0, fmt.Errorf("the delimiter must be a single character")
	}
	return runes[0], nil
}

func newCSVScannerFromOption(opt *Option) (c *CSVScanner, err error) {
	var selector Selector
	switch {
	case opt.IndexesList != "" && opt.HeadersList != "":
		return nil, fmt.Errorf("only one type of list may be specified")
	case opt.IndexesList != "":
		selector = NewIndexes(opt.IndexesList)
	case opt.HeadersList != "":
		selector = NewHeaders(opt.HeadersList)
	default:
		selector = NewAll()
	}

	reader, err := argf.From(opt.Files)
	if err != nil {
		return nil, err
	}

	c = NewCSVScanner(selector, reader)
	c.SetOutputDelimiter(opt.OutputDelimiter)
	switch {
	case opt.IsTSV:
		c.SetDelimiter('\t')
	default:
		delimiter, err := toDelimiter(opt.Delimiter)
		if err != nil {
			return nil, err
		}
		c.SetDelimiter(delimiter)
	}
	return c, nil
}

func do(c *CSVScanner) error {
	for c.Scan() {
		fmt.Println(c.Text())
	}
	return c.Err()
}

func printErr(err error) {
	fmt.Fprintln(os.Stderr, "cspv:", err)
}

func guideToHelp() {
	os.Stderr.WriteString(`
Try 'cspv --help' for more information.
`[1:])
}

func _main() int {
	opt, err := parseOption(os.Args[1:])
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	switch {
	case opt.IsHelp:
		usage()
		return 0
	case opt.IsVersion:
		version()
		return 0
	}

	c, err := newCSVScannerFromOption(opt)
	if err != nil {
		printErr(err)
		guideToHelp()
		return 2
	}
	if err = do(c); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ikawaha/kagome/tokenizer"
	"github.com/k0kubun/pp"
)

var sample = `日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は、国民の厳粛な信託によるものであつて、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基くものである。われらは、これに反する一切の憲法、法令及び詔勅を排除する。
　日本国民は、恒久の平和を念願し、人間相互の関係を支配する崇高な理想を深く自覚するのであつて、平和を愛する諸国民の公正と信義に信頼して、われらの安全と生存を保持しようと決意した。われらは、平和を維持し、専制と隷従、圧迫と偏狭を地上から永遠に除去しようと努めてゐる国際社会において、名誉ある地位を占めたいと思ふ。われらは、全世界の国民が、ひとしく恐怖と欠乏から免かれ、平和のうちに生存する権利を有することを確認する。
　われらは、いづれの国家も、自国のことのみに専念して他国を無視してはならないのであつて、政治道徳の法則は、普遍的なものであり、この法則に従ふことは、自国の主権を維持し、他国と対等関係に立たうとする各国の責務であると信ずる。
　日本国民は、国家の名誉にかけ、全力をあげてこの崇高な理想と目的を達成することを誓ふ。`

var pos = "名詞"

func main() {
	t := tokenizer.New()
	tokens := t.Analyze(sample, tokenizer.Normal)
	for _, token := range tokens {
		if token.Pos() == pos {
			pp.Printf("%s : %s\n", token.Surface, token.Pos())
		}
		continue
	}
}
package main

import (
	"github.com/ikawaha/kagome/tokenizer"
	"github.com/k0kubun/pp"
)

var sample = `日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は、国民の厳粛な信託によるものであつて、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基くものである。われらは、これに反する一切の憲法、法令及び詔勅を排除する。
　日本国民は、恒久の平和を念願し、人間相互の関係を支配する崇高な理想を深く自覚するのであつて、平和を愛する諸国民の公正と信義に信頼して、われらの安全と生存を保持しようと決意した。われらは、平和を維持し、専制と隷従、圧迫と偏狭を地上から永遠に除去しようと努めてゐる国際社会において、名誉ある地位を占めたいと思ふ。われらは、全世界の国民が、ひとしく恐怖と欠乏から免かれ、平和のうちに生存する権利を有することを確認する。
　われらは、いづれの国家も、自国のことのみに専念して他国を無視してはならないのであつて、政治道徳の法則は、普遍的なものであり、この法則に従ふことは、自国の主権を維持し、他国と対等関係に立たうとする各国の責務であると信ずる。
　日本国民は、国家の名誉にかけ、全力をあげてこの崇高な理想と目的を達成することを誓ふ。`

var pos = "名詞"

func main() {
	t := tokenizer.New()
	tokens := t.Analyze(sample, tokenizer.Normal)
	for _, token := range tokens {
		if token.Pos() == pos {
			pp.Printf("%s : %s\n", token.Surface, token.Pos())
		}
		continue
	}
}<commit_msg>fix duplication data.<commit_after>package main

import (
	"github.com/ikawaha/kagome/tokenizer"
	"github.com/k0kubun/pp"
)

var sample = `日本国民は、正当に選挙された国会における代表者を通じて行動し、われらとわれらの子孫のために、諸国民との協和による成果と、わが国全土にわたつて自由のもたらす恵沢を確保し、政府の行為によつて再び戦争の惨禍が起ることのないやうにすることを決意し、ここに主権が国民に存することを宣言し、この憲法を確定する。そもそも国政は、国民の厳粛な信託によるものであつて、その権威は国民に由来し、その権力は国民の代表者がこれを行使し、その福利は国民がこれを享受する。これは人類普遍の原理であり、この憲法は、かかる原理に基くものである。われらは、これに反する一切の憲法、法令及び詔勅を排除する。
　日本国民は、恒久の平和を念願し、人間相互の関係を支配する崇高な理想を深く自覚するのであつて、平和を愛する諸国民の公正と信義に信頼して、われらの安全と生存を保持しようと決意した。われらは、平和を維持し、専制と隷従、圧迫と偏狭を地上から永遠に除去しようと努めてゐる国際社会において、名誉ある地位を占めたいと思ふ。われらは、全世界の国民が、ひとしく恐怖と欠乏から免かれ、平和のうちに生存する権利を有することを確認する。
　われらは、いづれの国家も、自国のことのみに専念して他国を無視してはならないのであつて、政治道徳の法則は、普遍的なものであり、この法則に従ふことは、自国の主権を維持し、他国と対等関係に立たうとする各国の責務であると信ずる。
　日本国民は、国家の名誉にかけ、全力をあげてこの崇高な理想と目的を達成することを誓ふ。`

var pos = "名詞"

func main() {
	t := tokenizer.New()
	tokens := t.Analyze(sample, tokenizer.Normal)
	for _, token := range tokens {
		if token.Pos() == pos {
			pp.Printf("%s : %s\n", token.Surface, token.Pos())
		}
		continue
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/cellofellow/gopiano"
	"github.com/cellofellow/gopiano/responses"
	"github.com/GeertJohan/go.linenoise"
	"github.com/howeyc/gopass"
)

var pandora *gopiano.Client

func main() {
	// Create client and login partner.
	pandora, err := gopiano.NewClient(gopiano.AndroidClient)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	_, err = pandora.AuthPartnerLogin()
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	fmt.Println("Welcome to pianopub! Press ? for a list of commands.")
	email, err := linenoise.Line("[?] Email: ")
	if err == linenoise.KillSignalError {
		os.Exit(0)
	}
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("[?] Password: ")
	password := string(gopass.GetPasswd())

	fmt.Printf("(i) Login... ")
	_, err = pandora.AuthUserLogin(email, password)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("Ok.\n")

	fmt.Printf("(i) Get stations... ")
	stations, err := pandora.UserGetStationList(true)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("Ok\n")

	sort.Sort(stations.Result.Stations)

	var stationChoices map[int]responses.Station = make(map[int]responses.Station, 20)
	var quickmixStations map[string]bool = make(map[string]bool, 20)
	for i, s := range stations.Result.Stations {
		stationChoices[i] = s
		if s.IsQuickMix {
			for _, id := range s.QuickMixStationIDs {
				quickmixStations[id] = true
			}
		}
	}

	fstring := "\t%2d) %s%s %s\n"
	for i := 0; i < len(stationChoices); i++ {
		s := stationChoices[i]
		var inQuickMix, isQuickMix string
		if _, yes := quickmixStations[s.StationID]; yes {
			inQuickMix = "q"
		} else {
			inQuickMix = " "
		}
		if s.IsQuickMix {
			isQuickMix = "Q"
		} else {
			isQuickMix = " "
		}
		fmt.Printf(fstring, i, inQuickMix, isQuickMix, s.StationName)
	}

	str, err := linenoise.Line("[?] Select station: ")
	if err == linenoise.KillSignalError {
		os.Exit(0)
	}
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	fields := strings.Fields(str)
	choice, err := strconv.ParseInt(fields[0], 10, 0)
	if err != nil {
		fmt.Println("You must enter an integer.")
		os.Exit(1)
	}
	var station responses.Station
	if s, ok := stationChoices[int(choice)]; ok {
		station = s
	} else {
		fmt.Println("Station %d not found.", choice)
		os.Exit(1)
	}

	playlistResponse, err := pandora.StationGetPlaylist(station.StationToken)
	if err != nil {
		fmt.Println("Unexpected error: %v", choice)
		os.Exit(1)
	}
	for _, item := range playlistResponse.Result.Items {
		fmt.Printf("%s by %s from %s %s\n", item.SongName, item.ArtistName, item.AlbumName,
			item.AudioURLMap["mediumQuality"].AudioURL)
	}
}

<commit_msg>Add MPD for playing. Still planning on using PortAudio in the future.<commit_after>package main

import (
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"

	"github.com/cellofellow/gopiano"
	"github.com/cellofellow/gopiano/responses"
	"github.com/GeertJohan/go.linenoise"
	"github.com/howeyc/gopass"
	"github.com/turbowookie/gompd/mpd"
)

var pandora *gopiano.Client

func main() {
	// Create client and login partner.
	pandora, err := gopiano.NewClient(gopiano.AndroidClient)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	_, err = pandora.AuthPartnerLogin()
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	fmt.Println("Welcome to pianopub! Press ? for a list of commands.")
	email, err := linenoise.Line("[?] Email: ")
	if err == linenoise.KillSignalError {
		os.Exit(0)
	}
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("[?] Password: ")
	password := string(gopass.GetPasswd())

	fmt.Printf("(i) Login... ")
	_, err = pandora.AuthUserLogin(email, password)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("Ok.\n")

	fmt.Printf("(i) Get stations... ")
	stations, err := pandora.UserGetStationList(true)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	fmt.Printf("Ok\n")

	sort.Sort(stations.Result.Stations)

	var stationChoices map[int]responses.Station = make(map[int]responses.Station, 20)
	var quickmixStations map[string]bool = make(map[string]bool, 20)
	for i, s := range stations.Result.Stations {
		stationChoices[i] = s
		if s.IsQuickMix {
			for _, id := range s.QuickMixStationIDs {
				quickmixStations[id] = true
			}
		}
	}

	fstring := "\t%2d) %s%s %s\n"
	for i := 0; i < len(stationChoices); i++ {
		s := stationChoices[i]
		var inQuickMix, isQuickMix string
		if _, yes := quickmixStations[s.StationID]; yes {
			inQuickMix = "q"
		} else {
			inQuickMix = " "
		}
		if s.IsQuickMix {
			isQuickMix = "Q"
		} else {
			isQuickMix = " "
		}
		fmt.Printf(fstring, i, inQuickMix, isQuickMix, s.StationName)
	}

	str, err := linenoise.Line("[?] Select station: ")
	if err == linenoise.KillSignalError {
		os.Exit(0)
	}
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}

	fields := strings.Fields(str)
	choice, err := strconv.ParseInt(fields[0], 10, 0)
	if err != nil {
		fmt.Println("You must enter an integer.")
		os.Exit(1)
	}
	var station responses.Station
	if s, ok := stationChoices[int(choice)]; ok {
		station = s
	} else {
		fmt.Println("Station %d not found.", choice)
		os.Exit(1)
	}

	playlistResponse, err := pandora.StationGetPlaylist(station.StationToken)
	if err != nil {
		fmt.Println("Unexpected error: %v", choice)
		os.Exit(1)
	}

	mpdclient, err := mpd.Dial("tcp", "localhost:6600")
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
	defer mpdclient.Close()
	for _, item := range playlistResponse.Result.Items {
		fmt.Printf("%s by %s from %s\n", item.SongName, item.ArtistName, item.AlbumName)
		err = mpdclient.Add(item.AudioURLMap["mediumQuality"].AudioURL)
		if err != nil {
			fmt.Println("Unexpected error: %v", err)
			os.Exit(1)
		}

	}
	err = mpdclient.Play(0)
	if err != nil {
		fmt.Println("Unexpected error: %v", err)
		os.Exit(1)
	}
}

<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Starting up...")
	http.HandleFunc("/", handler)
	fmt.Println("Start webserver")
	http.ListenAndServe(":8080", nil)
	fmt.Println("Finishing")
}

func handler(rw http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(rw, "
Hello World from a docker container...
")
}
<commit_msg>Switch to port 80 for compatibility with buildpack<commit_after>package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Starting up...")
	http.HandleFunc("/", handler)
	fmt.Println("Start webserver")
	http.ListenAndServe(":80", nil)
	fmt.Println("Finishing")
}

func handler(rw http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(rw, "
Hello World from a docker container...
")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/captncraig/github-webhooks"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

var scriptDir string
var scriptExt = ".sh"

func init() {
	scriptDir = os.Getenv("TINYCI-SCRIPT-DIR")

	if scriptDir == "" {
		var err error
		scriptDir, err = os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
		scriptDir = filepath.Join(scriptDir, "scripts")
	}
	if runtime.GOOS == "windows" {
		scriptExt = ".bat"
	}
}

func main() {

	gitHooks := webhooks.WebhookListener{}
	gitHooks.OnPush = githubHook
	http.HandleFunc("/gh", gitHooks.GetHttpListener())
	http.ListenAndServe(":4567", nil)
}

func githubHook(event *webhooks.PushEvent, _ *webhooks.WebhookContext) {
	repo := strings.Replace(event.Repository.FullName, "/", ".", -1)
	refPath := strings.Split(event.Ref, "/")
	ref := refPath[len(refPath)-1]
	runScriptIfExists(fmt.Sprintf("%s", repo))
	runScriptIfExists(fmt.Sprintf("%s:%s", repo, ref))
}

func runScriptIfExists(name string) {
	filename := filepath.Join(scriptDir, name+scriptExt)
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		fmt.Printf("Script does not exist: %s. Skipping.\n", filename)
		return
	}
	cmd := exec.Command(filename)
	output, err := cmd.CombinedOutput()
	fmt.Println(output, err)
}
<commit_msg>refining output<commit_after>package main

import (
	"fmt"
	"github.com/captncraig/github-webhooks"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
)

var scriptDir string
var scriptExt = ".sh"

func init() {
	scriptDir = os.Getenv("TINYCI-SCRIPT-DIR")

	if scriptDir == "" {
		var err error
		scriptDir, err = os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
		scriptDir = filepath.Join(scriptDir, "scripts")
	}
	if runtime.GOOS == "windows" {
		scriptExt = ".bat"
	}
}

func main() {

	gitHooks := webhooks.WebhookListener{}
	gitHooks.OnPush = githubHook
	http.HandleFunc("/gh", gitHooks.GetHttpListener())
	http.ListenAndServe(":4567", nil)
}

func githubHook(event *webhooks.PushEvent, _ *webhooks.WebhookContext) {
	repo := strings.Replace(event.Repository.FullName, "/", ".", -1)
	refPath := strings.Split(event.Ref, "/")
	ref := refPath[len(refPath)-1]
	runScriptIfExists(fmt.Sprintf("%s", repo))
	runScriptIfExists(fmt.Sprintf("%s:%s", repo, ref))
}

func runScriptIfExists(name string) {
	filename := filepath.Join(scriptDir, name+scriptExt)
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		log.Printf("Script does not exist: %s. Skipping.\n", filename)
		return
	}
	cmd := exec.Command(filename)
	log.Printf("Executing %s...\n", filename)
	output, err := cmd.CombinedOutput()
	if err != nil {
		log.Printf("Error executing %s: %s", filename, err.Error())
	}
	log.Println(output)
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"

	"github.com/docker/machine/commands"
	"github.com/docker/machine/utils"
	"github.com/docker/machine/version"
)

func main() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			os.Setenv("DEBUG", "1")
			initLogging(log.DebugLevel)
		}
	}

	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Docker Machine Contributors"
	app.Email = "https://github.com/docker/machine"
	app.Before = func(c *cli.Context) error {
		os.Setenv("MACHINE_STORAGE_PATH", c.GlobalString("storage-path"))
		return nil
	}
	app.Commands = commands.Commands
	app.CommandNotFound = cmdNotFound
	app.Usage = "Create and manage machines running Docker."
	app.Version = version.VERSION + " (" + version.GITCOMMIT + ")"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_STORAGE_PATH",
			Name:   "storage-path",
			Value:  utils.GetBaseDir(),
			Usage:  "Configures storage path",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CA_CERT",
			Name:   "tls-ca-cert",
			Usage:  "CA to verify remotes against",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CA_KEY",
			Name:   "tls-ca-key",
			Usage:  "Private key to generate certificates",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CLIENT_CERT",
			Name:   "tls-client-cert",
			Usage:  "Client cert to use for TLS",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CLIENT_KEY",
			Name:   "tls-client-key",
			Usage:  "Private key used in client TLS auth",
			Value:  "",
		},
	}

	app.Run(os.Args)
}

func cmdNotFound(c *cli.Context, command string) {
	log.Fatalf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		c.App.Name,
	)
}
<commit_msg>Reformatting usage message to look more like docker's<commit_after>package main

import (
	"os"
	"path"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"

	"github.com/docker/machine/commands"
	"github.com/docker/machine/utils"
	"github.com/docker/machine/version"
)

var AppHelpTemplate = `
Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

func main() {
	for _, f := range os.Args {
		if f == "-D" || f == "--debug" || f == "-debug" {
			os.Setenv("DEBUG", "1")
			initLogging(log.DebugLevel)
		}
	}

	cli.AppHelpTemplate = AppHelpTemplate
	app := cli.NewApp()
	app.Name = path.Base(os.Args[0])
	app.Author = "Docker Machine Contributors"
	app.Email = "https://github.com/docker/machine"
	app.Before = func(c *cli.Context) error {
		os.Setenv("MACHINE_STORAGE_PATH", c.GlobalString("storage-path"))
		return nil
	}
	app.Commands = commands.Commands
	app.CommandNotFound = cmdNotFound
	app.Usage = "Create and manage machines running Docker."
	app.Version = version.VERSION + " (" + version.GITCOMMIT + ")"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "Enable debug mode",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_STORAGE_PATH",
			Name:   "storage-path",
			Value:  utils.GetBaseDir(),
			Usage:  "Configures storage path",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CA_CERT",
			Name:   "tls-ca-cert",
			Usage:  "CA to verify remotes against",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CA_KEY",
			Name:   "tls-ca-key",
			Usage:  "Private key to generate certificates",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CLIENT_CERT",
			Name:   "tls-client-cert",
			Usage:  "Client cert to use for TLS",
			Value:  "",
		},
		cli.StringFlag{
			EnvVar: "MACHINE_TLS_CLIENT_KEY",
			Name:   "tls-client-key",
			Usage:  "Private key used in client TLS auth",
			Value:  "",
		},
	}

	app.Run(os.Args)
}

func cmdNotFound(c *cli.Context, command string) {
	log.Fatalf(
		"%s: '%s' is not a %s command. See '%s --help'.",
		c.App.Name,
		command,
		c.App.Name,
		c.App.Name,
	)
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "os/exec"

    "errors"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/loadavg.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(raw[:]), "\n")
        headers := strings.Fields(lines[0])

        var cpuLoads [][2]string

        // Last 3 headers are CPU loads, clean them up
        for _, load := range headers[len(headers)-3:] {
            // Remove trailing coma if there
            cleanLoad := strings.Split(string(load), ",")[0]

            loadFloat, err := strconv.ParseFloat(cleanLoad, 32)

            if err != nil {
                continue
            }

            loadPercentage := int(loadFloat * 100) / runtime.NumCPU()

            cpuLoads = append(cpuLoads, [2]string{
                cleanLoad,
                strconv.Itoa(loadPercentage),
            })
        }

        return json.Marshal(cpuLoads)
    })

    m.Get("/sh/ping.php", func () ([]byte, error) {
        HOSTS := [4]string{
            "wikipedia.org",
            "github.com",
            "google.com",
            "gnu.org",
        }

        var entries [][]string

        for _, host := range HOSTS {
            ping, err := pingHost(host, 2)

            if err != nil {
                continue
            }

            entries = append(entries, []string{
                host,
                ping,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/netstat.php", func () ([]byte, error) {
        raw, err := exec.Command("netstat", "-nt").Output()

        if err != nil {
            return nil, err
        }

        // Get entries as a table
        entries := parseCommandTable(raw, 2, 1)

        // Connections we care about
        var connections [][]string

        // Filter by protocol
        for _, entry := range entries {
            // Skip bad entries or non tcp
            if len(entry) != 6 || (entry[0] != "tcp" && entry[0] != "tcp4") {
                continue
            }

            connections = append(connections, entry)
        }

        // Count connections from a machine
        connectionCount := make(map[string]int)

        // Extract
        for _, conn := range connections {
            // Foreign Address
            remoteAddr := conn[4]

            // Increment counter
            connectionCount[remoteAddr]++
        }

        // Expected output by client
        var output [][2]string

        for remoteAddr, count := range connectionCount {
            // Compensate for difference between OSX and linux
            parts := strings.Split(strings.Replace(remoteAddr, ",", ".", 1), ".")
            ip := strings.Join(parts[:4], ".")
            // port := parts[4]

            output = append(output, [2]string{
                strconv.Itoa(count),
                ip,
            })
        }

        return json.Marshal(output)
    })

    m.Get("/sh/where.php", func () ([]byte, error) {
        SOFTWARE := []string{
            "php",
            "node",
            "mysql",
            "vim",
            "python",
            "ruby",
            "java",
            "apache2",
            "nginx",
            "openssl",
            "vsftpd",
            "make",
        }

        var entries [][2]string

        for _, bin := range SOFTWARE {
            path, err := exec.LookPath(bin)

            if err != nil {
                path = "Not Installed"
            }

            entries = append(entries, [2]string{
                bin,
                path,
            })
        }

        return json.Marshal(entries)
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}

// Get average pingTime to a host
func pingHost(hostname string, pingCount int) (string, error) {
    raw, err := exec.Command("ping", "-c", strconv.Itoa(pingCount), hostname).Output()

    if err != nil {
        return "", err
    }

    lines := strings.Split(string(raw[:]), "\n")

    if len(lines) < 2 {
        return "", errors.New("Bad output for ping command")
    }

    // Get 2nd last line
    lastLine := lines[len(lines)-2]

    // Extract average ping time as a string
    pingTime := strings.Split(strings.Split(lastLine, "=")[1], "/")[1]

    return pingTime, nil
}
<commit_msg>Add mem command<commit_after>package main

import (
    "os"
    "os/exec"

    "errors"

    "io/ioutil"

    "log"

//    "fmt"
    "strings"
    "runtime"
    "strconv" // For Itoa
//    "encoding/csv"
    "encoding/json"

    "github.com/go-martini/martini"
)

func main() {
    m := martini.Classic()

    // CPU count
    m.Get("/sh/numberofcores.php", func () ([]byte, error) {
        return json.Marshal(runtime.NumCPU())
    })

    // Server's hostname
    m.Get("/sh/hostname.php", func () ([]byte, error) {
        host, err := os.Hostname()

        if err != nil {
            return nil, err
        }

        return json.Marshal(host)
    })

    // PS
    m.Get("/sh/ps.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("ps", "aux").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/df.php", func () ([]byte, error) {
        // Run uptime command
        rawOutput, err := exec.Command("df", "-Ph").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(parseCommandTable(rawOutput, 1, 1))
    })

    m.Get("/sh/time.php", func () ([]byte, error) {
        raw, err := exec.Command("date").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/issue.php", func () ([]byte, error) {
        raw, err := exec.Command("uname", "-rsm").Output()

        if err != nil {
            return nil, err
        }

        return json.Marshal(string(raw[:]))
    })

    m.Get("/sh/users.php", func () ([]byte, error) {
        data, err := ioutil.ReadFile("/etc/passwd")

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(data), "\n")

        // Output records
        var records [][]string

        for _, line := range lines {
            parts := strings.Split(line, ":")

            // Skip bad or empty lines
            if len(parts) != 7 {
                log.Println(len(parts))
                continue
            }

            // Parse base 10, 16 bit UID integer
            uid, err := strconv.ParseInt(parts[2], 10, 16)

            // Error parsing UID
            if err != nil {
                continue
            }

            userType := "user"

            // Check if system user
            if uid <= 499 {
                userType = "system"
            }

            user := []string{
                // User type
                userType,
                // Username
                parts[0],
                // Home directory
                parts[6],
            }

            records = append(records, user)
        }

        return json.Marshal(records)
    })

    m.Get("/sh/online.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        // We'll add all the parsed lines here
        var entries [][]string

        // Skip first and last line of output
        for _, entry := range parseCommandTable(raw, 2, 1) {
            entries = append(entries, []string{
                // User
                entry[0],
                // From
                entry[2],
                // Login at
                entry[3],
                // Idle
                entry[4],
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/loadavg.php", func () ([]byte, error) {
        raw, err := exec.Command("w").Output()

        if err != nil {
            return nil, err
        }

        lines := strings.Split(string(raw[:]), "\n")
        headers := strings.Fields(lines[0])

        var cpuLoads [][2]string

        // Last 3 headers are CPU loads, clean them up
        for _, load := range headers[len(headers)-3:] {
            // Remove trailing coma if there
            cleanLoad := strings.Split(string(load), ",")[0]

            loadFloat, err := strconv.ParseFloat(cleanLoad, 32)

            if err != nil {
                continue
            }

            loadPercentage := int(loadFloat * 100) / runtime.NumCPU()

            cpuLoads = append(cpuLoads, [2]string{
                cleanLoad,
                strconv.Itoa(loadPercentage),
            })
        }

        return json.Marshal(cpuLoads)
    })

    m.Get("/sh/ping.php", func () ([]byte, error) {
        HOSTS := [4]string{
            "wikipedia.org",
            "github.com",
            "google.com",
            "gnu.org",
        }

        var entries [][]string

        for _, host := range HOSTS {
            ping, err := pingHost(host, 2)

            if err != nil {
                continue
            }

            entries = append(entries, []string{
                host,
                ping,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/netstat.php", func () ([]byte, error) {
        raw, err := exec.Command("netstat", "-nt").Output()

        if err != nil {
            return nil, err
        }

        // Get entries as a table
        entries := parseCommandTable(raw, 2, 1)

        // Connections we care about
        var connections [][]string

        // Filter by protocol
        for _, entry := range entries {
            // Skip bad entries or non tcp
            if len(entry) != 6 || (entry[0] != "tcp" && entry[0] != "tcp4") {
                continue
            }

            connections = append(connections, entry)
        }

        // Count connections from a machine
        connectionCount := make(map[string]int)

        // Extract
        for _, conn := range connections {
            // Foreign Address
            remoteAddr := conn[4]

            // Increment counter
            connectionCount[remoteAddr]++
        }

        // Expected output by client
        var output [][2]string

        for remoteAddr, count := range connectionCount {
            // Compensate for difference between OSX and linux
            parts := strings.Split(strings.Replace(remoteAddr, ",", ".", 1), ".")
            ip := strings.Join(parts[:4], ".")
            // port := parts[4]

            output = append(output, [2]string{
                strconv.Itoa(count),
                ip,
            })
        }

        return json.Marshal(output)
    })

    m.Get("/sh/where.php", func () ([]byte, error) {
        SOFTWARE := []string{
            "php",
            "node",
            "mysql",
            "vim",
            "python",
            "ruby",
            "java",
            "apache2",
            "nginx",
            "openssl",
            "vsftpd",
            "make",
        }

        var entries [][2]string

        for _, bin := range SOFTWARE {
            path, err := exec.LookPath(bin)

            if err != nil {
                path = "Not Installed"
            }

            entries = append(entries, [2]string{
                bin,
                path,
            })
        }

        return json.Marshal(entries)
    })

    m.Get("/sh/mem.php", func () ([]byte, error) {
        var entries []string

        raw, err := exec.Command("free", "-m").Output()

        if err != nil {
            // OS X fallback
            raw, err := exec.Command("vm_stat").Output()

            if err != nil {
                return nil, err
            }

            vmMap := parseCommandMap(raw)

            freePages := toMB(vmMap["Pages free"])
            activePages := toMB(vmMap["Pages active"])
            inactivePages := toMB(vmMap["Pages inactive"])
            speculativePages := toMB(vmMap["Pages speculative"])

            free := freePages + speculativePages
            used := activePages + inactivePages

            return json.Marshal([]string{
                "Mem:",

                // Total
                strconv.Itoa(free + used),

                // Used
                strconv.Itoa(used),

                // Free
                strconv.Itoa(free),
            })
        }

        // Linux
        entries = parseCommandTable(raw, 2, 1)[0][:4]

        return json.Marshal(entries)
    })

    // Serve static files
    m.Get("/.*", martini.Static(""))

    m.Run()
}

func parseCommandTable(rawOutput []byte, headerCount int, footerCount int) [][]string {
    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // We'll add all the parsed lines here
    var entries [][]string

    // Lines of output
    lines := strings.Split(output, "\n")

    // Skip first and last line of output
    for _, str := range lines[headerCount:len(lines)-footerCount] {
        entries = append(entries, strings.Fields(str))
    }

    return entries
}

func parseCommandMap(rawOutput []byte) map[string]string {
    data := make(map[string]string)

    // Convert output to a string (it's not binary data, so this is ok)
    output := string(rawOutput[:])

    // Lines of output
    lines := strings.Split(output, "\n")

    for _, line := range lines {
        parts := strings.Split(line, ":")

        // Bad line, skip it
        if len(parts) != 2 {
            continue
        }

        key := strings.TrimSpace(parts[0])
        value := strings.TrimSpace(parts[1])

        // Remove trailing dot if exists
        if value[len(value) - 1] == '.' {
            value = value[:len(value) - 1]
        }

        data[key] = value
    }

    return data
}

// Get average pingTime to a host
func pingHost(hostname string, pingCount int) (string, error) {
    raw, err := exec.Command("ping", "-c", strconv.Itoa(pingCount), hostname).Output()

    if err != nil {
        return "", err
    }

    lines := strings.Split(string(raw[:]), "\n")

    if len(lines) < 2 {
        return "", errors.New("Bad output for ping command")
    }

    // Get 2nd last line
    lastLine := lines[len(lines)-2]

    // Extract average ping time as a string
    pingTime := strings.Split(strings.Split(lastLine, "=")[1], "/")[1]

    return pingTime, nil
}

func toMB(x string) int {
    num, _ := strconv.ParseInt(x, 10, 32)

    // 256 = 4096 / (1024 * 1024)
    return int(num) / 256
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"unicode/utf16"
)

type File struct {
	StringPool  *ResStringPool
	ResourceMap []uint32
	Namespace   *ResXMLTreeNamespaceExt
}

const (
	RES_NULL_TYPE        = 0x0000
	RES_STRING_POOL_TYPE = 0x0001
	RES_TABLE_TYPE       = 0x0002
	RES_XML_TYPE         = 0x0003

	// Chunk types in RES_XML_TYPE
	RES_XML_FIRST_CHUNK_TYPE     = 0x0100
	RES_XML_START_NAMESPACE_TYPE = 0x0100
	RES_XML_END_NAMESPACE_TYPE   = 0x0101
	RES_XML_START_ELEMENT_TYPE   = 0x0102
	RES_XML_END_ELEMENT_TYPE     = 0x0103
	RES_XML_CDATA_TYPE           = 0x0104
	RES_XML_LAST_CHUNK_TYPE      = 0x017f

	// This contains a uint32_t array mapping strings in the string
	// pool back to resource identifiers.  It is optional.
	RES_XML_RESOURCE_MAP_TYPE = 0x0180

	// Chunk types in RES_TABLE_TYPE
	RES_TABLE_PACKAGE_TYPE   = 0x0200
	RES_TABLE_TYPE_TYPE      = 0x0201
	RES_TABLE_TYPE_SPEC_TYPE = 0x0202
)

type ResChunkHeader struct {
	Type       uint16
	HeaderSize uint16
	Size       uint32
}

const SORTED_FLAG = 1 << 0
const UTF8_FLAG = 1 << 8

type ResStringPoolRef uint32

const NilResStringPoolRef = ResStringPoolRef(0xFFFFFFFF)

type ResStringPoolHeader struct {
	Header      ResChunkHeader
	StringCount uint32
	StyleCount  uint32
	Flags       uint32
	StringStart uint32
	StylesStart uint32
}

type ResStringPool struct {
	Header  ResStringPoolHeader
	Strings []string
	Styles  []string
}

type ResXMLTreeNode struct {
	Header     ResChunkHeader
	LineNumber uint32
	Comment    ResStringPoolRef
}

type ResXMLTreeNamespaceExt struct {
	Prefix ResStringPoolRef
	Uri    ResStringPoolRef
}

type ResXMLTreeAttrExt struct {
	NS             ResStringPoolRef
	Name           ResStringPoolRef
	AttributeStart uint16
	AttributeSize  uint16
	AttributeCount uint16
	IdIndex        uint16
	ClassIndex     uint16
	StyleIndex     uint16
}

type ResXMLTreeAttribute struct {
	NS         ResStringPoolRef
	Name       ResStringPoolRef
	RawValue   ResStringPoolRef
	TypedValue ResValue
}

const (
	TYPE_NULL            = 0x00
	TYPE_REFERENCE       = 0x01
	TYPE_ATTRIBUTE       = 0x02
	TYPE_STRING          = 0x03
	TYPE_FLOAT           = 0x04
	TYPE_DIMENSION       = 0x05
	TYPE_FRACTION        = 0x06
	TYPE_FIRST_INT       = 0x10
	TYPE_INT_DEC         = 0x10
	TYPE_INT_HEX         = 0x11
	TYPE_INT_BOOLEAN     = 0x12
	TYPE_FIRST_COLOR_INT = 0x1c
	TYPE_INT_COLOR_ARGB8 = 0x1c
	TYPE_INT_COLOR_RGB8  = 0x1d
	TYPE_INT_COLOR_ARGB4 = 0x1e
	TYPE_INT_COLOR_RGB4  = 0x1f
	TYPE_LAST_COLOR_INT  = 0x1f
	TYPE_LAST_INT        = 0x1f
)

type ResValue struct {
	Size     uint16
	Res0     uint8
	DataType uint8
	Data     uint32
}

type ResXMLTreeEndElementExt struct {
	NS   ResStringPoolRef
	Name ResStringPoolRef
}

func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	offset := uint32(header.HeaderSize)

	for offset < header.Size {
		sr.Seek(int64(offset), os.SEEK_SET)
		chunkHeader := &ResChunkHeader{}
		binary.Read(sr, binary.LittleEndian, chunkHeader)

		var err error
		chunkReader := io.NewSectionReader(r, int64(offset), int64(chunkHeader.Size))
		switch chunkHeader.Type {
		case RES_STRING_POOL_TYPE:
			f.StringPool, err = ReadStringPool(chunkReader)
		case RES_XML_RESOURCE_MAP_TYPE:
			f.ResourceMap, err = ReadResourceMap(chunkReader)
		case RES_XML_START_NAMESPACE_TYPE:
			err = f.ReadStartNamespace(chunkReader)
		case RES_XML_START_ELEMENT_TYPE:
			err = f.ReadStartElement(chunkReader)
		case RES_XML_END_ELEMENT_TYPE:
			err = f.ReadEndElement(chunkReader)
		}
		if err != nil {
			return nil, err
		}

		offset += chunkHeader.Size
	}
	return f, nil
}

func (f *File) GetString(ref ResStringPoolRef) string {
	if ref == NilResStringPoolRef {
		return ""
	}
	return f.StringPool.Strings[int(ref)]
}

func ReadStringPool(sr *io.SectionReader) (*ResStringPool, error) {
	sp := new(ResStringPool)
	binary.Read(sr, binary.LittleEndian, &sp.Header)

	stringStarts := make([]uint32, sp.Header.StringCount)
	binary.Read(sr, binary.LittleEndian, stringStarts)
	styleStarts := make([]uint32, sp.Header.StyleCount)
	binary.Read(sr, binary.LittleEndian, styleStarts)

	sp.Strings = make([]string, sp.Header.StringCount)
	for i, start := range stringStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StringStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StringStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Strings[i] = str
	}

	sp.Styles = make([]string, sp.Header.StyleCount)
	for i, start := range styleStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StylesStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StylesStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Styles[i] = str
	}

	return sp, nil
}

func ReadUTF16(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint16, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(utf16.Decode(buf)), nil
}

func ReadUTF8(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint8, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

func ReadResourceMap(sr *io.SectionReader) ([]uint32, error) {
	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	count := (header.Size - uint32(header.HeaderSize)) / 4
	fmt.Println(header.Size, header.HeaderSize, count)
	resourceMap := make([]uint32, count)
	if err := binary.Read(sr, binary.LittleEndian, resourceMap); err != nil {
		return nil, err
	}
	return resourceMap, nil
}

func (f *File) ReadStartNamespace(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	namespace := new(ResXMLTreeNamespaceExt)
	binary.Read(sr, binary.LittleEndian, namespace)
	f.Namespace = namespace
	return nil
}

func (f *File) ReadStartElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	attrExt := new(ResXMLTreeAttrExt)
	binary.Read(sr, binary.LittleEndian, attrExt)

	fmt.Println(f.GetString(attrExt.Name))

	offset := int64(attrExt.AttributeStart + header.Header.HeaderSize)
	for i := 0; i < int(attrExt.AttributeCount); i++ {
		sr.Seek(offset, os.SEEK_SET)
		attr := new(ResXMLTreeAttribute)
		binary.Read(sr, binary.LittleEndian, attr)
		fmt.Println(f.GetString(attr.Name), f.GetString(attr.RawValue))
		offset += int64(attrExt.AttributeSize)
	}
	return nil
}

func (f *File) ReadEndElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
		return err
	}
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	ext := new(ResXMLTreeEndElementExt)
	if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
		return err
	}
	if ext.NS != NilResStringPoolRef {
		fmt.Printf("</%s:%s>\n", f.GetString(ext.NS), f.GetString(ext.Name))
	} else {
		fmt.Printf("</%s>\n", f.GetString(ext.Name))
	}
	return nil
}

func main() {
	f, _ := os.Open("AndroidManifest.xml")
	fmt.Println(NewFile(f))
}
<commit_msg>bufferにXML文章として出力<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"unicode/utf16"
)

type File struct {
	StringPool  *ResStringPool
	ResourceMap []uint32
	Namespace   *ResXMLTreeNamespaceExt
	buffer      bytes.Buffer
}

const (
	RES_NULL_TYPE        = 0x0000
	RES_STRING_POOL_TYPE = 0x0001
	RES_TABLE_TYPE       = 0x0002
	RES_XML_TYPE         = 0x0003

	// Chunk types in RES_XML_TYPE
	RES_XML_FIRST_CHUNK_TYPE     = 0x0100
	RES_XML_START_NAMESPACE_TYPE = 0x0100
	RES_XML_END_NAMESPACE_TYPE   = 0x0101
	RES_XML_START_ELEMENT_TYPE   = 0x0102
	RES_XML_END_ELEMENT_TYPE     = 0x0103
	RES_XML_CDATA_TYPE           = 0x0104
	RES_XML_LAST_CHUNK_TYPE      = 0x017f

	// This contains a uint32_t array mapping strings in the string
	// pool back to resource identifiers.  It is optional.
	RES_XML_RESOURCE_MAP_TYPE = 0x0180

	// Chunk types in RES_TABLE_TYPE
	RES_TABLE_PACKAGE_TYPE   = 0x0200
	RES_TABLE_TYPE_TYPE      = 0x0201
	RES_TABLE_TYPE_SPEC_TYPE = 0x0202
)

type ResChunkHeader struct {
	Type       uint16
	HeaderSize uint16
	Size       uint32
}

const SORTED_FLAG = 1 << 0
const UTF8_FLAG = 1 << 8

type ResStringPoolRef uint32

const NilResStringPoolRef = ResStringPoolRef(0xFFFFFFFF)

type ResStringPoolHeader struct {
	Header      ResChunkHeader
	StringCount uint32
	StyleCount  uint32
	Flags       uint32
	StringStart uint32
	StylesStart uint32
}

type ResStringPool struct {
	Header  ResStringPoolHeader
	Strings []string
	Styles  []string
}

type ResXMLTreeNode struct {
	Header     ResChunkHeader
	LineNumber uint32
	Comment    ResStringPoolRef
}

type ResXMLTreeNamespaceExt struct {
	Prefix ResStringPoolRef
	Uri    ResStringPoolRef
}

type ResXMLTreeAttrExt struct {
	NS             ResStringPoolRef
	Name           ResStringPoolRef
	AttributeStart uint16
	AttributeSize  uint16
	AttributeCount uint16
	IdIndex        uint16
	ClassIndex     uint16
	StyleIndex     uint16
}

type ResXMLTreeAttribute struct {
	NS         ResStringPoolRef
	Name       ResStringPoolRef
	RawValue   ResStringPoolRef
	TypedValue ResValue
}

const (
	TYPE_NULL            = 0x00
	TYPE_REFERENCE       = 0x01
	TYPE_ATTRIBUTE       = 0x02
	TYPE_STRING          = 0x03
	TYPE_FLOAT           = 0x04
	TYPE_DIMENSION       = 0x05
	TYPE_FRACTION        = 0x06
	TYPE_FIRST_INT       = 0x10
	TYPE_INT_DEC         = 0x10
	TYPE_INT_HEX         = 0x11
	TYPE_INT_BOOLEAN     = 0x12
	TYPE_FIRST_COLOR_INT = 0x1c
	TYPE_INT_COLOR_ARGB8 = 0x1c
	TYPE_INT_COLOR_RGB8  = 0x1d
	TYPE_INT_COLOR_ARGB4 = 0x1e
	TYPE_INT_COLOR_RGB4  = 0x1f
	TYPE_LAST_COLOR_INT  = 0x1f
	TYPE_LAST_INT        = 0x1f
)

type ResValue struct {
	Size     uint16
	Res0     uint8
	DataType uint8
	Data     uint32
}

type ResXMLTreeEndElementExt struct {
	NS   ResStringPoolRef
	Name ResStringPoolRef
}

func NewFile(r io.ReaderAt) (*File, error) {
	f := new(File)
	sr := io.NewSectionReader(r, 0, 1<<63-1)

	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	offset := uint32(header.HeaderSize)

	for offset < header.Size {
		sr.Seek(int64(offset), os.SEEK_SET)
		chunkHeader := &ResChunkHeader{}
		binary.Read(sr, binary.LittleEndian, chunkHeader)

		var err error
		chunkReader := io.NewSectionReader(r, int64(offset), int64(chunkHeader.Size))
		switch chunkHeader.Type {
		case RES_STRING_POOL_TYPE:
			f.StringPool, err = ReadStringPool(chunkReader)
		case RES_XML_RESOURCE_MAP_TYPE:
			f.ResourceMap, err = ReadResourceMap(chunkReader)
		case RES_XML_START_NAMESPACE_TYPE:
			err = f.ReadStartNamespace(chunkReader)
		case RES_XML_START_ELEMENT_TYPE:
			err = f.ReadStartElement(chunkReader)
		case RES_XML_END_ELEMENT_TYPE:
			err = f.ReadEndElement(chunkReader)
		}
		if err != nil {
			return nil, err
		}

		offset += chunkHeader.Size
	}
	return f, nil
}

func (f *File) GetString(ref ResStringPoolRef) string {
	if ref == NilResStringPoolRef {
		return ""
	}
	return f.StringPool.Strings[int(ref)]
}

func ReadStringPool(sr *io.SectionReader) (*ResStringPool, error) {
	sp := new(ResStringPool)
	binary.Read(sr, binary.LittleEndian, &sp.Header)

	stringStarts := make([]uint32, sp.Header.StringCount)
	binary.Read(sr, binary.LittleEndian, stringStarts)
	styleStarts := make([]uint32, sp.Header.StyleCount)
	binary.Read(sr, binary.LittleEndian, styleStarts)

	sp.Strings = make([]string, sp.Header.StringCount)
	for i, start := range stringStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StringStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StringStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Strings[i] = str
	}

	sp.Styles = make([]string, sp.Header.StyleCount)
	for i, start := range styleStarts {
		var str string
		var err error
		if (sp.Header.Flags & UTF8_FLAG) == 0 {
			str, err = ReadUTF16(sr, int64(sp.Header.StylesStart+start))
		} else {
			str, err = ReadUTF8(sr, int64(sp.Header.StylesStart+start))
		}
		if err != nil {
			return nil, err
		}
		sp.Styles[i] = str
	}

	return sp, nil
}

func ReadUTF16(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint16, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(utf16.Decode(buf)), nil
}

func ReadUTF8(sr *io.SectionReader, offset int64) (string, error) {
	var size uint16
	sr.Seek(offset, os.SEEK_SET)
	if err := binary.Read(sr, binary.LittleEndian, &size); err != nil {
		return "", err
	}
	buf := make([]uint8, size)
	if err := binary.Read(sr, binary.LittleEndian, buf); err != nil {
		return "", err
	}
	return string(buf), nil
}

func ReadResourceMap(sr *io.SectionReader) ([]uint32, error) {
	header := new(ResChunkHeader)
	binary.Read(sr, binary.LittleEndian, header)
	count := (header.Size - uint32(header.HeaderSize)) / 4
	resourceMap := make([]uint32, count)
	if err := binary.Read(sr, binary.LittleEndian, resourceMap); err != nil {
		return nil, err
	}
	return resourceMap, nil
}

func (f *File) ReadStartNamespace(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	namespace := new(ResXMLTreeNamespaceExt)
	binary.Read(sr, binary.LittleEndian, namespace)
	f.Namespace = namespace
	return nil
}

func (f *File) ReadStartElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	binary.Read(sr, binary.LittleEndian, header)
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	ext := new(ResXMLTreeAttrExt)
	binary.Read(sr, binary.LittleEndian, ext)

	fmt.Fprintf(&f.buffer, "<%s", f.AddNamespace(ext.NS, ext.Name))

	offset := int64(ext.AttributeStart + header.Header.HeaderSize)
	for i := 0; i < int(ext.AttributeCount); i++ {
		sr.Seek(offset, os.SEEK_SET)
		attr := new(ResXMLTreeAttribute)
		binary.Read(sr, binary.LittleEndian, attr)

		var value string
		if attr.RawValue != NilResStringPoolRef {
			value = f.GetString(attr.RawValue)
		} else {
			data := attr.TypedValue.Data
			switch attr.TypedValue.DataType {
			case TYPE_NULL:
				value = ""
			case TYPE_REFERENCE:
				value = fmt.Sprintf("@0x%08X", data)
			case TYPE_INT_DEC:
				value = fmt.Sprintf("%d", data)
			case TYPE_INT_HEX:
				value = fmt.Sprintf("0x%08X", data)
			case TYPE_INT_BOOLEAN:
				if data != 0 {
					value = "true"
				} else {
					value = "false"
				}
			default:
				value = fmt.Sprintf("@0x%08X", data)
			}
		}

		fmt.Fprintf(&f.buffer, " %s=\"%s\"", f.AddNamespace(attr.NS, attr.Name), value)
		offset += int64(ext.AttributeSize)
	}
	fmt.Fprint(&f.buffer, ">")
	return nil
}

func (f *File) ReadEndElement(sr *io.SectionReader) error {
	header := new(ResXMLTreeNode)
	if err := binary.Read(sr, binary.LittleEndian, header); err != nil {
		return err
	}
	sr.Seek(int64(header.Header.HeaderSize), os.SEEK_SET)
	ext := new(ResXMLTreeEndElementExt)
	if err := binary.Read(sr, binary.LittleEndian, ext); err != nil {
		return err
	}
	fmt.Fprintf(&f.buffer, "</%s>", f.AddNamespace(ext.NS, ext.Name))
	return nil
}

func (f *File) AddNamespace(ns, name ResStringPoolRef) string {
	if ns != NilResStringPoolRef {
		return fmt.Sprintf("%s:%s", f.GetString(f.Namespace.Prefix), f.GetString(name))
	} else {
		return f.GetString(name)
	}
}

func main() {
	f, _ := os.Open("AndroidManifest.xml")
	xml, _ := NewFile(f)
	fmt.Println(xml.buffer.String())
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/mux"
)

func main() {
	router := mux.NewRouter()
	packageHandler := &PackageHandler{name: "TestServer"}
	internalHostName := "ups.127.0.0.1.xip.io"

	internalRouter := router.Host(internalHostName).Subrouter()

	internalRouter.Path("/packages/{guid}").Methods("PUT").HandlerFunc(packageHandler.put)
	internalRouter.Path("/packages/{guid}").Methods("GET").HandlerFunc(packageHandler.get)
	internalRouter.Path("/packages/{guid}").Methods("DELETE").HandlerFunc(packageHandler.delete)

	srv := &http.Server{
		Handler:      router,
		Addr:         "0.0.0.0:8000",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())
}

type DataStore interface {
}

type PackageHandler struct {
	name string
}

func (handler *PackageHandler) put(responseWriter http.ResponseWriter, request *http.Request) {
	fmt.Fprintf(responseWriter, "%s says: Hello, %s\n\n", handler.name, mux.Vars(request)["guid"])
}

func (handler *PackageHandler) get(responseWriter http.ResponseWriter, request *http.Request) {
	fmt.Fprintf(responseWriter, "%s says: Hello, %s\n\n", handler.name, mux.Vars(request)["guid"])
}

func (handler *PackageHandler) delete(responseWriter http.ResponseWriter, request *http.Request) {
	fmt.Fprintf(responseWriter, "%s says: Hello, %s\n\n", handler.name, mux.Vars(request)["guid"])
}
<commit_msg>Early version of POC complete<commit_after>package main

import (
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"path/filepath"

	"net/url"

	"github.com/davecgh/go-spew/spew"
	"github.com/gorilla/mux"
)

func main() {
	router := mux.NewRouter()
	packageHandler := &PackageHandler{blobStore: &LocalBlobStore{pathPrefix: "/tmp"}}
	signHandler := &SignHandler{}
	internalHostName := "internal.127.0.0.1.xip.io"
	publicHostName := "public.127.0.0.1.xip.io"

	internalRouter := router.Host(internalHostName).Subrouter()
	publicRouter := router.Host(publicHostName).Subrouter()

	signedUrlHandler := &SignedUrlHandler{
		internalRouter:   internalRouter,
		internalHostName: internalHostName,
	}

	internalRouter.Path("/packages/{guid}").Methods("PUT").HandlerFunc(packageHandler.put)
	internalRouter.Path("/packages/{guid}").Methods("GET").HandlerFunc(packageHandler.get)
	internalRouter.Path("/packages/{guid}").Methods("DELETE").HandlerFunc(packageHandler.delete)

	internalRouter.Path("/sign/{path}").Methods("GET").HandlerFunc(signHandler.Sign)

	publicRouter.PathPrefix("/signed").Methods("GET", "PUT").HandlerFunc(signedUrlHandler.decode)

	srv := &http.Server{
		Handler:      router,
		Addr:         "0.0.0.0:8000",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())
}

type BlobStore interface {
	Exists(path string) bool
	Get(path string) io.Reader
	Put(path string, src io.Reader)
	Delete(path string)
}

type LocalBlobStore struct {
	pathPrefix string
}

func (blobstore *LocalBlobStore) Exists(path string) bool {
	_, err := os.Stat(filepath.Join(blobstore.pathPrefix, path))
	return err == nil
}
func (blobstore *LocalBlobStore) Get(path string) io.Reader {
	file, e := os.Open(filepath.Join(blobstore.pathPrefix, path))
	if e != nil {
		panic(e)
	}
	return file
}

func (blobstore *LocalBlobStore) Put(path string, src io.Reader) {
	// TODO
}

func (blobstore *LocalBlobStore) Delete(path string) {
	// TODO
}

type PackageHandler struct {
	blobStore BlobStore
}

func (handler *PackageHandler) put(responseWriter http.ResponseWriter, request *http.Request) {
	file, _, e := request.FormFile("package")
	if e != nil {
		panic(e)
	}
	defer file.Close()
	handler.blobStore.Put("/packages/"+partitionedKey(mux.Vars(request)["guid"]), file)
}

func (handler *PackageHandler) get(responseWriter http.ResponseWriter, request *http.Request) {
	blob := handler.blobStore.Get("/packages/" + partitionedKey(mux.Vars(request)["guid"]))
	io.Copy(responseWriter, blob)
}

func partitionedKey(guid string) string {
	return filepath.Join(guid[0:2], guid[2:4], guid)
}

func (handler *PackageHandler) delete(responseWriter http.ResponseWriter, request *http.Request) {
	handler.blobStore.Delete("/packages/" + partitionedKey(mux.Vars(request)["guid"]))
}

type SignHandler struct {
}

func (handler *SignHandler) Sign(responseWriter http.ResponseWriter, request *http.Request) {

}

type SignedUrlHandler struct {
	internalRouter   *mux.Router
	internalHostName string
}

func (handler *SignedUrlHandler) decode(responseWriter http.ResponseWriter, request *http.Request) {
	if !validSignature(request) {
		responseWriter.WriteHeader(403)
		return
	}
	r := *request
	url, e := url.ParseRequestURI(strings.Replace(request.URL.String(), "/signed", "", 1))
	if e != nil {
		log.Fatal(e)
	}
	r.URL = url
	r.RequestURI = url.RequestURI()
	r.Host = handler.internalHostName
	spew.Dump(r)
	handler.internalRouter.ServeHTTP(responseWriter, &r)
}

func validSignature(request *http.Request) bool {
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"flag"
	"os"
	"path/filepath"
	"strings"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"github.com/Knorkebrot/ansirgb"
	"github.com/olekukonko/ts"
)

type Block struct {
	top	*ansirgb.Color
	bottom	*ansirgb.Color
}

func (b *Block) String() string {
	ret := fmt.Sprintf("\033[48;5;%dm", b.bottom.Code)
	if b.top != nil {
		ret += fmt.Sprintf("\033[38;5;%dm", b.top.Code)
		// If it's not a UTF-8 terminal, fall back to '#'
		if strings.Contains(os.Getenv("LC_ALL"), "UTF-8") ||
		   strings.Contains(os.Getenv("LANG"), "UTF-8") {
			ret += "\u2580"
		} else {
			ret += "#"
		}
	} else {
		ret += " "
	}
	return ret
}

func reset() {
	// add a space to prevent artifacts after resizing
	fmt.Printf("\033[0m ")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s file [file...]\n", os.Args[0])
	flag.PrintDefaults()
}

func main() {
	var width int
	flag.IntVar(&width, "w", 0, "Output width, use 0 for terminal width")
	flag.Usage = usage
	flag.Parse()

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if width == 0 {
		size, err := ts.GetSize()
		if err != nil {
			fmt.Fprintln(os.Stderr, err, "\nYou may need to "+
				"set width manually using -w num")
			os.Exit(2)
		}
		width = size.Col() - 1	// -1 for the reset column
	}

	for _, fpath := range flag.Args() {
		fh, err := os.Open(fpath)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(10)
		}

		img, _, err := image.Decode(fh)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			fh.Close()
			os.Exit(20)
		}

		imgWidth := img.Bounds().Dx()
		imgHeight := img.Bounds().Dy()

		if imgWidth < width {
			width = imgWidth
		}

		ratio := float64(imgWidth) / float64(width)
		rows := int(float64(imgHeight) / ratio)

		for i := 1; i < rows; i += 2 {
			for j := 0; j < width; j++ {
				// TODO: get average color of the area instead
				// of one pixel?
				x := int(ratio * float64(j))
				yTop := int(ratio * float64(i - 1))
				yBottom := int(ratio * float64(i))

				top := ansirgb.Convert(img.At(x, yTop))
				bottom := ansirgb.Convert(img.At(x, yBottom))

				b := &Block{}
				b.bottom = bottom

				// Foreground colors are lighter in some terminals.
				// Ignore top (FG) if it's the same color anyway
				if top.Code != bottom.Code {
					b.top = top
				}

				fmt.Printf("%s", b)
			}
			reset()
			fmt.Printf("\n")
		}
		fh.Close()

		fmt.Println("File:", filepath.Base(fpath), "size:", imgWidth, "x", imgHeight)
	}
}
<commit_msg>Nitro activated<commit_after>package main

import (
	"fmt"
	"flag"
	"os"
	"path/filepath"
	"strings"
	"image"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"github.com/Knorkebrot/ansirgb"
	"github.com/olekukonko/ts"
)

type Block struct {
	top	*ansirgb.Color
	bottom	*ansirgb.Color
}

func (b *Block) String() string {
	ret := fmt.Sprintf("\033[48;5;%dm", b.bottom.Code)
	if b.top != nil {
		ret += fmt.Sprintf("\033[38;5;%dm", b.top.Code)
		// If it's not a UTF-8 terminal, fall back to '#'
		if strings.Contains(os.Getenv("LC_ALL"), "UTF-8") ||
		   strings.Contains(os.Getenv("LANG"), "UTF-8") {
			ret += "\u2580"
		} else {
			ret += "#"
		}
	} else {
		ret += " "
	}
	return ret
}

func cursorUp(count int) {
	fmt.Printf("\033[%dA", count)
}

func reset() {
	// add a space to prevent artifacts after resizing
	fmt.Printf("\033[0m ")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s file [file...]\n", os.Args[0])
	flag.PrintDefaults()
}

func main() {
	var width int
	flag.IntVar(&width, "w", 0, "Output width, use 0 for terminal width")
	flag.Usage = usage
	flag.Parse()

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if width == 0 {
		size, err := ts.GetSize()
		if err != nil {
			fmt.Fprintln(os.Stderr, err, "\nYou may need to "+
				"set width manually using -w num")
			os.Exit(2)
		}
		width = size.Col() - 1	// -1 for the reset column
	}

	for _, fpath := range flag.Args() {
		fh, err := os.Open(fpath)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(10)
		}

		img, _, err := image.Decode(fh)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			fh.Close()
			os.Exit(20)
		}
		fh.Close()

		imgWidth := img.Bounds().Dx()
		imgHeight := img.Bounds().Dy()

		if imgWidth < width {
			width = imgWidth
		}

		ratio := float64(imgWidth) / float64(width)
		rows := int(float64(imgHeight) / ratio)

		for i := 1; i < rows; i += 2 {
			fmt.Println("")
		}
		cursorUp(rows / 2)

		for i := 1; i < rows; i += 2 {
			for j := 0; j < width; j++ {
				// TODO: get average color of the area instead
				// of one pixel?
				x := int(ratio * float64(j))
				yTop := int(ratio * float64(i - 1))
				yBottom := int(ratio * float64(i))

				top := ansirgb.Convert(img.At(x, yTop))
				bottom := ansirgb.Convert(img.At(x, yBottom))

				b := &Block{}
				b.bottom = bottom

				// Foreground colors are lighter in some terminals.
				// Ignore top (FG) if it's the same color anyway
				if top.Code != bottom.Code {
					b.top = top
				}

				fmt.Printf("%s", b)
			}
			reset()
			fmt.Printf("\n")
		}
		fmt.Println("File:", filepath.Base(fpath), "size:", imgWidth, "x", imgHeight)
	}
}
<|endoftext|>


<commit_before>package main

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

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

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

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

	argsStruct := NewArgs(args)

	p.Connection = cliConnection

	cfDomains := manifest.CfDomains{}
	var err error

	cfDomains.SharedDomains, err = p.SharedDomains()
	if err != nil {
		log.Fatalf("Failed to get shared domains: %v", err)
	}

	cfDomains.DefaultDomain = cfDomains.SharedDomains[0]
	if err != nil {
		log.Fatalf("Failed to get default shared domain: %v", err)
	}

	cfDomains.PrivateDomains, err = p.PrivateDomains()
	if err != nil {
		log.Fatalf("Failed to get private domains: %v", err)
	}

	p.Deployer.Setup(cliConnection)

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

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

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

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

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

	newAppName := appName + "-new"

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

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

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

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

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

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

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

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

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

	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

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

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

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

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

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

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

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

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

func (p *CfPlugin) PrivateDomains() (domains []string, apiErr error) {
	path := "/v2/private_domains"
	return p.listCfDomains(path)
}

func (p *CfPlugin) SharedDomains() (domains []string, apiErr error) {
	path := "/v2/shared_domains"
	return p.listCfDomains(path)
}

func (p *CfPlugin) listCfDomains(cfPath string) (domains []string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", cfPath); err != nil {
		return
	}

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

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

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

	for i, _ := range response.Resources {
		domains = append(domains, response.Resources[i].Entity.Name)
	}
	return
}

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

func main() {

	log.SetFlags(0)

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

	// TODO issue #24 - (Rufus) - not sure if I'm using the plugin correctly, but if I build (go build) and run without arguments
	// I expected to see available arguments but instead the code panics.
	plugin.Start(&p)
}
<commit_msg>Do not assume there is always at least one shared domain<commit_after>package main

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

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

var PluginVersion string

type CfPlugin struct {
	Connection plugin.CliConnection
	Deployer   BlueGreenDeployer
}

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

	argsStruct := NewArgs(args)

	p.Connection = cliConnection

	cfDomains := manifest.CfDomains{}
	var err error

	cfDomains.SharedDomains, err = p.SharedDomains()
	if err != nil {
		log.Fatalf("Failed to get shared domains: %v", err)
	}

	if len(cfDomains.SharedDomains) < 1 {
		log.Fatalf("Failed to get default shared domain (no shared domains defined)")
	} else {
		cfDomains.DefaultDomain = cfDomains.SharedDomains[0]
	}

	cfDomains.PrivateDomains, err = p.PrivateDomains()
	if err != nil {
		log.Fatalf("Failed to get private domains: %v", err)
	}

	p.Deployer.Setup(cliConnection)

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

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

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

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

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

	newAppName := appName + "-new"

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

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

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

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

	p.Deployer.UnmapRoutesFromApp(newAppName, tempRoute)

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

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

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

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

	uniqueRoutes := p.UnionRouteLists(newAppRoutes, liveAppRoutes)

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

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

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

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

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

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

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

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

func (p *CfPlugin) PrivateDomains() (domains []string, apiErr error) {
	path := "/v2/private_domains"
	return p.listCfDomains(path)
}

func (p *CfPlugin) SharedDomains() (domains []string, apiErr error) {
	path := "/v2/shared_domains"
	return p.listCfDomains(path)
}

func (p *CfPlugin) listCfDomains(cfPath string) (domains []string, err error) {
	var res []string
	if res, err = p.Connection.CliCommandWithoutTerminalOutput("curl", cfPath); err != nil {
		return
	}

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

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

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

	for i, _ := range response.Resources {
		domains = append(domains, response.Resources[i].Entity.Name)
	}
	return
}

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

func main() {

	log.SetFlags(0)

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

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