<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"

	home "github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
)

var privateKey []byte
var passphrase []byte
var publicKey []byte

var Version string
var BuildTime string
var Build string

var RuntimeArgs struct {
	Passphrase    string
	ImportFile    string
	ExportFile    string
	SSHKey        string // path to key, usually "~/.ssh/id_rsa"
	WorkingPath   string // main path, usually "~/.sdees/"
	FullPath      string // path with working file, usuallly "~/.sdees/notes.txt/"
	TempPath      string // usually "~/.sdees/temp/"
	SdeesDir      string // name of sdees dir, like ".sdees"
	ServerFileSet map[string]bool
	Debug         bool
	EditWhole     bool
	EditLocally   bool
	ListFiles     bool
	UpdateSdees   bool
}

var ConfigArgs struct {
	WorkingFile string
	ServerHost  string
	ServerPort  string
	ServerUser  string
	SdeesDir    string
}

func main() {
	RuntimeArgs.SdeesDir = ".sdeesgo"
	fmt.Println(Version, Build, BuildTime)
	app := cli.NewApp()
	app.Name = "sdees"
	app.Version = Version + " " + Build + " " + BuildTime
	app.Usage = "sync, decrypt, edit, encrypt, and sync"
	app.Action = func(c *cli.Context) error {
		// Set the log level
		if RuntimeArgs.Debug == false {
			logger.Level(2)
		} else {
			logger.Level(0)
		}
		// Set the paths
		homeDir, _ := home.Dir()
		RuntimeArgs.WorkingPath = path.Join(homeDir, RuntimeArgs.SdeesDir)
		RuntimeArgs.SSHKey = path.Join(homeDir, ".ssh", "id_rsa")

		// Determine if intialization is needed
		if !exists(RuntimeArgs.WorkingPath) {
			initialize()
		}
		if !exists(path.Join(RuntimeArgs.WorkingPath, "config.json")) {
			initialize()
		} else {
			// Load prevoius parameters
			jsonBlob, _ := ioutil.ReadFile(path.Join(RuntimeArgs.WorkingPath, "config.json"))
			err := json.Unmarshal(jsonBlob, &ConfigArgs)
			if err != nil {
				log.Fatal(err)
			}
		}

		workingFile := c.Args().Get(0)
		if len(workingFile) > 0 {
			ConfigArgs.WorkingFile = workingFile
		}

		// Save current config parameters
		b, err := json.Marshal(ConfigArgs)
		if err != nil {
			log.Println(err)
		}
		ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

		RuntimeArgs.FullPath = path.Join(RuntimeArgs.WorkingPath, ConfigArgs.WorkingFile)
		if !exists(RuntimeArgs.FullPath) {
			err := os.MkdirAll(RuntimeArgs.FullPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		RuntimeArgs.TempPath = path.Join(RuntimeArgs.WorkingPath, "temp")
		if !exists(RuntimeArgs.TempPath) {
			err := os.MkdirAll(RuntimeArgs.TempPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		// Run Importing/Exporting
		if len(RuntimeArgs.ImportFile) > 0 {
			importFile(RuntimeArgs.ImportFile)
			os.Exit(1)
		}
		if len(RuntimeArgs.ExportFile) > 0 {
			exportFile(RuntimeArgs.ExportFile)
			os.Exit(1)
		}

		run()
		return nil
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "import",
			Usage:       "Import text from `FILE`",
			Destination: &RuntimeArgs.ImportFile,
		},
		cli.StringFlag{
			Name:        "export",
			Usage:       "Export text from `FILE`",
			Destination: &RuntimeArgs.ExportFile,
		},
		cli.BoolFlag{
			Name:        "edit, e",
			Usage:       "Edit whole document",
			Destination: &RuntimeArgs.EditWhole,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Turn on debug mode",
			Destination: &RuntimeArgs.Debug,
		},
		cli.BoolFlag{
			Name:        "local, l",
			Usage:       "Work locally",
			Destination: &RuntimeArgs.EditLocally,
		},
		cli.BoolFlag{
			Name:        "update, u",
			Usage:       "Update sdees",
			Destination: &RuntimeArgs.UpdateSdees,
		},
		cli.BoolFlag{
			Name:        "list, ls",
			Usage:       "List available files",
			Destination: &RuntimeArgs.ListFiles,
		},
	}
	app.Run(os.Args)
}

func initialize() {
	// Make directory
	err := os.MkdirAll(RuntimeArgs.WorkingPath, 0711)
	if err != nil {
		log.Println("Error creating directory")
		log.Println(err)
		return
	}
	fmt.Print("Enter server address (default: localhost): ")
	fmt.Scanln(&ConfigArgs.ServerHost)
	if len(ConfigArgs.ServerHost) == 0 {
		ConfigArgs.ServerHost = "localhost"
	}

	currentUser, _ := user.Current()
	fmt.Printf("Enter server user (default: %s): ", currentUser.Username)
	fmt.Scanln(&ConfigArgs.ServerUser)
	if len(ConfigArgs.ServerUser) == 0 {
		ConfigArgs.ServerUser = currentUser.Username
	}

	fmt.Printf("Enter server port (default: %s): ", "22")
	fmt.Scanln(&ConfigArgs.ServerPort)
	if len(ConfigArgs.ServerPort) == 0 {
		ConfigArgs.ServerPort = "22"
	}

	fmt.Printf("Enter new file (default: %s): ", "notes.txt")
	fmt.Scanln(&ConfigArgs.WorkingFile)
	if len(ConfigArgs.WorkingFile) == 0 {
		ConfigArgs.WorkingFile = "notes.txt"
	}

	b, err := json.Marshal(ConfigArgs)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

}
<commit_msg>Added -ls functionality<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path"

	home "github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
)

var privateKey []byte
var passphrase []byte
var publicKey []byte

var Version string
var BuildTime string
var Build string

var RuntimeArgs struct {
	Passphrase    string
	ImportFile    string
	ExportFile    string
	SSHKey        string // path to key, usually "~/.ssh/id_rsa"
	WorkingPath   string // main path, usually "~/.sdees/"
	FullPath      string // path with working file, usuallly "~/.sdees/notes.txt/"
	TempPath      string // usually "~/.sdees/temp/"
	SdeesDir      string // name of sdees dir, like ".sdees"
	ServerFileSet map[string]bool
	Debug         bool
	EditWhole     bool
	EditLocally   bool
	ListFiles     bool
	UpdateSdees   bool
}

var ConfigArgs struct {
	WorkingFile string
	ServerHost  string
	ServerPort  string
	ServerUser  string
	SdeesDir    string
}

func main() {
	RuntimeArgs.SdeesDir = ".sdeesgo"
	fmt.Println(Version, Build, BuildTime)
	app := cli.NewApp()
	app.Name = "sdees"
	app.Version = Version + " " + Build + " " + BuildTime
	app.Usage = "sync, decrypt, edit, encrypt, and sync"
	app.Action = func(c *cli.Context) error {
		// Set the log level
		if RuntimeArgs.Debug == false {
			logger.Level(2)
		} else {
			logger.Level(0)
		}
		// Set the paths
		homeDir, _ := home.Dir()
		RuntimeArgs.WorkingPath = path.Join(homeDir, RuntimeArgs.SdeesDir)
		RuntimeArgs.SSHKey = path.Join(homeDir, ".ssh", "id_rsa")

		// Determine if intialization is needed
		if !exists(RuntimeArgs.WorkingPath) {
			initialize()
		}
		if !exists(path.Join(RuntimeArgs.WorkingPath, "config.json")) {
			initialize()
		} else {
			// Load prevoius parameters
			jsonBlob, _ := ioutil.ReadFile(path.Join(RuntimeArgs.WorkingPath, "config.json"))
			err := json.Unmarshal(jsonBlob, &ConfigArgs)
			if err != nil {
				log.Fatal(err)
			}
		}

		workingFile := c.Args().Get(0)
		if len(workingFile) > 0 {
			ConfigArgs.WorkingFile = workingFile
		}

		// Save current config parameters
		b, err := json.Marshal(ConfigArgs)
		if err != nil {
			log.Println(err)
		}
		ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

		RuntimeArgs.FullPath = path.Join(RuntimeArgs.WorkingPath, ConfigArgs.WorkingFile)
		if !exists(RuntimeArgs.FullPath) {
			err := os.MkdirAll(RuntimeArgs.FullPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		RuntimeArgs.TempPath = path.Join(RuntimeArgs.WorkingPath, "temp")
		if !exists(RuntimeArgs.TempPath) {
			err := os.MkdirAll(RuntimeArgs.TempPath, 0711)
			if err != nil {
				log.Fatal(err)
			}
		}

		// Run Importing/Exporting
		if len(RuntimeArgs.ImportFile) > 0 {
			importFile(RuntimeArgs.ImportFile)
			os.Exit(1)
		}
		if len(RuntimeArgs.ExportFile) > 0 {
			exportFile(RuntimeArgs.ExportFile)
			os.Exit(1)
		}

		if RuntimeArgs.ListFiles {
			fmt.Println("Available files:\n")
			for i, f := range listFiles() {
				fmt.Printf("%d) %s\n", i, f)
			}
			fmt.Print("\n")
			os.Exit(1)
		}
		// run main app (run.go)
		run()
		return nil
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "import",
			Usage:       "Import text from `FILE`",
			Destination: &RuntimeArgs.ImportFile,
		},
		cli.StringFlag{
			Name:        "export",
			Usage:       "Export text from `FILE`",
			Destination: &RuntimeArgs.ExportFile,
		},
		cli.BoolFlag{
			Name:        "edit, e",
			Usage:       "Edit whole document",
			Destination: &RuntimeArgs.EditWhole,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Turn on debug mode",
			Destination: &RuntimeArgs.Debug,
		},
		cli.BoolFlag{
			Name:        "local, l",
			Usage:       "Work locally",
			Destination: &RuntimeArgs.EditLocally,
		},
		cli.BoolFlag{
			Name:        "update, u",
			Usage:       "Update sdees",
			Destination: &RuntimeArgs.UpdateSdees,
		},
		cli.BoolFlag{
			Name:        "list, ls",
			Usage:       "List available files",
			Destination: &RuntimeArgs.ListFiles,
		},
	}
	app.Run(os.Args)
}

func initialize() {
	// Make directory
	err := os.MkdirAll(RuntimeArgs.WorkingPath, 0711)
	if err != nil {
		log.Println("Error creating directory")
		log.Println(err)
		return
	}
	fmt.Print("Enter server address (default: localhost): ")
	fmt.Scanln(&ConfigArgs.ServerHost)
	if len(ConfigArgs.ServerHost) == 0 {
		ConfigArgs.ServerHost = "localhost"
	}

	currentUser, _ := user.Current()
	fmt.Printf("Enter server user (default: %s): ", currentUser.Username)
	fmt.Scanln(&ConfigArgs.ServerUser)
	if len(ConfigArgs.ServerUser) == 0 {
		ConfigArgs.ServerUser = currentUser.Username
	}

	fmt.Printf("Enter server port (default: %s): ", "22")
	fmt.Scanln(&ConfigArgs.ServerPort)
	if len(ConfigArgs.ServerPort) == 0 {
		ConfigArgs.ServerPort = "22"
	}

	fmt.Printf("Enter new file (default: %s): ", "notes.txt")
	fmt.Scanln(&ConfigArgs.WorkingFile)
	if len(ConfigArgs.WorkingFile) == 0 {
		ConfigArgs.WorkingFile = "notes.txt"
	}

	b, err := json.Marshal(ConfigArgs)
	if err != nil {
		log.Println(err)
	}
	ioutil.WriteFile(path.Join(RuntimeArgs.WorkingPath, "config.json"), b, 0644)

}
<|endoftext|>


<commit_before>package main

func main() {
	runViper()
}
<commit_msg>Switch to plain main file for master branch<commit_after>package main

import "fmt"

func main() {
	fmt.Println("Hello world!")
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"html/template"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/daaku/go.httpgzip"
	"golang.org/x/crypto/acme/autocert"
)

var templates = template.Must(template.New("").Funcs(template.FuncMap{"add": func(a, b int) int { return a + b }}).ParseGlob("./views/*.tmpl"))

func getFiles(folder, fileType string) []string {
	files, err := ioutil.ReadDir(folder)
	if err != nil {
		panic(err)
	}
	var templateList []string
	for _, file := range files {
		if strings.HasSuffix(file.Name(), fileType) {
			templateList = append(templateList, folder+file.Name())
		}
	}
	return templateList
}

type Keyboards struct {
	Keyboards map[string]string
}

func keyboardHandler(w http.ResponseWriter, r *http.Request) {
	keyboards := getFiles("./static/keyboards/", ".jpg")
	matchedBoards := Keyboards{make(map[string]string)}
	for _, keyboard := range keyboards {
		dir, file := path.Split(keyboard)
		matchedBoards.Keyboards[path.Join("/", dir, file)] = path.Join("/", dir, "thumbs", file)
	}
	if err := templates.ExecuteTemplate(w, "keyboards.tmpl", matchedBoards); err != nil {
		log.Println(err)
	}
}

func serveStatic(filename string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=31536000")
		http.ServeFile(w, r, filename)
	}
}

func CatchPanic(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Recovered from panic: %v", r)
				http.Error(w, "Something went wrong!", http.StatusInternalServerError)
			}
		}()

		handler.ServeHTTP(w, r)
	})
}

