<commit_before>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("firefox_ip")
	viper.BindEnv("firefox_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("firefox_ip") || !viper.IsSet("firefox_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both FIREFOX_IP and FIREFOX_PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			fmt.Println("Program rejected.  Invalid duration.")
		}

		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	ip := viper.Get("FIREFOX_IP")
	port := viper.GetInt("FIREFOX_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("It is possible Firefox needs to be started or restarted.")
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	log.Printf("Running program for %s:  %s\n", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
		Unpause()
	case <-skip:
		fmt.Println("Current program skiped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		for IsPaused() {
			fmt.Println("Paused.")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Println("Program list is paused.")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Needs validation...

	// Now do something with the program.. play it?

	// Stop normal rotation
	Pause()
	skip <- struct{}{}

	go runProgram(p)
	w.Write([]byte("Program accepted\n"))

}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Pausing from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skippingfrom web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.0.4"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			fmt.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	fmt.Println("Starting gotator: version", version)
	Unpause()

	InitializeConfig()

	go LoadAndRunLoop()
	go readKeyboardLoop()

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		fmt.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		go log.Fatal(http.ListenAndServe(listen_port, r))
	} else {
		fmt.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<commit_msg>Fixed typo<commit_after>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("firefox_ip")
	viper.BindEnv("firefox_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("firefox_ip") || !viper.IsSet("firefox_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both FIREFOX_IP and FIREFOX_PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			fmt.Println("Program rejected.  Invalid duration.")
		}

		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	ip := viper.Get("FIREFOX_IP")
	port := viper.GetInt("FIREFOX_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("It is possible Firefox needs to be started or restarted.")
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	log.Printf("Running program for %s:  %s\n", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
		Unpause()
	case <-skip:
		fmt.Println("Current program skipped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		for IsPaused() {
			fmt.Println("Paused.")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Println("Program list is paused.")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Needs validation...

	// Now do something with the program.. play it?

	// Stop normal rotation
	Pause()
	skip <- struct{}{}

	go runProgram(p)
	w.Write([]byte("Program accepted\n"))

}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Pausing from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skippingfrom web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.0.4"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			fmt.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	fmt.Println("Starting gotator: version", version)
	Unpause()

	InitializeConfig()

	go LoadAndRunLoop()
	go readKeyboardLoop()

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		fmt.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		go log.Fatal(http.ListenAndServe(listen_port, r))
	} else {
		fmt.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<|endoftext|>


<commit_before>package main

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

	"github.com/alext/tablecloth"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"gopkg.in/unrolled/render.v1"

	"github.com/alphagov/publishing-api/request_logger"
)

var (
	arbiterHost      = getEnvDefault("URL_ARBITER", "http://url-arbiter.dev.gov.uk")
	contentStoreHost = getEnvDefault("CONTENT_STORE", "http://content-store.dev.gov.uk")
	port             = getEnvDefault("PORT", "3000")
	requestLogDest   = getEnvDefault("REQUEST_LOG", "STDOUT")

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

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

func BuildHTTPMux(arbiterURL, contentStoreURL string) http.Handler {
	httpMux := mux.NewRouter()
	httpMux.Methods("GET").Path("/healthcheck").HandlerFunc(HealthCheckHandler)
	contentStoreHandler := NewContentStoreHandler(arbiterURL, contentStoreURL)
	httpMux.Methods("PUT").Path("/content{base_path:.*}").HandlerFunc(contentStoreHandler.PutContentStoreRequest)
	httpMux.Methods("PUT").Path("/publish-intent{base_path:.*}").HandlerFunc(contentStoreHandler.PutContentStoreRequest)
	httpMux.Methods("GET").Path("/publish-intent{base_path:.*}").HandlerFunc(contentStoreHandler.GetContentStoreRequest)
	httpMux.Methods("DELETE").Path("/publish-intent{base_path:.*}").HandlerFunc(contentStoreHandler.DeleteContentStoreRequest)
	return httpMux
}

func main() {
	httpMux := BuildHTTPMux(arbiterHost, contentStoreHost)

	requestLogger, err := request_logger.New(requestLogDest)
	if err != nil {
		log.Fatal(err)
	}

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

	// Set working dir for tablecloth if available. This is to allow restarts
	// to pick up new versions.  See
	// http://godoc.org/github.com/alext/tablecloth#pkg-variables for details
	if wd := os.Getenv("GOVUK_APP_ROOT"); wd != "" {
		tablecloth.WorkingDir = wd
	}

	err = tablecloth.ListenAndServe(":"+port, middleware)
	if err != nil {
		log.Fatal(err)
	}
}

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

	return val
}
<commit_msg>Require a leading slash on routes<commit_after>package main

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

	"github.com/alext/tablecloth"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
	"gopkg.in/unrolled/render.v1"

	"github.com/alphagov/publishing-api/request_logger"
)

var (
	arbiterHost      = getEnvDefault("URL_ARBITER", "http://url-arbiter.dev.gov.uk")
	contentStoreHost = getEnvDefault("CONTENT_STORE", "http://content-store.dev.gov.uk")
	port             = getEnvDefault("PORT", "3000")
	requestLogDest   = getEnvDefault("REQUEST_LOG", "STDOUT")

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

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

func BuildHTTPMux(arbiterURL, contentStoreURL string) http.Handler {
	httpMux := mux.NewRouter()
	httpMux.Methods("GET").Path("/healthcheck").HandlerFunc(HealthCheckHandler)
	contentStoreHandler := NewContentStoreHandler(arbiterURL, contentStoreURL)
	httpMux.Methods("PUT").Path("/content{base_path:/.*}").HandlerFunc(contentStoreHandler.PutContentStoreRequest)
	httpMux.Methods("PUT").Path("/publish-intent{base_path:/.*}").HandlerFunc(contentStoreHandler.PutContentStoreRequest)
	httpMux.Methods("GET").Path("/publish-intent{base_path:/.*}").HandlerFunc(contentStoreHandler.GetContentStoreRequest)
	httpMux.Methods("DELETE").Path("/publish-intent{base_path:/.*}").HandlerFunc(contentStoreHandler.DeleteContentStoreRequest)
	return httpMux
}

func main() {
	httpMux := BuildHTTPMux(arbiterHost, contentStoreHost)

	requestLogger, err := request_logger.New(requestLogDest)
	if err != nil {
		log.Fatal(err)
	}

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

	// Set working dir for tablecloth if available. This is to allow restarts
	// to pick up new versions.  See
	// http://godoc.org/github.com/alext/tablecloth#pkg-variables for details
	if wd := os.Getenv("GOVUK_APP_ROOT"); wd != "" {
		tablecloth.WorkingDir = wd
	}

	err = tablecloth.ListenAndServe(":"+port, middleware)
	if err != nil {
		log.Fatal(err)
	}
}

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

	return val
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/golang/glog"
	"github.com/tonglil/labeler/types"
	"github.com/tonglil/labeler/writer"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

const (
	api      = "https://api.github.com/"
	apiEnv   = "GITHUB_API"
	tokenEnv = "GITHUB_TOKEN"
)

var (
	// Deliberately uninitialized, see getVersion().
	version string
)

var (
	// Get labels
	scan bool

	// Configuration options
	dryrun   bool
	token    string
	endpoint string
	repo     string

	// App info
	help        bool
	versionFlag bool
)

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [-version] [-help] [<options>] <file.yaml>\n", os.Args[0])
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "Manage labels on GitHub as code")
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "Available options:")

	flag.PrintDefaults()

	fmt.Fprintln(os.Stderr, "")

	os.Exit(1)
}

func init() {
	flag.BoolVar(&scan, "scan", false, "Scan the repo for label information")

	flag.BoolVar(&dryrun, "dry-run", false, "Show what would happen")
	flag.StringVar(&repo, "repo", "", "Use a different repository (default: \"from file\")")
	flag.StringVar(&token, "token", "", "Use a different GithHub token [overrides GITHUB_TOKEN environment variable]")
	flag.StringVar(&endpoint, "endpoint", api, "Use a different GithHub API endpoint [overrides GITHUB_API environment variable]")

	flag.BoolVar(&help, "help", false, "Show help")
	flag.BoolVar(&versionFlag, "version", false, "Show version")

	flag.Usage = usage

	flag.Set("logtostderr", "true")
}

func main() {
	flag.Parse()

	if help || len(flag.Args()) != 1 {
		flag.Usage()
	}

	if versionFlag {
		fmt.Fprintf(os.Stdout, "version %s\n", getVersion())
		os.Exit(0)
	}

	file := flag.Args()[0]

	endpoint := getEndpoint(endpoint)

	token, err := getToken(token)
	if err != nil {
		fatal(err)
	}

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)

	err = setEndpoint(client, endpoint)
	if err != nil {
		fatal(err)
	}

	opt := &types.Options{
		DryRun:   dryrun,
		Repo:     repo,
		Filename: file,
	}

	if opt.DryRun {
		glog.V(0).Infof("Dry run enabled - changes will not be applied")
	}

	if scan {
		//reader.Run(client, file, opt)
	} else {
		err = writer.Run(client, file, opt)
	}

	if err != nil {
		fatal(err)
	}

	os.Exit(0)
}
<commit_msg>update main.go<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/golang/glog"
	"github.com/tonglil/labeler/types"
	"github.com/tonglil/labeler/writer"

	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
)

const (
	api      = "https://api.github.com/"
	apiEnv   = "GITHUB_API"
	tokenEnv = "GITHUB_TOKEN"
)

var (
	// Deliberately uninitialized, see getVersion().
	version string
)

var (
	// Get labels
	scan bool

	// Configuration options
	dryrun   bool
	token    string
	endpoint string
	repo     string

	// App info
	help        bool
	versionFlag bool
)

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [<options>] <file.yaml>\n", os.Args[0])
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "Manage labels on GitHub as code")
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "Available options:")

	flag.PrintDefaults()

	fmt.Fprintln(os.Stderr, "")

	os.Exit(1)
}

