<commit_before>package main

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

var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
	return true
}} // use default options for webSocket
var visitor = 0

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.HandleFunc("/websocket", socketHandler)
	http.HandleFunc("/groupTalk", groupTalk)
	log.Fatal(http.ListenAndServeTLS(net.JoinHostPort(config.Server, srvPort), config.Cert, config.CertKey, nil))

}

//3 robot's group talk
func groupTalk(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	visitor++
	tlChan := make(chan string, 5)
	qinChan := make(chan string, 5)
	iceChan := make(chan string, 5)
	result := make(chan string, 10)
	initSentence := "你好"
	tlChan <- tlAI(initSentence)
	go func() {
		for {
			if visitor > 0 {
				msgToTl := <-tlChan
				replyFromTl := tlAI(msgToTl)
				go func() {
					qinChan <- replyFromTl
					//Ice is too slow
					if len(iceChan) < cap(iceChan) {
						iceChan <- replyFromTl
					}
				}()
				result <- "samaritan: " + replyFromTl
				//c.WriteMessage(websocket.TextMessage, []byte("samaritan: " + replyFromTl))
			}
		}
	}()

	go func() {
		for {
			if visitor > 0 {
				msgToQin := <-qinChan
				replyFromQin := qinAI(msgToQin)
				go func() {
					tlChan <- replyFromQin
					if len(iceChan) < cap(iceChan) {
						iceChan <- replyFromQin
					}
				}()
				result <- "菲菲: " + replyFromQin
				//c.WriteMessage(websocket.TextMessage, []byte("菲菲: " + replyFromQin))

			}
		}
	}()

	go func() {
		for {
			if visitor > 0 {
				msgToIce := <-iceChan
				replyFromIce := iceAI(msgToIce)
				go func() {
					tlChan <- replyFromIce
					qinChan <- replyFromIce
				}()
				result <- "小冰: " + replyFromIce
				//c.WriteMessage(websocket.TextMessage, []byte("小冰: " + replyFromIce))

			}
		}
	}()

	go func() {
		for {
			c.WriteMessage(websocket.TextMessage, []byte(<-result))
		}
	}()
	for {

		_, _, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			visitor--
			break
		}
	}
}

//used for web samaritan robot
func socketHandler(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	for {
		var in []byte
		var ret []string
		mt, in, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}
		ret = receive(string(in))
		for i := range ret {
			c.WriteMessage(mt, []byte(ret[i]))
			time.Sleep(time.Second)
		}
		c.WriteMessage(mt, []byte(""))
	}
}

//when webSocket unavailable, fallback to ajax long polling
func ajax(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	var messages = make(chan string)
	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() {
			if ret := iceAI(in); ret != "" {
				answer <- ret
			}
		}()
		go func() {
			if ret := tlAI(in); ret != "" {
				answer <- ret
			}
		}()
		go func() {
			if ret := qinAI(in); 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>memory leak<commit_after>package main

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

var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
	return true
}} // use default options for webSocket
var visitor = 0

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.HandleFunc("/websocket", socketHandler)
	http.HandleFunc("/groupTalk", groupTalk)
	log.Fatal(http.ListenAndServeTLS(net.JoinHostPort(config.Server, srvPort), config.Cert, config.CertKey, nil))

}

//3 robot's group talk
func groupTalk(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	visitor++
	tlChan := make(chan string, 5)
	qinChan := make(chan string, 5)
	iceChan := make(chan string, 5)
	result := make(chan string, 10)
	initSentence := "你好"
	tlChan <- tlAI(initSentence)
	go func() {
		for {
			if visitor > 0 {
				msgToTl := <-tlChan
				replyFromTl := tlAI(msgToTl)
				go func() {
					if replyFromTl != "" {
						qinChan <- replyFromTl
						iceChan <- replyFromTl
					}

				}()
				result <- "samaritan: " + replyFromTl
				//c.WriteMessage(websocket.TextMessage, []byte("samaritan: " + replyFromTl))
			}
		}
	}()

	go func() {
		for {
			if visitor > 0 {
				msgToQin := <-qinChan
				replyFromQin := qinAI(msgToQin)
				go func() {
					if replyFromQin != "" {
						tlChan <- replyFromQin
						iceChan <- replyFromQin
					}

				}()
				result <- "菲菲: " + replyFromQin
				//c.WriteMessage(websocket.TextMessage, []byte("菲菲: " + replyFromQin))

			}
		}
	}()

	go func() {
		for {
			if visitor > 0 {
				msgToIce := <-iceChan
				replyFromIce := iceAI(msgToIce)
				go func() {
					if replyFromIce != "" {
						tlChan <- replyFromIce
						qinChan <- replyFromIce
					}
				}()
				result <- "小冰: " + replyFromIce
				//c.WriteMessage(websocket.TextMessage, []byte("小冰: " + replyFromIce))

			}
		}
	}()

	go func() {
		for {
			c.WriteMessage(websocket.TextMessage, []byte(<-result))
		}
	}()
	for {

		_, _, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			visitor--
			break
		}
	}
}

//used for web samaritan robot
func socketHandler(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	for {
		var in []byte
		var ret []string
		mt, in, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}
		ret = receive(string(in))
		for i := range ret {
			c.WriteMessage(mt, []byte(ret[i]))
			time.Sleep(time.Second)
		}
		c.WriteMessage(mt, []byte(""))
	}
}

//when webSocket unavailable, fallback to ajax long polling
func ajax(w http.ResponseWriter, r *http.Request) {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	var messages = make(chan string)
	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() {
			if ret := iceAI(in); ret != "" {
				answer <- ret
			}
		}()
		go func() {
			if ret := tlAI(in); ret != "" {
				answer <- ret
			}
		}()
		go func() {
			if ret := qinAI(in); 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>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"

	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/transform"
	"math"
)

/**
 * Input: "Buchungstag";"Wertstellung (Valuta)";"Vorgang";"Buchungstext";"Umsatz in EUR";
 * Output: Date;Payee;Category;Memo;Outflow;Inflow
 */

func main() {

	if len(os.Args) < 3 {
		panic("Not enough command line arguments")
	}
	inputFileName := os.Args[1]
	outputFileName := os.Args[2]

	inputFile, err := os.Open(inputFileName)
	if err != nil {
		panic(err)
	}
	defer inputFile.Close()
	outputFile, err := os.Create(outputFileName)
	if err != nil {
		panic(err)
	}
	defer inputFile.Close()
	dec := transform.NewReader(inputFile, charmap.ISO8859_15.NewDecoder())
	scanner := bufio.NewScanner(dec)
	writer := bufio.NewWriter(outputFile)

	for scanner.Scan() {
		inputTokens := strings.Split(scanner.Text(), ";")
		if len(inputTokens) < 5 {
			continue
		}
		outputTokens := make([]string, 6)
		if strings.Contains(inputTokens[0], "Buchungstag") {
			outputTokens = strings.Split("Date;Payee;Category;Memo;Outflow;Inflow", ";")
		} else {
			outputTokens[0] = inputTokens[0]
			rawValue := strings.Replace(removeQuotes(inputTokens[4]), ".", "", -1)
			value, _ := strconv.ParseFloat(strings.Replace(rawValue, ",", ".", 1), 64)
			valueStr := strconv.FormatFloat(math.Abs(value), 'f', 2, 64)
			if value < 0 {
				outputTokens[4] = valueStr
			} else {
				outputTokens[5] = valueStr
			}

			if strings.Contains(inputTokens[2], "Lastschrift") {
				s := strings.Split(inputTokens[3], " Buchungstext: ")
				outputTokens[3] = removeQuotes(s[1])
				outputTokens[1] = removeQuotes(strings.Replace(s[0], "Auftraggeber: ", "", 1))
			} else if strings.Contains(inputTokens[2], "Wertpapiere") {
				outputTokens[3] = removeQuotes(strings.Replace(inputTokens[3], "Buchungstext: ", "", 1))
			} else if strings.Contains(inputTokens[2], "Überweisung") {
				s := strings.Split(inputTokens[3], " Buchungstext: ")
				outputTokens[3] = removeQuotes(s[1])
				outputTokens[1] = removeQuotes(strings.Replace(s[0], "Empfänger: ", "", 1))
			} else {
				outputTokens[3] = removeQuotes(inputTokens[3])
			}
		}

		doPayeeFiltering(outputTokens)
		filterRef(outputTokens)

		fmt.Fprintln(writer, strings.Join(outputTokens, ";"))
	}

}

var markets = []struct {
	in  string
	out string
}{
	{"E-CENTER", "Edeka"},
	{"EDEKA", "Edeka"},
	{"ROSSMANN", "Rossmann"},
	{"ALDI", "Aldi"},
	{"ERGO", "Ergo Direkt"},
	{"COSMOS", "Cosmos Leben"},
	{"1u1", "1und1"},
	{"VOLKSWAGEN", "Volkswagen"},
	{"COM-IN", "COM-IN"},
	{"Anna Roiser", "Anna Roiser"},
	{"Norma", "Norma"},
	{"McFit", "McFit"},
	{"Stadtwerke Ingolstadt", "Stadtwerke Ingolstadt"},
	{"e.solutions", "Einkommen"},
	{"Willner", "Willner"},
	{"REWE", "REWE"},
	{"C+A", "C+A"},
	{"Schuh Muecke", "Schuh Mücke"},
	{"E-TANKEN", "Tankstelle"},
	{"Bauhaus", "Bauhaus"},
}

func removeQuotes(s string) string {
	return strings.Replace(s, "\"", "", -1)
}

func doPayeeFiltering(tokens []string) {
	for _, market := range markets {
		if CaseInsensitiveContains(tokens[1], market.in) {
			tokens[1] = market.out
			tokens[3] = ""
		}
	}
}

func filterRef(tokens []string) {
	tokens[3] = strings.Split(tokens[3], " End-to-End-Ref.:")[0]
}

func CaseInsensitiveContains(s, substr string) bool {
	s, substr = strings.ToUpper(s), strings.ToUpper(substr)
	return strings.Contains(s, substr)
}
<commit_msg>Added handling vor visa reports<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"

	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/transform"
	"math"
)

/**
 * Input: "Buchungstag";"Wertstellung (Valuta)";"Vorgang";"Buchungstext";"Umsatz in EUR";
 * Output: Date;Payee;Category;Memo;Outflow;Inflow
 */

func main() {

	if len(os.Args) < 3 {
		panic("Not enough command line arguments")
	}
	inputFileName := os.Args[1]
	outputFileName := os.Args[2]

	inputFile, err := os.Open(inputFileName)
	if err != nil {
		panic(err)
	}
	defer inputFile.Close()
	outputFile, err := os.Create(outputFileName)
	if err != nil {
		panic(err)
	}
	defer inputFile.Close()
	dec := transform.NewReader(inputFile, charmap.ISO8859_15.NewDecoder())
	scanner := bufio.NewScanner(dec)
	writer := bufio.NewWriter(outputFile)
	defer writer.Flush()

	hasReference := false
	for scanner.Scan() {
		inputTokens := strings.Split(scanner.Text(), ";")
		fmt.Println(inputTokens)
		if len(inputTokens) < 5 {
			continue
		}
		outputTokens := make([]string, 6)

		if !hasReference && strings.Contains(inputTokens[3], "Referenz") {
			hasReference = true
		}
		if hasReference {
			inputTokens = append(inputTokens[:3], inputTokens[4:]...)
		}
		if strings.Contains(inputTokens[0], "Buchungstag") {
			outputTokens = strings.Split("Date;Payee;Category;Memo;Outflow;Inflow", ";")
		} else {
			outputTokens[0] = removeQuotes(inputTokens[0])
			rawValue := strings.Replace(removeQuotes(inputTokens[4]), ".", "", -1)
			value, _ := strconv.ParseFloat(strings.Replace(rawValue, ",", ".", 1), 64)
			valueStr := strconv.FormatFloat(math.Abs(value), 'f', 2, 64)
			if value < 0 {
				outputTokens[4] = valueStr
			} else {
				outputTokens[5] = valueStr
			}

			if strings.Contains(inputTokens[2], "Lastschrift") {
				s := strings.Split(inputTokens[3], " Buchungstext: ")
				outputTokens[3] = removeQuotes(s[1])
				outputTokens[1] = removeQuotes(strings.Replace(s[0], "Auftraggeber: ", "", 1))
			} else if strings.Contains(inputTokens[2], "Wertpapiere") {
				outputTokens[3] = removeQuotes(strings.Replace(inputTokens[3], "Buchungstext: ", "", 1))
				outputTokens[1] = "Transfer: .comdirect Depot"
			} else if strings.Contains(inputTokens[2], "Überweisung") {
				s := strings.Split(inputTokens[3], " Buchungstext: ")
				outputTokens[3] = removeQuotes(s[1])
				outputTokens[1] = removeQuotes(strings.Replace(s[0], "Empfänger: ", "", 1))
			} else if strings.Contains(inputTokens[2], "Visa-Umsatz") {
				outputTokens[1] = removeQuotes(inputTokens[3])
			} else if strings.Contains(inputTokens[2], "Visa-Kartenabrechnung") {
				outputTokens[1] = "Transfer: .comdirect"
			} else {
				outputTokens[3] = removeQuotes(inputTokens[3])
			}
		}

		doPayeeFiltering(outputTokens)
		filterRef(outputTokens)

		fmt.Fprintln(writer, strings.Join(outputTokens, ","))
	}

}