func RedirectToHTTPS(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		host, _, err := net.SplitHostPort(r.RemoteAddr)
		if err != nil {
			http.Redirect(w, r, "https://sadbox.org"+r.RequestURI, http.StatusMovedPermanently)
			return
		}

		ip := net.ParseIP(host)
		if ip == nil {
			http.Redirect(w, r, "https://sadbox.org"+r.RequestURI, http.StatusMovedPermanently)
			return
		}

		if !ip.IsLoopback() {
			http.Redirect(w, r, "https://sadbox.org"+r.RequestURI, http.StatusMovedPermanently)
			return
		}

		handler.ServeHTTP(w, r)
	})
}

func AddHeaders(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=120")
		w.Header().Set("Strict-Transport-Security", "max-age=31536000")
		handler.ServeHTTP(w, r)
	})
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteHost := r.Header.Get("X-Forwarded-For")
		if remoteHost == "" {
			remoteHost = r.RemoteAddr
		}
		log.Printf("%s %s %s", remoteHost, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	log.Println("Starting sadbox.org")

	geekhack, err := NewGeekhack()
	if err != nil {
		log.Fatal(err)
	}
	defer geekhack.db.Close()

	// These files have to be here
	http.HandleFunc("/favicon.ico", serveStatic("./static/favicon.ico"))
	http.HandleFunc("/sitemap.xml", serveStatic("./static/sitemap.xml"))
	http.HandleFunc("/robots.txt", serveStatic("./static/robots.txt"))
	http.HandleFunc("/humans.txt", serveStatic("./static/humans.txt"))
	http.HandleFunc("/static/jquery.min.js", serveStatic("./vendor/jquery.min.js"))
	http.HandleFunc("/static/highcharts.js", serveStatic("./vendor/highcharts.js"))
	http.HandleFunc("/static/bootstrap.min.css", serveStatic("./vendor/bootstrap.min.css"))
	http.HandleFunc("/mu-fea81392-5746180a-5e50de1d-fb4a7b05.txt", serveStatic("./static/blitz.txt"))

	// The plain-jane stuff I serve up
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}

		if err := templates.ExecuteTemplate(w, "main.tmpl", nil); err != nil {
			log.Println(err)
		}
	})
	http.HandleFunc("/keyboards", keyboardHandler)

	// Geekhack stats! the geekhack struct will handle the routing to sub-things
	http.Handle("/geekhack/", geekhack)
	// Redirects to the right URL so I don't break old links
	http.Handle("/ghstats", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))
	http.Handle("/geekhack", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))

	// The rest of the static files
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))

	localhost_znc, err := url.Parse("http://127.0.0.1:6698")
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/znc/", httputil.NewSingleHostReverseProxy(localhost_znc))
	http.Handle("/znc", http.RedirectHandler("/znc/", http.StatusMovedPermanently))

	servemux := httpgzip.NewHandler(
		CatchPanic(
			Log(
				AddHeaders(http.DefaultServeMux))))

	go func() {
		log.Fatal(http.ListenAndServe(":http", RedirectToHTTPS(servemux)))
	}()

	m := autocert.Manager{
		Prompt:     autocert.AcceptTOS,
		Cache:      autocert.DirCache("/home/sadbox-web/cert-cache"),
		HostPolicy: autocert.HostWhitelist("www.sadbox.org", "sadbox.org", "www.sadbox.es", "sadbox.es"),
	}

	tlsconfig := &tls.Config{
		MinVersion:               tls.VersionTLS10, // Disable SSLv3
		PreferServerCipherSuites: true,
		GetCertificate:           m.GetCertificate,
	}

	server := &http.Server{Addr: ":https", Handler: servemux, TLSConfig: tlsconfig}
	log.Fatal(server.ListenAndServeTLS("", ""))
}
<commit_msg>Add New domains and redirect to them properly<commit_after>package main

import (
	"crypto/tls"
	"html/template"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/daaku/go.httpgzip"
	"golang.org/x/crypto/acme/autocert"
)

var templates = template.Must(template.New("").Funcs(template.FuncMap{"add": func(a, b int) int { return a + b }}).ParseGlob("./views/*.tmpl"))

func getFiles(folder, fileType string) []string {
	files, err := ioutil.ReadDir(folder)
	if err != nil {
		panic(err)
	}
	var templateList []string
	for _, file := range files {
		if strings.HasSuffix(file.Name(), fileType) {
			templateList = append(templateList, folder+file.Name())
		}
	}
	return templateList
}

type Keyboards struct {
	Keyboards map[string]string
}

func keyboardHandler(w http.ResponseWriter, r *http.Request) {
	keyboards := getFiles("./static/keyboards/", ".jpg")
	matchedBoards := Keyboards{make(map[string]string)}
	for _, keyboard := range keyboards {
		dir, file := path.Split(keyboard)
		matchedBoards.Keyboards[path.Join("/", dir, file)] = path.Join("/", dir, "thumbs", file)
	}
	if err := templates.ExecuteTemplate(w, "keyboards.tmpl", matchedBoards); err != nil {
		log.Println(err)
	}
}

func serveStatic(filename string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=31536000")
		http.ServeFile(w, r, filename)
	}
}

func CatchPanic(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Recovered from panic: %v", r)
				http.Error(w, "Something went wrong!", http.StatusInternalServerError)
			}
		}()

		handler.ServeHTTP(w, r)
	})
}

func SendToHTTPS(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
}

func RedirectToHTTPS(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		host, _, err := net.SplitHostPort(r.RemoteAddr)
		if err != nil {
			SendToHTTPS(w, r)
			return
		}

		ip := net.ParseIP(host)
		if ip == nil {
			SendToHTTPS(w, r)
			return
		}

		if !ip.IsLoopback() {
			SendToHTTPS(w, r)
			return
		}

		handler.ServeHTTP(w, r)
	})
}

func AddHeaders(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Cache-Control", "max-age=120")
		w.Header().Set("Strict-Transport-Security", "max-age=31536000")
		handler.ServeHTTP(w, r)
	})
}

func Log(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remoteHost := r.Header.Get("X-Forwarded-For")
		if remoteHost == "" {
			remoteHost = r.RemoteAddr
		}
		log.Printf("%s %s %s", remoteHost, r.Method, r.URL)
		handler.ServeHTTP(w, r)
	})
}

func main() {
	log.Println("Starting sadbox.org")

	geekhack, err := NewGeekhack()
	if err != nil {
		log.Fatal(err)
	}
	defer geekhack.db.Close()

	// These files have to be here
	http.HandleFunc("/favicon.ico", serveStatic("./static/favicon.ico"))
	http.HandleFunc("/sitemap.xml", serveStatic("./static/sitemap.xml"))
	http.HandleFunc("/robots.txt", serveStatic("./static/robots.txt"))
	http.HandleFunc("/humans.txt", serveStatic("./static/humans.txt"))
	http.HandleFunc("/static/jquery.min.js", serveStatic("./vendor/jquery.min.js"))
	http.HandleFunc("/static/highcharts.js", serveStatic("./vendor/highcharts.js"))
	http.HandleFunc("/static/bootstrap.min.css", serveStatic("./vendor/bootstrap.min.css"))
	http.HandleFunc("/mu-fea81392-5746180a-5e50de1d-fb4a7b05.txt", serveStatic("./static/blitz.txt"))

	// The plain-jane stuff I serve up
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}

		if err := templates.ExecuteTemplate(w, "main.tmpl", nil); err != nil {
			log.Println(err)
		}
	})
	http.HandleFunc("/keyboards", keyboardHandler)

	// Geekhack stats! the geekhack struct will handle the routing to sub-things
	http.Handle("/geekhack/", geekhack)
	// Redirects to the right URL so I don't break old links
	http.Handle("/ghstats", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))
	http.Handle("/geekhack", http.RedirectHandler("/geekhack/", http.StatusMovedPermanently))

	// The rest of the static files
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static/"))))

	localhost_znc, err := url.Parse("http://127.0.0.1:6698")
	if err != nil {
		log.Fatal(err)
	}
	http.Handle("/znc/", httputil.NewSingleHostReverseProxy(localhost_znc))
	http.Handle("/znc", http.RedirectHandler("/znc/", http.StatusMovedPermanently))

	servemux := httpgzip.NewHandler(
		CatchPanic(
			Log(
				AddHeaders(http.DefaultServeMux))))

	go func() {
		log.Fatal(http.ListenAndServe(":http", RedirectToHTTPS(servemux)))
	}()

	m := autocert.Manager{
		Prompt: autocert.AcceptTOS,
		Cache:  autocert.DirCache("/home/sadbox-web/cert-cache"),
		HostPolicy: autocert.HostWhitelist(
			"www.sadbox.org", "sadbox.org",
			"www.sadbox.es", "sadbox.es",
			"www.geekwhack.org", "geekwhack.org"),
	}

	tlsconfig := &tls.Config{
		MinVersion:               tls.VersionTLS10, // Disable SSLv3
		PreferServerCipherSuites: true,
		GetCertificate:           m.GetCertificate,
	}

	server := &http.Server{Addr: ":https", Handler: servemux, TLSConfig: tlsconfig}
	log.Fatal(server.ListenAndServeTLS("", ""))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/coreos/go-etcd/etcd"
	_ "github.com/davecgh/go-spew/spew"
	"github.com/jessevdk/go-flags"
	"github.com/kelseyhightower/envconfig"
	"github.com/rcrowley/go-metrics"
	"github.com/rcrowley/go-metrics/librato"
	"log"
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	// DefaultInterval is the check check interval for a url specified in seconds
	DefaultInterval int = 15

	// DefaultSplay is the rand splay to introduce on checks so we don't flood
	DefaultSplay int = 5

	// DefaultAlertLevel is the level we alert at when no level is specified
	DefaultAlertLevel string = "WARN"
)

type Options struct {
	Etcd   []string `short:"e" long:"etcd" description:"Etcd Server url. Multiple servers can be specified" default:"http://localhost:4001"`
	Prefix string   `short:"p" long:"prefix" description:"the prefix to use in etcd for storing check urls" default:"/urlmon"`
	User   string   `short:"u" long:"user" description:"librato user"`
	Token  string   `short:"t" long:"token"  description:"librato token"`
	Port   int      `short:"P" long:"port"  description:"The port to start the status interface on" default:"9731"`
	Sensu  string   `short:"s" long:"sensu" description:"Sensu client address" default:"localhost:3030"`
}

type Check struct {
	Id           string
	URL          *url.URL
	Content      string
	Level        string
	ContentRegex *regexp.Regexp
	Interval     int
	Splay        int
	Registry     metrics.Registry
	shutdown     bool
}