func init() {
	flag.BoolVar(&scan, "scan", false, "Scan the repo for label information")

	flag.BoolVar(&dryrun, "dry-run", false, "Show what would happen (default false)")
	flag.StringVar(&repo, "repo", "", "Use a different repository (default \"from file\")")
	flag.StringVar(&token, "token", "", "Use a different GithHub token [overrides GITHUB_TOKEN environment variable]")
	flag.StringVar(&endpoint, "endpoint", api, "Use a different GithHub API endpoint [overrides GITHUB_API environment variable]")

	flag.BoolVar(&help, "help", false, "Show help")
	flag.BoolVar(&versionFlag, "version", false, "Show version")

	flag.Usage = usage

	flag.Set("logtostderr", "true")
}

func main() {
	flag.Parse()

	if help || len(flag.Args()) != 1 {
		flag.Usage()
	}

	if versionFlag {
		fmt.Fprintf(os.Stdout, "version %s\n", getVersion())
		os.Exit(0)
	}

	file := flag.Args()[0]

	endpoint := getEndpoint(endpoint)

	token, err := getToken(token)
	if err != nil {
		fatal(err)
	}

	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	tc := oauth2.NewClient(oauth2.NoContext, ts)

	client := github.NewClient(tc)

	err = setEndpoint(client, endpoint)
	if err != nil {
		fatal(err)
	}

	opt := &types.Options{
		DryRun:   dryrun,
		Repo:     repo,
		Filename: file,
	}

	if opt.DryRun {
		glog.V(0).Infof("Dry run enabled - changes will not be applied")
	}

	if scan {
		//reader.Run(client, file, opt)
	} else {
		err = writer.Run(client, file, opt)
	}

	if err != nil {
		fatal(err)
	}

	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

// TODO
// args: host, port

// output:
// Port ping host:port
// Successful connection to host:port time=201ms
// Successful connection to host:port time=195ms
// Successful connection to host:port time=198ms
// --- host:port ping statistics ---
// n connections attempted, m successful, x% failed
// round-trip min/avg/max/stddev = a/b/c/d ms

// error output:
// portping: cannot resolve host: Unknown host
// portping: connect to address host: Connection refused

// flag: -c count
// flags: --tcp, --udp; default is tcp
// flag: -W timeout

// test with: 192.168.1.10
//tcp        0      0 127.0.1.1:53            0.0.0.0:*               LISTEN
//tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
//tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN
//tcp        0      0 127.0.0.1:8089          0.0.0.0:*               LISTEN
//tcp6       0      0 :::22                   :::*                    LISTEN
//tcp6       0      0 ::1:631                 :::*                    LISTEN

// drop default count, print forever, until cancel with Control-C, and print stats

func main() {
}
<commit_msg>cli works<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"strconv"
)

// TODO
// flags: --tcp, --udp; default is tcp
// flag: -W timeout

// drop default count, print forever, until cancel with Control-C, and print stats

func exit() {
	flag.Usage()
	os.Exit(1)
}

func main() {
	flag.Usage = func() {
		fmt.Printf("Usage: %s [options] host port\n\n", os.Args[0])
		flag.PrintDefaults()
	}

	countPtr := flag.Int("count", 5, "stop after count connections")
	flag.Parse()

	if len(flag.Args()) < 2 {
		exit()
	}

	host := flag.Args()[0]
	port, parseErr := strconv.Atoi(flag.Args()[1])
	if parseErr != nil {
		exit()
	}

	addr := fmt.Sprintf("%s:%d", host, port)
	fmt.Printf("Starting to ping %s ...\n", addr)

	c := make(chan error)
	go PingN(host, port, *countPtr, c)

	for i := 0; i < *countPtr; i++ {
		// TODO print details only if verbose, otherwise print just OpError.Err
		var msg string
		if err := <-c; err == nil {
			msg = "success"
		} else {
			msg = err.Error()
		}
		// TODO add time
		fmt.Printf("port ping %s [%d] -> %s\n", addr, i + 1, msg)
	}

	// TODO print summary
	// --- host:port ping statistics ---
	// n connections attempted, m successful, x% failed
	// round-trip min/avg/max/stddev = a/b/c/d ms
}
<|endoftext|>


<commit_before>package main

import (
	// import plugins to ensure they're bound into the executable
	_ "github.com/30x/apidAnalytics"
	_ "github.com/30x/apidApigeeSync"
	_ "github.com/30x/apidGatewayDeploy"
	_ "github.com/30x/apidVerifyAPIKey"

	// other imports
	"flag"
	"fmt"
	"os"
	"reflect"

	"github.com/30x/apid-core"
	"github.com/30x/apid-core/factory"
)

func main() {
	// clean exit messages w/o stack track during initialization
	defer func() {
		if r := recover(); r != nil {
			// if coming from logrus, it's already been printed. otherwise...
			if reflect.TypeOf(r).String() != "*logrus.Entry" {
				fmt.Println(r)
			}
			os.Exit(1)
		}
	}()

	f := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	configFlag := f.String("config", "", "path to the yaml config file [./apid_config.yaml]")
	cleanFlag := f.Bool("clean", false, "start clean, deletes all existing data from local_storage_path")

	f.Parse(os.Args[1:])

	configFile := *configFlag
	if configFile != "" {
		os.Setenv("APID_CONFIG_FILE", configFile)
	}

	apid.Initialize(factory.DefaultServicesFactory())

	log := apid.Log()
	config := apid.Config()

	if *cleanFlag {
		localStorage := config.GetString("local_storage_path")
		log.Infof("removing existing data from: %s", localStorage)
		if err := os.RemoveAll(localStorage); err != nil {
			log.Panicf("Failed to clean data directory: %v", err)
		}
		if err := os.MkdirAll(localStorage, 0700); err != nil {
			log.Panicf("can't create local storage path %s:%v", localStorage, err)
		}
	}

	log.Debug("initializing...")

	apid.InitializePlugins()

	// start client API listener
	log.Debug("listening...")

	api := apid.API()
	err := api.Listen()
	if err != nil {
		log.Print(err)
	}

	log.Infof("Wait for plugins to gracefully shutdown")
	apid.ShutdownPluginsAndWait()
	log.Infof("Apid graceful shutdown succeeded")
}
<commit_msg>add --version<commit_after>package main

import (
	// import plugins to ensure they're bound into the executable
	_ "github.com/30x/apidAnalytics"
	_ "github.com/30x/apidApigeeSync"
	_ "github.com/30x/apidGatewayDeploy"
	_ "github.com/30x/apidVerifyAPIKey"

	// other imports
	"flag"
	"fmt"
	"os"
	"reflect"

	"github.com/30x/apid-core"
	"github.com/30x/apid-core/factory"
)

const (
	VERSION_NUMBER = "0.0.23"
)

func main() {
	// clean exit messages w/o stack track during initialization
	defer func() {
		if r := recover(); r != nil {
			// if coming from logrus, it's already been printed. otherwise...
			if reflect.TypeOf(r).String() != "*logrus.Entry" {
				fmt.Println(r)
			}
			os.Exit(1)
		}
	}()

	f := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	configFlag := f.String("config", "", "path to the yaml config file [./apid_config.yaml]")
	cleanFlag := f.Bool("clean", false, "start clean, deletes all existing data from local_storage_path")
	versionFlag := f.Bool("version", false, "display the version number of apid and exits")

	f.Parse(os.Args[1:])

	if *versionFlag {
		fmt.Println("APID Version Number: " + VERSION_NUMBER)
		return
	}

	configFile := *configFlag
	if configFile != "" {
		os.Setenv("APID_CONFIG_FILE", configFile)
	}

	apid.Initialize(factory.DefaultServicesFactory())

	log := apid.Log()
	config := apid.Config()

	if *cleanFlag {
		localStorage := config.GetString("local_storage_path")
		log.Infof("removing existing data from: %s", localStorage)
		if err := os.RemoveAll(localStorage); err != nil {
			log.Panicf("Failed to clean data directory: %v", err)
		}
		if err := os.MkdirAll(localStorage, 0700); err != nil {
			log.Panicf("can't create local storage path %s:%v", localStorage, err)
		}
	}

	log.Debug("initializing...")

	apid.InitializePlugins()

	// start client API listener
	log.Debug("listening...")

	api := apid.API()
	err := api.Listen()
	if err != nil {
		log.Print(err)
	}

	log.Infof("Wait for plugins to gracefully shutdown")
	apid.ShutdownPluginsAndWait()
	log.Infof("Apid graceful shutdown succeeded")
}
<|endoftext|>


<commit_before>package main

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

	"github.com/cucumber/godog"
	"github.com/ii/xds-test-harness/internal/parser"
	"github.com/ii/xds-test-harness/internal/runner"
	"github.com/ii/xds-test-harness/internal/types"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/pflag"
)

var (
	debug          = pflag.BoolP("debug", "D", false, "sets log level to debug")
	testWriting    = pflag.BoolP("testwriting", "W", false, "Sets a pretty output that doesn't write to file, for better feedback while writing tests.")
	config         = pflag.StringP("config", "C", "", "Path to optional config file. This file sets the adapter and target addresses and supported variants.")
	adapterAddress = pflag.StringP("adapter", "A", ":17000", "port of adapter on target")
	targetAddress  = pflag.StringP("target", "T", ":18000", "port of xds target to test")
	nodeID         = pflag.StringP("nodeID", "N", "test-id", "node id of target")
	variant        = pflag.StringArrayP("variant", "V", []string{"sotw non-aggregated", "sotw aggregated", "incremental non-aggregated", "incremental aggregated"}, "xDS protocol variant your server supports. Add a separate flag per each supported variant.\n Possibleariants are: sotw non-aggregated\n, sotw aggregated\n, incremental non-aggregated\n, incremental aggregated\n.")
	godogOpts      = godog.Options{}
)

func init() {
	godog.BindCommandLineFlags("godog.", &godogOpts)
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
}