var markets = []struct {
	in  string
	out string
}{
	{"E-CENTER", "Edeka"},
	{"EDEKA", "Edeka"},
	{"ROSSMANN", "Rossmann"},
	{"ALDI", "Aldi"},
	{"ERGO", "Ergo Direkt"},
	{"COSMOS", "Transfer: Cosmos Leben"},
	{"1u1", "1und1"},
	{"VOLKSWAGEN", "Volkswagen"},
	{"COM-IN", "COM-IN"},
	{"Anna Roiser", "Anna Roiser"},
	{"Norma", "Norma"},
	{"McFit", "McFit"},
	{"Stadtwerke Ingolstadt", "Stadtwerke Ingolstadt"},
	{"e.solutions", "Einkommen"},
	{"Willner", "Willner"},
	{"REWE", "REWE"},
	{"C+A", "C+A"},
	{"Schuh Muecke", "Schuh Mücke"},
	{"E-TANKEN", "Tankstelle"},
	{"Bauhaus", "Bauhaus"},
	{"Visa-Monatsabrechnung", "Transfer: Visa"},
	{"BARCLAYCARD", "Barcleycard"},
	{"AMAZON.DE", "Amazon"},
	{"Amazon DE Marketplace", "Amazon Marketplace"},
}

func removeQuotes(s string) string {
	return strings.Replace(s, "\"", "", -1)
}

func doPayeeFiltering(tokens []string) {
	for _, market := range markets {
		if CaseInsensitiveContains(tokens[1], market.in) {
			tokens[1] = market.out
			tokens[3] = ""
		}
	}
}

func filterRef(tokens []string) {
	tokens[3] = strings.Split(tokens[3], " End-to-End-Ref.:")[0]
}

func CaseInsensitiveContains(s, substr string) bool {
	s, substr = strings.ToUpper(s), strings.ToUpper(substr)
	return strings.Contains(s, substr)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/rs/cors"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
	"google.golang.org/api/calendar/v3"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func main() {
	//	Set up our flags
	port := flag.Int("port", 3000, "The port to listen on")
	authEmail := flag.String("authEmail", "ReplaceWithSvcAcctEmail", "Service account email address")
	authSubject := flag.String("authSubject", "user@domain.com", "Impersonated user email address")
	allowedOrigins := flag.String("allowedOrigins", "*", "A comma-separated list of valid CORS origins")
	keyFilePath := flag.String("keyFile", "key.pem", "The location of the PEM encoded private key")

	//	Parse the command line for flags:
	flag.Parse()

	//	Read the key file in:
	keydata, err := ioutil.ReadFile(*keyFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// Your credentials should be obtained from the Google
	// Developer Console (https://console.developers.google.com).
	conf := &jwt.Config{
		Email: *authEmail,
		// The contents of your RSA private key or your PEM file
		// that contains a private key.
		// If you have a p12 file instead, you
		// can use `openssl` to export the private key into a pem file.
		//
		//    $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
		//
		// The field only supports PEM containers with no passphrase.
		// The openssl command will convert p12 keys to passphrase-less PEM containers.
		PrivateKey: keydata,
		Scopes: []string{
			calendar.CalendarScope,
			calendar.CalendarReadonlyScope,
		},
		TokenURL: google.JWTTokenURL,
		// If you would like to impersonate a user, you can
		// create a transport with a subject. The following GET
		// request will be made on the behalf of user@example.com.
		// Optional.
		Subject: *authSubject,
	}

	// Initiate an http.Client, the following GET request will be
	// authorized and authenticated on the behalf of user@example.com.
	client := conf.Client(oauth2.NoContext)

	r := mux.NewRouter()
	r.HandleFunc("/calendar/{calendarid}", func(w http.ResponseWriter, r *http.Request) {

		//	Parse the calendarid from the url
		id := mux.Vars(r)["calendarid"]

		//	Get a connection to the calendar service
		//	If we have errors, return them using standard HTTP service method
		svc, err := calendar.New(client)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		//	Get the list of events from now until the end of today
		now := time.Now()
		end := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Add(24 * time.Hour)

		events, err := svc.Events.List(id).
			TimeMin(now.Format(time.RFC3339)).
			TimeMax(end.Format(time.RFC3339)).
			SingleEvents(true).
			OrderBy("startTime").Do()

		//	If we have errors, return them using standard HTTP service method
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		//	Set the content type header and return the JSON
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(events)
	})

	//	CORS handler
	c := cors.New(cors.Options{
		AllowedOrigins:   strings.Split(*allowedOrigins, ","),
		AllowCredentials: true,
	})
	handler := c.Handler(r)

	//	Indicate what port we're starting the service on
	portString := strconv.Itoa(*port)
	fmt.Println("Allowed origins: ", *allowedOrigins)
	fmt.Println("Starting server on :", portString)
	http.ListenAndServe(":"+portString, handler)
}
<commit_msg>Added environment config<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/rs/cors"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"golang.org/x/oauth2/jwt"
	"google.golang.org/api/calendar/v3"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

var (
	//	Flags
	port           = flag.Int("port", 3000, "The port to listen on")
	authEmail      = flag.String("authEmail", "ReplaceWithSvcAcctEmail", "Service account email address")
	authSubject    = flag.String("authSubject", "user@domain.com", "Impersonated user email address")
	allowedOrigins = flag.String("allowedOrigins", "*", "A comma-separated list of valid CORS origins")
	keyFilePath    = flag.String("keyFile", "key.pem", "The location of the PEM encoded private key")
)

func parseEnvironment() {
	//	Check for the listen port
	if env_port := os.Getenv("CALENDAR_PORT"); env_port != "" {
		*port, _ = strconv.Atoi(env_port)
	}

	//	Check for allowed origins
	if env_origins := os.Getenv("CALENDAR_ALLOWED_ORIGINS"); env_origins != "" {
		*allowedOrigins = env_origins
	}

	//	Auth email
	if env_auth_email := os.Getenv("CALENDAR_AUTHEMAIL"); env_auth_email != "" {
		*authEmail = env_auth_email
	}

	//	Auth subject
	if env_auth_subject := os.Getenv("CALENDAR_AUTHSUBJECT"); env_auth_subject != "" {
		*authSubject = env_auth_subject
	}

	//	Key file path
	if env_keyfilepath := os.Getenv("CALENDAR_KEYFILEPATH"); env_keyfilepath != "" {
		*keyFilePath = env_keyfilepath
	}

}

func main() {
	//	Parse environment variables:
	parseEnvironment()

	//	Parse the command line for flags:
	flag.Parse()

	//	Read the key file in:
	keydata, err := ioutil.ReadFile(*keyFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// Your credentials should be obtained from the Google
	// Developer Console (https://console.developers.google.com).
	conf := &jwt.Config{
		Email: *authEmail,
		// The contents of your RSA private key or your PEM file
		// that contains a private key.
		// If you have a p12 file instead, you
		// can use `openssl` to export the private key into a pem file.
		//
		//    $ openssl pkcs12 -in key.p12 -passin pass:notasecret -out key.pem -nodes
		//
		// The field only supports PEM containers with no passphrase.
		// The openssl command will convert p12 keys to passphrase-less PEM containers.
		PrivateKey: keydata,
		Scopes: []string{
			calendar.CalendarScope,
			calendar.CalendarReadonlyScope,
		},
		TokenURL: google.JWTTokenURL,
		// If you would like to impersonate a user, you can
		// create a transport with a subject. The following GET
		// request will be made on the behalf of user@example.com.
		// Optional.
		Subject: *authSubject,
	}

	// Initiate an http.Client, the following GET request will be
	// authorized and authenticated on the behalf of user@example.com.
	client := conf.Client(oauth2.NoContext)

	r := mux.NewRouter()
	r.HandleFunc("/calendar/{calendarid}", func(w http.ResponseWriter, r *http.Request) {

		//	Parse the calendarid from the url
		id := mux.Vars(r)["calendarid"]

		//	Get a connection to the calendar service
		//	If we have errors, return them using standard HTTP service method
		svc, err := calendar.New(client)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		//	Get the list of events from now until the end of today
		now := time.Now()
		end := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).Add(24 * time.Hour)

		events, err := svc.Events.List(id).
			TimeMin(now.Format(time.RFC3339)).
			TimeMax(end.Format(time.RFC3339)).
			SingleEvents(true).
			OrderBy("startTime").Do()

		//	If we have errors, return them using standard HTTP service method
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		//	Set the content type header and return the JSON
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(events)
	})

	//	CORS handler
	c := cors.New(cors.Options{
		AllowedOrigins:   strings.Split(*allowedOrigins, ","),
		AllowCredentials: true,
	})
	handler := c.Handler(r)

	//	Indicate what port we're starting the service on
	portString := strconv.Itoa(*port)
	fmt.Println("Allowed origins: ", *allowedOrigins)
	fmt.Println("Starting server on :", portString)
	http.ListenAndServe(":"+portString, handler)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"strconv"

	"github.com/alecthomas/kingpin"
	"github.com/gorilla/mux"
)

type Configure struct {
	Addr     string
	Root     string
	HttpAuth string
	Cert     string
	Key      string
}

var gcfg = Configure{}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Gorilla!\n"))
}

func parseFlags() {
	kingpin.HelpFlag.Short('h')
	kingpin.Flag("addr", "listen address").Short('a').Default(":8000").StringVar(&gcfg.Addr)
	kingpin.Parse()
}

func main() {
	parseFlags()

	r := mux.NewRouter()
	r.HandleFunc("/", IndexHandler)
	log.Printf("Listening on addr: %s\n", strconv.Quote(gcfg.Addr))
	log.Fatal(http.ListenAndServe(gcfg.Addr, r))
}
<commit_msg>use type struct as http.Handler<commit_after>package main

import (
	"log"
	"net/http"
	"strconv"

	"github.com/alecthomas/kingpin"
	"github.com/gorilla/mux"
)

type Configure struct {
	Addr     string
	Root     string
	HttpAuth string
	Cert     string
	Key      string
}

var gcfg = Configure{}

func FileHandler(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "unknown")
}

type HTTPStaticServer struct {
	Root string
	m    *mux.Router
}

func NewHTTPStaticServer(root string) *HTTPStaticServer {
	m := mux.NewRouter()
	s := &HTTPStaticServer{
		Root: root,
		m:    m,
	}
	m.HandleFunc("/", s.hIndex)
	return s
}

func (s *HTTPStaticServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	s.m.ServeHTTP(w, r)
}

func (s *HTTPStaticServer) hIndex(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello world!"))
}

func parseFlags() {
	kingpin.HelpFlag.Short('h')
	kingpin.Flag("addr", "listen address").Short('a').Default(":8000").StringVar(&gcfg.Addr)
	kingpin.Parse()
}

func main() {
	parseFlags()
	ss := NewHTTPStaticServer("/")

	log.Printf("Listening on addr: %s\n", strconv.Quote(gcfg.Addr))
	log.Fatal(http.ListenAndServe(gcfg.Addr, ss))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/GeertJohan/yubigo"
	"github.com/kisom/whitelist"
	"github.com/qbit/puber/backend"
)