type SensuEvent struct {
	Name     string   `json:name`
	Handlers []string `json:handlers`
	Output   string   `json:output`
	Status   int      `json:status`
}

type LazyResponse map[string]interface{}

var (
	Checks []Check
	opts   Options
)

func (c *Check) setupInterval() {
	if c.Interval <= 0 {
		c.Interval = DefaultInterval
	}

	if c.Splay <= 0 {
		c.Splay = DefaultSplay
	}

	// build up splay and add to interval
	c.Interval += rand.Intn(c.Splay)
}

// reportStatus reports if
func (c *Check) reportStatus(status int, msg string) {
	s := "Success:"
	if status != 0 {
		s = "Fail:"
	}
	log.Println(s, c.Id, c.URL.String(), msg)

	// for now handler is hardcode TODO: move it to default/param/env
	event := SensuEvent{
		Name:     c.URL.String(),
		Handlers: []string{"hipchat"},
		Output:   msg,
		Status:   status,
	}

	go event.send()
}

// Monitor sets up the monitoring loop
func (c *Check) Monitor() {
	// build the splay/random timing into the interval
	c.setupInterval()

	// setup the guage
	g := metrics.NewGauge()

	metrics.Register(fmt.Sprintf("urlmon.request.%s", c.Id), g)
	// loop for shutdown and spaly/sleep
	for c.shutdown != true {
		// we sleep first here so that on startup we don't overwhelm
		s := time.Duration(c.Interval) * time.Second
		time.Sleep(s)

		// time.Since reports in nanoseocnds
		start := time.Now()
		r, err := http.Get(c.URL.String())
		g.Update(int64(time.Since(start)))
		if err != nil {
			c.reportStatus(1, err.Error())
		} else {
			r.Body.Close()
			c.reportStatus(0, r.Status)
		}
	}
}

// easy way to signal the monitor to shutdown
func (c *Check) Shutdown() {

	c.shutdown = true
}

// String Adds stringer interface to the lazy response
func (r LazyResponse) String() (s string) {
	b, err := json.MarshalIndent(r, "", "  ")
	if err != nil {
		s = ""
		return
	}
	s = string(b)
	return
}

// send the sensu event to the local sensu port
func (e *SensuEvent) send() {
	conn, err := net.Dial("tcp", opts.Sensu)
	if err != nil {
		log.Println("Error connecting to sensu client socket.", err.Error())
		return
	}
	defer conn.Close()

	j, err := json.Marshal(e)
	if err != nil {
		log.Println("Error marshaling event data.", err.Error())
		return
	}
	fmt.Fprintf(conn, string(j))
}

// libratoMetrics starts the reporting metrics on this check to librato
func libratoMetrics() {
	host, err := os.Hostname()
	if err != nil {
		host = "localhost"
	}

	// start the metrics collector should be per-check
	log.Println("starting metrics")
	librato.Librato(metrics.DefaultRegistry,
		60*time.Second, // interval
		opts.User,      // account owner email address
		opts.Token,     // Librato API token
		// This should be per check I think
		host,             // source
		[]float64{95},    // precentiles to send
		time.Millisecond, // time unit
	)
}

// valueStr Converts a string to an int where a blank string or errvalue returns a 0
// This is a helper mostly for creating a Check where the interval or splay may be an empty string.
func valueStr(value string) int {
	v, err := strconv.Atoi(value)
	if err != nil {
		v = 0
	}
	return v
}

// createCheck populates check struct with data from etcd check
func createCheck(node *etcd.Node) (*Check, error) {
	// create a check
	c := Check{Id: path.Base(node.Key)}
	for _, child := range node.Nodes {
		log.Printf("  - %s", path.Base(child.Key))
		switch strings.ToUpper(path.Base(child.Key)) {
		case "URL":
			u, err := url.Parse(child.Value)
			if err != nil {
				log.Fatalf("Url isn't valid for key: %s, %s", node.Key, err.Error())
			}
			c.URL = u
		case "CONTENT":
			c.Content = child.Value
		case "REGEX":
			r, err := regexp.Compile(child.Value)
			if err != nil {
				log.Fatalf("couldn't compile regex for Check: %s, %s", node.Key, err.Error())
			}
			c.ContentRegex = r
		case "LEVEL":
			l := strings.ToUpper(child.Value)
			if l == "" {
				l = DefaultAlertLevel
			}
			c.Level = l
		case "SPLAY":
			c.Splay = valueStr(child.Value)
		case "INTERVAL":
			c.Interval = valueStr(child.Value)
		}
	}

	// set defaults
	if c.Splay == 0 {
		c.Splay = DefaultSplay
	}
	if c.Interval == 0 {
		c.Interval = DefaultInterval
	}
	if c.Level == "" {
		c.Level = DefaultAlertLevel
	}

	// BUG: Checks may be malformed in various ways, createCheck needs to implment more validations before returning the check
	return &c, nil
}

// loadChecks reads etcd popilates Checks, and starts their monitor
func loadChecks(client *etcd.Client) {
	// create etcd watch chan for reparsing config
	resp, err := client.Get(fmt.Sprintf("%s/checks", opts.Prefix), true, true)
	if err != nil {
		log.Fatalf("Problem fetching Checks from etcd: %s", err)
	}

	for _, n := range Checks {
		// signal that monitor to shutdown
		n.Shutdown()
	}
	// this clears the slice. we will have to realloc that mem, but gc should get round to it.
	Checks = nil

	for _, n := range resp.Node.Nodes {
		// these top level nodes should be a directory
		if !n.Dir {
			log.Printf("Error loading config %s is not a dir, skipping", n.Key)
			continue
		}

		log.Printf("Loading: %s: %s\n", n.Key, n.Value)
		c, err := createCheck(n)
		if err != nil {
			log.Println("Failed to create check, skipping: ", n.Key, err)
			continue
		}
		// start monitoring this check
		go c.Monitor()
		Checks = append(Checks, *c)
	}
}

// Create our Etcd Dir structure
func setupEtcd(client *etcd.Client) {
	for _, path := range []string{opts.Prefix, fmt.Sprintf("%s/checks", opts.Prefix)} {
		if _, err := client.Get(path, false, false); err != nil {
			log.Printf("Creating dir in etcd: %s ", path)
			if _, err := client.CreateDir(path, 0); err != nil {
				log.Fatalf("Couldn't create etcd dir: %s, %s ", err)
			}
		}
	}
}

func statusHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, LazyResponse{"checkdata": Checks})
}

func main() {
	err := envconfig.Process("urlmon", &opts)
	if err != nil {
		log.Fatalf("Error parsing ENV vars %s", err)
	}

	if _, err := flags.Parse(&opts); err != nil {
		if err.(*flags.Error).Type == flags.ErrHelp {
			os.Exit(0)
		} else {
			log.Println(err.Error())
			os.Exit(1)
		}
	}

	etcdClient := etcd.NewClient(opts.Etcd)
	setupEtcd(etcdClient)

	watchChan := make(chan *etcd.Response)
	// setup recursive watch of the keyspace
	go etcdClient.Watch(opts.Prefix, 0, true, watchChan, nil)

	// start the metrics
	if opts.User != "" && opts.Token != "" {
		go libratoMetrics()
	}

	loadChecks(etcdClient)

	http.HandleFunc("/status", statusHandler)
	go http.ListenAndServe(fmt.Sprintf(":%d", opts.Port), nil)
	log.Printf("Status server up and running on ':%d'", opts.Port)

	// loop and reload checks when etcd changes
	for {
		r := <-watchChan
		log.Printf("Reloading checks from etcd, triggered by '%s' on '%s' with value: '%s' ", r.Action, r.Node.Key, r.Node.Value)
		loadChecks(etcdClient)
	}
}
<commit_msg>Shipit!<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/coreos/go-etcd/etcd"
	_ "github.com/davecgh/go-spew/spew"
	"github.com/jessevdk/go-flags"
	"github.com/kelseyhightower/envconfig"
	"github.com/rcrowley/go-metrics"
	"github.com/rcrowley/go-metrics/librato"
	"log"
	"math/rand"
	"net"
	"net/http"
	_ "net/http/pprof"
	"net/url"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	// DefaultInterval is the check check interval for a url specified in seconds
	DefaultInterval int = 15

	// DefaultSplay is the rand splay to introduce on checks so we don't flood
	DefaultSplay int = 5

	// DefaultAlertLevel is the level we alert at when no level is specified
	DefaultAlertLevel string = "WARN"
)

type Options struct {
	Etcd     string `short:"e" long:"etcd" description:"Etcd Server url. Comma separate multiple servers" default:"http://localhost:4001"`
	Prefix   string `short:"p" long:"prefix" description:"the prefix to use in etcd for storing check urls" default:"/urlmon"`
	User     string `short:"u" long:"user" description:"librato user"`
	Token    string `short:"t" long:"token"  description:"librato token"`
	Port     int    `short:"P" long:"port"  description:"The port to start the status interface on" default:"9731"`
	Sensu    string `short:"s" long:"sensu" description:"Sensu client address" default:"localhost:3030"`
	Handlers string `short:"H" long:"handlers" description:"Sensu handler to use for alert message. comma separatemultiples" default:"hipchat"`
}

type Check struct {
	Id           string
	URL          *url.URL
	Content      string
	Level        string
	ContentRegex *regexp.Regexp
	Interval     int
	Splay        int
	Registry     metrics.Registry
	shutdown     chan struct{}
}

type SensuEvent struct {
	Name     string   `json:"name"`
	Handlers []string `json:"handlers"`
	Output   string   `json:"output"`
	Status   int      `json:"status"`
}

type LazyResponse map[string]interface{}

var (
	Checks []Check
	opts   Options
)

func (c *Check) setupInterval() {
	if c.Interval <= 0 {
		c.Interval = DefaultInterval
	}

	if c.Splay <= 0 {
		c.Splay = DefaultSplay
	}

	// build up splay and add to interval
	c.Interval += rand.Intn(c.Splay)
}

// reportStatus reports if
func (c *Check) reportStatus(status int, msg string) {
	s := "Success:"
	if status != 0 {
		s = "Fail:"
	}
	log.Println(s, c.Id, c.URL.String(), msg)

	// for now handler is hardcode TODO: move it to default/param/env
	event := SensuEvent{
		Name:     c.Id,
		Output:   fmt.Sprintf("%s::%s", msg, c.URL),
		Handlers: strings.Split(opts.Handlers, ","),
		Status:   status,
	}

	event.send()
}

// Monitor sets up the monitoring loop
func (c *Check) Monitor() {
	// build the splay/random timing into the interval
	c.setupInterval()

	// setup the guage
	g := metrics.NewGauge()

	metrics.Register(fmt.Sprintf("urlmon.request.%s", c.Id), g)
	// loop for shutdown and spaly/sleep
	for {
		select {
		case <-c.shutdown:
			log.Printf("%s Shutdown", c.Id)
			return
		default:
			// we sleep first here so that on startup we don't overwhelm
			s := time.Duration(c.Interval) * time.Second
			time.Sleep(s)

			// time.Since reports in nanoseocnds
			start := time.Now()
			r, err := http.Get(c.URL.String())
			g.Update(int64(time.Since(start)))
			if err != nil {
				c.reportStatus(2, err.Error())
			} else {
				r.Body.Close()
				c.reportStatus(0, r.Status)
			}
		}
	}
}

// easy way to signal the monitor to shutdown
func (c *Check) Shutdown() {
	c.shutdown <- struct{}{}
}

// String Adds stringer interface to the lazy response
func (r LazyResponse) String() (s string) {
	b, err := json.MarshalIndent(r, "", "  ")
	if err != nil {
		s = ""
		return
	}
	s = string(b)
	return
}

// send the sensu event to the local sensu port
func (e *SensuEvent) send() {
	conn, err := net.Dial("tcp", opts.Sensu)
	if err != nil {
		log.Println("Error connecting to sensu client socket.", err.Error())
		return
	}
	defer conn.Close()

	j, err := json.Marshal(e)
	if err != nil {
		log.Println("Error marshaling event data.", err.Error())
		return
	}
	fmt.Fprintf(conn, string(j))
}