func main() {
	pflag.Parse()
	godogTags := godogOpts.Tags

	if *debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	// default to using CLI Flag for settings
	err, supportedVariants := parser.ParseSupportedVariants(*variant)
	if err != nil {
		log.Fatal().Msgf("Cannot parse variants from CLI: %v\n", err)
	}
	// If config present, use it for all non-debugging values
	if *config != "" {
		*targetAddress, *adapterAddress, *nodeID, supportedVariants = parser.ValuesFromConfig(*config)
	}

	var results types.Results
	for _, variant := range supportedVariants {
		log.Info().
			Msgf("Starting Tests for %v\n", string(variant))

		suite := runner.NewSuite(variant, *testWriting)
		err, variantResults := suite.Run(*adapterAddress, *targetAddress, *nodeID, godogTags)
		if err != nil {
			log.Fatal().
				Msgf("Error when attempting to run test suite: %v\n", err)
		}
		results = runner.UpdateResults(results, variantResults)
	}
	if !*testWriting {
		printResults(results)
		file, _ := json.MarshalIndent(results, "", "  ")
		_ = ioutil.WriteFile("results.json", file, 0644)
	}
	os.Exit(0)
}

func printResults(results types.Results) {

	divider := "-------------------"
	fmt.Println("\nTest Suite Finished\n" + divider)
	fmt.Printf("Ran %v tests across %v variants\n\n", results.Total, len(results.Variants))
	fmt.Printf("Passed: %v\nFailed: %v", results.Passed, results.Failed)
	fmt.Printf("\n\nResults broken down by Variant....\n\n")
	for _, variant := range results.ResultsByVariant {
		fmt.Println(variant.Name+"\n"+divider)
		fmt.Println(variantResults(variant))
	}
}

func variantResults(results types.VariantResults) string {
	total := fmt.Sprintf("Total tests: %v\n", results.Total)
	passed := fmt.Sprintf("Passed: %v\n", results.Passed)
	failed := fmt.Sprintf("Failed: %v\n", results.Failed)
	var failedTests string
	if len(results.FailedScenarios) > 0 {
		failedTests = "Failed Tests:\n"
		for _, test := range results.FailedScenarios {
			failedTests = failedTests + "  - " + test.Name + "\n"
		}
	}
	return total + passed + failed + failedTests
}
<commit_msg>show skipped, pending, undefined results<commit_after>package main

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

	"github.com/cucumber/godog"
	"github.com/ii/xds-test-harness/internal/parser"
	"github.com/ii/xds-test-harness/internal/runner"
	"github.com/ii/xds-test-harness/internal/types"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"github.com/spf13/pflag"
)

var (
	debug          = pflag.BoolP("debug", "D", false, "sets log level to debug")
	testWriting    = pflag.BoolP("testwriting", "W", false, "Sets a pretty output that doesn't write to file, for better feedback while writing tests.")
	config         = pflag.StringP("config", "C", "", "Path to optional config file. This file sets the adapter and target addresses and supported variants.")
	adapterAddress = pflag.StringP("adapter", "A", ":17000", "port of adapter on target")
	targetAddress  = pflag.StringP("target", "T", ":18000", "port of xds target to test")
	nodeID         = pflag.StringP("nodeID", "N", "test-id", "node id of target")
	variant        = pflag.StringArrayP("variant", "V", []string{"sotw non-aggregated", "sotw aggregated", "incremental non-aggregated", "incremental aggregated"}, "xDS protocol variant your server supports. Add a separate flag per each supported variant.\n Possibleariants are: sotw non-aggregated\n, sotw aggregated\n, incremental non-aggregated\n, incremental aggregated\n.")
	godogOpts      = godog.Options{}
)

func init() {
	godog.BindCommandLineFlags("godog.", &godogOpts)
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
}

func main() {
	pflag.Parse()
	godogTags := godogOpts.Tags

	if *debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	// default to using CLI Flag for settings
	err, supportedVariants := parser.ParseSupportedVariants(*variant)
	if err != nil {
		log.Fatal().Msgf("Cannot parse variants from CLI: %v\n", err)
	}
	// If config present, use it for all non-debugging values
	if *config != "" {
		*targetAddress, *adapterAddress, *nodeID, supportedVariants = parser.ValuesFromConfig(*config)
	}

	var results types.Results
	for _, variant := range supportedVariants {
		log.Info().
			Msgf("Starting Tests for %v\n", string(variant))

		suite := runner.NewSuite(variant, *testWriting)
		err, variantResults := suite.Run(*adapterAddress, *targetAddress, *nodeID, godogTags)
		if err != nil {
			log.Fatal().
				Msgf("Error when attempting to run test suite: %v\n", err)
		}
		results = runner.UpdateResults(results, variantResults)
	}
	if !*testWriting {
		printResults(results)
		file, _ := json.MarshalIndent(results, "", "  ")
		_ = ioutil.WriteFile("results.json", file, 0644)
	}
	os.Exit(0)
}

func printResults(results types.Results) {

	divider := "-------------------"
	fmt.Println("\nTest Suite Finished\n" + divider)
	fmt.Printf("Ran %v tests across %v variants\n\n", results.Total, len(results.Variants))
	fmt.Println("Passed: ", results.Passed)
	if results.Failed > 0 {
	  fmt.Println("Failed: ", results.Failed)
	}
	if results.Skipped > 0 {
	  fmt.Println("Skipped: ", results.Skipped)
	}
	if results.Undefined > 0 {
	  fmt.Println("Undefined: ", results.Undefined)
	}
	if results.Pending > 0 {
	  fmt.Println("Pending: ", results.Pending)
	}
	fmt.Printf("\n\nResults broken down by Variant....\n\n")
	for _, variant := range results.ResultsByVariant {
		fmt.Println(variant.Name+"\n"+divider)
		fmt.Println(variantResults(variant))
	}
}