type puberReq struct {
	User   string `json:"user"`
	PubKey string `json:"pubKey"`
	YKey   string `json:"yKey"`
}

var listen string
var redisServer string
var prefix string
var yubiServer string
var yubiSKey string
var yubiCID string
var err error
var debug bool
var store = backend.MemStore{}
var be backend.Backend

func auth(ykey string) (*yubigo.YubiResponse, bool, error) {
	yubiAuth, err := yubigo.NewYubiAuth(yubiCID, yubiSKey)
	if yubiServer != "" {
		log.Printf("using '%s'", yubiServer)
		yubiAuth.SetApiServerList(yubiServer)
	}
	if err != nil {
		log.Println(err)
	}

	return yubiAuth.Verify(ykey)
}

func handleIdx(w http.ResponseWriter, r *http.Request) {
	data, err := be.GetCount()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "I currently have %d key(s)", data)
}

func handleAll(w http.ResponseWriter, r *http.Request) {
	keys, err := be.GetAll()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var data string
	for i := range keys {
		for j := range keys[i] {
			data += keys[i][j] + "\n"
		}
	}

	fmt.Fprintf(w, data)
}

func handleUser(w http.ResponseWriter, r *http.Request) {
	u, err := url.Parse(r.URL.Path)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	parts := strings.Split(u.String(), "/")
	user := parts[len(parts)-1]

	match, err := regexp.Match(",", []byte(user))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	var data string

	if match {
		users := strings.Split(user, ",")
		var d []string
		for i := range users {
			d, err = be.Get(users[i])
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}

			for j := range d {
				data += d[j] + "\n"
			}

		}
	} else {
		var d []string
		d, err = be.Get(user)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data += strings.Join(d, "\n")

	}
	fmt.Fprintf(w, data)
}

func readPost(r *http.Request) (*puberReq, error) {
	var data puberReq

	if r.Body == nil {
		return nil, errors.New("empty request")
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	defer r.Body.Close()

	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return &data, nil
}

func handleAdd(w http.ResponseWriter, r *http.Request) {
	data, err := readPost(r)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	result, ok, err := auth(data.YKey)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if debug {
		log.Println(result.GetRequestQuery())
	}

	if ok {
		be.Add(data.User, data.PubKey)
		fmt.Fprintf(w, "Added\n")
	} else {
		log.Println("Auth Failed!")
		http.Error(w, "Auth Failed!", http.StatusUnauthorized)
	}
}

func handleRm(w http.ResponseWriter, r *http.Request) {
	data, err := readPost(r)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	_, ok, err := auth(data.YKey)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if ok {
		if data.PubKey != "" {
			_, err := be.RM(data.User, data.PubKey)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
			fmt.Fprintf(w, fmt.Sprintf("Removed '%s' from '%s'\n", data.PubKey, data.User))
		} else {
			_, err := be.RMAll(data.User)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
			fmt.Fprintf(w, "Removed\n")
		}
	} else {
		log.Println("Auth Failed!")
		http.Error(w, "Auth Failed!", http.StatusUnauthorized)
	}
}

func init() {
	store.Init()
	be = backend.Backend(&store)
}

func main() {
	addWL := whitelist.NewBasic()
	rmWL := whitelist.NewBasic()
	wlAddHandler, err := whitelist.NewHandlerFunc(handleAdd, nil, addWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	wlRMHandler, err := whitelist.NewHandlerFunc(handleRm, nil, rmWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	flag.StringVar(&listen, "listen", ":8081", "listen string")
	whiteList := flag.String("wl", "localhost", "comma seperated list of hosts to allow access to /add")
	flag.StringVar(&redisServer, "redishost", "localhost:6379", "redis server")
	flag.StringVar(&prefix, "prefix", "puber", "prefix to store redis keys with")
	flag.StringVar(&yubiServer, "yserver", "api.yubico.com/wsapi/2.0/verify", "YubiAuth server to authenticate against")
	flag.StringVar(&yubiSKey, "yskey", "", "Yubi API Key")
	flag.StringVar(&yubiCID, "ycid", "", "Yubi Client ID")

	flag.BoolVar(&debug, "debug", false, "Enable debugging")

	flag.Parse()

	if debug {
		be.Add("debug", "debug key")
		be.Add("debug", "debug key two")
		be.Add("debug", "debug key three")
	}

	for _, host := range strings.Split(*whiteList, ",") {
		ip, err := net.LookupHost(host)
		if err != nil {
			log.Fatal(err)
		}
		for i := range ip {
			log.Printf("whitelisting: %s (%s)\n", host, ip[i])

			// TODO: It's ghetto to have two whitelists.
			// Reduce this down to use one.
			addWL.Add(net.ParseIP(ip[i]))
			rmWL.Add(net.ParseIP(ip[i]))
		}
	}

	http.HandleFunc("/", handleIdx)
	http.HandleFunc("/all", handleAll)
	http.HandleFunc("/user/", handleUser)
	http.Handle("/add", wlAddHandler)
	http.Handle("/rm", wlRMHandler)

	log.Printf("Listening on '%s'\n", listen)
	log.Fatal(http.ListenAndServe(listen, nil))
}
<commit_msg>remove unused flags<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"

	"github.com/GeertJohan/yubigo"
	"github.com/kisom/whitelist"
	"github.com/qbit/puber/backend"
)

type puberReq struct {
	User   string `json:"user"`
	PubKey string `json:"pubKey"`
	YKey   string `json:"yKey"`
}

var yubiServer string
var yubiSKey string
var yubiCID string
var err error
var debug bool
var store = backend.MemStore{}
var be backend.Backend

func auth(ykey string) (*yubigo.YubiResponse, bool, error) {
	yubiAuth, err := yubigo.NewYubiAuth(yubiCID, yubiSKey)
	if yubiServer != "" {
		log.Printf("using '%s'", yubiServer)
		yubiAuth.SetApiServerList(yubiServer)
	}
	if err != nil {
		log.Println(err)
	}

	return yubiAuth.Verify(ykey)
}

func handleIdx(w http.ResponseWriter, r *http.Request) {
	data, err := be.GetCount()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "I currently have %d key(s)", data)
}

func handleAll(w http.ResponseWriter, r *http.Request) {
	keys, err := be.GetAll()
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var data string
	for i := range keys {
		for j := range keys[i] {
			data += keys[i][j] + "\n"
		}
	}

	fmt.Fprintf(w, data)
}

func handleUser(w http.ResponseWriter, r *http.Request) {
	u, err := url.Parse(r.URL.Path)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	parts := strings.Split(u.String(), "/")
	user := parts[len(parts)-1]

	match, err := regexp.Match(",", []byte(user))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	var data string

	if match {
		users := strings.Split(user, ",")
		var d []string
		for i := range users {
			d, err = be.Get(users[i])
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}

			for j := range d {
				data += d[j] + "\n"
			}

		}
	} else {
		var d []string
		d, err = be.Get(user)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		data += strings.Join(d, "\n")

	}
	fmt.Fprintf(w, data)
}