// libratoMetrics starts the reporting metrics on this check to librato
func libratoMetrics() {
	host, err := os.Hostname()
	if err != nil {
		host = "localhost"
	}

	// start the metrics collector should be per-check
	log.Println("starting metrics")
	librato.Librato(metrics.DefaultRegistry,
		60*time.Second, // interval
		opts.User,      // account owner email address
		opts.Token,     // Librato API token
		// This should be per check I think
		host,             // source
		[]float64{95},    // precentiles to send
		time.Millisecond, // time unit
	)
}

// valueStr Converts a string to an int where a blank string or errvalue returns a 0
// This is a helper mostly for creating a Check where the interval or splay may be an empty string.
func valueStr(value string) int {
	v, err := strconv.Atoi(value)
	if err != nil {
		v = 0
	}
	return v
}

// createCheck populates check struct with data from etcd check
func createCheck(node *etcd.Node) (*Check, error) {
	// create a check
	c := Check{Id: path.Base(node.Key)}
	c.shutdown = make(chan struct{}, 1)
	for _, child := range node.Nodes {
		log.Printf("  - %s", path.Base(child.Key))
		switch strings.ToUpper(path.Base(child.Key)) {
		case "URL":
			u, err := url.Parse(child.Value)
			if err != nil {
				log.Printf("Url isn't valid for key: %s, %s", node.Key, err.Error())
				continue
			}
			c.URL = u
		case "CONTENT":
			c.Content = child.Value
		case "REGEX":
			r, err := regexp.Compile(child.Value)
			if err != nil {
				log.Fatalf("couldn't compile regex for Check: %s, %s", node.Key, err.Error())
			}
			c.ContentRegex = r
		case "LEVEL":
			l := strings.ToUpper(child.Value)
			if l == "" {
				l = DefaultAlertLevel
			}
			c.Level = l
		case "SPLAY":
			c.Splay = valueStr(child.Value)
		case "INTERVAL":
			c.Interval = valueStr(child.Value)
		}
	}

	// set defaults
	if c.Splay == 0 {
		c.Splay = DefaultSplay
	}
	if c.Interval == 0 {
		c.Interval = DefaultInterval
	}
	if c.Level == "" {
		c.Level = DefaultAlertLevel
	}
	if c.URL == nil {
		return &c, errors.New("No URL for check")
	}

	// BUG: Checks may be malformed in various ways, createCheck needs to implment more validations before returning the check
	return &c, nil
}

// loadChecks reads etcd popilates Checks, and starts their monitor
func loadChecks(client *etcd.Client) {
	resp, err := client.Get(fmt.Sprintf("%s/checks", opts.Prefix), true, true)
	if err != nil {
		log.Fatalf("Problem fetching Checks from etcd: %s", err)
	}

	for _, n := range Checks {
		// signal that monitor to shutdown
		log.Println("Shutting down ", n.Id)
		n.Shutdown()
	}

	// this clears the slice.
	Checks = nil

	for _, n := range resp.Node.Nodes {
		// these top level nodes should be a directory
		if !n.Dir {
			log.Printf("Error loading config %s is not a dir, skipping", n.Key)
			continue
		}

		log.Printf("Loading: %s: %s\n", n.Key, n.Value)
		c, err := createCheck(n)
		if err != nil {
			log.Println("Failed to create check, skipping: ", n.Key, err)
			continue
		}
		// start monitoring this check
		go c.Monitor()
		Checks = append(Checks, *c)
	}
}

// Create our Etcd Dir structure
func setupEtcd(client *etcd.Client) {
	for _, path := range []string{opts.Prefix, fmt.Sprintf("%s/checks", opts.Prefix)} {
		if _, err := client.Get(path, false, false); err != nil {
			log.Printf("Creating dir in etcd: %s ", path)
			if _, err := client.CreateDir(path, 0); err != nil {
				log.Fatal("Couldn't create etcd dir: ", err)
			}
		}
	}
}

func statusHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, LazyResponse{"checkdata": Checks})
}