func variantResults(results types.VariantResults) string {
	total := fmt.Sprintf("Total tests: %v\n", results.Total)
	passed := fmt.Sprintf("Passed: %v\n", results.Passed)
	failed := fmt.Sprintf("Failed: %v\n", results.Failed)
	skipped := fmt.Sprintf("Skipped: %v\n", results.Skipped)
	undefined := fmt.Sprintf("Undefined: %v\n", results.Undefined)
	pending := fmt.Sprintf("Pending: %v\n", results.Pending)
	var failedTests string
	if len(results.FailedScenarios) > 0 {
		failedTests = "Failed Tests:\n"
		for _, test := range results.FailedScenarios {
			failedTests = failedTests + "  - " + test.Name + "\n"
		}
	}
	return total + passed + failed + failedTests + skipped + undefined + pending
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/evolsnow/robot/conn"
	"golang.org/x/net/websocket"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var messages = make(chan string)

func main() {
	var configFile string
	var debug bool

	flag.StringVar(&configFile, "c", "config.json", "specify config file")
	flag.BoolVar(&debug, "d", false, "debug mode")
	flag.Parse()
	config, err := ParseConfig(configFile)
	if err != nil {
		log.Fatal("a vailid json config file must exist")
	}

	//connect to redis
	redisPort := strconv.Itoa(config.RedisPort)
	redisServer := net.JoinHostPort(config.RedisAddress, redisPort)
	if !conn.Ping(redisServer, config.RedisPassword) {
		log.Fatal("connect to redis server failed")
	}
	conn.Pool = conn.NewPool(redisServer, config.RedisPassword, config.RedisDB)

	//create robot and run
	robot := newRobot(config.RobotToken, config.RobotName, config.WebHookUrl)
	robot.bot.Debug = debug
	go robot.run()

	//run server and web samaritan
	srvPort := strconv.Itoa(config.Port)
	http.HandleFunc("/ajax", ajax)
	http.Handle("/websocket", websocket.Handler(socketHandler))
	log.Fatal(http.ListenAndServeTLS(net.JoinHostPort(config.Server, srvPort), config.Cert, config.CertKey, nil))

}

//used for web samaritan robot
func socketHandler(ws *websocket.Conn) {
	for {
		var in string
		var ret []string
		if err := websocket.Message.Receive(ws, &in); err != nil {
			log.Println("socket closed")
			return
		}
		ret = receive(in)

		for i := range ret {
			websocket.Message.Send(ws, ret[i])
			time.Sleep(time.Second)
		}
		websocket.Message.Send(ws, "")
	}
}

//when webSocket unavailable, fallback to ajax long polling
func ajax(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	if r.Method == "GET" {
		w.Write([]byte(<-messages))
	} else {
		body := r.FormValue("text")
		if body != "" {
			go func(string) {
				ret := receive(body)
				for i := range ret {
					messages <- ret[i]
					time.Sleep(time.Second)
				}
				messages <- ""
			}(body)
		}
	}
}

//receive from client
func receive(in string) (ret []string) {
	fmt.Printf("Received: %s\n", in)
	var response string
	var answer = make(chan string)
	sf := func(c rune) bool {
		return c == ',' || c == '，' || c == ';' || c == '。' || c == '.' || c == '？' || c == '?'
	}
	if chinese(in) {
		go func() {
			answer <- iceAI(in)
		}()
		go func() {
			answer <- tlAI(in)
		}()
		go func() {
			ret := qinAI(in)
			if ret != "" {
				answer <- strings.Replace(ret, "Jarvis", "samaritan", -1)
			}
		}()
		response = <-answer
		// Separate into fields with func.
		ret = strings.FieldsFunc(response, sf)

	} else {
		response = mitAI(in)
		ret = strings.FieldsFunc(response, sf)
	}
	return
}
<commit_msg>recover needed when client closed<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/evolsnow/robot/conn"
	"golang.org/x/net/websocket"
	"log"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

var messages = make(chan string)

func main() {
	var configFile string
	var debug bool

	flag.StringVar(&configFile, "c", "config.json", "specify config file")
	flag.BoolVar(&debug, "d", false, "debug mode")
	flag.Parse()
	config, err := ParseConfig(configFile)
	if err != nil {
		log.Fatal("a vailid json config file must exist")
	}

	//connect to redis
	redisPort := strconv.Itoa(config.RedisPort)
	redisServer := net.JoinHostPort(config.RedisAddress, redisPort)
	if !conn.Ping(redisServer, config.RedisPassword) {
		log.Fatal("connect to redis server failed")
	}
	conn.Pool = conn.NewPool(redisServer, config.RedisPassword, config.RedisDB)

	//create robot and run
	robot := newRobot(config.RobotToken, config.RobotName, config.WebHookUrl)
	robot.bot.Debug = debug
	go robot.run()

	//run server and web samaritan
	srvPort := strconv.Itoa(config.Port)
	http.HandleFunc("/ajax", ajax)
	http.Handle("/websocket", websocket.Handler(socketHandler))
	log.Fatal(http.ListenAndServeTLS(net.JoinHostPort(config.Server, srvPort), config.Cert, config.CertKey, nil))

}

//used for web samaritan robot
func socketHandler(ws *websocket.Conn) {
	for {
		var in string
		var ret []string
		if err := websocket.Message.Receive(ws, &in); err != nil {
			log.Println("socket closed")
			return
		}
		ret = receive(in)

		for i := range ret {
			websocket.Message.Send(ws, ret[i])
			time.Sleep(time.Second)
		}
		websocket.Message.Send(ws, "")
	}
}

//when webSocket unavailable, fallback to ajax long polling
func ajax(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	if r.Method == "GET" {
		w.Write([]byte(<-messages))
	} else {
		body := r.FormValue("text")
		if body != "" {
			go func(string) {
				ret := receive(body)
				for i := range ret {
					messages <- ret[i]
					time.Sleep(time.Second)
				}
				messages <- ""
			}(body)
		}
	}
}

//receive from client
func receive(in string) (ret []string) {
	defer func() {
		if p := recover(); p != nil {
			err := fmt.Errorf("client closed error: %v", p)
			log.Println(err)
		}
	}()
	fmt.Printf("Received: %s\n", in)
	var response string
	var answer = make(chan string)
	sf := func(c rune) bool {
		return c == ',' || c == '，' || c == ';' || c == '。' || c == '.' || c == '？' || c == '?'
	}
	if chinese(in) {
		go func() {
			answer <- iceAI(in)
		}()
		go func() {
			answer <- tlAI(in)
		}()
		go func() {
			ret := qinAI(in)
			if ret != "" {
				answer <- strings.Replace(ret, "Jarvis", "samaritan", -1)
			}
		}()
		response = <-answer
		// Separate into fields with func.
		ret = strings.FieldsFunc(response, sf)

	} else {
		response = mitAI(in)
		ret = strings.FieldsFunc(response, sf)
	}
	return
}
<|endoftext|>


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

package main

import (
	"bufio"
	"crypto/tls"
	"crypto/x509"
	"encoding/binary"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/square/certigo/jceks"
	"golang.org/x/crypto/pkcs12"
	"golang.org/x/crypto/ssh/terminal"
)

var (
	app = kingpin.New("certigo", "A command line certificate examination utility.")

	dump      = app.Command("dump", "Display information about a certificate.")
	dumpFiles = dump.Arg("file", "Certificate file to dump (or stdin if not specified).").ExistingFiles()
	dumpType  = dump.Flag("format", "Format of given input (heuristic guess if not specified).").String()

	connect     = app.Command("connect", "Connect to a server and print its certificate.")
	connectTo   = connect.Arg("server:port", "Hostname or IP to connect to.").String()
	connectName = connect.Flag("name", "Override the server name used for SNI.").String()
)

var fileExtToFormat = map[string]string{
	".pem":   "PEM",
	".crt":   "PEM",
	".p12":   "PKCS12",
	".pfx":   "PKCS12",
	".jceks": "JCEKS",
	".jks":   "JCEKS", // Only partially supported
	".der":   "DER",
}

type certWithAlias struct {
	alias string
	file  string
	cert  *x509.Certificate
}

func main() {
	app.Version("1.0.1")

	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case dump.FullCommand(): // Dump certificate
		files := []*os.File{}
		if *dumpFiles != nil {
			for _, filename := range *dumpFiles {
				rawFile, err := os.Open(filename)
				if err != nil {
					fmt.Fprintf(os.Stderr, "unable to open file: %s\n", err)
					os.Exit(1)
				}
				files = append(files, rawFile)
				defer rawFile.Close()
			}
		} else {
			files = append(files, os.Stdin)
		}

		wg := &sync.WaitGroup{}
		certs := make(chan certWithAlias, 1)

		go displayCerts(wg, certs, len(files) > 1)

		readCerts(wg, certs, files)

		wg.Wait()
	case connect.FullCommand(): // Get certs by connecting to a server
		conn, err := tls.Dial("tcp", *connectTo, &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         *connectName,
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error connecting: %v\n", err)
			os.Exit(1)
		}
		defer conn.Close()
		for i, cert := range conn.ConnectionState().PeerCertificates {
			fmt.Printf("** CERTIFICATE %d **\n", i+1)
			displayCert(certWithAlias{cert: cert})
			fmt.Println()
		}
	}
}

func readCerts(wg *sync.WaitGroup, certs chan<- certWithAlias, files []*os.File) {
	for _, file := range files {
		reader := bufio.NewReaderSize(file, 4)
		format, ok := formatForFile(reader, file.Name(), *dumpType)
		if !ok {
			fmt.Fprintf(os.Stderr, "unable to guess file type (for file %s)\n", file.Name())
			os.Exit(1)
		}

		readCertsFromFile(wg, reader, file.Name(), format, certs)
	}
}

func displayCerts(wg *sync.WaitGroup, certs <-chan certWithAlias, showFiles bool) {
	i := 1
	for cert := range certs {
		fmt.Printf("** CERTIFICATE %d **\n", i)
		if cert.file != "" && showFiles {
			fmt.Printf("File  : %s\n", path.Base(cert.file))
		}
		displayCert(cert)
		fmt.Println()
		wg.Done()
		i++
	}
}

func readPassword(prompt string) string {
	var tty *os.File
	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
	if err != nil {
		tty = os.Stdin
	} else {
		defer tty.Close()
	}

	tty.WriteString(prompt)
	password, err := terminal.ReadPassword(int(tty.Fd()))
	tty.WriteString("\n")
	if err != nil {
		fmt.Fprintf(os.Stderr, "error reading password: %s", err)
		os.Exit(1)
	}

	return strings.TrimSuffix(string(password), "\n")
}

// formatForFile returns the file format (either from flags or
// based on file extension).
func formatForFile(file *bufio.Reader, filename, format string) (string, bool) {
	// First, honor --format flag we got from user
	if format != "" {
		return format, true
	}

	// Second, attempt to guess based on extension
	guess, ok := fileExtToFormat[strings.ToLower(filepath.Ext(filename))]
	if ok {
		return guess, true
	}

	// Third, attempt to guess based on first 4 bytes of input
	data, err := file.Peek(4)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}

	// Heuristics for guessing -- best effort.
	magic := binary.BigEndian.Uint32(data)
	if magic == 0xCECECECE || magic == 0xFEEDFEED {
		// JCEKS/JKS files always start with this prefix
		return "JCEKS", true
	}
	if magic == 0x2D2D2D2D || magic == 0x434f4e4e {
		// Starts with '----' or 'CONN' (what s_client prints...)
		return "PEM", true
	}
	if magic&0xFFFF0000 == 0x30820000 {
		// Looks like the input is DER-encoded, so it's either PKCS12 or X.509.
		if magic&0x0000FF00 == 0x0300 {
			// Probably X.509
			return "DER", true
		}
		return "PKCS12", true
	}

	return "", false
}

// pemScanner will return a bufio.Scanner that splits the input
// from the given reader into PEM blocks.
func pemScanner(reader io.Reader) *bufio.Scanner {
	scanner := bufio.NewScanner(reader)

	scanner.Split(func(data []byte, atEOF bool) (int, []byte, error) {
		block, rest := pem.Decode(data)
		if block != nil {
			size := len(data) - len(rest)
			return size, data[:size], nil
		}

		return 0, nil, nil
	})

	return scanner
}