func readPost(r *http.Request) (*puberReq, error) {
	var data puberReq

	if r.Body == nil {
		return nil, errors.New("empty request")
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	defer r.Body.Close()

	err = json.Unmarshal(body, &data)
	if err != nil {
		return nil, err
	}

	return &data, nil
}

func handleAdd(w http.ResponseWriter, r *http.Request) {
	data, err := readPost(r)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	result, ok, err := auth(data.YKey)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if debug {
		log.Println(result.GetRequestQuery())
	}

	if ok {
		be.Add(data.User, data.PubKey)
		fmt.Fprintf(w, "Added\n")
	} else {
		log.Println("Auth Failed!")
		http.Error(w, "Auth Failed!", http.StatusUnauthorized)
	}
}

func handleRm(w http.ResponseWriter, r *http.Request) {
	data, err := readPost(r)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	_, ok, err := auth(data.YKey)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	if ok {
		if data.PubKey != "" {
			_, err := be.RM(data.User, data.PubKey)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
			fmt.Fprintf(w, fmt.Sprintf("Removed '%s' from '%s'\n", data.PubKey, data.User))
		} else {
			_, err := be.RMAll(data.User)
			if err != nil {
				log.Println(err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
			}
			fmt.Fprintf(w, "Removed\n")
		}
	} else {
		log.Println("Auth Failed!")
		http.Error(w, "Auth Failed!", http.StatusUnauthorized)
	}
}

func init() {
	store.Init()
	be = backend.Backend(&store)
}

func main() {
	addWL := whitelist.NewBasic()
	rmWL := whitelist.NewBasic()
	wlAddHandler, err := whitelist.NewHandlerFunc(handleAdd, nil, addWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	wlRMHandler, err := whitelist.NewHandlerFunc(handleRm, nil, rmWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	listen := flag.String("listen", ":8081", "listen string")
	whiteList := flag.String("wl", "localhost", "comma seperated list of hosts to allow access to /add")

	flag.StringVar(&yubiServer, "yserver", "api.yubico.com/wsapi/2.0/verify", "YubiAuth server to authenticate against")
	flag.StringVar(&yubiSKey, "yskey", "", "Yubi API Key")
	flag.StringVar(&yubiCID, "ycid", "", "Yubi Client ID")
	flag.BoolVar(&debug, "debug", false, "Enable debugging")

	flag.Parse()

	if debug {
		be.Add("debug", "debug key")
		be.Add("debug", "debug key two")
		be.Add("debug", "debug key three")
	}

	for _, host := range strings.Split(*whiteList, ",") {
		ip, err := net.LookupHost(host)
		if err != nil {
			log.Fatal(err)
		}
		for i := range ip {
			log.Printf("whitelisting: %s (%s)\n", host, ip[i])

			// TODO: It's ghetto to have two whitelists.
			// Reduce this down to use one.
			addWL.Add(net.ParseIP(ip[i]))
			rmWL.Add(net.ParseIP(ip[i]))
		}
	}

	http.HandleFunc("/", handleIdx)
	http.HandleFunc("/all", handleAll)
	http.HandleFunc("/user/", handleUser)
	http.Handle("/add", wlAddHandler)
	http.Handle("/rm", wlRMHandler)

	log.Printf("Listening on '%s'\n", *listen)
	log.Fatal(http.ListenAndServe(*listen, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/ChristianSiegert/panoptikos/asset"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"strings"
)

type Page struct {
	CssFilename      string
	IsProductionMode bool
	JsFilename       string
}

var page Page

// Command-line flags
var (
	httpPort           = flag.String("port", "8080", "HTTP port the web server listens to.")
	isProductionMode   = flag.Bool("production", false, "Whether the server should run in production mode.")
	jsCompilationLevel = flag.String("js-compilation-level", asset.JS_COMPILATION_LEVEL_ADVANCED_OPTIMIZATIONS, "Either WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS or ADVANCED_OPTIMIZATIONS. See https://developers.google.com/closure/compiler/docs/compilation_levels. Advanced optimizations can break your code. Only used in production mode.")
	verbose            = flag.Bool("verbose", false, "Whether additional information should be displayed.")
)

// RegEx patterns
var (
	assetUrlPattern    = regexp.MustCompile("\\.(?:css|ico|js|png)$")
	whitespacePattern1 = regexp.MustCompile(">[ \f\n\r\t]+<")
	whitespacePattern2 = regexp.MustCompile(">[ \f\n\r\t]+\\{\\{")
	whitespacePattern3 = regexp.MustCompile("\\}\\}[ \f\n\r\t]+<")
)

func main() {
	// Set maximum number of CPUs that can be executing simultaneously
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Parse command-line flags
	flag.Parse()

	log.Println("Production mode:", *isProductionMode)
	page.IsProductionMode = *isProductionMode

	page.CssFilename = asset.CompileCss()

	if *isProductionMode {
		page.JsFilename = asset.CompileJavaScript(*jsCompilationLevel, *verbose)
	}

	http.HandleFunc("/", handleRequest)
	log.Println("Web server is running at 127.0.0.1:" + *httpPort + ".")

	if error := http.ListenAndServe(":"+*httpPort, nil); error != nil {
		log.Fatal("Could not start web server: ", error)
	}
}

func handleRequest(responseWriter http.ResponseWriter, request *http.Request) {
	// Redirect legacy URLs to home page to prevent 404 Not Found errors
	if request.URL.Path == "/feedback" ||
		request.URL.Path == "/feeds" ||
		request.URL.Path == "/preferences" ||
		strings.Index(request.URL.Path, "/pictures") == 0 ||
		strings.Index(request.URL.Path, "/referrals/by-source") == 0 ||
		strings.Index(request.URL.Path, "/sources/select") == 0 {
		http.Redirect(responseWriter, request, "/", http.StatusMovedPermanently)
		return
	}

	if request.URL.Path == "/" {
		fileContent, error := ioutil.ReadFile("views/layouts/default.html")

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		// Remove unnecessary whitespace
		cleanedFileContent := whitespacePattern1.ReplaceAllString(string(fileContent), "><")
		cleanedFileContent = whitespacePattern2.ReplaceAllString(cleanedFileContent, ">{{")
		cleanedFileContent = whitespacePattern3.ReplaceAllString(cleanedFileContent, "}}<")

		parsedTemplate, error := template.New("default").Parse(cleanedFileContent)

		if error != nil {
			http.Error(responseWriter, error.Error(), http.StatusInternalServerError)
			log.Println("Error:", error)
			return
		}

		if error := parsedTemplate.Execute(responseWriter, page); error != nil {
			http.Error(responseWriter, error.Error(), http.StatusInternalServerError)
			log.Println("Error:", error)
			return
		}

		return
	}

	if assetUrlPattern.MatchString(request.URL.Path) {
		file, error := os.Open("webroot" + request.URL.Path)

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		fileInfo, error := file.Stat()

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		http.ServeContent(responseWriter, request, "webroot"+request.URL.Path, fileInfo.ModTime(), file)
		return
	}

	http.NotFound(responseWriter, request)
}
<commit_msg>Log message for whether the server was started in development or production mode is now a sentence.<commit_after>package main

import (
	"flag"
	"github.com/ChristianSiegert/panoptikos/asset"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"runtime"
	"strings"
)

type Page struct {
	CssFilename      string
	IsProductionMode bool
	JsFilename       string
}

var page Page

// Command-line flags
var (
	httpPort           = flag.String("port", "8080", "HTTP port the web server listens to.")
	isProductionMode   = flag.Bool("production", false, "Whether the server should run in production mode.")
	jsCompilationLevel = flag.String("js-compilation-level", asset.JS_COMPILATION_LEVEL_ADVANCED_OPTIMIZATIONS, "Either WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS or ADVANCED_OPTIMIZATIONS. See https://developers.google.com/closure/compiler/docs/compilation_levels. Advanced optimizations can break your code. Only used in production mode.")
	verbose            = flag.Bool("verbose", false, "Whether additional information should be displayed.")
)

// RegEx patterns
var (
	assetUrlPattern    = regexp.MustCompile("\\.(?:css|ico|js|png)$")
	whitespacePattern1 = regexp.MustCompile(">[ \f\n\r\t]+<")
	whitespacePattern2 = regexp.MustCompile(">[ \f\n\r\t]+\\{\\{")
	whitespacePattern3 = regexp.MustCompile("\\}\\}[ \f\n\r\t]+<")
)

func main() {
	// Set maximum number of CPUs that can be executing simultaneously
	runtime.GOMAXPROCS(runtime.NumCPU())

	// Parse command-line flags
	flag.Parse()

	if *isProductionMode {
		log.Println("Starting in production mode.")
	} else {
		log.Println("Starting in development mode.")
	}

	page.IsProductionMode = *isProductionMode
	page.CssFilename = asset.CompileCss()

	if *isProductionMode {
		page.JsFilename = asset.CompileJavaScript(*jsCompilationLevel, *verbose)
	}

	http.HandleFunc("/", handleRequest)
	log.Println("Web server is running at 127.0.0.1:" + *httpPort + ".")

	if error := http.ListenAndServe(":"+*httpPort, nil); error != nil {
		log.Fatal("Could not start web server: ", error)
	}
}

func handleRequest(responseWriter http.ResponseWriter, request *http.Request) {
	// Redirect legacy URLs to home page to prevent 404 Not Found errors
	if request.URL.Path == "/feedback" ||
		request.URL.Path == "/feeds" ||
		request.URL.Path == "/preferences" ||
		strings.Index(request.URL.Path, "/pictures") == 0 ||
		strings.Index(request.URL.Path, "/referrals/by-source") == 0 ||
		strings.Index(request.URL.Path, "/sources/select") == 0 {
		http.Redirect(responseWriter, request, "/", http.StatusMovedPermanently)
		return
	}

	if request.URL.Path == "/" {
		fileContent, error := ioutil.ReadFile("views/layouts/default.html")

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		// Remove unnecessary whitespace
		cleanedFileContent := whitespacePattern1.ReplaceAllString(string(fileContent), "><")
		cleanedFileContent = whitespacePattern2.ReplaceAllString(cleanedFileContent, ">{{")
		cleanedFileContent = whitespacePattern3.ReplaceAllString(cleanedFileContent, "}}<")

		parsedTemplate, error := template.New("default").Parse(cleanedFileContent)

		if error != nil {
			http.Error(responseWriter, error.Error(), http.StatusInternalServerError)
			log.Println("Error:", error)
			return
		}

		if error := parsedTemplate.Execute(responseWriter, page); error != nil {
			http.Error(responseWriter, error.Error(), http.StatusInternalServerError)
			log.Println("Error:", error)
			return
		}

		return
	}

	if assetUrlPattern.MatchString(request.URL.Path) {
		file, error := os.Open("webroot" + request.URL.Path)

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		fileInfo, error := file.Stat()

		if error != nil {
			http.NotFound(responseWriter, request)
			log.Println("Error:", error)
			return
		}

		http.ServeContent(responseWriter, request, "webroot"+request.URL.Path, fileInfo.ModTime(), file)
		return
	}

	http.NotFound(responseWriter, request)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/urfave/cli"
)

// Version set at compile-time
var Version string

func main() {
	app := cli.NewApp()
	app.Name = "line plugin"
	app.Usage = "line plugin"
	app.Action = run
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "secret",
			Usage:  "line channel secret",
			EnvVar: "PLUGIN_CHANNEL_SECRET,LINE_CHANNEL_SECRET",
		},
		cli.StringFlag{
			Name:   "token",
			Usage:  "line channel access token",
			EnvVar: "PLUGIN_CHANNEL_TOKEN,LINE_CHANNEL_TOKEN",
		},
		cli.StringSliceFlag{
			Name:   "to",
			Usage:  "line user ID",
			EnvVar: "PLUGIN_TO,LINE_TO",
		},
		cli.StringSliceFlag{
			Name:   "message",
			Usage:  "line message",
			EnvVar: "PLUGIN_MESSAGE,LINE_MESSAGE",
		},
		cli.StringSliceFlag{
			Name:   "image",
			Usage:  "line image",
			EnvVar: "PLUGIN_IMAGE,LINE_IMAGE",
		},
		cli.StringSliceFlag{
			Name:   "video",
			Usage:  "line video",
			EnvVar: "PLUGIN_VIDEO,LINE_VIDEO",
		},
		cli.StringSliceFlag{
			Name:   "audio",
			Usage:  "line audio",
			EnvVar: "PLUGIN_AUDIO,LINE_AUDIO",
		},
		cli.StringSliceFlag{
			Name:   "sticker",
			Usage:  "line sticker",
			EnvVar: "PLUGIN_STICKER,LINE_STICKER",
		},
		cli.StringSliceFlag{
			Name:   "location",
			Usage:  "line location",
			EnvVar: "PLUGIN_LOCATION,LINE_LOCATION",
		},
		cli.StringFlag{
			Name:   "delimiter",
			Usage:  "line delimiter",
			Value:  "::",
			EnvVar: "PLUGIN_DELIMITER,LINE_DELIMITER",
		},
		cli.BoolFlag{
			Name:   "match.email",
			Usage:  "send message when only match email",
			EnvVar: "PLUGIN_ONLY_MATCH_EMAIL",
		},
		cli.IntFlag{
			Name:   "port",
			Usage:  "webhook port",
			EnvVar: "LINE_WEBHOOK_PORT",
			Value:  8088,
		},
		cli.StringFlag{
			Name:   "repo.owner",
			Usage:  "repository owner",
			EnvVar: "DRONE_REPO_OWNER",
		},
		cli.StringFlag{
			Name:   "repo.name",
			Usage:  "repository name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "commit.sha",
			Usage:  "git commit sha",
			EnvVar: "DRONE_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "commit.branch",
			Value:  "master",
			Usage:  "git commit branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit.author",
			Usage:  "git author name",
			EnvVar: "DRONE_COMMIT_AUTHOR",
		},
		cli.StringFlag{
			Name:   "commit.author.email",
			Usage:  "git author email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.StringFlag{
			Name:   "commit.message",
			Usage:  "commit message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "build.event",
			Value:  "push",
			Usage:  "build event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.IntFlag{
			Name:   "build.number",
			Usage:  "build number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.StringFlag{
			Name:   "build.status",
			Usage:  "build status",
			Value:  "success",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build.link",
			Usage:  "build link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build.tag",
			Usage:  "build tag",
			EnvVar: "DRONE_TAG",
		},
		cli.Float64Flag{
			Name:   "job.started",
			Usage:  "job started",
			EnvVar: "DRONE_JOB_STARTED",
		},
		cli.Float64Flag{
			Name:   "job.finished",
			Usage:  "job finished",
			EnvVar: "DRONE_JOB_FINISHED",
		},
		cli.StringFlag{
			Name:  "env-file",
			Usage: "source env file",
		},
	}
	app.Run(os.Args)
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}

	plugin := Plugin{
		Repo: Repo{
			Owner: c.String("repo.owner"),
			Name:  c.String("repo.name"),
		},
		Build: Build{
			Tag:      c.String("build.tag"),
			Number:   c.Int("build.number"),
			Event:    c.String("build.event"),
			Status:   c.String("build.status"),
			Commit:   c.String("commit.sha"),
			Branch:   c.String("commit.branch"),
			Author:   c.String("commit.author"),
			Email:    c.String("commit.author.email"),
			Message:  c.String("commit.message"),
			Link:     c.String("build.link"),
			Started:  c.Float64("job.started"),
			Finished: c.Float64("job.finished"),
		},
		Config: Config{
			ChannelSecret: c.String("secret"),
			ChannelToken:  c.String("token"),
			To:            c.StringSlice("to"),
			Delimiter:     c.String("delimiter"),
			MatchEmail:    c.Bool("match.email"),
			Message:       c.StringSlice("message"),
			Image:         c.StringSlice("image"),
			Video:         c.StringSlice("video"),
			Audio:         c.StringSlice("audio"),
			Sticker:       c.StringSlice("sticker"),
			Location:      c.StringSlice("location"),
			Port:          c.Int("port"),
		},
	}

	command := c.Args().Get(0)

	if command == "webhook" {
		return plugin.Webhook()
	}

	return plugin.Exec()
}
<commit_msg>docs: update cli template.<commit_after>package main

import (
	"os"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/urfave/cli"
)

// Version set at compile-time
var Version string

func main() {
	app := cli.NewApp()
	app.Name = "Drone LINE"
	app.Usage = "Send LINE notification"
	app.Copyright = "Copyright (c) 2017 Bo-Yi Wu"
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Bo-Yi Wu",
			Email: "appleboy.tw@gmail.com",
		},
	}
	app.Action = run
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "secret, s",
			Usage:  "line channel secret",
			EnvVar: "PLUGIN_CHANNEL_SECRET,LINE_CHANNEL_SECRET",
		},
		cli.StringFlag{
			Name:   "token, t",
			Usage:  "line channel access token",
			EnvVar: "PLUGIN_CHANNEL_TOKEN,LINE_CHANNEL_TOKEN",
		},
		cli.StringSliceFlag{
			Name:   "to, u",
			Usage:  "line user ID",
			EnvVar: "PLUGIN_TO,LINE_TO",
		},
		cli.StringSliceFlag{
			Name:   "message, m",
			Usage:  "line message",
			EnvVar: "PLUGIN_MESSAGE,LINE_MESSAGE",
		},
		cli.StringSliceFlag{
			Name:   "image",
			Usage:  "line image",
			EnvVar: "PLUGIN_IMAGE,LINE_IMAGE",
		},
		cli.StringSliceFlag{
			Name:   "video",
			Usage:  "line video",
			EnvVar: "PLUGIN_VIDEO,LINE_VIDEO",
		},
		cli.StringSliceFlag{
			Name:   "audio",
			Usage:  "line audio",
			EnvVar: "PLUGIN_AUDIO,LINE_AUDIO",
		},
		cli.StringSliceFlag{
			Name:   "sticker",
			Usage:  "line sticker",
			EnvVar: "PLUGIN_STICKER,LINE_STICKER",
		},
		cli.StringSliceFlag{
			Name:   "location",
			Usage:  "line location",
			EnvVar: "PLUGIN_LOCATION,LINE_LOCATION",
		},
		cli.StringFlag{
			Name:   "delimiter",
			Usage:  "line delimiter",
			Value:  "::",
			EnvVar: "PLUGIN_DELIMITER,LINE_DELIMITER",
		},
		cli.BoolFlag{
			Name:   "match.email",
			Usage:  "send message when only match email",
			EnvVar: "PLUGIN_ONLY_MATCH_EMAIL",
		},
		cli.IntFlag{
			Name:   "port, P",
			Usage:  "webhook port",
			EnvVar: "LINE_WEBHOOK_PORT",
			Value:  8088,
		},
		cli.StringFlag{
			Name:   "repo.owner",
			Usage:  "repository owner",
			EnvVar: "DRONE_REPO_OWNER",
		},
		cli.StringFlag{
			Name:   "repo.name",
			Usage:  "repository name",
			EnvVar: "DRONE_REPO_NAME",
		},
		cli.StringFlag{
			Name:   "commit.sha",
			Usage:  "git commit sha",
			EnvVar: "DRONE_COMMIT_SHA",
		},
		cli.StringFlag{
			Name:   "commit.branch",
			Value:  "master",
			Usage:  "git commit branch",
			EnvVar: "DRONE_COMMIT_BRANCH",
		},
		cli.StringFlag{
			Name:   "commit.author",
			Usage:  "git author name",
			EnvVar: "DRONE_COMMIT_AUTHOR",
		},
		cli.StringFlag{
			Name:   "commit.author.email",
			Usage:  "git author email",
			EnvVar: "DRONE_COMMIT_AUTHOR_EMAIL",
		},
		cli.StringFlag{
			Name:   "commit.message",
			Usage:  "commit message",
			EnvVar: "DRONE_COMMIT_MESSAGE",
		},
		cli.StringFlag{
			Name:   "build.event",
			Value:  "push",
			Usage:  "build event",
			EnvVar: "DRONE_BUILD_EVENT",
		},
		cli.IntFlag{
			Name:   "build.number",
			Usage:  "build number",
			EnvVar: "DRONE_BUILD_NUMBER",
		},
		cli.StringFlag{
			Name:   "build.status",
			Usage:  "build status",
			Value:  "success",
			EnvVar: "DRONE_BUILD_STATUS",
		},
		cli.StringFlag{
			Name:   "build.link",
			Usage:  "build link",
			EnvVar: "DRONE_BUILD_LINK",
		},
		cli.StringFlag{
			Name:   "build.tag",
			Usage:  "build tag",
			EnvVar: "DRONE_TAG",
		},
		cli.Float64Flag{
			Name:   "job.started",
			Usage:  "job started",
			EnvVar: "DRONE_JOB_STARTED",
		},
		cli.Float64Flag{
			Name:   "job.finished",
			Usage:  "job finished",
			EnvVar: "DRONE_JOB_FINISHED",
		},
		cli.StringFlag{
			Name:  "env-file",
			Usage: "source env file",
		},
	}

	// Override a template
	cli.AppHelpTemplate = `
________                                       .____    .___ _______  ___________
\______ \_______  ____   ____   ____           |    |   |   |\      \ \_   _____/
 |    |  \_  __ \/  _ \ /    \_/ __ \   ______ |    |   |   |/   |   \ |    __)_
 |    |   \  | \(  <_> )   |  \  ___/  /_____/ |    |___|   /    |    \|        \
/_______  /__|   \____/|___|  /\___  >         |_______ \___\____|__  /_______  /
        \/                  \/     \/                  \/           \/        \/
                                                              version: {{.Version}}
NAME:
   {{.Name}} - {{.Usage}}

USAGE:
   {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
   {{if len .Authors}}
AUTHOR:
   {{range .Authors}}{{ . }}{{end}}
   {{end}}{{if .Commands}}
COMMANDS:
{{range .Commands}}{{if not .HideHelp}}   {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
GLOBAL OPTIONS:
   {{range .VisibleFlags}}{{.}}
   {{end}}{{end}}{{if .Copyright }}
COPYRIGHT:
   {{.Copyright}}
   {{end}}{{if .Version}}
VERSION:
   {{.Version}}
   {{end}}
REPOSITORY:
    Github: https://github.com/appleboy/drone-line
`
	app.Run(os.Args)
}