func main() {
	err := envconfig.Process("urlmon", &opts)
	if err != nil {
		log.Fatalf("Error parsing ENV vars %s", err)
	}

	if _, err := flags.Parse(&opts); err != nil {
		if err.(*flags.Error).Type == flags.ErrHelp {
			os.Exit(0)
		} else {
			log.Println(err.Error())
			os.Exit(1)
		}
	}

	etcdServers := strings.Split(opts.Etcd, ",")
	etcdClient := etcd.NewClient(etcdServers)
	setupEtcd(etcdClient)

	watchChan := make(chan *etcd.Response)
	// setup recursive watch of the keyspace
	go etcdClient.Watch(opts.Prefix, 0, true, watchChan, nil)

	// start the metrics
	if opts.User != "" && opts.Token != "" {
		go libratoMetrics()
	}

	loadChecks(etcdClient)

	http.HandleFunc("/status", statusHandler)
	go http.ListenAndServe(fmt.Sprintf(":%d", opts.Port), nil)
	log.Printf("Status server up and running on ':%d'", opts.Port)

	// loop and reload checks when etcd changes
	for {
		r := <-watchChan
		log.Printf("Reloading checks from etcd, triggered by '%s' on '%s' with value: '%s' ", r.Action, r.Node.Key, r.Node.Value)
		loadChecks(etcdClient)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	jd "github.com/josephburnett/jd/lib"
	"github.com/josephburnett/jd/web/serve"
)

const version = "HEAD"

var mset = flag.Bool("mset", false, "Arrays as multisets")
var output = flag.String("o", "", "Output file")
var patch = flag.Bool("p", false, "Patch mode")
var port = flag.Int("port", 0, "Serve web UI on port")
var set = flag.Bool("set", false, "Arrays as sets")
var setkeys = flag.String("setkeys", "", "Keys to identify set objects")
var ver = flag.Bool("version", false, "Print version and exit")
var yaml = flag.Bool("yaml", false, "Read and write YAML")

func main() {
	flag.Parse()
	if *ver {
		fmt.Printf("jd version %v\n", version)
		return
	}
	if *port != 0 {
		err := serveWeb(strconv.Itoa(*port))
		if err != nil {
			fmt.Println(err.Error())
		}
		return
	}
	metadata, err := parseMetadata()
	if err != nil {
		log.Fatalf(err.Error())
	}
	var a, b string
	switch len(flag.Args()) {
	case 1:
		a = readFile(flag.Arg(0))
		b = readStdin()
	case 2:
		a = readFile(flag.Arg(0))
		b = readFile(flag.Arg(1))
	default:
		printUsageAndExit()
	}
	if *patch {
		printPatch(a, b, metadata)
	} else {
		printDiff(a, b, metadata)
	}
}

func serveWeb(port string) error {
	if serve.Handle == nil {
		return fmt.Errorf("The web UI wasn't include in this build. Use `make release` to include it.")
	}
	http.HandleFunc("/", serve.Handle)
	log.Printf("Listening on :%v...", port)
	return http.ListenAndServe(":"+port, nil)
}

func parseMetadata() ([]jd.Metadata, error) {
	metadata := make([]jd.Metadata, 0)
	if *set {
		metadata = append(metadata, jd.SET)
	}
	if *mset {
		metadata = append(metadata, jd.MULTISET)
	}
	if *setkeys != "" {
		keys := make([]string, 0)
		ks := strings.Split(*setkeys, ",")
		for _, k := range ks {
			trimmed := strings.TrimSpace(k)
			if trimmed == "" {
				return nil, fmt.Errorf("Invalid set key: %v", k)
			}
			keys = append(keys, trimmed)
		}
		metadata = append(metadata, jd.Setkeys(keys...))
	}
	return metadata, nil
}

func printUsageAndExit() {
	for _, line := range []string{
		``,
		`Usage: jd [OPTION]... FILE1 [FILE2]`,
		`Diff and patch JSON files.`,
		``,
		`Prints the diff of FILE1 and FILE2 to STDOUT.`,
		`When FILE2 is omitted the second input is read from STDIN.`,
		`When patching (-p) FILE1 is a diff.`,
		``,
		`Options:`,
		`  -p        Apply patch FILE1 to FILE2 or STDIN.`,
		`  -o=FILE3  Write to FILE3 instead of STDOUT.`,
		`  -set      Treat arrays as sets.`,
		`  -mset     Treat arrays as multisets (bags).`,
		`  -setkeys  Keys to identify set objects`,
		`  -yaml     Read and write YAML instead of JSON.`,
		`  -port=N   Serve web UI on port N`,
		``,
		`Examples:`,
		`  jd a.json b.json`,
		`  cat b.json | jd a.json`,
		`  jd -o patch a.json b.json; jd patch a.json`,
		`  jd -set a.json b.json`,
		``,
		`Version: ` + version,
		``,
	} {
		fmt.Println(line)
	}
	os.Exit(1)
}

func printDiff(a, b string, metadata []jd.Metadata) {
	var aNode, bNode jd.JsonNode
	var err error
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	if *yaml {
		bNode, err = jd.ReadYamlString(b)
	} else {
		bNode, err = jd.ReadJsonString(b)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	diff := aNode.Diff(bNode, metadata...)
	if *output == "" {
		fmt.Print(diff.Render())
	} else {
		ioutil.WriteFile(*output, []byte(diff.Render()), 0644)
	}
}

func printPatch(p, a string, metadata []jd.Metadata) {
	diff, err := jd.ReadDiffString(p)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var aNode jd.JsonNode
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	bNode, err := aNode.Patch(diff)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var out string
	if *yaml {
		out = bNode.Yaml(metadata...)
	} else {
		out = bNode.Json(metadata...)
	}
	if *output == "" {
		fmt.Print(out)
	} else {
		ioutil.WriteFile(*output, []byte(out), 0644)
	}
}

func readFile(filename string) string {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}

func readStdin() string {
	r := bufio.NewReader(os.Stdin)
	bytes, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}
<commit_msg>Explicitly return exit codes when differences are found.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"

	jd "github.com/josephburnett/jd/lib"
	"github.com/josephburnett/jd/web/serve"
)

const version = "HEAD"

var mset = flag.Bool("mset", false, "Arrays as multisets")
var output = flag.String("o", "", "Output file")
var patch = flag.Bool("p", false, "Patch mode")
var port = flag.Int("port", 0, "Serve web UI on port")
var set = flag.Bool("set", false, "Arrays as sets")
var setkeys = flag.String("setkeys", "", "Keys to identify set objects")
var ver = flag.Bool("version", false, "Print version and exit")
var yaml = flag.Bool("yaml", false, "Read and write YAML")

func main() {
	flag.Parse()
	if *ver {
		fmt.Printf("jd version %v\n", version)
		return
	}
	if *port != 0 {
		err := serveWeb(strconv.Itoa(*port))
		if err != nil {
			fmt.Println(err.Error())
		}
		return
	}
	metadata, err := parseMetadata()
	if err != nil {
		log.Fatalf(err.Error())
	}
	var a, b string
	switch len(flag.Args()) {
	case 1:
		a = readFile(flag.Arg(0))
		b = readStdin()
	case 2:
		a = readFile(flag.Arg(0))
		b = readFile(flag.Arg(1))
	default:
		printUsageAndExit()
	}
	if *patch {
		printPatch(a, b, metadata)
	} else {
		printDiff(a, b, metadata)
	}
}

func serveWeb(port string) error {
	if serve.Handle == nil {
		return fmt.Errorf("The web UI wasn't include in this build. Use `make release` to include it.")
	}
	http.HandleFunc("/", serve.Handle)
	log.Printf("Listening on :%v...", port)
	return http.ListenAndServe(":"+port, nil)
}

func parseMetadata() ([]jd.Metadata, error) {
	metadata := make([]jd.Metadata, 0)
	if *set {
		metadata = append(metadata, jd.SET)
	}
	if *mset {
		metadata = append(metadata, jd.MULTISET)
	}
	if *setkeys != "" {
		keys := make([]string, 0)
		ks := strings.Split(*setkeys, ",")
		for _, k := range ks {
			trimmed := strings.TrimSpace(k)
			if trimmed == "" {
				return nil, fmt.Errorf("Invalid set key: %v", k)
			}
			keys = append(keys, trimmed)
		}
		metadata = append(metadata, jd.Setkeys(keys...))
	}
	return metadata, nil
}

func printUsageAndExit() {
	for _, line := range []string{
		``,
		`Usage: jd [OPTION]... FILE1 [FILE2]`,
		`Diff and patch JSON files.`,
		``,
		`Prints the diff of FILE1 and FILE2 to STDOUT.`,
		`When FILE2 is omitted the second input is read from STDIN.`,
		`When patching (-p) FILE1 is a diff.`,
		``,
		`Options:`,
		`  -p        Apply patch FILE1 to FILE2 or STDIN.`,
		`  -o=FILE3  Write to FILE3 instead of STDOUT.`,
		`  -set      Treat arrays as sets.`,
		`  -mset     Treat arrays as multisets (bags).`,
		`  -setkeys  Keys to identify set objects`,
		`  -yaml     Read and write YAML instead of JSON.`,
		`  -port=N   Serve web UI on port N`,
		``,
		`Examples:`,
		`  jd a.json b.json`,
		`  cat b.json | jd a.json`,
		`  jd -o patch a.json b.json; jd patch a.json`,
		`  jd -set a.json b.json`,
		``,
		`Version: ` + version,
		``,
	} {
		fmt.Println(line)
	}
	os.Exit(1)
}

func printDiff(a, b string, metadata []jd.Metadata) {
	var aNode, bNode jd.JsonNode
	var err error
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	if *yaml {
		bNode, err = jd.ReadYamlString(b)
	} else {
		bNode, err = jd.ReadJsonString(b)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	diff := aNode.Diff(bNode, metadata...)
	if *output == "" {
		str := diff.Render()
		if  str == "" {
			os.Exit(0)
		}
		fmt.Print(str)
		os.Exit(1)
	} else {
		str := diff.Render()
		if str == "" {
			os.Exit(0)
		}
		ioutil.WriteFile(*output, []byte(str), 0644)
		os.Exit(1)
	}
}

func printPatch(p, a string, metadata []jd.Metadata) {
	diff, err := jd.ReadDiffString(p)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var aNode jd.JsonNode
	if *yaml {
		aNode, err = jd.ReadYamlString(a)
	} else {
		aNode, err = jd.ReadJsonString(a)
	}
	if err != nil {
		log.Fatalf(err.Error())
	}
	bNode, err := aNode.Patch(diff)
	if err != nil {
		log.Fatalf(err.Error())
	}
	var out string
	if *yaml {
		out = bNode.Yaml(metadata...)
	} else {
		out = bNode.Json(metadata...)
	}
	if *output == "" {
		if out == "" {
			os.Exit(0)
		}
		fmt.Print(out)
		os.Exit(1)
	} else {
		if out == "" {
			os.Exit(0)
		}
		ioutil.WriteFile(*output, []byte(out), 0644)
		os.Exit(1)
	}
}

func readFile(filename string) string {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}

func readStdin() string {
	r := bufio.NewReader(os.Stdin)
	bytes, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatalf(err.Error())
	}
	return string(bytes)
}
<|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 (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"

	"github.com/ActiveState/tail"
	"github.com/fatih/color"
)

var signalChan = make(chan os.Signal, 1) // channel to catch ctrl-c

func processLine(line string, log logger) string {
	if len(line) == 0 {
		return line
	}
	brokenLine := strings.Split(line, " ")
	for i, s := range brokenLine {
		switch {
		case WordExists(s, log.GoodWords()):
			brokenLine[i] = color.GreenString(s)
		//case WordExists(s, log.GoodLines()):
		case WordExists(s, log.WarnWords()):
			brokenLine[i] = color.YellowString(s)
		case WordExists(s, log.BadLines()):
			color.Red(strings.Join(brokenLine, " "))
		default:
			continue
		}
	}
	return strings.Join(brokenLine, " ")
}

// Pointers to hold the contents of the flag args.
var (
	templateFlag = flag.String("t", "", "template to use for log parsing")
	logFileFlag  = flag.String("l", "", "log file to colorize")
)

const USAGE = `Usage: logcolor -t template -l logfile [-h]`

func main() {
	flag.Parse()

	signal.Notify(signalChan, os.Interrupt)
	// setup go routine to catch a ctrl-c
	go func() {
		for range signalChan {
			os.Exit(1)
		}
	}()

	/*
		if len(*templateFlag) != 1 {
			fmt.Println(USAGE)
			os.Exit(1)
		}
	*/

	var log logger
	switch *templateFlag {
	case "http":
		log = logger(&HTTP{})
	case "ftp":
		//f := &FTP{}
		/*
			case "sip":
				s := &SIP{}
			case "mysql":
				m := &MySQL{}
			case "rsync":
				r := &Rsync{}
			case "postgresql":
				p := &Postgresql{}
			case "openstack":
				o := &Openstack{}
		*/
	}

	t, err := tail.TailFile(*logFileFlag,
		tail.Config{Follow: true,
			ReOpen:    true,
			MustExist: true},
	)
	if err != nil {
		os.Exit(1)
	}
	for line := range t.Lines {
		fmt.Println(processLine(line.Text, log))
	}
	os.Exit(0)
}
<commit_msg>small change<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 (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strings"

	"github.com/ActiveState/tail"
	"github.com/fatih/color"
)

var signalChan = make(chan os.Signal, 1) // channel to catch ctrl-c

func processLine(line string, log logger) string {
	if len(line) == 0 {
		return line
	}
	brokenLine := strings.Split(line, " ")
	for i, s := range brokenLine {
		switch {
		case WordExists(s, log.GoodWords()):
			brokenLine[i] = color.GreenString(s)
		case WordExists(s, log.GoodLines()):
			brokenLine[i] = color.GreenString(s)
		case WordExists(s, log.WarnWords()):
			brokenLine[i] = color.YellowString(s)
		case WordExists(s, log.BadLines()):
			color.Red(strings.Join(brokenLine, " "))
		default:
			continue
		}
	}
	return strings.Join(brokenLine, " ")
}

// Pointers to hold the contents of the flag args.
var (
	templateFlag = flag.String("t", "", "template to use for log parsing")
	logFileFlag  = flag.String("l", "", "log file to colorize")
)

const USAGE = `Usage: logcolor -t template -l logfile [-h]`

func main() {
	flag.Parse()

	signal.Notify(signalChan, os.Interrupt)
	// setup go routine to catch a ctrl-c
	go func() {
		for range signalChan {
			os.Exit(1)
		}
	}()

	/*
		if len(*templateFlag) != 1 {
			fmt.Println(USAGE)
			os.Exit(1)
		}
	*/

	var log logger
	switch *templateFlag {
	case "http":
		log = logger(&HTTP{})
	case "ftp":
		//f := &FTP{}
		/*
			case "sip":
				s := &SIP{}
			case "mysql":
				m := &MySQL{}
			case "rsync":
				r := &Rsync{}
			case "postgresql":
				p := &Postgresql{}
			case "openstack":
				o := &Openstack{}
		*/
	}

	t, err := tail.TailFile(*logFileFlag,
		tail.Config{Follow: true,
			ReOpen:    true,
			MustExist: true},
	)
	if err != nil {
		os.Exit(1)
	}
	for line := range t.Lines {
		fmt.Println(processLine(line.Text, log))
	}
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/dustin/go-humanize"
	"github.com/mbndr/logo"
	"github.com/mmmorris1975/aws-runas/lib"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

const (
	VERSION = "1.0.0-alpha1"
)

var (
	listRoles    *bool
	listMfa      *bool
	showExpire   *bool
	sesCreds     *bool
	refresh      *bool
	verbose      *bool
	makeConf     *bool
	updateFlag   *bool
	profile      *string
	mfaArn       *string
	duration     *time.Duration
	roleDuration *time.Duration
	cmd          *[]string
	logLevel     = logo.WARN
	log          *logo.Logger
)

func init() {
	const (
		cmdDesc             = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc     = "duration of the retrieved session token"
		roleDurationArgDesc = "duration of the assume role credentials"
		listRoleArgDesc     = "list role ARNs you are able to assume"
		listMfaArgDesc      = "list the ARN of the MFA device associated with your account"
		showExpArgDesc      = "Show token expiration time"
		sesCredArgDesc      = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc      = "force a refresh of the cached credentials"
		verboseArgDesc      = "print verbose/debug messages"
		profileArgDesc      = "name of profile, or role ARN"
		cmdArgDesc          = "command to execute using configured profile"
		mfaArnDesc          = "ARN of MFA device needed to perform Assume Role operation"
		makeConfArgDesc     = "Build an AWS extended switch-role plugin configuration for all available roles"
		updateArgDesc       = "Check for updates to aws-runas"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Duration()
	roleDuration = kingpin.Flag("role-duration", roleDurationArgDesc).Short('a').Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	mfaArn = kingpin.Flag("mfa-arn", mfaArnDesc).Short('M').String()
	updateFlag = kingpin.Flag("update", updateArgDesc).Short('u').Bool()

	// if AWS_PROFILE env var is NOT set, it MUST be 1st non-flag arg
	// if AWS_PROFILE env var is set, all non-flag args will be treated as cmd
	if v, ok := os.LookupEnv("AWS_PROFILE"); !ok {
		profile = kingpin.Arg("profile", profileArgDesc).String()
	} else {
		profile = aws.String(v)
	}

	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func main() {
	// Tell kingpin to stop parsing flags once we start processing 'cmd', allows something like:
	// `aws-runas --verbose profile command -a --long_arg`
	// without needing an explicit `--` between 'profile' and 'cmd'
	kingpin.CommandLine.Interspersed(false)
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}
	log = logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	log.Debugf("PROFILE: %s", *profile)
	sess := lib.AwsSession(*profile)

	cm, err := lib.NewAwsConfigManager(&lib.ConfigManagerOptions{LogLevel: logLevel})
	if err != nil {
		log.Fatalf("Error loading configuration: %v", err)
	}

	switch {
	case *listMfa:
		log.Debug("List MFA")
		mfa, err := lib.LookupMfa(sess)
		if err != nil {
			log.Fatalf("Error retrieving MFA info: %v", err)
		}

		for _, d := range mfa {
			fmt.Printf("%s\n", *d.SerialNumber)
		}
	case *listRoles, *makeConf:
		u := iamUser(sess)
		userName := *u.UserName

		rg := lib.NewAwsRoleGetter(sess, userName, &lib.RoleGetterOptions{LogLevel: logLevel})
		roles := rg.Roles()

		if *listRoles {
			log.Debug("List Roles")
			fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.Arn)
			for _, v := range roles {
				fmt.Printf("  %s\n", v)
			}
		}

		if *makeConf {
			log.Debug("Make Configuration Files.")
			var mfa *string
			if mfaArn != nil && len(*mfaArn) > 0 {
				// MFA arn provided by cmdline option
				mfa = mfaArn
			} else {
				m, err := lib.LookupMfa(sess)
				if err != nil {
					log.Errorf("MFA lookup failed, will not configure MFA: %v", err)
				}

				if len(m) > 0 {
					// use 1st MFA device found
					mfa = m[0].SerialNumber
				}
			}

			if err := cm.BuildConfig(roles, mfa); err != nil {
				log.Fatalf("Error building config file: %v", err)
			}
		}
	case *updateFlag:
		log.Debug("Update check")
		if err := lib.VersionCheck(VERSION); err != nil {
			log.Debugf("Error from VersionCheck(): %v", err)
		}
	default:
		p, err := awsProfile(cm, *profile)
		if err != nil {
			log.Fatalf("Error building profile: %v", err)
		}

		// Add command-line option overrides
		if duration != nil && (*duration).Nanoseconds() > 0 {
			p.SessionDuration = *duration
		}

		if roleDuration != nil && (*roleDuration).Nanoseconds() > 0 {
			p.CredDuration = *roleDuration
		}

		if mfaArn != nil && len(*mfaArn) > 0 {
			p.MfaSerial = *mfaArn
		}
		log.Debugf("RESOLVED PROFILE: %+v", p)

		opts := lib.SessionTokenProviderOptions{
			LogLevel:             logLevel,
			SessionTokenDuration: p.SessionDuration,
			MfaSerial:            p.MfaSerial,
		}
		t, err := lib.NewSessionTokenProvider(p, &opts)
		if err != nil {
			log.Fatalf("Unable to build credential provider: %v", err)
		}

		if *refresh {
			os.Remove(t.CacheFile())
		}

		if *showExpire {
			exp_t := t.ExpirationTime()
			fmt_t := exp_t.Format("2006-01-02 15:04:05")
			hmn_t := humanize.Time(exp_t)

			tense := "will expire"
			if exp_t.Before(time.Now()) {
				tense = "expired"
			}
			fmt.Fprintf(os.Stderr, "Session credentials %s on %s (%s)\n", tense, fmt_t, hmn_t)
		}

		var creds credentials.Value
		if *sesCreds || len(p.RoleArn.Resource) < 1 {
			log.Debugf("Getting SESSION TOKEN credentials")
			c := credentials.NewCredentials(t)
			creds, err = c.Get()
			if err != nil {
				log.Fatalf("Unable to get SessionToken credentials: %v", err)
			}
		} else {
			log.Debugf("Getting ASSUME ROLE credentials")
			in := assumeRoleInput(p)
			res, err := t.AssumeRole(in)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
			c := res.Credentials
			creds = credentials.Value{
				AccessKeyID:     *c.AccessKeyId,
				SecretAccessKey: *c.SecretAccessKey,
				SessionToken:    *c.SessionToken,
				ProviderName:    "CachedCredentialsProvider",
			}
		}

		updateEnv(creds, p.Region)

		if len(*cmd) > 0 {
			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials()
		}
	}
}

func assumeRoleInput(p *lib.AWSProfile) *sts.AssumeRoleInput {
	i := new(sts.AssumeRoleInput)
	if p.CredDuration.Seconds() == 0 {
		i.DurationSeconds = aws.Int64(int64(lib.ASSUME_ROLE_DEFAULT_DURATION.Seconds()))
	} else {
		i.DurationSeconds = aws.Int64(int64(p.CredDuration.Seconds()))
	}

	if len(p.RoleArn.String()) > 0 {
		i.RoleArn = aws.String(p.RoleArn.String())
	}

	if len(p.RoleSessionName) > 0 {
		i.RoleSessionName = aws.String(p.RoleSessionName)
	}

	if len(p.ExternalId) > 0 {
		i.ExternalId = aws.String(p.ExternalId)
	}

	return i
}

func updateEnv(creds credentials.Value, region string) {
	// Explicitly unset AWS_PROFILE to avoid unintended consequences
	os.Unsetenv("AWS_PROFILE")

	// Pass AWS_REGION through if it was set in our env, or found in config.
	// Ensure that called program gets the expected region
	if len(region) > 0 {
		os.Setenv("AWS_REGION", region)
	}

	os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)

	// If session token creds were returned, set them. Otherwise explicitly
	// unset them to keep the sdk from getting confused.  AFAIK, we should
	// always have SessionTokens, since our entire process revolves around them.
	// But always code defensively
	if len(creds.SessionToken) > 0 {
		os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
		os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
	} else {
		os.Unsetenv("AWS_SESSION_TOKEN")
		os.Unsetenv("AWS_SECURITY_TOKEN")
	}
}

func iamUser(s *session.Session) *iam.User {
	i := iam.New(s)

	u, err := i.GetUser(new(iam.GetUserInput))
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	log.Debugf("USER: %+v", u)
	return u.User
}

func awsProfile(cm lib.ConfigManager, name string) (*lib.AWSProfile, error) {
	var p *lib.AWSProfile

	a, err := arn.Parse(name)
	if err != nil {
		p, err = cm.GetProfile(aws.String(name))
		if err != nil {
			return nil, fmt.Errorf("unable to get configuration for profile '%s': %v", name, err)
		}
	} else {
		if strings.HasPrefix(a.String(), lib.IAM_ARN) {
			p = &lib.AWSProfile{RoleArn: a}
		} else {
			return nil, fmt.Errorf("profile argument is not an IAM role ARN")
		}
	}

	return p, nil
}

func printCredentials() {
	format := "%s %s='%s'\n"
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	envVars := []string{
		"AWS_REGION",
		"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY",
		"AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN",
	}

	for _, v := range envVars {
		val, ok := os.LookupEnv(v)
		if ok {
			fmt.Printf(format, exportToken, v, val)
		}
	}
}
<commit_msg>Update version to beta2<commit_after>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/arn"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/dustin/go-humanize"
	"github.com/mbndr/logo"
	"github.com/mmmorris1975/aws-runas/lib"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"
)