// readCertsFromFile takes in a filename and format type and returns an
// array of all the certificates found in that file along with aliases
// for each cert if the format of the input was jceks. If no format
// is specified for the file, readCertsFromFile guesses what format was used
// based on the file extension used in the file name. If it can't
// guess based on this it returns and error.
func readCertsFromFile(wg *sync.WaitGroup, reader io.Reader, filename string, format string, out chan<- certWithAlias) {
	switch format {
	case "PEM":
		scanner := pemScanner(reader)
		for scanner.Scan() {
			block, _ := pem.Decode(scanner.Bytes())
			cert, err := x509.ParseCertificate(block.Bytes)
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
				os.Exit(1)
			}
			wg.Add(1)
			out <- certWithAlias{file: filename, cert: cert}
		}
	case "DER":
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error reading input: %s", err)
			os.Exit(1)
		}
		cert, err := x509.ParseCertificate(data)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
			os.Exit(1)
		}
		wg.Add(1)
		out <- certWithAlias{file: filename, cert: cert}
	case "PKCS12":
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error reading input: %s", err)
			os.Exit(1)
		}
		password := readPassword("Enter password: ")
		blocks, err := pkcs12.ToPEM(data, password)
		if err != nil || len(blocks) == 0 {
			fmt.Fprint(os.Stderr, "keystore appears to be empty or password was incorrect")
			os.Exit(1)
		}
		for _, block := range blocks {
			if block.Type == "CERTIFICATE" {
				cert, err := x509.ParseCertificate(block.Bytes)
				if err != nil {
					fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
					os.Exit(1)
				}
				wg.Add(1)
				out <- certWithAlias{file: filename, cert: cert}
			}
		}
	case "JCEKS":
		password := readPassword("Enter password: ")
		keyStore, err := jceks.LoadFromReader(reader, []byte(password))
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing keystore: %s", err)
			os.Exit(1)
		}
		for _, alias := range keyStore.ListCerts() {
			cert, _ := keyStore.GetCert(alias)
			wg.Add(1)
			out <- certWithAlias{file: filename, cert: cert}
		}
		for _, alias := range keyStore.ListPrivateKeys() {
			password := readPassword(fmt.Sprintf("Enter password for alias [%s]: ", alias))
			_, certArr, err := keyStore.GetPrivateKeyAndCerts(alias, []byte(password))
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing keystore: %s", err)
				os.Exit(1)
			}
			for _, cert := range certArr {
				wg.Add(1)
				out <- certWithAlias{file: filename, cert: cert}
			}
		}
	default:
		fmt.Fprintf(os.Stderr, "unknown file type: %s", format)
		os.Exit(1)
	}
}
<commit_msg>Skip non-certificate PEM blocks<commit_after>/*-
 * Copyright 2016 Square Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"bufio"
	"crypto/tls"
	"crypto/x509"
	"encoding/binary"
	"encoding/pem"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"

	"gopkg.in/alecthomas/kingpin.v2"

	"github.com/square/certigo/jceks"
	"golang.org/x/crypto/pkcs12"
	"golang.org/x/crypto/ssh/terminal"
)

var (
	app = kingpin.New("certigo", "A command line certificate examination utility.")

	dump      = app.Command("dump", "Display information about a certificate.")
	dumpFiles = dump.Arg("file", "Certificate file to dump (or stdin if not specified).").ExistingFiles()
	dumpType  = dump.Flag("format", "Format of given input (heuristic guess if not specified).").String()

	connect     = app.Command("connect", "Connect to a server and print its certificate.")
	connectTo   = connect.Arg("server:port", "Hostname or IP to connect to.").String()
	connectName = connect.Flag("name", "Override the server name used for SNI.").String()
)

var fileExtToFormat = map[string]string{
	".pem":   "PEM",
	".crt":   "PEM",
	".p12":   "PKCS12",
	".pfx":   "PKCS12",
	".jceks": "JCEKS",
	".jks":   "JCEKS", // Only partially supported
	".der":   "DER",
}

type certWithAlias struct {
	alias string
	file  string
	cert  *x509.Certificate
}

func main() {
	app.Version("1.0.1")

	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case dump.FullCommand(): // Dump certificate
		files := []*os.File{}
		if *dumpFiles != nil {
			for _, filename := range *dumpFiles {
				rawFile, err := os.Open(filename)
				if err != nil {
					fmt.Fprintf(os.Stderr, "unable to open file: %s\n", err)
					os.Exit(1)
				}
				files = append(files, rawFile)
				defer rawFile.Close()
			}
		} else {
			files = append(files, os.Stdin)
		}

		wg := &sync.WaitGroup{}
		certs := make(chan certWithAlias, 1)

		go displayCerts(wg, certs, len(files) > 1)

		readCerts(wg, certs, files)

		wg.Wait()
	case connect.FullCommand(): // Get certs by connecting to a server
		conn, err := tls.Dial("tcp", *connectTo, &tls.Config{
			InsecureSkipVerify: true,
			ServerName:         *connectName,
		})
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error connecting: %v\n", err)
			os.Exit(1)
		}
		defer conn.Close()
		for i, cert := range conn.ConnectionState().PeerCertificates {
			fmt.Printf("** CERTIFICATE %d **\n", i+1)
			displayCert(certWithAlias{cert: cert})
			fmt.Println()
		}
	}
}

func readCerts(wg *sync.WaitGroup, certs chan<- certWithAlias, files []*os.File) {
	for _, file := range files {
		reader := bufio.NewReaderSize(file, 4)
		format, ok := formatForFile(reader, file.Name(), *dumpType)
		if !ok {
			fmt.Fprintf(os.Stderr, "unable to guess file type (for file %s)\n", file.Name())
			os.Exit(1)
		}

		readCertsFromFile(wg, reader, file.Name(), format, certs)
	}
}

func displayCerts(wg *sync.WaitGroup, certs <-chan certWithAlias, showFiles bool) {
	i := 1
	for cert := range certs {
		fmt.Printf("** CERTIFICATE %d **\n", i)
		if cert.file != "" && showFiles {
			fmt.Printf("File  : %s\n", path.Base(cert.file))
		}
		displayCert(cert)
		fmt.Println()
		wg.Done()
		i++
	}
}

func readPassword(prompt string) string {
	var tty *os.File
	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
	if err != nil {
		tty = os.Stdin
	} else {
		defer tty.Close()
	}

	tty.WriteString(prompt)
	password, err := terminal.ReadPassword(int(tty.Fd()))
	tty.WriteString("\n")
	if err != nil {
		fmt.Fprintf(os.Stderr, "error reading password: %s", err)
		os.Exit(1)
	}

	return strings.TrimSuffix(string(password), "\n")
}

// formatForFile returns the file format (either from flags or
// based on file extension).
func formatForFile(file *bufio.Reader, filename, format string) (string, bool) {
	// First, honor --format flag we got from user
	if format != "" {
		return format, true
	}

	// Second, attempt to guess based on extension
	guess, ok := fileExtToFormat[strings.ToLower(filepath.Ext(filename))]
	if ok {
		return guess, true
	}

	// Third, attempt to guess based on first 4 bytes of input
	data, err := file.Peek(4)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}

	// Heuristics for guessing -- best effort.
	magic := binary.BigEndian.Uint32(data)
	if magic == 0xCECECECE || magic == 0xFEEDFEED {
		// JCEKS/JKS files always start with this prefix
		return "JCEKS", true
	}
	if magic == 0x2D2D2D2D || magic == 0x434f4e4e {
		// Starts with '----' or 'CONN' (what s_client prints...)
		return "PEM", true
	}
	if magic&0xFFFF0000 == 0x30820000 {
		// Looks like the input is DER-encoded, so it's either PKCS12 or X.509.
		if magic&0x0000FF00 == 0x0300 {
			// Probably X.509
			return "DER", true
		}
		return "PKCS12", true
	}

	return "", false
}

// pemScanner will return a bufio.Scanner that splits the input
// from the given reader into PEM blocks.
func pemScanner(reader io.Reader) *bufio.Scanner {
	scanner := bufio.NewScanner(reader)

	scanner.Split(func(data []byte, atEOF bool) (int, []byte, error) {
		block, rest := pem.Decode(data)
		if block != nil {
			size := len(data) - len(rest)
			return size, data[:size], nil
		}

		return 0, nil, nil
	})

	return scanner
}

// readCertsFromFile takes in a filename and format type and returns an
// array of all the certificates found in that file along with aliases
// for each cert if the format of the input was jceks. If no format
// is specified for the file, readCertsFromFile guesses what format was used
// based on the file extension used in the file name. If it can't
// guess based on this it returns and error.
func readCertsFromFile(wg *sync.WaitGroup, reader io.Reader, filename string, format string, out chan<- certWithAlias) {
	switch format {
	case "PEM":
		scanner := pemScanner(reader)
		for scanner.Scan() {
			block, _ := pem.Decode(scanner.Bytes())
			if block.Type != "CERTIFICATE" {
				// Skip non-certificate PEM blocks
				continue
			}
			cert, err := x509.ParseCertificate(block.Bytes)
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
				os.Exit(1)
			}
			wg.Add(1)
			out <- certWithAlias{file: filename, cert: cert}
		}
	case "DER":
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error reading input: %s", err)
			os.Exit(1)
		}
		cert, err := x509.ParseCertificate(data)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
			os.Exit(1)
		}
		wg.Add(1)
		out <- certWithAlias{file: filename, cert: cert}
	case "PKCS12":
		data, err := ioutil.ReadAll(reader)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error reading input: %s", err)
			os.Exit(1)
		}
		password := readPassword("Enter password: ")
		blocks, err := pkcs12.ToPEM(data, password)
		if err != nil || len(blocks) == 0 {
			fmt.Fprint(os.Stderr, "keystore appears to be empty or password was incorrect")
			os.Exit(1)
		}
		for _, block := range blocks {
			if block.Type == "CERTIFICATE" {
				cert, err := x509.ParseCertificate(block.Bytes)
				if err != nil {
					fmt.Fprintf(os.Stderr, "error parsing certificate: %s", err)
					os.Exit(1)
				}
				wg.Add(1)
				out <- certWithAlias{file: filename, cert: cert}
			}
		}
	case "JCEKS":
		password := readPassword("Enter password: ")
		keyStore, err := jceks.LoadFromReader(reader, []byte(password))
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing keystore: %s", err)
			os.Exit(1)
		}
		for _, alias := range keyStore.ListCerts() {
			cert, _ := keyStore.GetCert(alias)
			wg.Add(1)
			out <- certWithAlias{file: filename, cert: cert}
		}
		for _, alias := range keyStore.ListPrivateKeys() {
			password := readPassword(fmt.Sprintf("Enter password for alias [%s]: ", alias))
			_, certArr, err := keyStore.GetPrivateKeyAndCerts(alias, []byte(password))
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing keystore: %s", err)
				os.Exit(1)
			}
			for _, cert := range certArr {
				wg.Add(1)
				out <- certWithAlias{file: filename, cert: cert}
			}
		}
	default:
		fmt.Fprintf(os.Stderr, "unknown file type: %s", format)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/aws-cli"
	"github.com/enaml-ops/omg-cli/azure-cli"
	"github.com/enaml-ops/omg-cli/plugin/registry"
	"github.com/enaml-ops/omg-cli/utils/boshapi"
	"github.com/pivotalservices/gtils/osutils"
	"github.com/xchapter7x/lo"
)

var Version string
var CloudConfigPluginsDir = "./.plugins/cloudconfig"
var ProductPluginsDir = "./.plugins/product"
var cloudConfigCommands []cli.Command
var productCommands []cli.Command
var productList []string
var cloudconfigList []string

func main() {
	app := cli.NewApp()
	app.Version = Version
	app.Commands = []cli.Command{
		{
			Name:   "azure",
			Usage:  "azure [--flags] - deploy a bosh to azure",
			Action: azurecli.GetAction(BoshInitDeploy),
			Flags:  azurecli.GetFlags(),
		},
		{
			Name:   "aws",
			Usage:  "aws [--flags] - deploy a bosh to aws",
			Action: awscli.GetAction(BoshInitDeploy),
			Flags:  awscli.GetFlags(),
		},
		{
			Name: "list-cloudconfigs",
			Action: func(c *cli.Context) error {
				fmt.Println("Cloud Configs:")
				for _, plgn := range registry.ListCloudConfigs() {
					fmt.Println(plgn.Name, " - ", plgn.Path, " - ", plgn.Properties)
				}
				return nil
			},
		},
		{
			Name: "list-products",
			Action: func(c *cli.Context) error {
				fmt.Println("Products:")
				return nil
			},
		},

		{
			Name:  "register-plugin",
			Usage: "register-plugin -type [cloudconfig, product] -pluginpath <plugin-binary>",
			Action: func(c *cli.Context) (err error) {

				if c.String("type") != "" && c.String("pluginpath") != "" {
					err = registerPlugin(c.String("type"), c.String("pluginpath"))
				}
				return
			},
			Flags: []cli.Flag{
				cli.StringFlag{Name: "type", Value: "product", Usage: "define if the plugin to be registered is a cloud-config or a product"},
				cli.StringFlag{Name: "pluginpath", Value: "", Usage: "the path to the plugin you wish to register"},
			},
		},
		{
			Name:        "deploy-cloudconfig",
			Usage:       "deploy-cloudconfig <cloudconfig-name> [--flags] - deploy a cloudconfig to bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: cloudConfigCommands,
		},
		{
			Name:        "deploy-product",
			Usage:       "deploy-product <prod-name> [--flags] - deploy a product via bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: productCommands,
		},
	}
	app.Run(os.Args)
}

func init() {

	if strings.ToLower(os.Getenv("LOG_LEVEL")) != "debug" {
		log.SetOutput(ioutil.Discard)
	}
	registerCloudConfig()
}

func registerPlugin(typename, pluginpath string) (err error) {
	var srcPlugin *os.File

	if srcPlugin, err = os.Open(pluginpath); err == nil {
		defer srcPlugin.Close()

		switch typename {
		case "cloudconfig":
			dstFilepath := path.Join(CloudConfigPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		case "product":
			dstFilepath := path.Join(ProductPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		default:
			err = errors.New("invalid type selected")
			lo.G.Error("error: ", err)
		}
	}
	return
}

func copyPlugin(src io.Reader, dst string) (err error) {
	var dstPlugin *os.File
	if dstPlugin, err = osutils.SafeCreate(dst); err == nil {
		defer dstPlugin.Close()
		_, err = io.Copy(dstPlugin, src)
		os.Chmod(dst, 755)
	}
	return
}

func registerCloudConfig() {
	files, _ := ioutil.ReadDir(CloudConfigPluginsDir)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(CloudConfigPluginsDir, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		cloudConfigCommands = append(cloudConfigCommands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())
				manifest := cc.GetCloudConfig(c.Parent().Args())
				lo.G.Debug("we found a manifest and context: ", manifest, c)
				processManifest(c, manifest)
				return nil
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
}

func getBoshAuthFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "bosh-url", Value: "https://mybosh.com", Usage: "this is the url or ip of your bosh director"},
		cli.IntFlag{Name: "bosh-port", Value: 25555, Usage: "this is the port of your bosh director"},
		cli.StringFlag{Name: "bosh-user", Value: "bosh", Usage: "this is the username for your bosh director"},
		cli.StringFlag{Name: "bosh-pass", Value: "", Usage: "this is the pasword for your bosh director"},
		cli.BoolFlag{Name: "print-manifest", Usage: "if you would simply like to output a manifest the set this flag as true."},
	}
}

func processManifest(c *cli.Context, manifest []byte) (e error) {

	if c.Parent().Bool("print-manifest") {
		yamlString := string(manifest)
		fmt.Println(yamlString)

	} else {
		ccm := enaml.NewCloudConfigManifest(manifest)
		boshclient := boshapi.NewClient(c.Parent().String("bosh-user"), c.Parent().String("bosh-pass"), c.Parent().String("bosh-url"), c.Parent().Int("bosh-port"))
		if req, err := boshclient.NewCloudConfigRequest(*ccm); err == nil {
			httpClient := new(http.Client)

			if res, err := httpClient.Do(req); err != nil {
				lo.G.Error("res: ", res)
				lo.G.Error("error: ", err)
				e = err
			}
		} else {
			e = err
		}
	}
	return
}
<commit_msg>[#119868047] ignore self signed certs<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/aws-cli"
	"github.com/enaml-ops/omg-cli/azure-cli"
	"github.com/enaml-ops/omg-cli/plugin/registry"
	"github.com/enaml-ops/omg-cli/utils/boshapi"
	"github.com/pivotalservices/gtils/osutils"
	"github.com/xchapter7x/lo"
)

var Version string
var CloudConfigPluginsDir = "./.plugins/cloudconfig"
var ProductPluginsDir = "./.plugins/product"
var cloudConfigCommands []cli.Command
var productCommands []cli.Command
var productList []string
var cloudconfigList []string

func main() {
	app := cli.NewApp()
	app.Version = Version
	app.Commands = []cli.Command{
		{
			Name:   "azure",
			Usage:  "azure [--flags] - deploy a bosh to azure",
			Action: azurecli.GetAction(BoshInitDeploy),
			Flags:  azurecli.GetFlags(),
		},
		{
			Name:   "aws",
			Usage:  "aws [--flags] - deploy a bosh to aws",
			Action: awscli.GetAction(BoshInitDeploy),
			Flags:  awscli.GetFlags(),
		},
		{
			Name: "list-cloudconfigs",
			Action: func(c *cli.Context) error {
				fmt.Println("Cloud Configs:")
				for _, plgn := range registry.ListCloudConfigs() {
					fmt.Println(plgn.Name, " - ", plgn.Path, " - ", plgn.Properties)
				}
				return nil
			},
		},
		{
			Name: "list-products",
			Action: func(c *cli.Context) error {
				fmt.Println("Products:")
				return nil
			},
		},

		{
			Name:  "register-plugin",
			Usage: "register-plugin -type [cloudconfig, product] -pluginpath <plugin-binary>",
			Action: func(c *cli.Context) (err error) {

				if c.String("type") != "" && c.String("pluginpath") != "" {
					err = registerPlugin(c.String("type"), c.String("pluginpath"))
				}
				return
			},
			Flags: []cli.Flag{
				cli.StringFlag{Name: "type", Value: "product", Usage: "define if the plugin to be registered is a cloud-config or a product"},
				cli.StringFlag{Name: "pluginpath", Value: "", Usage: "the path to the plugin you wish to register"},
			},
		},
		{
			Name:        "deploy-cloudconfig",
			Usage:       "deploy-cloudconfig <cloudconfig-name> [--flags] - deploy a cloudconfig to bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: cloudConfigCommands,
		},
		{
			Name:        "deploy-product",
			Usage:       "deploy-product <prod-name> [--flags] - deploy a product via bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: productCommands,
		},
	}
	app.Run(os.Args)
}

func init() {

	if strings.ToLower(os.Getenv("LOG_LEVEL")) != "debug" {
		log.SetOutput(ioutil.Discard)
	}
	registerCloudConfig()
}

func registerPlugin(typename, pluginpath string) (err error) {
	var srcPlugin *os.File

	if srcPlugin, err = os.Open(pluginpath); err == nil {
		defer srcPlugin.Close()

		switch typename {
		case "cloudconfig":
			dstFilepath := path.Join(CloudConfigPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		case "product":
			dstFilepath := path.Join(ProductPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		default:
			err = errors.New("invalid type selected")
			lo.G.Error("error: ", err)
		}
	}
	return
}

func copyPlugin(src io.Reader, dst string) (err error) {
	var dstPlugin *os.File
	if dstPlugin, err = osutils.SafeCreate(dst); err == nil {
		defer dstPlugin.Close()
		_, err = io.Copy(dstPlugin, src)
		os.Chmod(dst, 755)
	}
	return
}

func registerCloudConfig() {
	files, _ := ioutil.ReadDir(CloudConfigPluginsDir)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(CloudConfigPluginsDir, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		cloudConfigCommands = append(cloudConfigCommands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())
				manifest := cc.GetCloudConfig(c.Parent().Args())
				lo.G.Debug("we found a manifest and context: ", manifest, c)
				processManifest(c, manifest)
				return nil
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
}

func getBoshAuthFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "bosh-url", Value: "https://mybosh.com", Usage: "this is the url or ip of your bosh director"},
		cli.IntFlag{Name: "bosh-port", Value: 25555, Usage: "this is the port of your bosh director"},
		cli.StringFlag{Name: "bosh-user", Value: "bosh", Usage: "this is the username for your bosh director"},
		cli.StringFlag{Name: "bosh-pass", Value: "", Usage: "this is the pasword for your bosh director"},
		cli.BoolFlag{Name: "print-manifest", Usage: "if you would simply like to output a manifest the set this flag as true."},
	}
}

func processManifest(c *cli.Context, manifest []byte) (e error) {

	if c.Parent().Bool("print-manifest") {
		yamlString := string(manifest)
		fmt.Println(yamlString)

	} else {
		ccm := enaml.NewCloudConfigManifest(manifest)
		boshclient := boshapi.NewClient(c.Parent().String("bosh-user"), c.Parent().String("bosh-pass"), c.Parent().String("bosh-url"), c.Parent().Int("bosh-port"))
		if req, err := boshclient.NewCloudConfigRequest(*ccm); err == nil {
			tr := &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			}
			httpClient := &http.Client{Transport: tr}

			if res, err := httpClient.Do(req); err != nil {
				lo.G.Error("res: ", res)
				lo.G.Error("error: ", err)
				e = err
			}
		} else {
			e = err
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-runewidth"
)

func usage() {
	os.Stderr.WriteString(`
Usage: ali [OPTION]... [FILE]...
Align FILE(s), or standard input.

Options:
  -s, --separator=STRING   use STRING to separate line (default: spaces)
  --help                   show this help message
  --version                print the version
`[1:])
}

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

var SPACES = regexp.MustCompile(`\s+`)

type Separator struct {
	re *regexp.Regexp
}

func NewSeparator() *Separator {
	return &Separator{}
}

func (s *Separator) String() string {
	return fmt.Sprint(*s)
}

func (s *Separator) Set(expr string) error {
	re, err := regexp.Compile(regexp.QuoteMeta(expr))
	if err != nil {
		return err
	}
	s.re = re
	return nil
}

func (s *Separator) Split(t string) []string {
	if s.re == nil {
		return SPACES.Split(t, -1)
	}

	matches := s.re.FindAllStringIndex(t, -1)
	if len(matches) == 0 {
		return []string{t}
	}

	sls := make([]string, 0, len(matches)*2+1)
	beg, end := 0, 0
	for _, match := range matches {
		end = match[0]
		sls = append(sls, t[beg:end])
		beg, end = match[0], match[1]
		sls = append(sls, t[beg:end])
		beg = match[1]
	}
	sls = append(sls, t[beg:])
	for i := 0; i < len(sls); i++ {
		sls[i] = strings.TrimSpace(sls[i])
	}
	return sls
}

type Aligner struct {
	Sep   *Separator
	lines [][]string
	width []int
}

func NewAligner() *Aligner {
	return &Aligner{
		Sep: NewSeparator(),
	}
}

func (a *Aligner) appendLine(s string) {
	sp := a.Sep.Split(s)
	for i, cell := range sp {
		if i == len(a.width) {
			a.width = append(a.width, 0)
		}

		w := runewidth.StringWidth(cell)
		if w > a.width[i] {
			a.width[i] = w
		}
	}
	a.lines = append(a.lines, sp)
}

func (a *Aligner) ReadAll(r io.Reader) error {
	s := bufio.NewScanner(r)
	for s.Scan() {
		a.appendLine(s.Text())
	}
	return s.Err()
}

func (a *Aligner) format(l []string) string {
	for i := 0; i < len(l); i++ {
		l[i] = l[i] + strings.Repeat(" ", a.width[i]-runewidth.StringWidth(l[i]))
	}
	return strings.TrimSpace(strings.Join(l, " "))
}

func (a *Aligner) Flush(w io.Writer) error {
	for _, l := range a.lines {
		_, err := fmt.Fprintln(w, a.format(l))
		if err != nil {
			return err
		}
	}
	return nil
}

func do(a *Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	a.Flush(os.Stdout)
	return nil
}

func _main() error {
	isHelp := flag.Bool("help", false, "")
	isVersion := flag.Bool("version", false, "")

	a := NewAligner()
	flag.Var(a.Sep, "s", "")
	flag.Var(a.Sep, "separator", "")

	flag.Usage = usage
	flag.Parse()
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "ali:", err)
		os.Exit(1)
	}
}
<commit_msg>Enable use regexp to separate line<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"strings"

	"github.com/mattn/go-runewidth"
)

func usage() {
	os.Stderr.WriteString(`
Usage: ali [OPTION]... [FILE]...
Align FILE(s), or standard input.

Options:
  -r, --regexp             PATTERN is a regular expression
  -s, --separator=PATTERN  use PATTERN to separate line (default: /\s+/)
  --help                   show this help message
  --version                print the version
`[1:])
}

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

var SPACES = regexp.MustCompile(`\s+`)

type Separator struct {
	re        *regexp.Regexp
	UseRegexp bool
}

func NewSeparator() *Separator {
	return &Separator{}
}

func (s *Separator) String() string {
	return fmt.Sprint(*s)
}

func (s *Separator) Set(expr string) error {
	if !s.UseRegexp {
		expr = regexp.QuoteMeta(expr)
	}
	re, err := regexp.Compile(expr)
	if err != nil {
		return err
	}
	s.re = re
	return nil
}

func (s *Separator) Split(t string) []string {
	if s.re == nil {
		return SPACES.Split(t, -1)
	}

	matches := s.re.FindAllStringIndex(t, -1)
	if len(matches) == 0 {
		return []string{t}
	}

	sls := make([]string, 0, len(matches)*2+1)
	beg, end := 0, 0
	for _, match := range matches {
		end = match[0]
		sls = append(sls, t[beg:end])
		beg, end = match[0], match[1]
		sls = append(sls, t[beg:end])
		beg = match[1]
	}
	sls = append(sls, t[beg:])
	for i := 0; i < len(sls); i++ {
		sls[i] = strings.TrimSpace(sls[i])
	}
	return sls
}

type Aligner struct {
	Sep   *Separator
	lines [][]string
	width []int
}

func NewAligner() *Aligner {
	return &Aligner{
		Sep: NewSeparator(),
	}
}

func (a *Aligner) appendLine(s string) {
	sp := a.Sep.Split(s)
	for i, cell := range sp {
		if i == len(a.width) {
			a.width = append(a.width, 0)
		}

		w := runewidth.StringWidth(cell)
		if w > a.width[i] {
			a.width[i] = w
		}
	}
	a.lines = append(a.lines, sp)
}

func (a *Aligner) ReadAll(r io.Reader) error {
	s := bufio.NewScanner(r)
	for s.Scan() {
		a.appendLine(s.Text())
	}
	return s.Err()
}

func (a *Aligner) format(l []string) string {
	for i := 0; i < len(l); i++ {
		l[i] = l[i] + strings.Repeat(" ", a.width[i]-runewidth.StringWidth(l[i]))
	}
	return strings.TrimSpace(strings.Join(l, " "))
}

func (a *Aligner) Flush(w io.Writer) error {
	for _, l := range a.lines {
		_, err := fmt.Fprintln(w, a.format(l))
		if err != nil {
			return err
		}
	}
	return nil
}

func do(a *Aligner, r io.Reader) error {
	if err := a.ReadAll(r); err != nil {
		return err
	}
	a.Flush(os.Stdout)
	return nil
}

func _main() error {
	isHelp := flag.Bool("help", false, "")
	isVersion := flag.Bool("version", false, "")

	a := NewAligner()
	flag.Var(a.Sep, "s", "")
	flag.Var(a.Sep, "separator", "")
	flag.BoolVar(&a.Sep.UseRegexp, "r", false, "")
	flag.BoolVar(&a.Sep.UseRegexp, "regexp", false, "")

	flag.Usage = usage
	flag.Parse()
	switch {
	case *isHelp:
		usage()
		return nil
	case *isVersion:
		version()
		return nil
	}

	if flag.NArg() < 1 {
		return do(a, os.Stdin)
	}

	var input []io.Reader
	for _, fname := range flag.Args() {
		f, err := os.Open(fname)
		if err != nil {
			return err
		}
		defer f.Close()
		input = append(input, f)
	}
	return do(a, io.MultiReader(input...))
}

func main() {
	if err := _main(); err != nil {
		fmt.Fprintln(os.Stderr, "ali:", err)
		os.Exit(1)
	}
}
<|endoftext|>


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

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

type GeoContent struct {
	LatLong string `json:"latLon"`
	Utm     string `json:"utm"`
	Mgrs    string `json:"mgrs"`
}

type ResultGeoLoc struct {
	Results GeoContent `json:"result"`
}

func getGeoLoc(body []byte) (*ResultGeoLoc, error) {
	var s = new(ResultGeoLoc)
	err := json.Unmarshal(body, &s)
	if err != nil {
		fmt.Println("whoops:", err)
	}
	return s, err
}

func main() {
	getAllUser()
	// line bot
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
	//test

}
func callbackHandler(w http.ResponseWriter, r *http.Request) {
	bot.SendText([]string{"ufa92a3a52f197e19bfddeb5ca0595e93"}, "deploy done!")

	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		log.Println("-->", content)

		//Log detail receive content
		if content != nil {
			log.Println("RECEIVE Msg:", content.IsMessage, " OP:", content.IsOperation, " type:", content.ContentType, " from:", content.From, "to:", content.To, " ID:", content.ID)
		}
		// user add friend
		if content != nil && content.IsOperation && content.OpType == linebot.OpTypeAddedAsFriend {
			out := fmt.Sprintf("Bot แปลงพิกัด Eggyo\nวิธีใช้\nเพียงแค่กดแชร์ Location ที่ต้องการ ระบบจะทำการแปลง Location เป็นพิกัดระบบต่างๆ และหาความสูงจากระดับน้ำทะเลให้\nกด #help เพื่อดูวิธีใช้อื่นๆ \nติดต่อผู้พัฒนา LINE ID : eggyo")
			//result.RawContent.Params[0] is who send your bot friend added operation, otherwise you cannot get in content or operation content.
			_, err = bot.SendText([]string{content.From}, out)
			addNewUser(content.From)

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

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {

			text, err := content.TextContent()
			var processedText = messageCheck(text.Text)
			_, err = bot.SendText([]string{content.From}, processedText)

			if err != nil {
				log.Println(err)
			}
		}
		if content != nil && content.ContentType == linebot.ContentTypeLocation {
			_, err = bot.SendText([]string{content.From}, "ระบบกำลังประมวลผล...")

			loc, err := content.LocationContent()

			// add eggyo geo test
			resp, err := http.Get("http://eggyo-geo-node.herokuapp.com/geo/" + FloatToString(loc.Latitude) + "/" + FloatToString(loc.Longitude))
			if err != nil {
				println(err.Error())
				return
			}
			defer resp.Body.Close()
			body, err := ioutil.ReadAll(resp.Body)
			log.Println(string(body))

			var elev = callGoogleElev(loc.Latitude, loc.Longitude)
			geo, err := getGeoLoc([]byte(body))
			_, err = bot.SendText([]string{content.From}, "LatLong :"+geo.Results.LatLong)
			_, err = bot.SendText([]string{content.From}, "Utm :"+geo.Results.Utm+"\n\nMgrs :"+geo.Results.Mgrs+"\n\nAltitude :"+elev)
			if err != nil {
				log.Println(err)
			}
		}
	}
}
<commit_msg>v.3.6.5<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client
var eggyoID = "ufa92a3a52f197e19bfddeb5ca0595e93"

type GeoContent struct {
	LatLong string `json:"latLon"`
	Utm     string `json:"utm"`
	Mgrs    string `json:"mgrs"`
}

type ResultGeoLoc struct {
	Results GeoContent `json:"result"`
}

func getGeoLoc(body []byte) (*ResultGeoLoc, error) {
	var s = new(ResultGeoLoc)
	err := json.Unmarshal(body, &s)
	if err != nil {
		fmt.Println("whoops:", err)
	}
	return s, err
}

func main() {
	getAllUser()
	// line bot
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
	//test

}
func callbackHandler(w http.ResponseWriter, r *http.Request) {

	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		log.Println("-->", content)

		//Log detail receive content
		if content != nil {
			log.Println("RECEIVE Msg:", content.IsMessage, " OP:", content.IsOperation, " type:", content.ContentType, " from:", content.From, "to:", content.To, " ID:", content.ID)
		}
		// user add friend
		if content != nil && content.IsOperation && content.OpType == linebot.OpTypeAddedAsFriend {
			out := fmt.Sprintf("Bot แปลงพิกัด Eggyo\nวิธีใช้\nเพียงแค่กดแชร์ Location ที่ต้องการ ระบบจะทำการแปลง Location เป็นพิกัดระบบต่างๆ และหาความสูงจากระดับน้ำทะเลให้\nกด #help เพื่อดูวิธีใช้อื่นๆ \nติดต่อผู้พัฒนา LINE ID : eggyo")
			//result.RawContent.Params[0] is who send your bot friend added operation, otherwise you cannot get in content or operation content.
			_, err = bot.SendText([]string{content.From}, out)
			bot.SendText([]string{eggyoID}, "bot has a new friend :"+content.From)

			addNewUser(content.From)

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

		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {

			text, err := content.TextContent()
			var processedText = messageCheck(text.Text)
			_, err = bot.SendText([]string{content.From}, processedText)
			bot.SendText([]string{eggyoID}, "bot get msg:"+processedText+"\nfrom :"+content.From)
			if err != nil {
				log.Println(err)
			}
		}
		if content != nil && content.ContentType == linebot.ContentTypeLocation {
			_, err = bot.SendText([]string{content.From}, "ระบบกำลังประมวลผล...")

			loc, err := content.LocationContent()

			// add eggyo geo test
			resp, err := http.Get("http://eggyo-geo-node.herokuapp.com/geo/" + FloatToString(loc.Latitude) + "/" + FloatToString(loc.Longitude))
			if err != nil {
				println(err.Error())
				return
			}
			defer resp.Body.Close()
			body, err := ioutil.ReadAll(resp.Body)
			log.Println(string(body))

			var elev = callGoogleElev(loc.Latitude, loc.Longitude)
			geo, err := getGeoLoc([]byte(body))
			_, err = bot.SendText([]string{content.From}, "LatLong :"+geo.Results.LatLong)
			_, err = bot.SendText([]string{content.From}, "Utm :"+geo.Results.Utm+"\n\nMgrs :"+geo.Results.Mgrs+"\n\nAltitude :"+elev)
			bot.SendText([]string{eggyoID}, "bot get loc:"+geo.Results.Mgrs+"\nfrom :"+content.From)

			if err != nil {
				log.Println(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

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

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

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

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

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

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

		baseftrwapp.OutputMetricsIfRequired(graphiteTCPAddress, graphitePrefix, logMetrics)

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

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

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

	app.Run(os.Args)
}

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

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

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

func boolEnv(key string, def bool) bool {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	b, err := strconv.ParseBool(v)
	if err != nil {
		log.Errorf("Could not convert %s:\"%s\" to int. Using default value: %d", key, v, def)
	}
	return b
}
<commit_msg>Using latest version of base-ft-rw-app-go<commit_after>package main

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

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

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

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

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

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

		baseftrwapp.OutputMetricsIfRequired(graphiteTCPAddress, graphitePrefix, logMetrics)

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

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

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

	app.Run(os.Args)
}

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

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

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

func boolEnv(key string, def bool) bool {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	b, err := strconv.ParseBool(v)
	if err != nil {
		log.Errorf("Could not convert %s:\"%s\" to int. Using default value: %d", key, v, def)
	}
	return b
}
<|endoftext|>


<commit_before>package main

import (
	"strconv"
	"sync"
	"time"

	"github.com/gizak/termui"
)

var (
	dataMutex, renderMutex sync.Mutex
	gcCounter, stwTime     int
	gcPercent              *termui.Gauge
	gcRate                 *termui.Par
	liveHeap, goalHeap     *termui.LineChart
	wallTime, cpuTime      *termui.BarChart
)

func render() {
	renderMutex.Lock()
	defer renderMutex.Unlock()
	termui.Render(termui.Body)
}

func refreshGCSummary() {
	ticker := time.NewTicker(5 * time.Second)

	for range ticker.C {
		dataMutex.Lock()

		gcRate.Text = strconv.Itoa(gcCounter / 5)
		gcPercent.Percent = 100 * stwTime / 5e6

		gcCounter = 0
		stwTime = 0

		dataMutex.Unlock()

		render()
	}
}

func refreshGraphs(data gcInfo) {
	liveHeap.Data = append(liveHeap.Data[1:], data.size.live)
	goalHeap.Data = append(goalHeap.Data[1:], data.size.goal)

	wallTime.Data = []int{
		data.wallTime.sweepTermination,
		data.wallTime.markAndSwap,
		data.wallTime.markTermination,
	}
	cpuTime.Data = []int{
		data.cpuTime.sweepTermination,
		data.cpuTime.markAndSwap,
		data.cpuTime.markTermination,
	}

	dataMutex.Lock()
	gcCounter++
	stwTime += data.wallTime.sweepTermination
	stwTime += data.wallTime.markTermination
	dataMutex.Unlock()

	render()
}

func sendEvents() {
	for data := range readStdin() {
		termui.SendCustomEvt("/feed", data)
	}
}

func main() {
	if err := termui.Init(); err != nil {
		panic(err)
	}
	defer termui.Close()

	gcPercent = newGauge("Percentage of Time Spent in GC")
	gcRate = newPar("GC Events per Second")

	liveHeap = newLineChart("Live heap size, MB")
	goalHeap = newLineChart("Goal heap size, MB")

	wallTime = newBarChart("Wall-clock time, us",
		[]string{"STW Sweep Termination", "Concurrent Mark & Swap", "STW Mark Termination"})
	cpuTime = newBarChart("CPU time, us",
		[]string{"STW Sweep Termination", "Concurrent Mark & Swap", "STW Mark Termination"})

	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(10, 0, gcPercent),
			termui.NewCol(2, 0, gcRate)),
		termui.NewRow(
			termui.NewCol(12, 0, liveHeap)),
		termui.NewRow(
			termui.NewCol(12, 0, goalHeap)),
		termui.NewRow(
			termui.NewCol(6, 0, wallTime),
			termui.NewCol(6, 0, cpuTime)))

	termui.Body.Align()

	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/feed", func(e termui.Event) {
		if data, ok := e.Data.(gcInfo); ok {
			refreshGraphs(data)

		}
	})

	render()

	go sendEvents()

	go refreshGCSummary()

	termui.Loop()
}
<commit_msg>Decrease refresh interval to 2 seconds<commit_after>package main

import (
	"strconv"
	"sync"
	"time"

	"github.com/gizak/termui"
)

const (
	refreshInterval = 2
)

var (
	dataMutex, renderMutex sync.Mutex
	gcCounter, stwTime     int
	gcPercent              *termui.Gauge
	gcRate                 *termui.Par
	liveHeap, goalHeap     *termui.LineChart
	wallTime, cpuTime      *termui.BarChart
)

func render() {
	renderMutex.Lock()
	defer renderMutex.Unlock()
	termui.Render(termui.Body)
}

func refreshGCSummary() {
	ticker := time.NewTicker(refreshInterval * time.Second)

	for range ticker.C {
		dataMutex.Lock()

		gcRate.Text = strconv.Itoa(gcCounter / refreshInterval)
		gcPercent.Percent = 100 * stwTime / refreshInterval / 1e6

		gcCounter = 0
		stwTime = 0

		dataMutex.Unlock()
	}
}

func refreshGraphs(data gcInfo) {
	liveHeap.Data = append(liveHeap.Data[1:], data.size.live)
	goalHeap.Data = append(goalHeap.Data[1:], data.size.goal)

	wallTime.Data = []int{
		data.wallTime.sweepTermination,
		data.wallTime.markAndSwap,
		data.wallTime.markTermination,
	}
	cpuTime.Data = []int{
		data.cpuTime.sweepTermination,
		data.cpuTime.markAndSwap,
		data.cpuTime.markTermination,
	}

	dataMutex.Lock()
	gcCounter++
	stwTime += data.wallTime.sweepTermination
	stwTime += data.wallTime.markTermination
	dataMutex.Unlock()

	render()
}

func sendEvents() {
	for data := range readStdin() {
		termui.SendCustomEvt("/feed", data)
	}
}

func main() {
	if err := termui.Init(); err != nil {
		panic(err)
	}
	defer termui.Close()

	gcPercent = newGauge("Percentage of Time Spent in GC")
	gcRate = newPar("GC Events per Second")

	liveHeap = newLineChart("Live heap size, MB")
	goalHeap = newLineChart("Goal heap size, MB")

	wallTime = newBarChart("Wall-clock time, us",
		[]string{"STW Sweep Termination", "Concurrent Mark & Swap", "STW Mark Termination"})
	cpuTime = newBarChart("CPU time, us",
		[]string{"STW Sweep Termination", "Concurrent Mark & Swap", "STW Mark Termination"})

	termui.Body.AddRows(
		termui.NewRow(
			termui.NewCol(10, 0, gcPercent),
			termui.NewCol(2, 0, gcRate)),
		termui.NewRow(
			termui.NewCol(12, 0, liveHeap)),
		termui.NewRow(
			termui.NewCol(12, 0, goalHeap)),
		termui.NewRow(
			termui.NewCol(6, 0, wallTime),
			termui.NewCol(6, 0, cpuTime)))

	termui.Body.Align()

	termui.Handle("/sys/kbd/q", func(termui.Event) {
		termui.StopLoop()
	})

	termui.Handle("/feed", func(e termui.Event) {
		if data, ok := e.Data.(gcInfo); ok {
			refreshGraphs(data)

		}
	})

	render()

	go sendEvents()

	go refreshGCSummary()

	termui.Loop()
}
<|endoftext|>