func run(c *cli.Context) error {
	if c.String("env-file") != "" {
		_ = godotenv.Load(c.String("env-file"))
	}

	plugin := Plugin{
		Repo: Repo{
			Owner: c.String("repo.owner"),
			Name:  c.String("repo.name"),
		},
		Build: Build{
			Tag:      c.String("build.tag"),
			Number:   c.Int("build.number"),
			Event:    c.String("build.event"),
			Status:   c.String("build.status"),
			Commit:   c.String("commit.sha"),
			Branch:   c.String("commit.branch"),
			Author:   c.String("commit.author"),
			Email:    c.String("commit.author.email"),
			Message:  c.String("commit.message"),
			Link:     c.String("build.link"),
			Started:  c.Float64("job.started"),
			Finished: c.Float64("job.finished"),
		},
		Config: Config{
			ChannelSecret: c.String("secret"),
			ChannelToken:  c.String("token"),
			To:            c.StringSlice("to"),
			Delimiter:     c.String("delimiter"),
			MatchEmail:    c.Bool("match.email"),
			Message:       c.StringSlice("message"),
			Image:         c.StringSlice("image"),
			Video:         c.StringSlice("video"),
			Audio:         c.StringSlice("audio"),
			Sticker:       c.StringSlice("sticker"),
			Location:      c.StringSlice("location"),
			Port:          c.Int("port"),
		},
	}

	command := c.Args().Get(0)

	if command == "webhook" {
		return plugin.Webhook()
	}

	return plugin.Exec()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"database/sql"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	_ "github.com/mattn/go-sqlite3"
	"github.com/pkg/errors"
)

type tagType int

const (
	GTAGS tagType = iota
	GRTAGS
	GPATH
)

func (t tagType) String() string {
	switch t {
	case GTAGS:
		return "GTAGS"
	case GRTAGS:
		return "GRTAGS"
	case GPATH:
		return "GPATH"
	}
	panic("invalid tagType")
}

type standard struct {
	tagName    string
	fileID     int
	lineNumber int
	lineImage  string
}

func (s standard) String() string {
	return fmt.Sprintf("%d @n %d %s", s.fileID, s.lineNumber, s.lineImage)
}

type compact struct {
	fileID      int
	lineNumbers []int
}

func (c compact) String() string {
	continueCounter := 0
	output := fmt.Sprintf("%d", c.lineNumbers[0]) // [0] must be exist
	for l := 1; l < len(c.lineNumbers); l++ {
		diff := c.lineNumbers[l] - c.lineNumbers[l-1]
		if continueCounter == 0 {
			if diff == 1 {
				output += "-"
				continueCounter++
			} else {
				output += fmt.Sprintf(",%d", diff)
			}
		} else {
			if diff == 1 {
				continueCounter++
			} else {
				output += fmt.Sprintf("%d,%d", continueCounter, diff)
				continueCounter = 0
			}
		}
	}
	if continueCounter != 0 {
		output += fmt.Sprintf("%d", continueCounter)
	}
	return fmt.Sprintf("%d @n %s", c.fileID, output)
}

type global struct {
	fileID      int
	gtagsData   []standard
	grtagsData  map[string]*compact
	db          map[tagType]*sql.DB
	transaction map[tagType]*sql.Tx
	// lineImageScanner
	basePath    string
	currentFile *os.File
	currentLine int
	scanner     *bufio.Scanner
	fset        *token.FileSet
}

func newGlobal(fset *token.FileSet, basePath string) (*global, error) {
	g := &global{
		fileID:      0,
		gtagsData:   make([]standard, 0),
		grtagsData:  make(map[string]*compact),
		db:          make(map[tagType]*sql.DB),
		transaction: make(map[tagType]*sql.Tx),
		basePath:    basePath,
		currentFile: nil,
		currentLine: 0,
		scanner:     nil,
		fset:        fset,
	}

	dbfiles := []tagType{
		GTAGS,
		GRTAGS,
		GPATH,
	}

	var err error
	for _, file := range dbfiles {
		os.Remove("./" + file.String())
		g.db[file], err = sql.Open("sqlite3", file.String())
		if err != nil {
			return nil, err
		}
		_, err = g.db[file].Exec(`create table db (key text, dat text, extra text)`)
		if err != nil {
			return nil, err
		}
		g.transaction[file], err = g.db[file].Begin()
		if err != nil {
			return nil, err
		}
	}

	g.insertEntry(GTAGS, " __.COMPRESS", " __.COMPRESS ddefine ttypedef", nil)
	g.insertEntry(GTAGS, " __.COMPNAME", " __.COMPNAME", nil)
	g.insertEntry(GTAGS, " __.VERSION", " __.VERSION 6", nil)

	g.insertEntry(GRTAGS, " __.COMPACT", " __.COMPACT", nil)
	g.insertEntry(GRTAGS, " __.COMPLINE", " __.COMPLINE", nil)
	g.insertEntry(GRTAGS, " __.COMPNAME", " __.COMPNAME", nil)
	g.insertEntry(GRTAGS, " __.VERSION", " __.VERSION 6", nil)

	g.insertEntry(GPATH, " __.VERSION", " __.VERSION 2", nil)
	g.insertEntry(GPATH, " __.NEXTKEY", "1", nil)

	return g, nil
}

func (g *global) insertEntry(tag tagType, key, dat, extra interface{}) {
	_, err := g.transaction[tag].Exec(`insert into db (key, dat, extra) values (?, ?, ?)`, key, dat, extra)
	if err != nil {
		log.Panicln("failed to exec", err, "tag:", tag, "|key:", key, "|dat:", dat, "|extra:", extra)
	}
}

func (g *global) dump() {
	if g.fileID == 0 {
		return
	}

	for _, s := range g.gtagsData {
		g.insertEntry(GTAGS, s.tagName, s.String(), strconv.Itoa(s.fileID))
	}
	for tagName, compact := range g.grtagsData {
		g.insertEntry(GRTAGS, tagName, compact.String(), strconv.Itoa(compact.fileID))
	}

	filepath, _ := filepath.Rel(g.basePath, g.currentFile.Name())
	filepath = "./" + filepath
	if *verbose {
		log.Println(filepath)
	}

	g.insertEntry(GPATH, filepath, g.fileID, nil)
	g.insertEntry(GPATH, g.fileID, filepath, nil)
	g.insertEntry(GPATH, " __.NEXTKEY", strconv.Itoa(g.fileID+1), nil)
}

func (g *global) finalize() error {
	if g.currentFile != nil {
		err := g.currentFile.Close()
		if err != nil {
			return err
		}
	}
	g.dump()

	dbfiles := []tagType{
		GTAGS,
		GRTAGS,
		GPATH,
	}

	for _, file := range dbfiles {
		g.transaction[file].Commit()
		g.db[file].Close()
	}

	return nil
}

func (g *global) switchFile(abspath string) (err error) {
	// Close and Setup Scanner
	if g.currentFile != nil {
		err := g.currentFile.Close()
		if err != nil {
			return errors.Wrapf(err, "failed to close current file, current: %s abspath: %s", g.currentFile.Name(), abspath)
		}
	}
	g.currentFile, err = os.Open(abspath)
	if err != nil {
		return errors.Wrap(err, "failed to open next file ")
	}
	g.scanner = bufio.NewScanner(g.currentFile)
	g.currentLine = 0

	// Reset parsed data
	g.gtagsData = make([]standard, 0)
	g.grtagsData = make(map[string]*compact)
	g.fileID++

	return nil
}