const (
	VERSION = "1.0.0-beta2"
)

var (
	listRoles    *bool
	listMfa      *bool
	showExpire   *bool
	sesCreds     *bool
	refresh      *bool
	verbose      *bool
	makeConf     *bool
	updateFlag   *bool
	profile      *string
	mfaArn       *string
	duration     *time.Duration
	roleDuration *time.Duration
	cmd          *[]string
	logLevel     = logo.WARN
	log          *logo.Logger
)

func init() {
	const (
		cmdDesc             = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc     = "duration of the retrieved session token"
		roleDurationArgDesc = "duration of the assume role credentials"
		listRoleArgDesc     = "list role ARNs you are able to assume"
		listMfaArgDesc      = "list the ARN of the MFA device associated with your account"
		showExpArgDesc      = "Show token expiration time"
		sesCredArgDesc      = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc      = "force a refresh of the cached credentials"
		verboseArgDesc      = "print verbose/debug messages"
		profileArgDesc      = "name of profile, or role ARN"
		cmdArgDesc          = "command to execute using configured profile"
		mfaArnDesc          = "ARN of MFA device needed to perform Assume Role operation"
		makeConfArgDesc     = "Build an AWS extended switch-role plugin configuration for all available roles"
		updateArgDesc       = "Check for updates to aws-runas"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Duration()
	roleDuration = kingpin.Flag("role-duration", roleDurationArgDesc).Short('a').Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	mfaArn = kingpin.Flag("mfa-arn", mfaArnDesc).Short('M').String()
	updateFlag = kingpin.Flag("update", updateArgDesc).Short('u').Bool()

	// if AWS_PROFILE env var is NOT set, it MUST be 1st non-flag arg
	// if AWS_PROFILE env var is set, all non-flag args will be treated as cmd
	if v, ok := os.LookupEnv("AWS_PROFILE"); !ok {
		profile = kingpin.Arg("profile", profileArgDesc).String()
	} else {
		profile = aws.String(v)
	}

	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func main() {
	// Tell kingpin to stop parsing flags once we start processing 'cmd', allows something like:
	// `aws-runas --verbose profile command -a --long_arg`
	// without needing an explicit `--` between 'profile' and 'cmd'
	kingpin.CommandLine.Interspersed(false)
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}
	log = logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	log.Debugf("PROFILE: %s", *profile)
	sess := lib.AwsSession(*profile)

	cm, err := lib.NewAwsConfigManager(&lib.ConfigManagerOptions{LogLevel: logLevel})
	if err != nil {
		log.Fatalf("Error loading configuration: %v", err)
	}

	switch {
	case *listMfa:
		log.Debug("List MFA")
		mfa, err := lib.LookupMfa(sess)
		if err != nil {
			log.Fatalf("Error retrieving MFA info: %v", err)
		}

		for _, d := range mfa {
			fmt.Printf("%s\n", *d.SerialNumber)
		}
	case *listRoles, *makeConf:
		u := iamUser(sess)
		userName := *u.UserName

		rg := lib.NewAwsRoleGetter(sess, userName, &lib.RoleGetterOptions{LogLevel: logLevel})
		roles := rg.Roles()

		if *listRoles {
			log.Debug("List Roles")
			fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.Arn)
			for _, v := range roles {
				fmt.Printf("  %s\n", v)
			}
		}

		if *makeConf {
			log.Debug("Make Configuration Files.")
			var mfa *string
			if mfaArn != nil && len(*mfaArn) > 0 {
				// MFA arn provided by cmdline option
				mfa = mfaArn
			} else {
				m, err := lib.LookupMfa(sess)
				if err != nil {
					log.Errorf("MFA lookup failed, will not configure MFA: %v", err)
				}

				if len(m) > 0 {
					// use 1st MFA device found
					mfa = m[0].SerialNumber
				}
			}

			if err := cm.BuildConfig(roles, mfa); err != nil {
				log.Fatalf("Error building config file: %v", err)
			}
		}
	case *updateFlag:
		log.Debug("Update check")
		if err := lib.VersionCheck(VERSION); err != nil {
			log.Debugf("Error from VersionCheck(): %v", err)
		}
	default:
		p, err := awsProfile(cm, *profile)
		if err != nil {
			log.Fatalf("Error building profile: %v", err)
		}

		// Add command-line option overrides
		if duration != nil && (*duration).Nanoseconds() > 0 {
			p.SessionDuration = *duration
		}

		if roleDuration != nil && (*roleDuration).Nanoseconds() > 0 {
			p.CredDuration = *roleDuration
		}

		if mfaArn != nil && len(*mfaArn) > 0 {
			p.MfaSerial = *mfaArn
		}
		log.Debugf("RESOLVED PROFILE: %+v", p)

		opts := lib.SessionTokenProviderOptions{
			LogLevel:             logLevel,
			SessionTokenDuration: p.SessionDuration,
			MfaSerial:            p.MfaSerial,
		}
		t, err := lib.NewSessionTokenProvider(p, &opts)
		if err != nil {
			log.Fatalf("Unable to build credential provider: %v", err)
		}

		if *refresh {
			os.Remove(t.CacheFile())
		}

		if *showExpire {
			exp_t := t.ExpirationTime()
			fmt_t := exp_t.Format("2006-01-02 15:04:05")
			hmn_t := humanize.Time(exp_t)

			tense := "will expire"
			if exp_t.Before(time.Now()) {
				tense = "expired"
			}
			fmt.Fprintf(os.Stderr, "Session credentials %s on %s (%s)\n", tense, fmt_t, hmn_t)
		}

		var creds credentials.Value
		if *sesCreds || len(p.RoleArn.Resource) < 1 {
			log.Debugf("Getting SESSION TOKEN credentials")
			c := credentials.NewCredentials(t)
			creds, err = c.Get()
			if err != nil {
				log.Fatalf("Unable to get SessionToken credentials: %v", err)
			}
		} else {
			log.Debugf("Getting ASSUME ROLE credentials")
			in := assumeRoleInput(p)
			res, err := t.AssumeRole(in)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
			c := res.Credentials
			creds = credentials.Value{
				AccessKeyID:     *c.AccessKeyId,
				SecretAccessKey: *c.SecretAccessKey,
				SessionToken:    *c.SessionToken,
				ProviderName:    "CachedCredentialsProvider",
			}
		}

		updateEnv(creds, p.Region)

		if len(*cmd) > 0 {
			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials()
		}
	}
}

func assumeRoleInput(p *lib.AWSProfile) *sts.AssumeRoleInput {
	i := new(sts.AssumeRoleInput)
	if p.CredDuration.Seconds() == 0 {
		i.DurationSeconds = aws.Int64(int64(lib.ASSUME_ROLE_DEFAULT_DURATION.Seconds()))
	} else {
		i.DurationSeconds = aws.Int64(int64(p.CredDuration.Seconds()))
	}

	if len(p.RoleArn.String()) > 0 {
		i.RoleArn = aws.String(p.RoleArn.String())
	}

	if len(p.RoleSessionName) > 0 {
		i.RoleSessionName = aws.String(p.RoleSessionName)
	}

	if len(p.ExternalId) > 0 {
		i.ExternalId = aws.String(p.ExternalId)
	}

	return i
}