func (g *global) addFuncDecl(node *ast.FuncDecl) {
	ident := node.Name
	pos := g.fset.Position(node.Pos())
	for ; g.currentLine < pos.Line; g.currentLine++ {
		g.scanner.Scan()
	}
	lineImage := strings.Replace(strings.TrimSpace(g.scanner.Text()), ident.Name, "@n", -1)

	g.gtagsData = append(g.gtagsData, standard{
		tagName:    ident.Name,
		fileID:     g.fileID,
		lineNumber: pos.Line,
		lineImage:  lineImage,
	})
}

func (g *global) addIdent(ident *ast.Ident) {
	pos := g.fset.Position(ident.Pos())
	r, found := g.grtagsData[ident.Name]
	if found {
		r.lineNumbers = append(r.lineNumbers, pos.Line)
	} else {
		g.grtagsData[ident.Name] = &compact{
			fileID:      g.fileID,
			lineNumbers: []int{pos.Line},
		}
	}
}

func (g *global) parse(node ast.Node) bool {
	if node == nil {
		return false
	}
	if _, ok := node.(*ast.Package); ok {
		return true
	}
	pos := g.fset.Position(node.Pos())
	absPath, err := filepath.Abs(pos.Filename)
	if err != nil {
		log.Fatal("failed to get absolute path: ", err)
	}
	if g.currentFile == nil || g.currentFile.Name() != absPath {
		g.dump()

		err = g.switchFile(absPath)
		if err != nil {
			log.Fatal("failed to switch file: ", err)
		}
	}

	switch node.(type) {
	case *ast.FuncDecl:
		g.addFuncDecl(node.(*ast.FuncDecl))
	case *ast.Ident:
		g.addIdent(node.(*ast.Ident))
	}
	return true
}

var verbose *bool

func main() {
	verbose = flag.Bool("v", false, "Verbose mode.")
	flag.Parse()

	basePath, err := filepath.Abs(".")
	if err != nil {
		log.Fatal("failed to get absolute path: ", err)
	}

	fset := token.NewFileSet() // positions are relative to fset
	g, err := newGlobal(fset, basePath)
	if err != nil {
		log.Fatal(err)
	}

	err = filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			pkgs, err := parser.ParseDir(fset, path, nil, 0)
			if err != nil {
				log.Fatal(err)
			}
			for _, p := range pkgs {
				ast.Inspect(p, g.parse)
			}
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}

	err = g.finalize()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>ignore hidden and missing files<commit_after>package main

import (
	"bufio"
	"database/sql"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	_ "github.com/mattn/go-sqlite3"
	"github.com/pkg/errors"
)

type tagType int

const (
	GTAGS tagType = iota
	GRTAGS
	GPATH
)

func (t tagType) String() string {
	switch t {
	case GTAGS:
		return "GTAGS"
	case GRTAGS:
		return "GRTAGS"
	case GPATH:
		return "GPATH"
	}
	panic("invalid tagType")
}

type standard struct {
	tagName    string
	fileID     int
	lineNumber int
	lineImage  string
}

func (s standard) String() string {
	return fmt.Sprintf("%d @n %d %s", s.fileID, s.lineNumber, s.lineImage)
}

type compact struct {
	fileID      int
	lineNumbers []int
}

func (c compact) String() string {
	continueCounter := 0
	output := fmt.Sprintf("%d", c.lineNumbers[0]) // [0] must be exist
	for l := 1; l < len(c.lineNumbers); l++ {
		diff := c.lineNumbers[l] - c.lineNumbers[l-1]
		if continueCounter == 0 {
			if diff == 1 {
				output += "-"
				continueCounter++
			} else {
				output += fmt.Sprintf(",%d", diff)
			}
		} else {
			if diff == 1 {
				continueCounter++
			} else {
				output += fmt.Sprintf("%d,%d", continueCounter, diff)
				continueCounter = 0
			}
		}
	}
	if continueCounter != 0 {
		output += fmt.Sprintf("%d", continueCounter)
	}
	return fmt.Sprintf("%d @n %s", c.fileID, output)
}

type global struct {
	fileID      int
	gtagsData   []standard
	grtagsData  map[string]*compact
	db          map[tagType]*sql.DB
	transaction map[tagType]*sql.Tx
	// lineImageScanner
	basePath    string
	currentFile *os.File
	currentLine int
	scanner     *bufio.Scanner
	fset        *token.FileSet
}

func newGlobal(fset *token.FileSet, basePath string) (*global, error) {
	g := &global{
		fileID:      0,
		gtagsData:   make([]standard, 0),
		grtagsData:  make(map[string]*compact),
		db:          make(map[tagType]*sql.DB),
		transaction: make(map[tagType]*sql.Tx),
		basePath:    basePath,
		currentFile: nil,
		currentLine: 0,
		scanner:     nil,
		fset:        fset,
	}

	dbfiles := []tagType{
		GTAGS,
		GRTAGS,
		GPATH,
	}

	var err error
	for _, file := range dbfiles {
		os.Remove("./" + file.String())
		g.db[file], err = sql.Open("sqlite3", file.String())
		if err != nil {
			return nil, err
		}
		_, err = g.db[file].Exec(`create table db (key text, dat text, extra text)`)
		if err != nil {
			return nil, err
		}
		g.transaction[file], err = g.db[file].Begin()
		if err != nil {
			return nil, err
		}
	}

	g.insertEntry(GTAGS, " __.COMPRESS", " __.COMPRESS ddefine ttypedef", nil)
	g.insertEntry(GTAGS, " __.COMPNAME", " __.COMPNAME", nil)
	g.insertEntry(GTAGS, " __.VERSION", " __.VERSION 6", nil)

	g.insertEntry(GRTAGS, " __.COMPACT", " __.COMPACT", nil)
	g.insertEntry(GRTAGS, " __.COMPLINE", " __.COMPLINE", nil)
	g.insertEntry(GRTAGS, " __.COMPNAME", " __.COMPNAME", nil)
	g.insertEntry(GRTAGS, " __.VERSION", " __.VERSION 6", nil)

	g.insertEntry(GPATH, " __.VERSION", " __.VERSION 2", nil)
	g.insertEntry(GPATH, " __.NEXTKEY", "1", nil)

	return g, nil
}

func (g *global) insertEntry(tag tagType, key, dat, extra interface{}) {
	_, err := g.transaction[tag].Exec(`insert into db (key, dat, extra) values (?, ?, ?)`, key, dat, extra)
	if err != nil {
		log.Panicln("failed to exec", err, "tag:", tag, "|key:", key, "|dat:", dat, "|extra:", extra)
	}
}

func (g *global) dump() {
	if g.fileID == 0 {
		return
	}

	for _, s := range g.gtagsData {
		g.insertEntry(GTAGS, s.tagName, s.String(), strconv.Itoa(s.fileID))
	}
	for tagName, compact := range g.grtagsData {
		g.insertEntry(GRTAGS, tagName, compact.String(), strconv.Itoa(compact.fileID))
	}

	filepath, _ := filepath.Rel(g.basePath, g.currentFile.Name())
	filepath = "./" + filepath
	if *verbose {
		log.Println(filepath)
	}

	g.insertEntry(GPATH, filepath, g.fileID, nil)
	g.insertEntry(GPATH, g.fileID, filepath, nil)
	g.insertEntry(GPATH, " __.NEXTKEY", strconv.Itoa(g.fileID+1), nil)
}

func (g *global) finalize() error {
	if g.currentFile != nil {
		err := g.currentFile.Close()
		if err != nil {
			return err
		}
	}
	g.dump()

	dbfiles := []tagType{
		GTAGS,
		GRTAGS,
		GPATH,
	}

	for _, file := range dbfiles {
		g.transaction[file].Commit()
		g.db[file].Close()
	}

	return nil
}

func (g *global) switchFile(abspath string) (err error) {
	// Close and Setup Scanner
	if g.currentFile != nil {
		err := g.currentFile.Close()
		if err != nil {
			return errors.Wrapf(err, "failed to close current file, current: %s abspath: %s", g.currentFile.Name(), abspath)
		}
	}
	g.currentFile, err = os.Open(abspath)
	if err != nil {
		return errors.Wrap(err, "failed to open next file ")
	}
	g.scanner = bufio.NewScanner(g.currentFile)
	g.currentLine = 0

	// Reset parsed data
	g.gtagsData = make([]standard, 0)
	g.grtagsData = make(map[string]*compact)
	g.fileID++

	return nil
}

func (g *global) addFuncDecl(node *ast.FuncDecl) {
	ident := node.Name
	pos := g.fset.Position(node.Pos())
	for ; g.currentLine < pos.Line; g.currentLine++ {
		g.scanner.Scan()
	}
	lineImage := strings.Replace(strings.TrimSpace(g.scanner.Text()), ident.Name, "@n", -1)

	g.gtagsData = append(g.gtagsData, standard{
		tagName:    ident.Name,
		fileID:     g.fileID,
		lineNumber: pos.Line,
		lineImage:  lineImage,
	})
}

func (g *global) addIdent(ident *ast.Ident) {
	pos := g.fset.Position(ident.Pos())
	r, found := g.grtagsData[ident.Name]
	if found {
		r.lineNumbers = append(r.lineNumbers, pos.Line)
	} else {
		g.grtagsData[ident.Name] = &compact{
			fileID:      g.fileID,
			lineNumbers: []int{pos.Line},
		}
	}
}

func (g *global) parse(node ast.Node) bool {
	if node == nil {
		return false
	}
	if _, ok := node.(*ast.Package); ok {
		return true
	}
	pos := g.fset.Position(node.Pos())
	absPath, err := filepath.Abs(pos.Filename)
	if err != nil {
		log.Fatal("failed to get absolute path: ", err)
	}
	if g.currentFile == nil || g.currentFile.Name() != absPath {
		// only add data into gtags file if currentFile is not nil
		if g.currentFile != nil {
			g.dump()
		}

		err = g.switchFile(absPath)
		if err != nil {
			log.Print("failed to switch file: ", err)
			return false
		}
	}

	switch node.(type) {
	case *ast.FuncDecl:
		g.addFuncDecl(node.(*ast.FuncDecl))
	case *ast.Ident:
		g.addIdent(node.(*ast.Ident))
	}
	return true
}

var verbose *bool

func main() {
	verbose = flag.Bool("v", false, "Verbose mode.")
	flag.Parse()

	basePath, err := filepath.Abs(".")
	if err != nil {
		log.Fatal("failed to get absolute path: ", err)
	}

	fset := token.NewFileSet() // positions are relative to fset
	g, err := newGlobal(fset, basePath)
	if err != nil {
		log.Fatal(err)
	}

	err = filepath.Walk(basePath, func(path string, info os.FileInfo, err error) error {
		// Skip files if hidden
		if !info.IsDir() && info.Name()[0] == '.' {
			fmt.Println("Hidden file, skipping: ", path)
			return nil
		}
		if info.IsDir() {
			// if hidden directory - skip the entire dir
			if info.Name()[0] == '.' {
				fmt.Println("Hidden folder, skipping: ", path)
				return filepath.SkipDir
			}
			pkgs, err := parser.ParseDir(fset, path, nil, 0)
			if err != nil {
				log.Println("Error in parsing directory, skipping: ", path, err)
				return nil
			}
			for _, p := range pkgs {
				ast.Inspect(p, g.parse)
			}
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}

	err = g.finalize()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"

	"./schemas"
	"github.com/Shopify/sarama"
	"github.com/companieshouse/chs.go/avro"
	"github.com/companieshouse/chs.go/avro/schema"
	"github.com/companieshouse/chs.go/kafka/producer"
)

// Assigns all flags to variables
var (
	brokerPtr         = flag.String("broker", "", "Broker address")
	topicPtr          = flag.String("topic", "", "Topic name")
	schemaPtr         = flag.String("schema", "", "Schema name")
	schemaRegistryPtr = flag.String("schema-registry", "", "Schema Registry")
	partitionPtr      = flag.Int64("partition", 0, "Partition")
	zookeeperPtr      = flag.String("zookeeper", "", "Zookeeper address")
	offsetPtr         = flag.String("offset", "-1", "Offset number")
	jsonOutPtr        = flag.Int("json-out", -1, "Print deserialized JSON message")
)

func main() {
	flag.Parse()
    flag.PrintDefaults()
	fmt.Println("broker:", *brokerPtr)
	fmt.Println("topic:", *topicPtr)
	fmt.Println("schema:", *schemaPtr)
	fmt.Println("schema-registry:", *schemaRegistryPtr)
	fmt.Println("partition:", *partitionPtr)
	fmt.Println("zookeeper-registry:", *zookeeperPtr)
	fmt.Println("offset:", *offsetPtr)
	fmt.Println("json-out:", *jsonOutPtr)

	// create offset array
	offsetArray := createOffsetArray(*offsetPtr)

	// create default config for sarama
	config := sarama.NewConfig()

	//create consumer
	consumer, err := sarama.NewConsumer([]string{*brokerPtr}, config)
	if err != nil {
		panic(err)
	}

	// create messages chan
	messages := make(chan *sarama.ConsumerMessage)
	go consumePartition(consumer, *topicPtr, int32(*partitionPtr), messages, offsetArray)

	// create signals chan
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)

	consumed := 0
ConsumerLoop:
	for {
		select {
		case msg := <-messages:

			schemaStruct := schemas.IdentifySchema(*topicPtr)
			var err error

			// Get schema from schema registry and use it to create avro consumer
			schema, err := schema.Get(*schemaRegistryPtr, *topicPtr)
			consumerAvro := &avro.Schema{
				Definition: schema,
			}

			// Unmarshal message value and assign it to schemaStruct
			if err = consumerAvro.Unmarshal(msg.Value, schemaStruct); err != nil {
				fmt.Errorf("error unmarshalling avro: %v", err)
			}

			// create avro producer
			producerAvro := &avro.Schema{
				Definition: schema,
			}

			// Marshall schemaStruct that contains message value ready for republishing
			messageBytes, err := producerAvro.Marshal(schemaStruct)
			if err != nil {
                fmt.Errorf("error marshalling avro: %v", err)
			}

			// create producer message
			producerMessage := &producer.Message{
				Value: messageBytes,
				Topic: *topicPtr,
			}

			//create new producer
			p, err := producer.New(&producer.Config{Acks: &producer.WaitForAll, BrokerAddrs: []string{*brokerPtr}})
			if err != nil {
                fmt.Errorf("error creating producer: %v", err)
				os.Exit(1)
			}

			// republish message
			partition, offset, err := p.Send(producerMessage)
			if err != nil {
                fmt.Errorf("error republishing message to topic: %v", err)
			}

			fmt.Printf("Message republished to topic: %v using partition: %v offset: %v \n", *topicPtr, partition, offset)

			consumed++
		case <-signals:
			fmt.Println("break")
			break ConsumerLoop
		}
	}
}

// The offset slice is passed into method and is iterated over and each message
// related to the offset in the topic/partition is outputted into the 'out' chan
func consumePartition(consumer sarama.Consumer, topic string, partition int32, out chan *sarama.ConsumerMessage, offsetArray []int64) {
	for offset := range offsetArray {
		partitionConsumer, err := consumer.ConsumePartition(topic, partition, int64(offset))
		if err != nil {
			panic(err)
		}

		select {
		case msg := <-partitionConsumer.Messages():
			partitionConsumer.Close()
			out <- msg
		}
	}
}

// This creates the offset array depending on whether a range or a single value
// is entered as an argument to the tool
func createOffsetArray(offset string) []int64 {
	arraySize := make([]int64, 0)
	if strings.ContainsAny(offset, "-") {
		slice := strings.Split(offset, "-")
		minRange, err := strconv.ParseInt(slice[0], 10, 64)
		maxRange, err := strconv.ParseInt(slice[1], 10, 64)
		if err != nil {
			panic(err)
		}

		index := 0
		for value := minRange; value <= maxRange; value++ {
			arraySize = append(arraySize, value)
			index++
		}
	} else {
		value, err := strconv.ParseInt(offset, 10, 64)
		if err != nil {
			panic(err)
		}
		arraySize = append(arraySize, value)
	}
	return arraySize
}
<commit_msg>Add flag validation and help descriptions for flag<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"

	"./schemas"
	"github.com/Shopify/sarama"
	"github.com/companieshouse/chs.go/avro"
	"github.com/companieshouse/chs.go/avro/schema"
	"github.com/companieshouse/chs.go/kafka/producer"
)

// Assigns all flags to variables
var (
	brokerPtr         = flag.String("broker", "", "Broker address")
	topicPtr          = flag.String("topic", "", "Topic name")
	schemaPtr         = flag.String("schema", "", "Schema name")
	schemaRegistryPtr = flag.String("schema-registry", "", "Schema Registry")
	partitionPtr      = flag.Int64("partition", 0, "Partition (default: 0)")
	offsetPtr         = flag.String("offset", "", "Offset number")
	jsonOutPtr        = flag.Int64("json-out", 0, "Print deserialized JSON message (default: 0)")
)

func main() {
	flag.Parse()

	// check if all mandatory flags have been provided
    validateFlags()

    // Print flags and parameters of the tool
    printFlags()

	// create offset array
	offsetArray := createOffsetArray(*offsetPtr)

	// create default config for sarama
	config := sarama.NewConfig()

	//create consumer
	consumer, err := sarama.NewConsumer([]string{*brokerPtr}, config)
	if err != nil {
		panic(err)
	}

	// create messages chan
	messages := make(chan *sarama.ConsumerMessage)
	go consumePartition(consumer, *topicPtr, int32(*partitionPtr), messages, offsetArray)

	// create signals chan
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, os.Interrupt)

	consumed := 0
ConsumerLoop:
	for {
		select {
		case msg := <-messages:

			schemaStruct := schemas.IdentifySchema(*topicPtr)
			var err error

			// Get schema from schema registry and use it to create avro consumer
			schema, err := schema.Get(*schemaRegistryPtr, *schemaPtr)
			consumerAvro := &avro.Schema{
				Definition: schema,
			}

			// Unmarshal message value and assign it to schemaStruct
			if err = consumerAvro.Unmarshal(msg.Value, schemaStruct); err != nil {
				fmt.Errorf("error unmarshalling avro: %v", err)
			}

			// create avro producer
			producerAvro := &avro.Schema{
				Definition: schema,
			}

			// Marshall schemaStruct that contains message value ready for republishing
			messageBytes, err := producerAvro.Marshal(schemaStruct)
			if err != nil {
                fmt.Errorf("error marshalling avro: %v", err)
			}

			// create producer message
			producerMessage := &producer.Message{
				Value: messageBytes,
				Topic: *topicPtr,
			}

			//create new producer
			p, err := producer.New(&producer.Config{Acks: &producer.WaitForAll, BrokerAddrs: []string{*brokerPtr}})
			if err != nil {
                fmt.Errorf("error creating producer: %v", err)
				os.Exit(1)
			}

			// republish message
			partition, offset, err := p.Send(producerMessage)
			if err != nil {
                fmt.Errorf("error republishing message to topic: %v", err)
			}

			fmt.Printf("Message republished to topic: %v using partition: %v offset: %v \n", *topicPtr, partition, offset)

			consumed++
		case <-signals:
			fmt.Println("break")
			break ConsumerLoop
		}
	}
}

// Validates the flags to make sure all mandatory flags have been supplied
// throw an error if not the case
func validateFlags() {
    flag.VisitAll(func (f *flag.Flag) {
        if string(f.Value.String()) == "" {
            fmt.Printf("Value not supplied for: %v \n", f.Name)
            os.Exit(1)
        }
        //fmt.Printf("%v: %v\n", f.Name, f.Value)
    })
}

// Prints the flags and parameters of the tool
func printFlags() {
    fmt.Println("Parameters:")
    flag.VisitAll(func (f *flag.Flag) {
        fmt.Printf("%v: %v\n", f.Name, f.Value)
    })
}

// The offset slice is passed into method and is iterated over and each message
// related to the offset in the topic/partition is outputted into the 'out' chan
func consumePartition(consumer sarama.Consumer, topic string, partition int32, out chan *sarama.ConsumerMessage, offsetArray []int64) {
	for offset := range offsetArray {
		partitionConsumer, err := consumer.ConsumePartition(topic, partition, int64(offset))
		if err != nil {
			panic(err)
		}

		select {
		case msg := <-partitionConsumer.Messages():
			partitionConsumer.Close()
			out <- msg
		}
	}
}