func updateEnv(creds credentials.Value, region string) {
	// Explicitly unset AWS_PROFILE to avoid unintended consequences
	os.Unsetenv("AWS_PROFILE")

	// Pass AWS_REGION through if it was set in our env, or found in config.
	// Ensure that called program gets the expected region
	if len(region) > 0 {
		os.Setenv("AWS_REGION", region)
	}

	os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)

	// If session token creds were returned, set them. Otherwise explicitly
	// unset them to keep the sdk from getting confused.  AFAIK, we should
	// always have SessionTokens, since our entire process revolves around them.
	// But always code defensively
	if len(creds.SessionToken) > 0 {
		os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
		os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
	} else {
		os.Unsetenv("AWS_SESSION_TOKEN")
		os.Unsetenv("AWS_SECURITY_TOKEN")
	}
}

func iamUser(s *session.Session) *iam.User {
	i := iam.New(s)

	u, err := i.GetUser(new(iam.GetUserInput))
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	log.Debugf("USER: %+v", u)
	return u.User
}

func awsProfile(cm lib.ConfigManager, name string) (*lib.AWSProfile, error) {
	var p *lib.AWSProfile

	a, err := arn.Parse(name)
	if err != nil {
		p, err = cm.GetProfile(aws.String(name))
		if err != nil {
			return nil, fmt.Errorf("unable to get configuration for profile '%s': %v", name, err)
		}
	} else {
		if strings.HasPrefix(a.String(), lib.IAM_ARN) {
			p = &lib.AWSProfile{RoleArn: a}
		} else {
			return nil, fmt.Errorf("profile argument is not an IAM role ARN")
		}
	}

	return p, nil
}

func printCredentials() {
	format := "%s %s='%s'\n"
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	envVars := []string{
		"AWS_REGION",
		"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY",
		"AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN",
	}

	for _, v := range envVars {
		val, ok := os.LookupEnv(v)
		if ok {
			fmt.Printf(format, exportToken, v, val)
		}
	}
}
<|endoftext|>


<commit_before>/*
CLI utility for stress testing of HTTP servers with many concurrent connections

Usage:
 httpstress <URL list> [options]

Options:
 * `URL list` – URLs to fetch (required)
 * `-c NUM` – concurrent connections number (defaults to 1)
 * `-n NUM` – total connections number (optional)
 * `-v` – print version to stdout and exit

Example:
 httpstress http://localhost https://192.168.1.1 -c 1000

Returns 0 if no errors, 1 if some requests failed, 2 on kill and 3 in case of invalid options.

Prints elapsed time and error count for each URL to stdout (if any; does not count successful attempts).
Usage and runtime errors go to stderr.

Output is JSON-formatted. Example:
  {
    "errors": {
      "http://localhost": 500,
      "https://192.168.1.1": 3
    },
    "seconds": 12.8
  }

It follows HTTP redirects. Non-200 HTTP return code is an error.
*/
package main

import (
	"encoding/json"
	"fmt"
	"github.com/chillum/httpstress/lib"
	flag "github.com/ogier/pflag"
	"os"
	"runtime"
	"time"
)

// Application version
const Version = "6.1"

type results struct {
	Errors  interface{} `json:"errors"`
	Seconds *float32    `json:"seconds"`
}

type ver struct {
	App  string `json:"httpstress"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

func main() {
	var conn, max int
	var final results
	flag.IntVarP(&conn, "c", "c", 1, "concurrent connections count")
	flag.IntVarP(&max, "n", "n", 0, "total connections (optional)")
	version := flag.BoolP("version", "v", false, "print version to stdout and exit")
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "<URL list> [options]")
		fmt.Fprintln(os.Stderr, "  <URL list>: URLs to fetch (required)")
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, "Example:\n  httpstress http://localhost https://192.168.1.1 -c 1000")
		fmt.Fprintln(os.Stderr, "Docs:\n  https://github.com/chillum/httpstress/wiki")
		os.Exit(3)
	}
	flag.Parse()

	if *version {
		var ver ver
		ver.App = Version
		ver.Go = runtime.Version()
		ver.Os = runtime.GOOS
		ver.Arch = runtime.GOARCH
		json, _ := json.Marshal(&ver)
		fmt.Println(string(json))
		os.Exit(0)
	}

	urls := flag.Args()
	if len(urls) < 1 {
		flag.Usage()
	}

	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	start := time.Now()

	errors, err := httpstress.Test(conn, max, urls)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		flag.Usage()
	}

	elapsed := float32(int64(time.Since(start).Seconds() * 10)) / 10

	if len(errors) > 0 {
		defer os.Exit(1)
	}

	final.Errors = &errors
	final.Seconds = &elapsed

	json, _ := json.MarshalIndent(&final, "", "  ")
	fmt.Println(string(json))
}
<commit_msg>godoc update<commit_after>/*
CLI utility for stress testing of HTTP servers with many concurrent connections

Usage:
 httpstress <URL list> [options]

Options:
 * `URL list` – URLs to fetch (required)
 * `-c NUM` – concurrent connections number (defaults to 1)
 * `-n NUM` – total connections number (optional)
 * `-v` – print version to stdout and exit

Example:
 httpstress http://localhost https://192.168.1.1 -c 1000

Returns 0 if no errors, 1 if some requests failed, 2 on kill and 3 in case of invalid options.

Prints elapsed time and error count for each URL to stdout (if any; does not count successful attempts).
Usage and runtime errors go to stderr.

Output is JSON-formatted. Example:
  {
    "errors": {
      "http://localhost": 500,
      "https://192.168.1.1": 3
    },
    "seconds": 12.8
  }

It follows HTTP redirects. Non-200 HTTP return code is an error.

Be sure to set `ulimit -n` on Unix systems high enough.
*/
package main

import (
	"encoding/json"
	"fmt"
	"github.com/chillum/httpstress/lib"
	flag "github.com/ogier/pflag"
	"os"
	"runtime"
	"time"
)

// Application version
const Version = "6.1"

type results struct {
	Errors  interface{} `json:"errors"`
	Seconds *float32    `json:"seconds"`
}

type ver struct {
	App  string `json:"httpstress"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

func main() {
	var conn, max int
	var final results
	flag.IntVarP(&conn, "c", "c", 1, "concurrent connections count")
	flag.IntVarP(&max, "n", "n", 0, "total connections (optional)")
	version := flag.BoolP("version", "v", false, "print version to stdout and exit")
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "<URL list> [options]")
		fmt.Fprintln(os.Stderr, "  <URL list>: URLs to fetch (required)")
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, "Example:\n  httpstress http://localhost https://192.168.1.1 -c 1000")
		fmt.Fprintln(os.Stderr, "Docs:\n  https://github.com/chillum/httpstress/wiki")
		os.Exit(3)
	}
	flag.Parse()

	if *version {
		var ver ver
		ver.App = Version
		ver.Go = runtime.Version()
		ver.Os = runtime.GOOS
		ver.Arch = runtime.GOARCH
		json, _ := json.Marshal(&ver)
		fmt.Println(string(json))
		os.Exit(0)
	}

	urls := flag.Args()
	if len(urls) < 1 {
		flag.Usage()
	}

	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	start := time.Now()

	errors, err := httpstress.Test(conn, max, urls)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err)
		flag.Usage()
	}

	elapsed := float32(int64(time.Since(start).Seconds() * 10)) / 10

	if len(errors) > 0 {
		defer os.Exit(1)
	}

	final.Errors = &errors
	final.Seconds = &elapsed

	json, _ := json.MarshalIndent(&final, "", "  ")
	fmt.Println(string(json))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

// https://technet.microsoft.com/en-us/library/cc957408.aspx
// https://github.com/Mayccoll/Gogh

// Color
// 0 - Black
// 1 - Blue
// 2 - Green
// 3 - Aqua
// 4 - Red
// 5 - Purple
// 6 - Yellow
// 7 - White
// 8 - Gray
// 9 - Light Blue
// A - Light Green
// B - Light Aqua
// C - Light Red
// D - Light Purple
// E - Light Yellow
// F - Bright White

// PSColors is the type where the options are parsed in.
type PSColors struct {
	ColorTable00 string
	ColorTable01 string
	ColorTable02 string
	ColorTable03 string
	ColorTable04 string
	ColorTable05 string
	ColorTable06 string
	ColorTable07 string
	ColorTable08 string

	ColorTable09 string
	ColorTable10 string
	ColorTable11 string
	ColorTable12 string
	ColorTable13 string
	ColorTable14 string
	ColorTable15 string

	ScreenColors string
	PopupColors  string
}

// SetValue ...
func (p *PSColors) SetValue(attribute string, value string) {
	reflect.ValueOf(p).Elem().FieldByName(attribute).SetString(value)
}

// GetValue ...
func (p *PSColors) GetValue(field string) string {
	return reflect.ValueOf(p).Elem().FieldByName(field).String()
}

func createRegFileContent(colors PSColors) (string, error) {
	var buffer bytes.Buffer
	temp := template.New("template")
	temp.Parse(`Windows Registry Editor Version 5.00
; generated file
[HKEY_CURRENT_USER\Console]
"ColorTable00"=dword:{{.ColorTable00}}
"ColorTable01"=dword:{{.ColorTable01}}
"ColorTable02"=dword:{{.ColorTable02}}
"ColorTable03"=dword:{{.ColorTable03}}
"ColorTable04"=dword:{{.ColorTable04}}
"ColorTable05"=dword:{{.ColorTable05}}
"ColorTable06"=dword:{{.ColorTable06}}
"ColorTable07"=dword:{{.ColorTable07}}

"ColorTable08"=dword:{{.ColorTable08}}
"ColorTable09"=dword:{{.ColorTable09}}
"ColorTable10"=dword:{{.ColorTable10}}
"ColorTable11"=dword:{{.ColorTable11}}
"ColorTable12"=dword:{{.ColorTable12}}
"ColorTable13"=dword:{{.ColorTable13}}
"ColorTable14"=dword:{{.ColorTable14}}
"ColorTable15"=dword:{{.ColorTable15}}

"ScreenColors"=dword:{{.ScreenColors}}
"PopupColors"=dword:{{.PopupColors}}`)

	temp.Execute(&buffer, colors)
	return buffer.String(), nil
}

func dwordFromHex(hex string) string {
	v := strings.Join([]string{
		"00",
		hex[4:6],
		hex[2:4],
		hex[0:2],
	}, "")
	return strings.ToUpper(v)
}

type GoghExtractor struct{}