// This creates the offset array depending on whether a range or a single value
// is entered as an argument to the tool
func createOffsetArray(offset string) []int64 {
	arraySize := make([]int64, 0)
	if strings.ContainsAny(offset, "-") {
		slice := strings.Split(offset, "-")
		minRange, err := strconv.ParseInt(slice[0], 10, 64)
		maxRange, err := strconv.ParseInt(slice[1], 10, 64)
		if err != nil {
			panic(err)
		}

		index := 0
		for value := minRange; value <= maxRange; value++ {
			arraySize = append(arraySize, value)
			index++
		}
	} else {
		value, err := strconv.ParseInt(offset, 10, 64)
		if err != nil {
			panic(err)
		}
		arraySize = append(arraySize, value)
	}
	return arraySize
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Randy Westlund. All rights reserved.
 * This code is under the BSD-2-Clause license.
 *
 * This is the main file. Run it to launch the application.
 */
package main

import (
    "log"
    "strings"
    "os"
    "os/exec"
    "github.com/BurntSushi/toml"
)

/* The location of the configuration file to read. */
const config_file = "superv.conf"

/* A process definition, as read directly from the config file. */
type Process struct {
    /* A human-readable tag for process. */
    Name           string
    /* The path to the actual executable to run. */
    Path           string
    /* A string with arguments to be passed to the process. */
    Args           string
    /* Filenames for writing stdout and stderr. Defaults to /dev/null. */
    Stdout         string
    Stderr         string
    /* The number of milliseconds to wait before restarting a process. */
    Restart_delay  uint64
}

/* The config file definition. Currently, there are only [[process]] blocks,
 * but global options may be added in the future.
 */
type Config struct {
    /* This must be named after the [[process]] block in the config file. */
    Process      []Process
}

func main() {
    log.Println("Starting superv")
    /* Read the config file. */
    var config Config
    _, err := toml.DecodeFile(config_file, &config)
    if err != nil {
        log.Fatal("Failed to parse config file ", config_file, "\n", err)
    }

    /* Listen on this channel to know when all goroutines are done. */
    var done = make(chan bool)
    for _, p := range config.Process {
        log.Println("Launching ", p.Name)
        /* Launch the process in a new goroutine. */
        go launch(p, done)
    }
    /* Listen for one done signal from each goroutine. */
    for range config.Process {
        <-done
        log.Println("A process finished");
    }
    log.Println("Exiting");
}

/* Take a process and notification channel. Launch the process, wait for it to
 * exit, and signal completion.
 */
func launch(p Process, done chan bool) {
    /* Convert p.args to a slice, so the process gets separate arguments. */
    var cmd = exec.Command(p.Path, squeeze(strings.Split(p.Args, " "))...)
    /* Use the parent's stdout and stderr. */
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    cmd.Run()
    cmd.Wait()
    /* Signal completion. */
    done <- true
}

/* Remove empty strings from a slice of strings. Returns a new slice. */
func squeeze(string_slice []string) []string {
    var ss []string
    for _, s := range string_slice {
        if s != "" {
            ss = append(ss, s)
        }
    }
    return ss
}
<commit_msg>Implement logging to files<commit_after>/*
 * Copyright (c) 2016, Randy Westlund. All rights reserved.
 * This code is under the BSD-2-Clause license.
 *
 * This is the main file. Run it to launch the application.
 */
package main

import (
    "log"
    "strings"
    "os"
    "os/exec"
    "github.com/BurntSushi/toml"
)

/* The location of the configuration file to read. */
const config_file = "superv.conf"

/* A process definition, as read directly from the config file. */
type Process struct {
    /* A human-readable tag for process. */
    Name           string
    /* The path to the actual executable to run. */
    Path           string
    /* A string with arguments to be passed to the process. */
    Args           string
    /* Filenames for writing stdout and stderr. Defaults to /dev/null. */
    Stdout         string
    Stderr         string
    /* The number of milliseconds to wait before restarting a process. */
    Restart_delay  uint64
}

/* The config file definition. Currently, there are only [[process]] blocks,
 * but global options may be added in the future.
 */
type Config struct {
    /* This must be named after the [[process]] block in the config file. */
    Process      []Process
}

func main() {
    log.Println("Starting superv")
    /* Read the config file. */
    var config Config
    _, err := toml.DecodeFile(config_file, &config)
    if err != nil {
        log.Fatal("Failed to parse config file ", config_file, "\n", err)
    }

    /* Listen on this channel to know when all goroutines are done. */
    var done = make(chan bool)
    for _, p := range config.Process {
        log.Println("Launching ", p.Name)
        /* Launch the process in a new goroutine. */
        go launch(p, done)
    }
    /* Listen for one done signal from each goroutine. */
    for range config.Process {
        <-done
        log.Println("A process finished");
    }
    log.Println("Exiting");
}

/* Take a process and notification channel. Launch the process, wait for it to
 * exit, and signal completion.
 */
func launch(p Process, done chan bool) {
    /* Convert p.args to a slice, so the process gets separate arguments. */
    var cmd = exec.Command(p.Path, squeeze(strings.Split(p.Args, " "))...)

    /* If there's an output file for stdout specified, use it. */
    if p.Stdout != "" {
        stdout_file, err := os.OpenFile(p.Stdout,
                    os.O_CREATE | os.O_APPEND | os.O_WRONLY, 0664)
        if err != nil {
            log.Println("Failed to open log file ", p.Stdout, "\n", err)
        }
        defer stdout_file.Close()
        cmd.Stdout = stdout_file
    /* If not, use /dev/null. */
    } else {
        cmd.Stdout = nil
    }

    /* If there's an output file for stderr specified, use it. */
    if p.Stderr != "" {
        stderr_file, err := os.OpenFile(p.Stderr,
                    os.O_CREATE | os.O_APPEND | os.O_WRONLY, 0664)
        if err != nil {
            log.Println("Failed to open log file ", p.Stderr, "\n", err)
        }
        defer stderr_file.Close()
        cmd.Stderr = stderr_file
    /* If not, use /dev/null. */
    } else {
        cmd.Stderr = nil
    }

    /* Fire off the chiled process, then wait for it to complete. */
    cmd.Start()
    cmd.Wait()
    /* Signal completion. */
    done <- true
}

/* Remove empty strings from a slice of strings. Returns a new slice. */
func squeeze(string_slice []string) []string {
    var ss []string
    for _, s := range string_slice {
        if s != "" {
            ss = append(ss, s)
        }
    }
    return ss
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 - Cloud Instruments Co. Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package main

import (
	"fmt"
	log "github.com/cihub/seelog"
	"os"
	"strconv"
	"time"
)

var hostName string
var appName = "test"
var pid int

func init() {
	hostName, _ = os.Hostname()
	pid = os.Getpid()
}

var myLevelToString = map[log.LogLevel]string{
	log.TraceLvl:    "MyTrace",
	log.DebugLvl:    "MyDebug",
	log.InfoLvl:     "MyInfo",
	log.WarnLvl:     "MyWarn",
	log.ErrorLvl:    "MyError",
	log.CriticalLvl: "MyCritical",
	log.Off:         "MyOff",
}

var levelToSyslogSeverity = map[log.LogLevel]int{
	// Mapping to RFC 5424 where possible
	log.TraceLvl:    7,
	log.DebugLvl:    7,
	log.InfoLvl:     6,
	log.WarnLvl:     5,
	log.ErrorLvl:    3,
	log.CriticalLvl: 2,
	log.Off:         7,
}

func createSyslogHeaderFormatter(params string) log.FormatterFunc {
	facility := 20
	i, err := strconv.Atoi(params)
	if err == nil && i >= 0 && i <= 23 {
		facility = i
	}

	return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
		return fmt.Sprintf("<%d>1 %s %s %s %d - -", facility*8+levelToSyslogSeverity[level],
			time.Now().Format("2006-01-02T15:04:05Z07:00"),
			hostName, appName, pid)
	}
}

func createMyLevelFormatter(params string) log.FormatterFunc {
	return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
		levelStr, ok := myLevelToString[level]
		if !ok {
			return "Broken level!"
		}
		return levelStr
	}
}

func init() {
	// Errors are omitted here for simplicity. Do not omit them in production.
	_ = log.RegisterCustomFormatter("CustomSyslogHeader", createSyslogHeaderFormatter)
	_ = log.RegisterCustomFormatter("MyLevel", createMyLevelFormatter)
}

func customFormattersMain() {
	levelsFormatter()
	syslogCustomFormatter()
}

func levelsFormatter() {
	testConfig := `
<seelog type="sync">
	<outputs formatid="main">
		<console/>
	</outputs>
	<formats>
		<format id="main" format="%MyLevel %Msg%n"/>
	</formats>
</seelog>`

	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)

	log.Trace("Test message!")
}

func syslogCustomFormatter() {
	defer log.Flush()

	// NOTE: in real usecases a conn writer should be used instead of console.
	// Example: <conn formatid="syslogfmt" net="tcp4" addr="server.address:5514" usetls="true" insecureskipverify="true" />
	testConfig := `
<seelog type="sync">
	<outputs formatid="syslogfmt">
		<console/>
	</outputs>
	<formats>
		<format id="syslogfmt" format="%CustomSyslogHeader(20) %Msg%n"/>
	</formats>
</seelog>`

	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)

	log.Trace("Test message!")
}
<commit_msg>Minor rename.<commit_after>// Copyright (c) 2014 - Cloud Instruments Co. Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package main

import (
	"fmt"
	log "github.com/cihub/seelog"
	"os"
	"strconv"
	"time"
)

var hostName string
var appName = "test"
var pid int

func init() {
	hostName, _ = os.Hostname()
	pid = os.Getpid()
}

var myLevelToString = map[log.LogLevel]string{
	log.TraceLvl:    "MyTrace",
	log.DebugLvl:    "MyDebug",
	log.InfoLvl:     "MyInfo",
	log.WarnLvl:     "MyWarn",
	log.ErrorLvl:    "MyError",
	log.CriticalLvl: "MyCritical",
	log.Off:         "MyOff",
}

var levelToSyslogSeverity = map[log.LogLevel]int{
	// Mapping to RFC 5424 where possible
	log.TraceLvl:    7,
	log.DebugLvl:    7,
	log.InfoLvl:     6,
	log.WarnLvl:     5,
	log.ErrorLvl:    3,
	log.CriticalLvl: 2,
	log.Off:         7,
}

func createSyslogHeaderFormatter(params string) log.FormatterFunc {
	facility := 20
	i, err := strconv.Atoi(params)
	if err == nil && i >= 0 && i <= 23 {
		facility = i
	}

	return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
		return fmt.Sprintf("<%d>1 %s %s %s %d - -", facility*8+levelToSyslogSeverity[level],
			time.Now().Format("2006-01-02T15:04:05Z07:00"),
			hostName, appName, pid)
	}
}

func createMyLevelFormatter(params string) log.FormatterFunc {
	return func(message string, level log.LogLevel, context log.LogContextInterface) interface{} {
		levelStr, ok := myLevelToString[level]
		if !ok {
			return "Broken level!"
		}
		return levelStr
	}
}

func init() {
	// Errors are omitted here for simplicity. Do not omit them in production.
	_ = log.RegisterCustomFormatter("CustomSyslogHeader", createSyslogHeaderFormatter)
	_ = log.RegisterCustomFormatter("MyLevel", createMyLevelFormatter)
}

func customFormattersMain() {
	levelsFormatter()
	syslogCustomFormatter()
}

func levelsFormatter() {
	testConfig := `
<seelog type="sync">
	<outputs formatid="main">
		<console/>
	</outputs>
	<formats>
		<format id="main" format="%MyLevel %Msg%n"/>
	</formats>
</seelog>`

	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)

	log.Trace("Test message!")
}

func syslogCustomFormatter() {
	defer log.Flush()

	// NOTE: in real usecases a conn writer should be used instead of console.
	// Example: <conn formatid="syslogfmt" net="tcp4" addr="server.address:5514" tls="true" insecureskipverify="true" />
	testConfig := `
<seelog type="sync">
	<outputs formatid="syslogfmt">
		<console/>
	</outputs>
	<formats>
		<format id="syslogfmt" format="%CustomSyslogHeader(20) %Msg%n"/>
	</formats>
</seelog>`

	logger, _ := log.LoggerFromConfigAsBytes([]byte(testConfig))
	log.ReplaceLogger(logger)

	log.Trace("Test message!")
}
<|endoftext|>


<commit_before>package libvirt

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/mistifyio/mistify-agent/client"
)

// DomainXML populates a libvirt domain xml template with guest properties
func (lv *Libvirt) DomainXML(guest *client.Guest) (string, error) {
	fmt.Println(guest)

	const xml = `
<domain type="{{.Type}}">
  <name>{{.Id}}</name>
  <memory unit="MiB">{{.Memory}}</memory>
  <vcpu>{{.Cpu}}</vcpu>

  {{if .Metadata}}
  <metadata>
    {{range .Metadata}}
    {{end}}
  </metadata>
  {{end}}

  <os>
    <type>hvm</type>
  </os>
  <devices>
    {{range .Nics}}
    <interface type="bridge">
      <guest dev="{{.Name}}" />
      {{if .Mac}}<mac address="{{.Mac}}" />{{end}}
      <source bridge='{{.Network}}'/>
      <target dev="{{.Device}}" />
      {{if .Model}}<model type="{{.Model}}" />{{end}}
    </interface>
    {{end}}

    {{range .Disks}}
    <disk type="block" device="disk">
      <driver name="qemu" type="raw" />
      <source dev="{{.Source}}" />
      <target dev="{{.Device}}" bus="{{.Bus}}" />
    </disk>
    {{end}}
  </devices>
</domain>
`

	tmpl := template.New("xml")
	template.Must(tmpl.Parse(xml))

	buf := new(bytes.Buffer)
	err := tmpl.Execute(buf, guest)
	if err != nil {
		return "", err
	}

	return buf.String(), nil
}
<commit_msg>xml: specify zfs path to image source<commit_after>package libvirt

import (
	"bytes"
	"fmt"
	"text/template"

	"github.com/mistifyio/mistify-agent/client"
)

// DomainXML populates a libvirt domain xml template with guest properties
func (lv *Libvirt) DomainXML(guest *client.Guest) (string, error) {
	fmt.Println(guest)

	const xmlFormat = `
<domain type="{{.Type}}">
  <name>{{.Id}}</name>
  <memory unit="MiB">{{.Memory}}</memory>
  <vcpu>{{.Cpu}}</vcpu>

  {{if .Metadata}}
  <metadata>
    {{range .Metadata}}
    {{end}}
  </metadata>
  {{end}}

  <os>
    <type>hvm</type>
  </os>
  <devices>
    {{range .Nics}}
    <interface type="bridge">
      <guest dev="{{.Name}}" />
      {{if .Mac}}<mac address="{{.Mac}}" />{{end}}
      <source bridge='{{.Network}}'/>
      <target dev="{{.Device}}" />
      {{if .Model}}<model type="{{.Model}}" />{{end}}
    </interface>
    {{end}}

    {{range .Disks}}
    <disk type="block" device="disk">
      <driver name="qemu" type="raw" />
      <source dev="/dev/zvol/%s/images/{{.Source}}" />
      <target dev="{{.Device}}" bus="{{.Bus}}" />
    </disk>
    {{end}}
  </devices>
</domain>
`

	xml := fmt.Sprintf(xmlFormat, lv.zpool)
	tmpl := template.New("xml")
	template.Must(tmpl.Parse(xml))

	buf := new(bytes.Buffer)
	err := tmpl.Execute(buf, guest)
	if err != nil {
		return "", err
	}

	return buf.String(), nil
}
<|endoftext|>