func (e *GoghExtractor) Extract(in io.Reader) PSColors {

	scanner := bufio.NewScanner(in)

	colorRegex, _ := regexp.Compile(`COLOR_(\d{2})="#(\w{6})`)
	foregroundRegex, _ := regexp.Compile(`FOREGROUND_COLOR="#(\w{6})"`)
	backgroundRegex, _ := regexp.Compile(`BACKGROUND_COLOR="#(\w{6})"`)

	colors := PSColors{}
	var fgValue string
	var bgValue string

	for scanner.Scan() {
		text := scanner.Text()
		if colorRegex.MatchString(text) {
			matchesArr := colorRegex.FindStringSubmatch(text)
			value := dwordFromHex(matchesArr[2])
			valueInt, _ := strconv.Atoi(matchesArr[1])
			valueInt--
			key := padLeft(strconv.Itoa(valueInt), "0", 2)
			colors.SetValue("ColorTable"+key, strings.ToUpper(value))
		}
		if foregroundRegex.MatchString(text) {
			matchesArr := foregroundRegex.FindStringSubmatch(text)
			fgValue = matchesArr[1]
		}
		if backgroundRegex.MatchString(text) {
			matchesArr := backgroundRegex.FindStringSubmatch(text)
			bgValue = matchesArr[1]
		}
	}

	fgIndex := ""
	for i := 0; i < 16; i++ {
		key := "ColorTable" + padLeft(strconv.Itoa(i), "0", 2)
		if colors.GetValue(key) == fgValue {
			fgIndex = strconv.FormatInt(int64(i), 16)
			break
		}
	}

	if fgIndex == "" {
		fgPos := 5
		colors.SetValue("ColorTable"+padLeft(strconv.FormatInt(int64(fgPos), 10), "0", 2), dwordFromHex(fgValue))
		fgIndex = strconv.FormatInt(int64(fgPos), 16)
	}

	bgIndex := ""
	for i := 0; i < 16; i++ {
		key := "ColorsTable" + padLeft(strconv.Itoa(i), "0", 2)
		if colors.GetValue(key) == bgValue {
			bgIndex = padLeft(strconv.FormatInt(int64(i), 16), "0", 4)
			break
		}
	}

	if bgIndex == "" {
		bgPos := 6
		colors.SetValue("ColorTable"+padLeft(strconv.FormatInt(int64(bgPos), 10), "0", 2), dwordFromHex(bgValue))
		bgIndex = strconv.FormatInt(int64(bgPos), 16)
	}

	colors.SetValue("ScreenColors", padLeft(bgIndex+fgIndex, "0", 8))
	colors.SetValue("PopupColors", padLeft(fgIndex+bgIndex, "0", 8))

	return colors

}

func padLeft(str, pad string, lenght int) string {
	for {
		if len(str) == lenght {
			return str[0:lenght]
		}
		str = pad + str
	}
}

type Extractor interface {
	Extract(in io.Reader) PSColors
}

func main() {
	var inFile string
	var outFile string
	var inURL string
	var logFile string
	var goghTheme string

	flag.StringVar(&inFile, "inFile", "", "die datei die geparsed werden soll.")
	flag.StringVar(&outFile, "out", "", "Ausgabedatei. Default os.Stdout")
	flag.StringVar(&inURL, "inURL", "", "Load From URL https://mayccoll.github.io/Gogh/")
	flag.StringVar(&logFile, "logFile", "", "Log File")
	flag.StringVar(&goghTheme, "goghTheme", "", "Gogh Theme. Will be loaded from the internet.")

	flag.Parse()

	extractors := map[string]Extractor{
		"gogh": &GoghExtractor{},
	}

	if logFile != "" {
		logWriter, _ := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
		defer logWriter.Close()
		log.SetOutput(logWriter)
	}

	if goghTheme != "" {
		inURL = strings.Join([]string{
			"https://raw.githubusercontent.com/Mayccoll/Gogh/master/themes/",
			goghTheme,
			".sh",
		}, "")
	}

	if inFile == "" && inURL == "" {
		flag.Usage()
		return
	}

	var outWriter io.Writer

	if outFile == "" {
		outWriter = os.Stdout
	} else {
		outFileHandler, _ := os.OpenFile(outFile, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
		defer outFileHandler.Close()
		outWriter = outFileHandler
	}

	var inReader io.Reader

	if inFile != "" {
		inReader, _ = os.Open(inFile)
	} else {
		httpResp, _ := http.Get(inURL)
		inReader = httpResp.Body
	}

	colors := extractors["gogh"].Extract(inReader)
	regContent, _ := createRegFileContent(colors)

	fmt.Fprint(outWriter, regContent)

}
<commit_msg>Changes for fg und bg positions.<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

// https://technet.microsoft.com/en-us/library/cc957408.aspx
// https://github.com/Mayccoll/Gogh

// Color
// 0 - Black - x
// 1 - Blue
// 2 - Green - x (Git Diff)
// 3 - Aqua - x (Literal) (ProgressBackgroundColor)
// 4 - Red - x
// 5 - Purple /// - x (Text Color)
// 6 - Yellow - x
// 7 - White
// 8 - Gray - x (Parameter) (Sign)
// 9 - Light Blue
// A - Light Green - x (Reserved Word)
// B - Light Aqua
// C - Light Red - x (Error (Red))
// D - Light Purple
// E - Light Yellow - x (Command / Warning)
// F - Bright White

// $ (Get-Host).PrivateData
// ErrorForegroundColor    : Red
// ErrorBackgroundColor    : Black
// WarningForegroundColor  : Yellow
// WarningBackgroundColor  : Black
// DebugForegroundColor    : Yellow
// DebugBackgroundColor    : Black
// VerboseForegroundColor  : Yellow
// VerboseBackgroundColor  : Black
// ProgressForegroundColor : Yellow
// ProgressBackgroundColor : DarkCyan

// PSColors is the type where the options are parsed in.
type PSColors struct {
	ColorTable00 string
	ColorTable01 string
	ColorTable02 string
	ColorTable03 string
	ColorTable04 string
	ColorTable05 string
	ColorTable06 string
	ColorTable07 string
	ColorTable08 string

	ColorTable09 string
	ColorTable10 string
	ColorTable11 string
	ColorTable12 string
	ColorTable13 string
	ColorTable14 string
	ColorTable15 string

	ScreenColors string
	PopupColors  string
}

// SetValue ...
func (p *PSColors) SetValue(attribute string, value string) {
	reflect.ValueOf(p).Elem().FieldByName(attribute).SetString(value)
}

// GetValue ...
func (p *PSColors) GetValue(field string) string {
	return reflect.ValueOf(p).Elem().FieldByName(field).String()
}

func createRegFileContent(colors PSColors) (string, error) {
	var buffer bytes.Buffer
	temp := template.New("template")
	temp.Parse(`Windows Registry Editor Version 5.00
; generated file
[HKEY_CURRENT_USER\Console]
"ColorTable00"=dword:{{.ColorTable00}}
"ColorTable01"=dword:{{.ColorTable01}}
"ColorTable02"=dword:{{.ColorTable02}}
"ColorTable03"=dword:{{.ColorTable03}}
"ColorTable04"=dword:{{.ColorTable04}}
"ColorTable05"=dword:{{.ColorTable05}}
"ColorTable06"=dword:{{.ColorTable06}}
"ColorTable07"=dword:{{.ColorTable07}}

"ColorTable08"=dword:{{.ColorTable08}}
"ColorTable09"=dword:{{.ColorTable09}}
"ColorTable10"=dword:{{.ColorTable10}}
"ColorTable11"=dword:{{.ColorTable11}}
"ColorTable12"=dword:{{.ColorTable12}}
"ColorTable13"=dword:{{.ColorTable13}}
"ColorTable14"=dword:{{.ColorTable14}}
"ColorTable15"=dword:{{.ColorTable15}}

"ScreenColors"=dword:{{.ScreenColors}}
"PopupColors"=dword:{{.PopupColors}}`)

	temp.Execute(&buffer, colors)
	return buffer.String(), nil
}

func dwordFromHex(hex string) string {
	v := strings.Join([]string{
		"00",
		hex[4:6],
		hex[2:4],
		hex[0:2],
	}, "")
	return strings.ToUpper(v)
}

type GoghExtractor struct{}

func (e *GoghExtractor) Extract(in io.Reader, fgColorIndex int, bgColorIndex int) PSColors {

	scanner := bufio.NewScanner(in)

	colorRegex, _ := regexp.Compile(`COLOR_(\d{2})="#(\w{6})`)
	foregroundRegex, _ := regexp.Compile(`FOREGROUND_COLOR="#(\w{6})"`)
	backgroundRegex, _ := regexp.Compile(`BACKGROUND_COLOR="#(\w{6})"`)

	colors := PSColors{}
	var fgValue string
	var bgValue string

	for scanner.Scan() {
		text := scanner.Text()
		if colorRegex.MatchString(text) {
			matchesArr := colorRegex.FindStringSubmatch(text)
			value := dwordFromHex(matchesArr[2])
			valueInt, _ := strconv.Atoi(matchesArr[1])
			valueInt--
			key := padLeft(strconv.Itoa(valueInt), "0", 2)
			colors.SetValue("ColorTable"+key, strings.ToUpper(value))
		}
		if foregroundRegex.MatchString(text) {
			matchesArr := foregroundRegex.FindStringSubmatch(text)
			fgValue = matchesArr[1]
		}
		if backgroundRegex.MatchString(text) {
			matchesArr := backgroundRegex.FindStringSubmatch(text)
			bgValue = matchesArr[1]
		}
	}

	fgIndex := ""
	for i := 0; i < 16; i++ {
		key := "ColorTable" + padLeft(strconv.Itoa(i), "0", 2)
		if colors.GetValue(key) == fgValue {
			fgIndex = strconv.FormatInt(int64(i), 16)
			break
		}
	}

	if fgIndex == "" {
		colors.SetValue("ColorTable"+padLeft(strconv.FormatInt(int64(fgColorIndex), 10), "0", 2), dwordFromHex(fgValue))
		fgIndex = strconv.FormatInt(int64(fgColorIndex), 16)
	}

	bgIndex := ""
	for i := 0; i < 16; i++ {
		key := "ColorsTable" + padLeft(strconv.Itoa(i), "0", 2)
		if colors.GetValue(key) == bgValue {
			bgIndex = padLeft(strconv.FormatInt(int64(i), 16), "0", 4)
			break
		}
	}

	if bgIndex == "" {
		colors.SetValue("ColorTable"+padLeft(strconv.FormatInt(int64(bgColorIndex), 10), "0", 2), dwordFromHex(bgValue))
		bgIndex = strconv.FormatInt(int64(bgColorIndex), 16)
	}

	colors.SetValue("ScreenColors", padLeft(bgIndex+fgIndex, "0", 8))
	colors.SetValue("PopupColors", padLeft(fgIndex+bgIndex, "0", 8))

	return colors

}

func padLeft(str, pad string, lenght int) string {
	for {
		if len(str) == lenght {
			return str[0:lenght]
		}
		str = pad + str
	}
}

type Extractor interface {
	Extract(in io.Reader, fgColorIndex int, bgColorIndex int) PSColors
}

func main() {
	var inFile string
	var outFile string
	var inURL string
	var logFile string
	var goghTheme string

	var fgColorTableIndex int
	var bgColorTableIndex int

	flag.StringVar(&inFile, "inFile", "", "die datei die geparsed werden soll.")
	flag.StringVar(&outFile, "out", "", "Ausgabedatei. Default os.Stdout")
	flag.StringVar(&inURL, "inURL", "", "Load From URL https://mayccoll.github.io/Gogh/")
	flag.StringVar(&logFile, "logFile", "", "Log File")
	flag.StringVar(&goghTheme, "goghTheme", "", "Gogh Theme. Will be loaded from the internet.")
	flag.IntVar(&fgColorTableIndex, "fgColorIndex", 1, "Foreground color table index.")
	flag.IntVar(&bgColorTableIndex, "bgColorIndex", 4, "Foreground color table index.")

	flag.Parse()

	extractors := map[string]Extractor{
		"gogh": &GoghExtractor{},
	}

	if logFile != "" {
		logWriter, _ := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666)
		defer logWriter.Close()
		log.SetOutput(logWriter)
	}

	if goghTheme != "" {
		inURL = strings.Join([]string{
			"https://raw.githubusercontent.com/Mayccoll/Gogh/master/themes/",
			goghTheme,
			".sh",
		}, "")
	}

	if inFile == "" && inURL == "" {
		flag.Usage()
		return
	}

	var outWriter io.Writer

	if outFile == "" {
		outWriter = os.Stdout
	} else {
		outFileHandler, _ := os.OpenFile(outFile, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)
		defer outFileHandler.Close()
		outWriter = outFileHandler
	}

	var inReader io.Reader

	if inFile != "" {
		inReader, _ = os.Open(inFile)
	} else {
		httpResp, _ := http.Get(inURL)
		inReader = httpResp.Body
	}

	colors := extractors["gogh"].Extract(inReader, fgColorTableIndex, bgColorTableIndex)
	regContent, _ := createRegFileContent(colors)

	fmt.Fprint(outWriter, regContent)

}
<|endoftext|>