<commit_before>//go:generate goagen bootstrap -d github.com/tri125/gwentapi/design

package main

import (
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/tri125/gwentapi/app"
	"github.com/tri125/gwentapi/controllers"
)

func main() {
	// Create service
	service := goa.New("gwentapi")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(true))
	service.Use(middleware.ErrorHandler(service, true))
	service.Use(middleware.Recover())
	service.Use(gzip.Middleware(-1))
	// Mount "card" controller
	c := NewCardController(service)
	app.MountCardController(service, c)
	// Mount "faction" controller
	c2 := NewFactionController(service)
	app.MountFactionController(service, c2)
	// Mount "glyph" controller
	c3 := NewGlyphController(service)
	app.MountGlyphController(service, c3)
	// Mount "patch" controller
	c4 := NewPatchController(service)
	app.MountPatchController(service, c4)
	// Mount "phonebook" controller
	c5 := NewPhonebookController(service)
	app.MountPhonebookController(service, c5)
	// Mount "rarity" controller
	c6 := NewRarityController(service)
	app.MountRarityController(service, c6)
	// Mount "type" controller
	c8 := NewTypeController(service)
	app.MountTypeController(service, c8)

	//database
	var err error
	controllers.DBCon, err = controllers.NewDBConnection("client:thereisonlyonekinginthenorth@tcp/gwentapi?timeout=90s&strict=true&parseTime=true")
	if err != nil {
		panic(err.Error())
	}
	defer controllers.DBCon.Close()

	// Start service
	if err := service.ListenAndServe(":8080"); err != nil {
		service.LogError("startup", "err", err)
	}
}
<commit_msg>Adding variables to switch between debug/prod and others. Adding TLS call<commit_after>//go:generate goagen bootstrap -d github.com/tri125/gwentapi/design

package main

import (
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/tri125/gwentapi/app"
	"github.com/tri125/gwentapi/controllers"
)

var isDebug bool = true
var isVerbose bool = false
var enableGzip bool = true
var gzipLevel int = -1

var certFile string = "pathToCertFile"
var keyFile string = "pathToKeyFile"

func main() {
	// Create service
	service := goa.New("gwentapi")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(isVerbose))
	service.Use(middleware.ErrorHandler(service, isVerbose))
	service.Use(middleware.Recover())
	if enableGzip {
		service.Use(gzip.Middleware(gzipLevel))
	}
	// Mount "card" controller
	c := NewCardController(service)
	app.MountCardController(service, c)
	// Mount "faction" controller
	c2 := NewFactionController(service)
	app.MountFactionController(service, c2)
	// Mount "glyph" controller
	c3 := NewGlyphController(service)
	app.MountGlyphController(service, c3)
	// Mount "patch" controller
	c4 := NewPatchController(service)
	app.MountPatchController(service, c4)
	// Mount "phonebook" controller
	c5 := NewPhonebookController(service)
	app.MountPhonebookController(service, c5)
	// Mount "rarity" controller
	c6 := NewRarityController(service)
	app.MountRarityController(service, c6)
	// Mount "type" controller
	c8 := NewTypeController(service)
	app.MountTypeController(service, c8)

	//database
	var err error
	controllers.DBCon, err = controllers.NewDBConnection("client:thereisonlyonekinginthenorth@tcp/gwentapi?timeout=90s&strict=true&parseTime=true")
	if err != nil {
		panic(err.Error())
	}
	defer controllers.DBCon.Close()

	// Start service

	if isDebug {
		if err := service.ListenAndServe(":8080"); err != nil {
			service.LogError("startup", "err", err)
		}
	} else {
		if err := service.ListenAndServeTLS(":8080", "certFile", "keyfile"); err != nil {
			service.LogError("startup", "err", err)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"

	jp "github.com/dustin/go-jsonpointer"
)

var Usage = func() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s [-pretty] QUERY.. <FILE\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s -list <FILE\n", os.Args[0])
	flag.PrintDefaults()
}

var list = flag.Bool("list", false, "list all possible query strings")
var pretty = flag.Bool("pretty", false, "output in non-JSON, pretty format; not machine readable")

func main() {
	prog := path.Base(os.Args[0])
	log.SetFlags(0)
	log.SetPrefix(prog + ": ")

	flag.Usage = Usage
	flag.Parse()

	var all_matched = true

	dec := json.NewDecoder(os.Stdin)

	switch {

	case flag.NArg() == 0 && !*list:
		Usage()

	case *list && flag.NArg() > 0:
		log.Fatal("cannot combine -list with query")

	case *list && *pretty:
		log.Fatal("cannot combine -list with -pretty")

	case *list:
		for {
			var raw json.RawMessage

			err := dec.Decode(&raw)
			if err == io.EOF {
				break
			}
			if err != nil {
				log.Fatalf("reading json: %v", err)
			}
			p, err := jp.ListPointers(raw)
			if err != nil {
				log.Fatalf("listing pointers: %v", err)
			}
			for _, s := range p {
				fmt.Println(s)
			}
		}

	case !*list:
		for {
			var raw json.RawMessage

			err := dec.Decode(&raw)
			if err == io.EOF {
				break
			}
			if err != nil {
				log.Fatalf("reading json: %v", err)
			}

			for _, query := range flag.Args() {
				match, err := jp.Find(raw, query)
				if err != nil {
					log.Fatalf("matching: %v", err)
				}

				if match == nil {
					// did not match anything;
					// signal with an empty line
					all_matched = false
					fmt.Println()
					continue
				}

				if *pretty {
					var data interface{}
					err = json.Unmarshal(match, &data)
					if err != nil {
						log.Fatalf("parsing json: %v", err)
					}
					switch data.(type) {
					case string, int, float64:
						fmt.Println(data)
						continue
					default:
						// handle difficult types below
					}
				}

				// canonicalize whitespace
				var buf bytes.Buffer
				err = json.Compact(&buf, match)
				if err != nil {
					log.Fatalf("serializing json: %v", err)
				}
				buf.WriteByte('\n')
				_, err = buf.WriteTo(os.Stdout)
				if err != nil {
					log.Fatalf("writing json: %v", err)
				}
			}
		}

	default:
		panic("unreachable")
	}

	if !all_matched {
		os.Exit(1)
	}
}
<commit_msg>Avoid pointless variable<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path"

	jp "github.com/dustin/go-jsonpointer"
)

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s [-pretty] QUERY.. <FILE\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "  %s -list <FILE\n", os.Args[0])
	flag.PrintDefaults()
}

var list = flag.Bool("list", false, "list all possible query strings")
var pretty = flag.Bool("pretty", false, "output in non-JSON, pretty format; not machine readable")

func main() {
	prog := path.Base(os.Args[0])
	log.SetFlags(0)
	log.SetPrefix(prog + ": ")

	flag.Usage = usage
	flag.Parse()

	var all_matched = true

	dec := json.NewDecoder(os.Stdin)

	switch {

	case flag.NArg() == 0 && !*list:
		usage()

	case *list && flag.NArg() > 0:
		log.Fatal("cannot combine -list with query")

	case *list && *pretty:
		log.Fatal("cannot combine -list with -pretty")

	case *list:
		for {
			var raw json.RawMessage

			err := dec.Decode(&raw)
			if err == io.EOF {
				break
			}
			if err != nil {
				log.Fatalf("reading json: %v", err)
			}
			p, err := jp.ListPointers(raw)
			if err != nil {
				log.Fatalf("listing pointers: %v", err)
			}
			for _, s := range p {
				fmt.Println(s)
			}
		}

	case !*list:
		for {
			var raw json.RawMessage

			err := dec.Decode(&raw)
			if err == io.EOF {
				break
			}
			if err != nil {
				log.Fatalf("reading json: %v", err)
			}

			for _, query := range flag.Args() {
				match, err := jp.Find(raw, query)
				if err != nil {
					log.Fatalf("matching: %v", err)
				}

				if match == nil {
					// did not match anything;
					// signal with an empty line
					all_matched = false
					fmt.Println()
					continue
				}

				if *pretty {
					var data interface{}
					err = json.Unmarshal(match, &data)
					if err != nil {
						log.Fatalf("parsing json: %v", err)
					}
					switch data.(type) {
					case string, int, float64:
						fmt.Println(data)
						continue
					default:
						// handle difficult types below
					}
				}

				// canonicalize whitespace
				var buf bytes.Buffer
				err = json.Compact(&buf, match)
				if err != nil {
					log.Fatalf("serializing json: %v", err)
				}
				buf.WriteByte('\n')
				_, err = buf.WriteTo(os.Stdout)
				if err != nil {
					log.Fatalf("writing json: %v", err)
				}
			}
		}

	default:
		panic("unreachable")
	}

	if !all_matched {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"
)

const (
	httpListenPort            = 8081
	refreshRate               = 60 //in seconds
	wikiURI                   = "https://wiki.tox.chat/users/nodes?do=export_raw"
	maxUDPPacketSize          = 2048
	getNodesPacketID          = 2
	sendNodesIpv6PacketID     = 4
	bootstrapInfoPacketID     = 240
	bootstrapInfoPacketLength = 78
	maxMOTDLength             = 256
	queryTimeout              = 4 //in seconds
)

var (
	nodesList = list.New()
	crypto, _ = NewCrypto()
)

type toxNode struct {
	Ipv4Address    string `json:"ipv4"`
	Ipv6Address    string `json:"ipv6"`
	Port           int    `json:"port"`
	PublicKey      string `json:"public_key"`
	Maintainer     string `json:"maintainer"`
	Location       string `json:"location"`
	Status         bool   `json:"status"`
	Version        string `json:"version"`
	MOTD           string `json:"motd"`
	LastPing       int64  `json:"last_ping"`
	LastPingString string `json:"last_ping_string"`
}

func main() {
	if crypto == nil {
		log.Fatalf("Could not generate keypair")
	}

	go probeLoop()

	http.HandleFunc("/", handleHTTPRequest)
	http.HandleFunc("/json", handleJSONRequest)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", httpListenPort), nil))
}

func handleHTTPRequest(w http.ResponseWriter, r *http.Request) {
	urlPath := r.URL.Path[1:]
	if r.URL.Path == "/" {
		renderMainPage(w, "index.html")
		return
	}

	//TODO: make this more efficient
	data, err := ioutil.ReadFile(path.Join("./assets/", string(urlPath)))
	if err != nil {
		http.Error(w, http.StatusText(404), 404)
	} else {
		w.Write(data)
	}
}

func renderMainPage(w http.ResponseWriter, urlPath string) {
	tmpl, err2 := template.ParseFiles(path.Join("./assets/", string(urlPath)))

	if err2 != nil {
		http.Error(w, http.StatusText(500), 500)
		log.Printf("Internal server error while trying to serve index: %s", err2.Error())
	} else {
		nodes := nodesListToSlice(nodesList)
		tmpl.Execute(w, nodes)
	}
}

func handleJSONRequest(w http.ResponseWriter, r *http.Request) {
	nodes := nodesListToSlice(nodesList)

	bytes, err := json.Marshal(nodes)
	if err != nil {
		http.Error(w, http.StatusText(500), 500)
		return
	}

	w.Write(bytes)
}

func probeLoop() {
	for {
		nodes, err := parseNodes()
		if err != nil {
			log.Printf("Error while trying to parse nodes: %s", err.Error())
			continue
		}

		c := make(chan *toxNode)
		for e := nodes.Front(); e != nil; e = e.Next() {
			node, _ := e.Value.(*toxNode)
			go func() { c <- probeNode(node) }()
		}

		for i := 0; i < nodes.Len(); i++ {
			_ = <-c
		}

		nodesList = nodes
		time.Sleep(refreshRate * time.Second)
	}
}

func probeNode(node *toxNode) *toxNode {
	conn, err := newNodeConn(node)
	if err != nil {
		return node
	}

	err = getBootstrapInfo(node, conn)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
	}

	conn.Close()
	conn, err = newNodeConn(node)
	if err != nil {
		return node
	}

	err = getNodes(node, conn)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return node
	}
	conn.Close()

	node.LastPing = time.Now().Unix()
	node.Status = true
	return node
}

func getNodes(node *toxNode, conn net.Conn) error {
	nodePublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}

	plain := make([]byte, len(crypto.PublicKey)+8)
	copy(plain, crypto.PublicKey)
	copy(plain[len(crypto.PublicKey):], nextBytes(8)) //ping id

	nonce := nextNonce()
	sharedKey := crypto.CreateSharedKey(nodePublicKey)
	encrypted := encryptData(plain, sharedKey, nonce)[16:]

	payload := make([]byte, 1+len(crypto.PublicKey)+len(nonce)+len(encrypted))
	payload[0] = getNodesPacketID
	copy(payload[1:], crypto.PublicKey)
	copy(payload[1+len(crypto.PublicKey):], nonce)
	copy(payload[1+len(crypto.PublicKey)+len(nonce):], encrypted)
	conn.Write(payload)

	buffer := make([]byte, maxUDPPacketSize)
	_, err = conn.Read(buffer)

	if err != nil {
		return err
	} /*else if payload[0] != sendNodesIpv6PacketID {
		return fmt.Errorf("packet id: %d is not a sendnodesipv6 packet", payload[0])
	}

	right now we're happy if a node responds to our 'getnodes' request, without even validating the response
	this needs some more work

	on a side note: it looks like nodes are sending a 'getnodes' packet before 'sendnodesipv6',
	*/

	return nil
}

func newNodeConn(node *toxNode) (net.Conn, error) {
	conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", node.Ipv4Address, node.Port))
	if err != nil {
		return nil, err
	}
	conn.SetReadDeadline(time.Now().Add(queryTimeout * time.Second))
	return conn, nil
}

func getBootstrapInfo(node *toxNode, conn net.Conn) error {
	payload := make([]byte, bootstrapInfoPacketLength)
	payload[0] = bootstrapInfoPacketID
	conn.Write(payload)

	buffer := make([]byte, 1+4+maxMOTDLength)
	read, err := conn.Read(buffer)

	if err != nil {
		return err
	} else if buffer[0] != bootstrapInfoPacketID {
		return fmt.Errorf("packet id: %d is not a bootstrap info packet", buffer[0])
	}

	buffer = buffer[:read]
	if len(buffer) < 1+4 {
		return errors.New("bootstrap info packet too small")
	}

	node.Version = fmt.Sprintf("%d", binary.BigEndian.Uint32(buffer[1:1+4]))
	node.MOTD = string(bytes.Trim(buffer[1+4:], "\x00"))
	return nil
}

func parseNode(nodeString string) *toxNode {
	nodeString = stripSpaces(nodeString)
	if !strings.HasPrefix(nodeString, "|") {
		return nil
	}

	lineParts := strings.Split(nodeString, "|")
	if port, err := strconv.Atoi(strings.TrimSpace(lineParts[3])); err == nil && len(lineParts) == 8 {
		node := toxNode{
			strings.TrimSpace(lineParts[1]),
			strings.TrimSpace(lineParts[2]),
			port,
			strings.TrimSpace(lineParts[4]),
			strings.TrimSpace(lineParts[5]),
			strings.TrimSpace(lineParts[6]),
			false,
			"",
			"",
			0,
			"Never",
		}

		if node.Ipv6Address == "NONE" {
			node.Ipv6Address = "-"
		}

		return &node
	}

	return nil
}

func parseNodes() (*list.List, error) {
	res, err := http.Get(wikiURI)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	nodes := list.New()
	content, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(content), "\n")
	for _, line := range lines {
		node := parseNode(line)
		if node == nil {
			continue
		}

		oldNode := getOldNode(node.PublicKey)
		if oldNode != nil { //transfer last ping info
			node.LastPing = oldNode.LastPing
			node.LastPingString = oldNode.LastPingString
		}

		nodes.PushBack(node)
	}
	return nodes, nil
}

func getOldNode(publicKey string) *toxNode {
	for e := nodesList.Front(); e != nil; e = e.Next() {
		node, _ := e.Value.(*toxNode)
		if node.PublicKey == publicKey {
			return node
		}
	}
	return nil
}
<commit_msg>Don't forget to sleep when parsing nodes fails<commit_after>package main

import (
	"bytes"
	"container/list"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"path"
	"strconv"
	"strings"
	"text/template"
	"time"
)

const (
	httpListenPort            = 8081
	refreshRate               = 60 //in seconds
	wikiURI                   = "https://wiki.tox.chat/users/nodes?do=export_raw"
	maxUDPPacketSize          = 2048
	getNodesPacketID          = 2
	sendNodesIpv6PacketID     = 4
	bootstrapInfoPacketID     = 240
	bootstrapInfoPacketLength = 78
	maxMOTDLength             = 256
	queryTimeout              = 4 //in seconds
)

var (
	nodesList = list.New()
	crypto, _ = NewCrypto()
)

type toxNode struct {
	Ipv4Address    string `json:"ipv4"`
	Ipv6Address    string `json:"ipv6"`
	Port           int    `json:"port"`
	PublicKey      string `json:"public_key"`
	Maintainer     string `json:"maintainer"`
	Location       string `json:"location"`
	Status         bool   `json:"status"`
	Version        string `json:"version"`
	MOTD           string `json:"motd"`
	LastPing       int64  `json:"last_ping"`
	LastPingString string `json:"last_ping_string"`
}

func main() {
	if crypto == nil {
		log.Fatalf("Could not generate keypair")
	}

	go probeLoop()

	http.HandleFunc("/", handleHTTPRequest)
	http.HandleFunc("/json", handleJSONRequest)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", httpListenPort), nil))
}

func handleHTTPRequest(w http.ResponseWriter, r *http.Request) {
	urlPath := r.URL.Path[1:]
	if r.URL.Path == "/" {
		renderMainPage(w, "index.html")
		return
	}

	//TODO: make this more efficient
	data, err := ioutil.ReadFile(path.Join("./assets/", string(urlPath)))
	if err != nil {
		http.Error(w, http.StatusText(404), 404)
	} else {
		w.Write(data)
	}
}

func renderMainPage(w http.ResponseWriter, urlPath string) {
	tmpl, err2 := template.ParseFiles(path.Join("./assets/", string(urlPath)))

	if err2 != nil {
		http.Error(w, http.StatusText(500), 500)
		log.Printf("Internal server error while trying to serve index: %s", err2.Error())
	} else {
		nodes := nodesListToSlice(nodesList)
		tmpl.Execute(w, nodes)
	}
}

func handleJSONRequest(w http.ResponseWriter, r *http.Request) {
	nodes := nodesListToSlice(nodesList)

	bytes, err := json.Marshal(nodes)
	if err != nil {
		http.Error(w, http.StatusText(500), 500)
		return
	}

	w.Write(bytes)
}

func probeLoop() {
	for {
		nodes, err := parseNodes()
		if err != nil {
			log.Printf("Error while trying to parse nodes: %s", err.Error())
		} else {
			c := make(chan *toxNode)
			for e := nodes.Front(); e != nil; e = e.Next() {
				node, _ := e.Value.(*toxNode)
				go func() { c <- probeNode(node) }()
			}

			for i := 0; i < nodes.Len(); i++ {
				_ = <-c
			}

			nodesList = nodes
		}

		time.Sleep(refreshRate * time.Second)
	}
}

func probeNode(node *toxNode) *toxNode {
	conn, err := newNodeConn(node)
	if err != nil {
		return node
	}

	err = getBootstrapInfo(node, conn)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
	}

	conn.Close()
	conn, err = newNodeConn(node)
	if err != nil {
		return node
	}

	err = getNodes(node, conn)
	if err != nil {
		fmt.Printf("%s\n", err.Error())
		return node
	}
	conn.Close()

	node.LastPing = time.Now().Unix()
	node.Status = true
	return node
}

func getNodes(node *toxNode, conn net.Conn) error {
	nodePublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}

	plain := make([]byte, len(crypto.PublicKey)+8)
	copy(plain, crypto.PublicKey)
	copy(plain[len(crypto.PublicKey):], nextBytes(8)) //ping id

	nonce := nextNonce()
	sharedKey := crypto.CreateSharedKey(nodePublicKey)
	encrypted := encryptData(plain, sharedKey, nonce)[16:]

	payload := make([]byte, 1+len(crypto.PublicKey)+len(nonce)+len(encrypted))
	payload[0] = getNodesPacketID
	copy(payload[1:], crypto.PublicKey)
	copy(payload[1+len(crypto.PublicKey):], nonce)
	copy(payload[1+len(crypto.PublicKey)+len(nonce):], encrypted)
	conn.Write(payload)

	buffer := make([]byte, maxUDPPacketSize)
	_, err = conn.Read(buffer)

	if err != nil {
		return err
	} /*else if payload[0] != sendNodesIpv6PacketID {
		return fmt.Errorf("packet id: %d is not a sendnodesipv6 packet", payload[0])
	}

	right now we're happy if a node responds to our 'getnodes' request, without even validating the response
	this needs some more work

	on a side note: it looks like nodes are sending a 'getnodes' packet before 'sendnodesipv6',
	*/

	return nil
}

func newNodeConn(node *toxNode) (net.Conn, error) {
	conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", node.Ipv4Address, node.Port))
	if err != nil {
		return nil, err
	}
	conn.SetReadDeadline(time.Now().Add(queryTimeout * time.Second))
	return conn, nil
}

func getBootstrapInfo(node *toxNode, conn net.Conn) error {
	payload := make([]byte, bootstrapInfoPacketLength)
	payload[0] = bootstrapInfoPacketID
	conn.Write(payload)

	buffer := make([]byte, 1+4+maxMOTDLength)
	read, err := conn.Read(buffer)

	if err != nil {
		return err
	} else if buffer[0] != bootstrapInfoPacketID {
		return fmt.Errorf("packet id: %d is not a bootstrap info packet", buffer[0])
	}

	buffer = buffer[:read]
	if len(buffer) < 1+4 {
		return errors.New("bootstrap info packet too small")
	}

	node.Version = fmt.Sprintf("%d", binary.BigEndian.Uint32(buffer[1:1+4]))
	node.MOTD = string(bytes.Trim(buffer[1+4:], "\x00"))
	return nil
}

func parseNode(nodeString string) *toxNode {
	nodeString = stripSpaces(nodeString)
	if !strings.HasPrefix(nodeString, "|") {
		return nil
	}

	lineParts := strings.Split(nodeString, "|")
	if port, err := strconv.Atoi(strings.TrimSpace(lineParts[3])); err == nil && len(lineParts) == 8 {
		node := toxNode{
			strings.TrimSpace(lineParts[1]),
			strings.TrimSpace(lineParts[2]),
			port,
			strings.TrimSpace(lineParts[4]),
			strings.TrimSpace(lineParts[5]),
			strings.TrimSpace(lineParts[6]),
			false,
			"",
			"",
			0,
			"Never",
		}

		if node.Ipv6Address == "NONE" {
			node.Ipv6Address = "-"
		}

		return &node
	}

	return nil
}

func parseNodes() (*list.List, error) {
	res, err := http.Get(wikiURI)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	nodes := list.New()
	content, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

	lines := strings.Split(string(content), "\n")
	for _, line := range lines {
		node := parseNode(line)
		if node == nil {
			continue
		}

		oldNode := getOldNode(node.PublicKey)
		if oldNode != nil { //transfer last ping info
			node.LastPing = oldNode.LastPing
			node.LastPingString = oldNode.LastPingString
		}

		nodes.PushBack(node)
	}
	return nodes, nil
}

func getOldNode(publicKey string) *toxNode {
	for e := nodesList.Front(); e != nil; e = e.Next() {
		node, _ := e.Value.(*toxNode)
		if node.PublicKey == publicKey {
			return node
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/command/rubycommand"
	"github.com/bitrise-io/go-utils/fileutil"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	shellquote "github.com/kballard/go-shellquote"
)

// ConfigsModel ...
type ConfigsModel struct {
	WorkDir        string
	Lane           string
	UpdateFastlane string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		WorkDir:        os.Getenv("work_dir"),
		Lane:           os.Getenv("lane"),
		UpdateFastlane: os.Getenv("update_fastlane"),
	}
}

func (configs ConfigsModel) print() {
	log.Infof("Configs:")
	log.Printf("- WorkDir: %s", configs.WorkDir)
	log.Printf("- Lane: %s", configs.Lane)
	log.Printf("- UpdateFastlane: %s", configs.UpdateFastlane)
}

func (configs ConfigsModel) validate() error {
	if configs.Lane == "" {
		return errors.New("no Lane parameter specified")
	}

	if configs.WorkDir != "" {
		if exist, err := pathutil.IsDirExists(configs.WorkDir); err != nil {
			return fmt.Errorf("failed to check if WorkDir exist at: %s, error: %s", configs.WorkDir, err)
		} else if !exist {
			return fmt.Errorf("WorkDir not exist at: %s", configs.WorkDir)
		}
	}

	if configs.UpdateFastlane == "" {
		return errors.New("no UpdateFastlane parameter specified")
	} else if configs.UpdateFastlane != "true" && configs.UpdateFastlane != "false" {
		return fmt.Errorf(`invalid UpdateFastlane parameter specified: %s, available: ["true", "false"]`, configs.UpdateFastlane)
	}

	return nil
}

func failf(format string, v ...interface{}) {
	log.Errorf(format, v...)
	os.Exit(1)
}

func fastlaneVersionFromGemfileLockContent(content string) string {
	relevantLines := []string{}
	lines := strings.Split(content, "\n")

	specsStart := false
	for _, line := range lines {
		if strings.Contains(line, "specs:") {
			specsStart = true
		}

		trimmed := strings.Trim(line, " ")
		if trimmed == "" {
			specsStart = false
		}

		if specsStart {
			relevantLines = append(relevantLines, line)
		}
	}

	//     fastlane (1.109.0)
	exp := regexp.MustCompile(`fastlane \((.+)\)`)
	for _, line := range relevantLines {
		match := exp.FindStringSubmatch(line)
		if match != nil && len(match) == 2 {
			return match[1]
		}
	}

	return ""
}

func fastlaneVersionFromGemfileLock(gemfileLockPth string) (string, error) {
	content, err := fileutil.ReadStringFromFile(gemfileLockPth)
	if err != nil {
		return "", err
	}
	return fastlaneVersionFromGemfileLockContent(content), nil
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		failf("Issue with input: %s", err)
	}

	// Expand WorkDir
	fmt.Println()
	log.Infof("Expand WorkDir")

	workDir := configs.WorkDir
	if workDir == "" {
		log.Printf("WorkDir not set, using CurrentWorkingDirectory...")
		currentDir, err := pathutil.CurrentWorkingDirectoryAbsolutePath()
		if err != nil {
			failf("Failed to get current dir, error: %s", err)
		}
		workDir = currentDir
	} else {
		absWorkDir, err := pathutil.AbsPath(workDir)
		if err != nil {
			failf("Failed to expand path (%s), error: %s", workDir, err)
		}
		workDir = absWorkDir
	}

	log.Donef("Expanded WorkDir: %s", workDir)

	// Split lane option
	laneOptions, err := shellquote.Split(configs.Lane)
	if err != nil {
		failf("Failed to parse lane (%s), error: %s", configs.Lane, err)
	}

	// Determine desired Fastlane version
	fmt.Println()
	log.Infof("Determine desired Fastlane version")

	useBundler := false

	gemfileLockPth := filepath.Join(workDir, "Gemfile.lock")
	log.Printf("Checking Gemfile.lock (%s) for fastlane gem", gemfileLockPth)

	if exist, err := pathutil.IsPathExists(gemfileLockPth); err != nil {
		failf("Failed to check if Gemfile.lock exist at (%s), error: %s", gemfileLockPth, err)
	} else if exist {
		version, err := fastlaneVersionFromGemfileLock(gemfileLockPth)
		if err != nil {
			failf("Failed to read Fastlane versiom from Gemfile.lock (%s), error: %s", gemfileLockPth, err)
		}

		if version != "" {
			log.Printf("Gemfile.lock defined fastlane version: %s", version)

			useBundler = true
		} else {
			log.Printf("No fastlane version defined in Gemfile.lock")
		}
	} else {
		log.Printf("Gemfile.lock does not exist")
	}

	fmt.Println()

	// Install desired Fastlane version
	if useBundler {
		log.Infof("Install Fastlane with bundler")

		bundleInstallCmd := []string{"bundle", "install", "--jobs", "20", "--retry", "5"}

		log.Donef("$ %s", command.PrintableCommandArgs(false, bundleInstallCmd))

		cmd, err := rubycommand.NewFromSlice(bundleInstallCmd...)
		if err != nil {
			failf("Failed to create command model, error: %s", err)
		}

		cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
		cmd.SetDir(workDir)

		if err := cmd.Run(); err != nil {
			failf("Command failed, error: %s", err)
		}
	} else if configs.UpdateFastlane == "true" {
		log.Infof("Update system installed Fastlane")

		cmds, err := rubycommand.GemInstall("fastlane", "")
		if err != nil {
			failf("Failed to create command model, error: %s", err)
		}

		for _, cmd := range cmds {
			log.Donef("$ %s", cmd.PrintableCommandArgs())

			cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
			cmd.SetDir(workDir)

			if err := cmd.Run(); err != nil {
				failf("Command failed, error: %s", err)
			}
		}
	} else {
		log.Infof("Using system installed Fastlane")
	}

	fmt.Println()
	log.Infof("Fastlane version:")

	versionCmd := []string{"fastlane", "--version"}
	if useBundler {
		versionCmd = append([]string{"bundle", "exec"}, versionCmd...)
	}

	log.Donef("$ %s", command.PrintableCommandArgs(false, versionCmd))

	cmd, err := rubycommand.NewFromSlice(versionCmd...)
	if err != nil {
		failf("Command failed, error: %s", err)
	}

	cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
	cmd.SetDir(workDir)

	if err := cmd.Run(); err != nil {
		failf("Command failed, error: %s", err)
	}

	// Run fastlane
	fmt.Println()
	log.Infof("Run Fastlane")

	fastlaneCmd := []string{"fastlane"}
	fastlaneCmd = append(fastlaneCmd, laneOptions...)
	if useBundler {
		fastlaneCmd = append([]string{"bundle", "exec"}, fastlaneCmd...)
	}

	log.Donef("$ %s", command.PrintableCommandArgs(false, fastlaneCmd))

	cmd, err = rubycommand.NewFromSlice(fastlaneCmd...)
	if err != nil {
		failf("Failed to create command model, error: %s", err)
	}

	cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
	cmd.SetDir(workDir)

	if err := cmd.Run(); err != nil {
		fmt.Println()
		log.Errorf("Fastlane command: (%s) failed", cmd.PrintableCommandArgs())
		log.Errorf("If you want to send an issue report to fastlane (https://github.com/fastlane/fastlane/issues/new), you can find the output of fastlane env (below):")
		fmt.Println()

		inputReader := strings.NewReader("n")
		cmd, errEnv := rubycommand.New("fastlane", "env")
		if errEnv != nil {
			log.Warnf("Failed to create command model, error: %s", errEnv)
		} else {
			cmd.SetStdin(inputReader)
			cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
			cmd.SetDir(workDir)

			if errEnv := cmd.Run(); errEnv != nil {
				log.Warnf("Fastlane command: (%s) failed", cmd.PrintableCommandArgs())
			}
		}

		failf("Command failed, error: %s", err)
	}
}
<commit_msg>Moving fastlane logs to deploy dir (#27)<commit_after>package main

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/bitrise-io/go-utils/command"
	"github.com/bitrise-io/go-utils/command/rubycommand"
	"github.com/bitrise-io/go-utils/fileutil"
	"github.com/bitrise-io/go-utils/log"
	"github.com/bitrise-io/go-utils/pathutil"
	shellquote "github.com/kballard/go-shellquote"
)

// ConfigsModel ...
type ConfigsModel struct {
	WorkDir        string
	Lane           string
	UpdateFastlane string
}

func createConfigsModelFromEnvs() ConfigsModel {
	return ConfigsModel{
		WorkDir:        os.Getenv("work_dir"),
		Lane:           os.Getenv("lane"),
		UpdateFastlane: os.Getenv("update_fastlane"),
	}
}

func (configs ConfigsModel) print() {
	log.Infof("Configs:")
	log.Printf("- WorkDir: %s", configs.WorkDir)
	log.Printf("- Lane: %s", configs.Lane)
	log.Printf("- UpdateFastlane: %s", configs.UpdateFastlane)
}

func (configs ConfigsModel) validate() error {
	if configs.Lane == "" {
		return errors.New("no Lane parameter specified")
	}

	if configs.WorkDir != "" {
		if exist, err := pathutil.IsDirExists(configs.WorkDir); err != nil {
			return fmt.Errorf("failed to check if WorkDir exist at: %s, error: %s", configs.WorkDir, err)
		} else if !exist {
			return fmt.Errorf("WorkDir not exist at: %s", configs.WorkDir)
		}
	}

	if configs.UpdateFastlane == "" {
		return errors.New("no UpdateFastlane parameter specified")
	} else if configs.UpdateFastlane != "true" && configs.UpdateFastlane != "false" {
		return fmt.Errorf(`invalid UpdateFastlane parameter specified: %s, available: ["true", "false"]`, configs.UpdateFastlane)
	}

	return nil
}

func failf(format string, v ...interface{}) {
	log.Errorf(format, v...)
	os.Exit(1)
}

func fastlaneVersionFromGemfileLockContent(content string) string {
	relevantLines := []string{}
	lines := strings.Split(content, "\n")

	specsStart := false
	for _, line := range lines {
		if strings.Contains(line, "specs:") {
			specsStart = true
		}

		trimmed := strings.Trim(line, " ")
		if trimmed == "" {
			specsStart = false
		}

		if specsStart {
			relevantLines = append(relevantLines, line)
		}
	}

	//     fastlane (1.109.0)
	exp := regexp.MustCompile(`fastlane \((.+)\)`)
	for _, line := range relevantLines {
		match := exp.FindStringSubmatch(line)
		if match != nil && len(match) == 2 {
			return match[1]
		}
	}

	return ""
}

func fastlaneVersionFromGemfileLock(gemfileLockPth string) (string, error) {
	content, err := fileutil.ReadStringFromFile(gemfileLockPth)
	if err != nil {
		return "", err
	}
	return fastlaneVersionFromGemfileLockContent(content), nil
}

func main() {
	configs := createConfigsModelFromEnvs()

	fmt.Println()
	configs.print()

	if err := configs.validate(); err != nil {
		failf("Issue with input: %s", err)
	}

	// Expand WorkDir
	fmt.Println()
	log.Infof("Expand WorkDir")

	workDir := configs.WorkDir
	if workDir == "" {
		log.Printf("WorkDir not set, using CurrentWorkingDirectory...")
		currentDir, err := pathutil.CurrentWorkingDirectoryAbsolutePath()
		if err != nil {
			failf("Failed to get current dir, error: %s", err)
		}
		workDir = currentDir
	} else {
		absWorkDir, err := pathutil.AbsPath(workDir)
		if err != nil {
			failf("Failed to expand path (%s), error: %s", workDir, err)
		}
		workDir = absWorkDir
	}

	log.Donef("Expanded WorkDir: %s", workDir)

	// Split lane option
	laneOptions, err := shellquote.Split(configs.Lane)
	if err != nil {
		failf("Failed to parse lane (%s), error: %s", configs.Lane, err)
	}

	// Determine desired Fastlane version
	fmt.Println()
	log.Infof("Determine desired Fastlane version")

	useBundler := false

	gemfileLockPth := filepath.Join(workDir, "Gemfile.lock")
	log.Printf("Checking Gemfile.lock (%s) for fastlane gem", gemfileLockPth)

	if exist, err := pathutil.IsPathExists(gemfileLockPth); err != nil {
		failf("Failed to check if Gemfile.lock exist at (%s), error: %s", gemfileLockPth, err)
	} else if exist {
		version, err := fastlaneVersionFromGemfileLock(gemfileLockPth)
		if err != nil {
			failf("Failed to read Fastlane versiom from Gemfile.lock (%s), error: %s", gemfileLockPth, err)
		}

		if version != "" {
			log.Printf("Gemfile.lock defined fastlane version: %s", version)

			useBundler = true
		} else {
			log.Printf("No fastlane version defined in Gemfile.lock")
		}
	} else {
		log.Printf("Gemfile.lock does not exist")
	}

	fmt.Println()

	// Install desired Fastlane version
	if useBundler {
		log.Infof("Install Fastlane with bundler")

		bundleInstallCmd := []string{"bundle", "install", "--jobs", "20", "--retry", "5"}

		log.Donef("$ %s", command.PrintableCommandArgs(false, bundleInstallCmd))

		cmd, err := rubycommand.NewFromSlice(bundleInstallCmd...)
		if err != nil {
			failf("Failed to create command model, error: %s", err)
		}

		cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
		cmd.SetDir(workDir)

		if err := cmd.Run(); err != nil {
			failf("Command failed, error: %s", err)
		}
	} else if configs.UpdateFastlane == "true" {
		log.Infof("Update system installed Fastlane")

		cmds, err := rubycommand.GemInstall("fastlane", "")
		if err != nil {
			failf("Failed to create command model, error: %s", err)
		}

		for _, cmd := range cmds {
			log.Donef("$ %s", cmd.PrintableCommandArgs())

			cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
			cmd.SetDir(workDir)

			if err := cmd.Run(); err != nil {
				failf("Command failed, error: %s", err)
			}
		}
	} else {
		log.Infof("Using system installed Fastlane")
	}

	fmt.Println()
	log.Infof("Fastlane version:")

	versionCmd := []string{"fastlane", "--version"}
	if useBundler {
		versionCmd = append([]string{"bundle", "exec"}, versionCmd...)
	}

	log.Donef("$ %s", command.PrintableCommandArgs(false, versionCmd))

	cmd, err := rubycommand.NewFromSlice(versionCmd...)
	if err != nil {
		failf("Command failed, error: %s", err)
	}

	cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
	cmd.SetDir(workDir)

	if err := cmd.Run(); err != nil {
		failf("Command failed, error: %s", err)
	}

	// Run fastlane
	fmt.Println()
	log.Infof("Run Fastlane")

	fastlaneCmd := []string{"fastlane"}
	fastlaneCmd = append(fastlaneCmd, laneOptions...)
	if useBundler {
		fastlaneCmd = append([]string{"bundle", "exec"}, fastlaneCmd...)
	}

	log.Donef("$ %s", command.PrintableCommandArgs(false, fastlaneCmd))

	cmd, err = rubycommand.NewFromSlice(fastlaneCmd...)
	if err != nil {
		failf("Failed to create command model, error: %s", err)
	}

	cmd.SetStdout(os.Stdout).SetStderr(os.Stderr)
	cmd.SetDir(workDir)

	buildlogPth := ""

	if tempDir, err := pathutil.NormalizedOSTempDirPath("fastlane_logs"); err != nil {
		log.Errorf("Failed to create temp dir for fastlane logs, error: %s", err)
	} else {
		buildlogPth = tempDir
		cmd.AppendEnvs("FL_BUILDLOG_PATH=" + buildlogPth)
	}

	deployDir := os.Getenv("BITRISE_DEPLOY_DIR")
	if deployDir == "" {
		log.Warnf("No BITRISE_DEPLOY_DIR found")
	}
	deployPth := filepath.Join(deployDir, "fastlane_env.log")

	if err := cmd.Run(); err != nil {
		fmt.Println()
		log.Errorf("Fastlane command: (%s) failed", cmd.PrintableCommandArgs())
		log.Errorf("If you want to send an issue report to fastlane (https://github.com/fastlane/fastlane/issues/new), you can find the output of fastlane env int he following log file:")
		fmt.Println()
		log.Infof(deployPth)
		fmt.Println()

		if cmd, err := rubycommand.New("fastlane", "env"); err != nil {
			log.Warnf("Failed to create command model, error: %s", err)
		} else {
			inputReader := strings.NewReader("n")
			var outBuffer bytes.Buffer
			outWriter := bufio.NewWriter(&outBuffer)

			cmd.SetStdin(inputReader)
			cmd.SetStdout(outWriter).SetStderr(os.Stderr)
			cmd.SetDir(workDir)

			if errEnv := cmd.Run(); errEnv != nil {
				log.Warnf("Fastlane command: (%s) failed", cmd.PrintableCommandArgs())
			} else if outBuffer.String() != "" {
				if err := fileutil.WriteStringToFile(deployPth, outBuffer.String()); err != nil {
					log.Warnf("Failed to write fastlane env log file, error: %s", err)
				}
			}
		}
		failf("Command failed, error: %s", err)
	}

	if err := filepath.Walk(buildlogPth, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() {
			if relLogPath, err := filepath.Rel(buildlogPth, path); err == nil {
				return err
			} else if err := os.Rename(path, filepath.Join(deployDir, strings.Replace(relLogPath, "/", "_", -1))); err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		log.Errorf("Failed to walk directory, error: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
)

const space = "  " // Used for pretty printing
const br = "\n\n"

func main() {
	var command string

	helpMessage := "binpath command [arguments]"
	helpMessage = fmt.Sprintf("Example usage: \n%s%v", space, helpMessage)

	// Check arg for appname to load
	if len(os.Args) > 1 {
		command = os.Args[1]
	} else {
		fmt.Println(helpMessage)
		os.Exit(1)
	}

	// Look for help flag before executing command
	switch command {
	case "--help":
		fallthrough
	case "-help":
		fallthrough
	case "--h":
		fallthrough
	case "-h":
		fmt.Println(helpMessage)
		os.Exit(1)
	case "--show-bash-completion":
		checkForBin(command, true)
	default:
		checkForBin(command, false)
	}

}

func checkForBin(command string, showBashCompletion bool) {
	dirname := "." + string(filepath.Separator)

	d, err := os.Open(dirname)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer d.Close()

	files, err := d.Readdir(-1)
	if err != nil {
		fmt.Println(err)
		log.Fatal(err)
	}

	for _, file := range files {
		if file.Mode().IsDir() {
			if file.Name() == "bin" {
				dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
				if err != nil {
					log.Fatal(err)
				}

				// Set bin path
				binPath := filepath.Join(dir, file.Name())

				// If --show-bash-completion flag was used then list out files in binPath
				if showBashCompletion == true {
					// List files in bin folder
					listBinPathFiles(binPath)
				} else {
					// Execute command in binPath
					executeCommand(binPath, command)
				}

				os.Exit(0)
			}
		}
	}

	// If it doesn't move up a directory and test
	os.Chdir(".." + string(filepath.Separator))

	checkForBin(command, showBashCompletion)
}

// Print out files found in binpath
func listBinPathFiles(binPath string) {
	files, err := ioutil.ReadDir(binPath)
	if err != nil {
		fmt.Printf("-binpath: error reading: %v \n", binPath)
		os.Exit(1)
	}

	for _, file := range files {
		fmt.Println(file.Name())
	}
}

// Try to execute the command if a binpath is found
func executeCommand(binPath string, command string) {
	// Set path to command
	commandPath := filepath.Join(binPath, command)

	// Make to see if command exist in bin path
	_, err := os.Stat(commandPath)
	if err != nil {
		fmt.Printf("-binpath: %v: command not found in: %v \n", command, binPath)
		os.Exit(1)
	}

	// Create separator for easier reading
	separator := "-----------------------"
	fmt.Println(separator)

	// Notify if a bin is found
	fmt.Printf("Exec command: %v\n", commandPath)

	// Print separator for separation of binpath and command
	fmt.Println(separator)

	// And binPath to $PATH env
	v := fmt.Sprintf("$PATH:%v", binPath)
	os.Setenv("PATH", v)

	// Make sure to pass any arguments to the app
	args := os.Args[2:len(os.Args)]

	// Call command
	cmd := exec.Command(command, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if _, ok := err.(*exec.ExitError); ok {
		log.Fatal(err)
	}

}
<commit_msg>Don't show hidden "." files when listing out /bin contents<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const space = "  " // Used for pretty printing
const br = "\n\n"

func main() {
	var command string

	helpMessage := "binpath command [arguments]"
	helpMessage = fmt.Sprintf("Example usage: \n%s%v", space, helpMessage)

	// Check arg for appname to load
	if len(os.Args) > 1 {
		command = os.Args[1]
	} else {
		fmt.Println(helpMessage)
		os.Exit(1)
	}

	// Look for help flag before executing command
	switch command {
	case "--help":
		fallthrough
	case "-help":
		fallthrough
	case "--h":
		fallthrough
	case "-h":
		fmt.Println(helpMessage)
		os.Exit(1)
	case "--show-bash-completion":
		checkForBin(command, true)
	default:
		checkForBin(command, false)
	}

}

func checkForBin(command string, showBashCompletion bool) {
	dirname := "." + string(filepath.Separator)

	d, err := os.Open(dirname)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer d.Close()

	files, err := d.Readdir(-1)
	if err != nil {
		fmt.Println(err)
		log.Fatal(err)
	}

	for _, file := range files {
		if file.Mode().IsDir() {
			if file.Name() == "bin" {
				dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
				if err != nil {
					log.Fatal(err)
				}

				// Set bin path
				binPath := filepath.Join(dir, file.Name())

				// If --show-bash-completion flag was used then list out files in binPath
				if showBashCompletion == true {
					// List files in bin folder
					listBinPathFiles(binPath)
				} else {
					// Execute command in binPath
					executeCommand(binPath, command)
				}

				os.Exit(0)
			}
		}
	}

	// If it doesn't move up a directory and test
	os.Chdir(".." + string(filepath.Separator))

	checkForBin(command, showBashCompletion)
}

// Print out files found in binpath
func listBinPathFiles(binPath string) {
	files, err := ioutil.ReadDir(binPath)
	if err != nil {
		fmt.Printf("-binpath: error reading: %v \n", binPath)
		os.Exit(1)
	}

	for _, file := range files {
		name := file.Name()

		// If it's a hidden file don't print it
		if !strings.HasPrefix(name, ".") {
			fmt.Println(name)
		}
	}
}

// Try to execute the command if a binpath is found
func executeCommand(binPath string, command string) {
	// Set path to command
	commandPath := filepath.Join(binPath, command)

	// Make to see if command exist in bin path
	_, err := os.Stat(commandPath)
	if err != nil {
		fmt.Printf("-binpath: %v: command not found in: %v \n", command, binPath)
		os.Exit(1)
	}

	// Create separator for easier reading
	separator := "-----------------------"
	fmt.Println(separator)

	// Notify if a bin is found
	fmt.Printf("Exec command: %v\n", commandPath)

	// Print separator for separation of binpath and command
	fmt.Println(separator)

	// And binPath to $PATH env
	v := fmt.Sprintf("$PATH:%v", binPath)
	os.Setenv("PATH", v)

	// Make sure to pass any arguments to the app
	args := os.Args[2:len(os.Args)]

	// Call command
	cmd := exec.Command(command, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if _, ok := err.(*exec.ExitError); ok {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/goreleaser/goreleaser/pipeline/brew"
	"github.com/goreleaser/goreleaser/pipeline/build"
	"github.com/goreleaser/goreleaser/pipeline/archive"
	"github.com/goreleaser/goreleaser/pipeline/defaults"
	"github.com/goreleaser/goreleaser/pipeline/env"
	"github.com/goreleaser/goreleaser/pipeline/git"
	"github.com/goreleaser/goreleaser/pipeline/release"
	"github.com/goreleaser/goreleaser/pipeline/repos"
	"github.com/urfave/cli"
)

var version = "master"

var pipes = []pipeline.Pipe{
	// load data, set defaults, etc...
	defaults.Pipe{},
	env.Pipe{},
	git.Pipe{},
	repos.Pipe{},

	// real work
	build.Pipe{},
	archive.Pipe{},
	release.Pipe{},
	brew.Pipe{},
}

func main() {
	var app = cli.NewApp()
	app.Name = "release"
	app.Version = version
	app.Usage = "Deliver Go binaries as fast and easily as possible"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
			Value: "goreleaser.yml",
		},
	}
	app.Action = func(c *cli.Context) (err error) {
		var file = c.String("config")
		cfg, err := config.Load(file)
		// Allow failing to load the config file if file is not explicitly specified
		if err != nil && c.IsSet("config") {
			return cli.NewExitError(err.Error(), 1)
		}
		context := context.New(cfg)
		log.SetFlags(0)
		for _, pipe := range pipes {
			log.Println(pipe.Description())
			log.SetPrefix(" -> ")
			if err := pipe.Run(context); err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			log.SetPrefix("")
		}
		log.Println("Done!")
		return
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>goimports<commit_after>package main

import (
	"log"
	"os"

	"github.com/goreleaser/goreleaser/config"
	"github.com/goreleaser/goreleaser/context"
	"github.com/goreleaser/goreleaser/pipeline"
	"github.com/goreleaser/goreleaser/pipeline/archive"
	"github.com/goreleaser/goreleaser/pipeline/brew"
	"github.com/goreleaser/goreleaser/pipeline/build"
	"github.com/goreleaser/goreleaser/pipeline/defaults"
	"github.com/goreleaser/goreleaser/pipeline/env"
	"github.com/goreleaser/goreleaser/pipeline/git"
	"github.com/goreleaser/goreleaser/pipeline/release"
	"github.com/goreleaser/goreleaser/pipeline/repos"
	"github.com/urfave/cli"
)

var version = "master"

var pipes = []pipeline.Pipe{
	// load data, set defaults, etc...
	defaults.Pipe{},
	env.Pipe{},
	git.Pipe{},
	repos.Pipe{},

	// real work
	build.Pipe{},
	archive.Pipe{},
	release.Pipe{},
	brew.Pipe{},
}

func main() {
	var app = cli.NewApp()
	app.Name = "release"
	app.Version = version
	app.Usage = "Deliver Go binaries as fast and easily as possible"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "Load configuration from `FILE`",
			Value: "goreleaser.yml",
		},
	}
	app.Action = func(c *cli.Context) (err error) {
		var file = c.String("config")
		cfg, err := config.Load(file)
		// Allow failing to load the config file if file is not explicitly specified
		if err != nil && c.IsSet("config") {
			return cli.NewExitError(err.Error(), 1)
		}
		context := context.New(cfg)
		log.SetFlags(0)
		for _, pipe := range pipes {
			log.Println(pipe.Description())
			log.SetPrefix(" -> ")
			if err := pipe.Run(context); err != nil {
				return cli.NewExitError(err.Error(), 1)
			}
			log.SetPrefix("")
		}
		log.Println("Done!")
		return
	}
	if err := app.Run(os.Args); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"net/http"
	"github.com/pkg/errors"
	"encoding/json"
	"gopkg.in/yaml.v2"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	_ "github.com/mattn/go-sqlite3"
)

var settings = `
driver: sqlite3
rules:
  - path: /show/:id/
    query: SELECT * FROM test WHERE id = {{id}};
  - path: /showall/
    query: SELECT * FROM test; SELECT * FROM TEST;
  - path: /create/
    query: INSERT INTO test (body) VALUES ("lililil"), ("OUE");
`

// Response defines the JSON contents for response to resource request by HTTP.
type Response struct {
	Success bool `json:"success"`
	Rows []map[string]interface{} `json:"rows"`
	ErrorType string `json:"errorType"`
	ErrorDescription string `json:"errorDescription"`
}

// InputRule is part of InputConfig
type InputRule struct {
	Path string
	Before string
	Befores []string
	Query string
	Queries []string
	After string
	Afters []string
	Method string
	Transaction bool
}

// InputConfig is for reading YAML config file
type InputConfig struct {
	Driver string `yaml:"driver"`
	Rules []InputRule `yaml:"rules"`
}

// QuerySet contains all queries to execute.
type QuerySet struct {
	Befores []Query
	Queries []Query
	Afters []Query
}

func newQuerySet(db *sqlx.DB, rule Rule) (QuerySet, error) {
	befores, err := newQueries(db, rule.Befores)
	if err != nil {
		return QuerySet{}, err
	}

	queries, err := newQueries(db, rule.Queries)
	if err != nil {
		return QuerySet{}, err
	}

	afters, err := newQueries(db, rule.Afters)
	if err != nil {
		return QuerySet{}, err
	}

	return QuerySet{
		Befores: befores,
		Queries: queries,
		Afters: afters,
	}, nil
}

func newQueries(db *sqlx.DB, qss []string) ([]Query, error) {
	queries := []Query{}
	for _, qs := range qss {
		q, err := newQuery(db, qs)
		if err != nil {
			return []Query{}, err
		}
		queries = append(queries, q)
	}
	return queries, nil
}

func newQuery(db *sqlx.DB, qs string) (Query, error) {
	re := regexp.MustCompile(`\{\{(\w+)\}\}`)
	groups := re.FindAllStringSubmatch(qs, -1)

	argKeys := []string{}
	for _, group := range groups {
		argKeys = append(argKeys, group[1])
	}
	replaced := re.ReplaceAllString(qs, "?")
	stmt, err := db.Preparex(replaced)
	if err != nil {
		return Query{}, SQLParseError(errors.Wrap(err, "failed to parse SQL"))
	}
	return Query{
		SQL: stmt,
		ArgKeys: argKeys,
	}, nil
}

// Rule is part of `Config`, it's set of the routing path and the SQL query.
type Rule struct {
	Befores []string
	Queries []string
	Afters []string
	Path string
	Method Method
	Transaction bool
}

// Config contains configs of whole app
type Config struct {
	Driver string
	Rules []Rule
}

// Config returns one converted to Config struct
func (ic InputConfig) Config() (Config, error) {
	rules, err := normalizeRules(ic.Rules)
	if err != nil {
		return Config{}, err
	}

	return Config{
		Driver: ic.Driver,
		Rules: rules,
	}, nil
}

func normalizeRules(orig []InputRule) ([]Rule, error) {
	result := []Rule{}
	for _, rule := range orig {
		normalized, err := normalizeRule(rule)
		if err != nil {
			return []Rule{}, err
		}
		result = append(result, normalized)
	}
	return result, nil
}

func normalizeRule(orig InputRule) (Rule, error) {
	befores, err := normalizeBefores(orig.Before, orig.Befores)
	if err != nil {
		return Rule{}, err
	}

	queries, err := normalizeQuery(orig.Query, orig.Queries)
	if err != nil {
		return Rule{}, err
	}

	afters, err := normalizeAfters(orig.After, orig.Afters)
	if err != nil {
		return Rule{}, err
	}

	method, err := newMethod(orig.Method)
	if err != nil {
		return Rule{}, err
	}

	path, err := normalizePath(orig.Path)
	if err != nil {
		return Rule{}, err
	}

	return Rule{
		Befores: befores,
		Queries: queries,
		Afters: afters,
		Method: method,
		Path: path,
	}, nil
}

func normalizePath(orig string) (string, error) {
	return orig, nil
}

func normalizeBefores(before string, befores []string) ([]string, error) {
	if before != "" && len(befores) != 0 {
		return []string{}, fmt.Errorf("both of `before` and `befores` can't be defined in a rule")
	} else if before != "" {
		return []string{before}, nil
	} else if len(befores) > 0 {
		return befores, nil
	}
	return []string{}, nil
}

func normalizeAfters(after string, afters []string) ([]string, error) {
	if after != "" && len(afters) != 0 {
		return []string{}, fmt.Errorf("both of `after` and `afters` can't be defined in a rule")
	} else if after != "" {
		return []string{after}, nil
	} else if len(afters) > 0 {
		return afters, nil
	}
	return []string{}, nil
}

func normalizeQuery(query string, queries []string) ([]string, error) {
	if query != "" && len(queries) != 0 {
		return []string{}, fmt.Errorf("both of `query` and `queries` can't be defined in a rule")
	} else if query != "" {
		return []string{query}, nil
	} else if len(queries) > 0 {
		return queries, nil
	}
	return []string{}, fmt.Errorf("at least one SQL query must be given per rule")
}

func newMethod(method string) (Method, error) {
	switch method {
	case "GET":
		return GET, nil
	case "POST":
		return POST, nil
	case "PUT":
		return PUT, nil
	case "PATCH":
		return PATCH, nil
	case "DELETE":
		return DELETE, nil
	case "":
		return GET, nil
	}
	return "", fmt.Errorf("invalid method name")
}

// Method is enum for HTTP methods.
type Method string

const (
	// GET expresses GET method
	GET Method = "GET"

	// POST expresses POST method
	POST = "POST"

	// PUT expresses PUT method
	PUT = "PUT"

	// PATCH expresses PATCH method
	PATCH = "PATCH"

	// DELETE expresses DELETE method
	DELETE = "DELETE"
)

// QueryExecutionError causes in execution SQL query
type QueryExecutionError error

// UnknownArgError causes when given undefined parameters name in path at SOL.
type UnknownArgError error

// SQLParseError causes when failed to parse SQL.
type SQLParseError error

// Query is data set for one SQL query execution
type Query struct{
	SQL *sqlx.Stmt
	ArgKeys []string
}

// ExecuteWithArgMap executes the Query. `params` is map of param key and value.
func (q Query) ExecuteWithArgMap(params map[string]interface{}) (*sqlx.Rows, error) {
	args := []interface{}{}
	for _, argKey := range q.ArgKeys {
		arg, ok := params[argKey]
		if !ok {
			return nil, UnknownArgError(errors.Errorf("unknown argument name: %s", argKey))
		}
		args = append(args, arg)
	}
	return q.SQL.Queryx(args...)
}

func main() {
	inputConfig := InputConfig{}
	yaml.Unmarshal([]byte(settings), &inputConfig)
	config, err := inputConfig.Config()
	if err != nil {
		fmt.Printf("invalid configuration: %s\n", err)
		return
	}

	db, err := sqlx.Open(config.Driver, "./test.db")
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	for _, rule := range config.Rules {
		querySet, err := newQuerySet(db, rule)
		if err != nil {
			fmt.Println(errors.Wrap(err, "failed to compile query"))
			return
		}
		router.Handle(string(rule.Method), rule.Path, createHandler(db, querySet))
	}
	fmt.Println(http.ListenAndServe(":8000", router))
}

func createHandler(db *sqlx.DB, q QuerySet) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		rowMaps, err := executeQueriesRowMaps(db, q.Queries, createParamMap(params))
		if err != nil {
			bts, marshalErr := json.Marshal(Response{
				Success: false,
				ErrorType: getErrorType(err),
				ErrorDescription: err.Error(),
			})
			if marshalErr != nil {
				panic(marshalErr)
			}
			w.Write(bts)
		}

		bts, marshalErr := json.Marshal(Response{
			Success: true,
			Rows: rowMaps,
		})
		if marshalErr != nil {
			panic(marshalErr)
		}
		w.Write(bts)
	}
}

func getErrorType(err error) string {
	switch err.(type) {
	case QueryExecutionError:
		return "QueryExecutionError"
	}
	return "Unknown"
}

func executeQueriesRowMaps(db *sqlx.DB, qs []Query, paramMap map[string]interface{}) ([]map[string]interface{}, error) {
	concated := []map[string]interface{}{}
	for _, q := range qs {
		rowMap, err := executeRowMaps(db, q, paramMap)
		if err != nil {
			return nil, err
		}
		concated = append(concated, rowMap...)
	}
	return concated, nil
}

func executeRowMaps(db *sqlx.DB, q Query, paramMap map[string]interface{}) ([]map[string]interface{}, error) {
	rows, err := q.ExecuteWithArgMap(paramMap)
	if err != nil {
		return nil, QueryExecutionError(errors.Wrap(err, "failed to execute query"))
	}
	res, err := createMapSliceFromRows(rows)
	if err != nil {
		return nil, QueryExecutionError(errors.Wrap(err, "failed to create map slice from results"))
	}
	return res, nil
}

func createParamMap(params httprouter.Params) map[string]interface{} {
	result := make(map[string]interface{})
	for _, param := range params {
		result[param.Key] = param.Value
	}
	return result
}

type mapString []byte

func (bts mapString) MarshalText() ([]byte, error) {
	return bts, nil
}

func createMapSliceFromRows(rows *sqlx.Rows) ([]map[string]interface{}, error) {
	result := []map[string]interface{}{}
	for rows.Next() {
		cols := make(map[string]interface{})
		err := rows.MapScan(cols)
		if err != nil {
			return nil, err
		}

		newCols := make(map[string]interface{})
		for k, v := range cols {
			if str, ok := v.([]byte); ok {
				newCols[k] = mapString(str)
			} else {
				newCols[k] = v
			}
		}
		result = append(result, newCols)
	}
	return result, nil
}
<commit_msg>[Modify] define database filename in config file<commit_after>package main

import (
	"fmt"
	"regexp"
	"net/http"
	"github.com/pkg/errors"
	"encoding/json"
	"gopkg.in/yaml.v2"
	"github.com/jmoiron/sqlx"
	"github.com/julienschmidt/httprouter"
	_ "github.com/mattn/go-sqlite3"
)

var settings = `
db:
  driver: sqlite3
  filepath: test.db
rules:
  - path: /show/:id/
    query: SELECT * FROM test WHERE id = {{id}};
  - path: /showall/
    query: SELECT * FROM test; SELECT * FROM TEST;
  - path: /create/
    query: INSERT INTO test (body) VALUES ("lililil"), ("OUE");
`

// Response defines the JSON contents for response to resource request by HTTP.
type Response struct {
	Success bool `json:"success"`
	Rows []map[string]interface{} `json:"rows"`
	ErrorType string `json:"errorType"`
	ErrorDescription string `json:"errorDescription"`
}

// InputRule is part of InputConfig
type InputRule struct {
	Path string
	Before string
	Befores []string
	Query string
	Queries []string
	After string
	Afters []string
	Method string
	Transaction bool
}

// DBConfig is parameters for opening connection to database.
type DBConfig struct {
	Driver string `yaml:"driver"`
	Filepath string `yaml:"filepath"`
}

// InputConfig is for reading YAML config file
type InputConfig struct {
	DB DBConfig `yaml:"db"`
	Rules []InputRule `yaml:"rules"`
}

// QuerySet contains all queries to execute.
type QuerySet struct {
	Befores []Query
	Queries []Query
	Afters []Query
}

func newQuerySet(db *sqlx.DB, rule Rule) (QuerySet, error) {
	befores, err := newQueries(db, rule.Befores)
	if err != nil {
		return QuerySet{}, err
	}

	queries, err := newQueries(db, rule.Queries)
	if err != nil {
		return QuerySet{}, err
	}

	afters, err := newQueries(db, rule.Afters)
	if err != nil {
		return QuerySet{}, err
	}

	return QuerySet{
		Befores: befores,
		Queries: queries,
		Afters: afters,
	}, nil
}

func newQueries(db *sqlx.DB, qss []string) ([]Query, error) {
	queries := []Query{}
	for _, qs := range qss {
		q, err := newQuery(db, qs)
		if err != nil {
			return []Query{}, err
		}
		queries = append(queries, q)
	}
	return queries, nil
}

func newQuery(db *sqlx.DB, qs string) (Query, error) {
	re := regexp.MustCompile(`\{\{(\w+)\}\}`)
	groups := re.FindAllStringSubmatch(qs, -1)

	argKeys := []string{}
	for _, group := range groups {
		argKeys = append(argKeys, group[1])
	}
	replaced := re.ReplaceAllString(qs, "?")
	stmt, err := db.Preparex(replaced)
	if err != nil {
		return Query{}, SQLParseError(errors.Wrap(err, "failed to parse SQL"))
	}
	return Query{
		SQL: stmt,
		ArgKeys: argKeys,
	}, nil
}

// Rule is part of `Config`, it's set of the routing path and the SQL query.
type Rule struct {
	Befores []string
	Queries []string
	Afters []string
	Path string
	Method Method
	Transaction bool
}

// Config contains configs of whole app
type Config struct {
	DB DBConfig
	Rules []Rule
}

// Config returns one converted to Config struct
func (ic InputConfig) Config() (Config, error) {
	rules, err := normalizeRules(ic.Rules)
	if err != nil {
		return Config{}, err
	}

	return Config{
		DB: ic.DB,
		Rules: rules,
	}, nil
}

func normalizeRules(orig []InputRule) ([]Rule, error) {
	result := []Rule{}
	for _, rule := range orig {
		normalized, err := normalizeRule(rule)
		if err != nil {
			return []Rule{}, err
		}
		result = append(result, normalized)
	}
	return result, nil
}

func normalizeRule(orig InputRule) (Rule, error) {
	befores, err := normalizeBefores(orig.Before, orig.Befores)
	if err != nil {
		return Rule{}, err
	}

	queries, err := normalizeQuery(orig.Query, orig.Queries)
	if err != nil {
		return Rule{}, err
	}

	afters, err := normalizeAfters(orig.After, orig.Afters)
	if err != nil {
		return Rule{}, err
	}

	method, err := newMethod(orig.Method)
	if err != nil {
		return Rule{}, err
	}

	path, err := normalizePath(orig.Path)
	if err != nil {
		return Rule{}, err
	}

	return Rule{
		Befores: befores,
		Queries: queries,
		Afters: afters,
		Method: method,
		Path: path,
	}, nil
}

func normalizePath(orig string) (string, error) {
	return orig, nil
}

func normalizeBefores(before string, befores []string) ([]string, error) {
	if before != "" && len(befores) != 0 {
		return []string{}, fmt.Errorf("both of `before` and `befores` can't be defined in a rule")
	} else if before != "" {
		return []string{before}, nil
	} else if len(befores) > 0 {
		return befores, nil
	}
	return []string{}, nil
}

func normalizeAfters(after string, afters []string) ([]string, error) {
	if after != "" && len(afters) != 0 {
		return []string{}, fmt.Errorf("both of `after` and `afters` can't be defined in a rule")
	} else if after != "" {
		return []string{after}, nil
	} else if len(afters) > 0 {
		return afters, nil
	}
	return []string{}, nil
}

func normalizeQuery(query string, queries []string) ([]string, error) {
	if query != "" && len(queries) != 0 {
		return []string{}, fmt.Errorf("both of `query` and `queries` can't be defined in a rule")
	} else if query != "" {
		return []string{query}, nil
	} else if len(queries) > 0 {
		return queries, nil
	}
	return []string{}, fmt.Errorf("at least one SQL query must be given per rule")
}

func newMethod(method string) (Method, error) {
	switch method {
	case "GET":
		return GET, nil
	case "POST":
		return POST, nil
	case "PUT":
		return PUT, nil
	case "PATCH":
		return PATCH, nil
	case "DELETE":
		return DELETE, nil
	case "":
		return GET, nil
	}
	return "", fmt.Errorf("invalid method name")
}

// Method is enum for HTTP methods.
type Method string

const (
	// GET expresses GET method
	GET Method = "GET"

	// POST expresses POST method
	POST = "POST"

	// PUT expresses PUT method
	PUT = "PUT"

	// PATCH expresses PATCH method
	PATCH = "PATCH"

	// DELETE expresses DELETE method
	DELETE = "DELETE"
)

// QueryExecutionError causes in execution SQL query
type QueryExecutionError error

// UnknownArgError causes when given undefined parameters name in path at SOL.
type UnknownArgError error

// SQLParseError causes when failed to parse SQL.
type SQLParseError error

// Query is data set for one SQL query execution
type Query struct{
	SQL *sqlx.Stmt
	ArgKeys []string
}

// ExecuteWithArgMap executes the Query. `params` is map of param key and value.
func (q Query) ExecuteWithArgMap(params map[string]interface{}) (*sqlx.Rows, error) {
	args := []interface{}{}
	for _, argKey := range q.ArgKeys {
		arg, ok := params[argKey]
		if !ok {
			return nil, UnknownArgError(errors.Errorf("unknown argument name: %s", argKey))
		}
		args = append(args, arg)
	}
	return q.SQL.Queryx(args...)
}

func main() {
	inputConfig := InputConfig{}
	yaml.Unmarshal([]byte(settings), &inputConfig)
	config, err := inputConfig.Config()
	if err != nil {
		fmt.Printf("invalid configuration: %s\n", err)
		return
	}

	db, err := sqlx.Open(config.DB.Driver, config.DB.Filepath)
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	for _, rule := range config.Rules {
		querySet, err := newQuerySet(db, rule)
		if err != nil {
			fmt.Println(errors.Wrap(err, "failed to compile query"))
			return
		}
		router.Handle(string(rule.Method), rule.Path, createHandler(db, querySet))
	}
	fmt.Println(http.ListenAndServe(":8000", router))
}

func createHandler(db *sqlx.DB, q QuerySet) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		rowMaps, err := executeQueriesRowMaps(db, q.Queries, createParamMap(params))
		if err != nil {
			bts, marshalErr := json.Marshal(Response{
				Success: false,
				ErrorType: getErrorType(err),
				ErrorDescription: err.Error(),
			})
			if marshalErr != nil {
				panic(marshalErr)
			}
			w.Write(bts)
		}

		bts, marshalErr := json.Marshal(Response{
			Success: true,
			Rows: rowMaps,
		})
		if marshalErr != nil {
			panic(marshalErr)
		}
		w.Write(bts)
	}
}

func getErrorType(err error) string {
	switch err.(type) {
	case QueryExecutionError:
		return "QueryExecutionError"
	}
	return "Unknown"
}

func executeQueriesRowMaps(db *sqlx.DB, qs []Query, paramMap map[string]interface{}) ([]map[string]interface{}, error) {
	concated := []map[string]interface{}{}
	for _, q := range qs {
		rowMap, err := executeRowMaps(db, q, paramMap)
		if err != nil {
			return nil, err
		}
		concated = append(concated, rowMap...)
	}
	return concated, nil
}

func executeRowMaps(db *sqlx.DB, q Query, paramMap map[string]interface{}) ([]map[string]interface{}, error) {
	rows, err := q.ExecuteWithArgMap(paramMap)
	if err != nil {
		return nil, QueryExecutionError(errors.Wrap(err, "failed to execute query"))
	}
	res, err := createMapSliceFromRows(rows)
	if err != nil {
		return nil, QueryExecutionError(errors.Wrap(err, "failed to create map slice from results"))
	}
	return res, nil
}

func createParamMap(params httprouter.Params) map[string]interface{} {
	result := make(map[string]interface{})
	for _, param := range params {
		result[param.Key] = param.Value
	}
	return result
}

type mapString []byte

func (bts mapString) MarshalText() ([]byte, error) {
	return bts, nil
}

func createMapSliceFromRows(rows *sqlx.Rows) ([]map[string]interface{}, error) {
	result := []map[string]interface{}{}
	for rows.Next() {
		cols := make(map[string]interface{})
		err := rows.MapScan(cols)
		if err != nil {
			return nil, err
		}

		newCols := make(map[string]interface{})
		for k, v := range cols {
			if str, ok := v.([]byte); ok {
				newCols[k] = mapString(str)
			} else {
				newCols[k] = v
			}
		}
		result = append(result, newCols)
	}
	return result, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/jessevdk/go-flags"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"
)

const (
	expectingVersion = "1.1.1 DISABLED"                                  // number being expected. must be changed manually (for now).
	changeURLBase    = "https://code.google.com/p/go/source/detail?r=go" // base url to poll the tag
	updateInterval   = 6 * time.Second                                   // Update interval for the expected number
)

var defaultPage = "http://isgo1point3.outyet.org"

var (
	versions     = make(map[string]*version) // map with all versions by number(string)
	versionsLock sync.RWMutex                // map lock
)

var regexpNumber = regexp.MustCompile(`^[1-9](?:\.[0-9]){0,2}$`)

var colVersions *mgo.Collection
var colNV *mgo.Collection

var options struct {
	Listen string `short:"l" long:"listen" default:"141.138.139.6:80" description:"IP:post to listen on"`
}

func main() {
	args, err := flags.Parse(&options)
	if err != nil {
		log.Fatalln(err)
	}
	if len(args) > 0 {
		log.Fatalln("Unexpected arguments.")
	}

	mgoSess, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalln(err)
	}
	colVersions = mgoSess.DB("outyet").C("versions")
	colVersions.EnsureIndex(mgo.Index{
		Key:      []string{"number"},
		Unique:   true,
		DropDups: true,
	})
	colNV = mgoSess.DB("outyet").C("namevalue")
	colNV.EnsureIndex(mgo.Index{
		Key:      []string{"name"},
		Unique:   true,
		DropDups: true,
	})

	if err := http.ListenAndServe(options.Listen, http.HandlerFunc(rootHandler)); err != nil {
		log.Fatalln(err)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	// handler for stats page
	if r.Host == "stats.outyet.org" {
		statsHandler(w, r)
		return
	}

	// redirect for 'old' domain
	if r.Host == "isgo1point2outyet.com" {
		http.Redirect(w, r, "http://isgo1point2.outyet.org", http.StatusTemporaryRedirect)
		return
	}

	// only handle requests on /
	if r.RequestURI != "/" {
		http.NotFound(w, r)
		return
	}

	// check if Host header matches isgo*.outyet.org
	if !strings.HasSuffix(r.Host, ".outyet.org") || !strings.HasPrefix(r.Host, "isgo") {
		log.Printf("Invalid host format detected. %s\n", r.Host)
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	number := strings.Replace(r.Host[4:len(r.Host)-11], "point", ".", -1)
	log.Println(number)

	if !regexpNumber.MatchString(number) {
		http.Error(w, "invalid request format", http.StatusBadRequest)
		return
	}

	if strings.HasSuffix(number, ".0") {
		number = number[:len(number)-2]
		if len(number) > 0 {
			log.Printf(" > redirecting to %s\n", number)
			http.Redirect(w, r, "http://isgo"+strings.Replace(number, ".", "point", -1)+".outyet.org", http.StatusTemporaryRedirect)
			return
		}
		log.Println("invalid number")
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	// get right version in a safe way
	o := getVersion(number)

	// add hitCount's
	colVersions.Upsert(bson.M{"number": o.number}, bson.M{"$inc": bson.M{"hits": 1}})
	colNV.Upsert(bson.M{"name": "counts"}, bson.M{"$inc": bson.M{"hits": 1}})

	// execute template
	data := dataOutyet{
		Outyet: <-o.isOutyetChan, //retrieve outyet directly from channel
		Number: number,
	}
	err := tmplOutyet.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	data := &dataStats{}

	colNV.Find(bson.M{"name": "counts"}).One(data)
	colVersions.Find(nil).Sort("number").All(&data.Versions)

	for _, v := range data.Versions {
		// get outyet for given version number
		v.Outyet = <-getVersion(v.Number).isOutyetChan

		// add hitCount's
		colVersions.Upsert(bson.M{"number": v.Number}, bson.M{"$inc": bson.M{"hits": 1}})
	}

	err := tmplStats.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}
<commit_msg>default page to go1.5<commit_after>package main

import (
	"github.com/jessevdk/go-flags"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log"
	"net/http"
	"regexp"
	"strings"
	"sync"
	"time"
)

const (
	expectingVersion = "1.1.1 DISABLED"                                  // number being expected. must be changed manually (for now).
	changeURLBase    = "https://code.google.com/p/go/source/detail?r=go" // base url to poll the tag
	updateInterval   = 6 * time.Second                                   // Update interval for the expected number
)

var defaultPage = "http://isgo1point5.outyet.org"

var (
	versions     = make(map[string]*version) // map with all versions by number(string)
	versionsLock sync.RWMutex                // map lock
)

var regexpNumber = regexp.MustCompile(`^[1-9](?:\.[0-9]){0,2}$`)

var colVersions *mgo.Collection
var colNV *mgo.Collection

var options struct {
	Listen string `short:"l" long:"listen" default:"141.138.139.6:80" description:"IP:post to listen on"`
}

func main() {
	args, err := flags.Parse(&options)
	if err != nil {
		log.Fatalln(err)
	}
	if len(args) > 0 {
		log.Fatalln("Unexpected arguments.")
	}

	mgoSess, err := mgo.Dial("localhost")
	if err != nil {
		log.Fatalln(err)
	}
	colVersions = mgoSess.DB("outyet").C("versions")
	colVersions.EnsureIndex(mgo.Index{
		Key:      []string{"number"},
		Unique:   true,
		DropDups: true,
	})
	colNV = mgoSess.DB("outyet").C("namevalue")
	colNV.EnsureIndex(mgo.Index{
		Key:      []string{"name"},
		Unique:   true,
		DropDups: true,
	})

	if err := http.ListenAndServe(options.Listen, http.HandlerFunc(rootHandler)); err != nil {
		log.Fatalln(err)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	// handler for stats page
	if r.Host == "stats.outyet.org" {
		statsHandler(w, r)
		return
	}

	// redirect for 'old' domain
	if r.Host == "isgo1point2outyet.com" {
		http.Redirect(w, r, "http://isgo1point2.outyet.org", http.StatusTemporaryRedirect)
		return
	}

	// only handle requests on /
	if r.RequestURI != "/" {
		http.NotFound(w, r)
		return
	}

	// check if Host header matches isgo*.outyet.org
	if !strings.HasSuffix(r.Host, ".outyet.org") || !strings.HasPrefix(r.Host, "isgo") {
		log.Printf("Invalid host format detected. %s\n", r.Host)
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	number := strings.Replace(r.Host[4:len(r.Host)-11], "point", ".", -1)
	log.Println(number)

	if !regexpNumber.MatchString(number) {
		http.Error(w, "invalid request format", http.StatusBadRequest)
		return
	}

	if strings.HasSuffix(number, ".0") {
		number = number[:len(number)-2]
		if len(number) > 0 {
			log.Printf(" > redirecting to %s\n", number)
			http.Redirect(w, r, "http://isgo"+strings.Replace(number, ".", "point", -1)+".outyet.org", http.StatusTemporaryRedirect)
			return
		}
		log.Println("invalid number")
		http.Redirect(w, r, defaultPage, http.StatusTemporaryRedirect)
		return
	}

	// get right version in a safe way
	o := getVersion(number)

	// add hitCount's
	colVersions.Upsert(bson.M{"number": o.number}, bson.M{"$inc": bson.M{"hits": 1}})
	colNV.Upsert(bson.M{"name": "counts"}, bson.M{"$inc": bson.M{"hits": 1}})

	// execute template
	data := dataOutyet{
		Outyet: <-o.isOutyetChan, //retrieve outyet directly from channel
		Number: number,
	}
	err := tmplOutyet.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}

func statsHandler(w http.ResponseWriter, r *http.Request) {
	data := &dataStats{}

	colNV.Find(bson.M{"name": "counts"}).One(data)
	colVersions.Find(nil).Sort("number").All(&data.Versions)

	for _, v := range data.Versions {
		// get outyet for given version number
		v.Outyet = <-getVersion(v.Number).isOutyetChan

		// add hitCount's
		colVersions.Upsert(bson.M{"number": v.Number}, bson.M{"$inc": bson.M{"hits": 1}})
	}

	err := tmplStats.Execute(w, data)
	if err != nil {
		log.Print(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"os/signal"

	"net/http"
	_ "net/http/pprof"
)

const version = "2.1.0.beta1"

type ctxKey string

func main() {
	if len(os.Getenv("IMGPROXY_PPROF_BIND")) > 0 {
		go func() {
			http.ListenAndServe(os.Getenv("IMGPROXY_PPROF_BIND"), nil)
		}()
	}

	s := startServer()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, os.Kill)

	<-stop

	shutdownServer(s)
	shutdownVips()
}
<commit_msg>Bump version<commit_after>package main

import (
	"os"
	"os/signal"

	"net/http"
	_ "net/http/pprof"
)

const version = "2.1.0.beta2"

type ctxKey string

func main() {
	if len(os.Getenv("IMGPROXY_PPROF_BIND")) > 0 {
		go func() {
			http.ListenAndServe(os.Getenv("IMGPROXY_PPROF_BIND"), nil)
		}()
	}

	s := startServer()

	stop := make(chan os.Signal, 1)
	signal.Notify(stop, os.Interrupt, os.Kill)

	<-stop

	shutdownServer(s)
	shutdownVips()
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessions"
	"github.com/martini-contrib/strict"
	"html"
	"html/template"
	"log"
	"time"
)

func main() {

	helpers := template.FuncMap{
		// Unescape unescapes and parses HTML from database objects.
		// Used in templates such as "/post/display.tmpl"
		"unescape": func(s string) template.HTML {
			return template.HTML(html.UnescapeString(s))
		},
		// Title renders post name as a page title.
		// Otherwise it defaults to Vertigo.
		"title": func(t interface{}) string {
			post, exists := t.(Post)
			if exists {
				return post.Title
			}
			return "Vertigo"
		},
		// Date helper returns unix date as more readable one in string format.
		"date": func(d int64) string {
			return time.Unix(d, 0).String()
		},
	}

	m := martini.Classic()
	store := sessions.NewCookieStore([]byte("heartbleed"))
	m.Use(sessions.Sessions("user", store))
	m.Use(middleware())
	m.Use(strict.Strict)
	m.Use(gzip.All())
	m.Use(render.Renderer(render.Options{
		Layout: "layout",
		Funcs:  []template.FuncMap{helpers}, // Specify helper function maps for templates to access.
	}))

	m.Get("/", Homepage)

	m.Group("/feeds", func(r martini.Router) {
		r.Get("", func(res render.Render) {
			res.Redirect("/feeds/rss", 302)
		})
		r.Get("/atom", ReadFeed)
		r.Get("/rss", ReadFeed)
	})

	m.Group("/post", func(r martini.Router) {

		// Please note that `/new` route has to be before the `/:title` route. Otherwise the program will try
		// to fetch for Post named "new".
		// For now I'll keep it this way to streamline route naming.
		r.Get("/new", ProtectedPage, func(res render.Render) {
			res.HTML(200, "post/new", nil)
		})
		r.Get("/:title", ReadPost)
		r.Get("/:title/edit", EditPost)
		r.Post("/:title/edit", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/:title/delete", DeletePost)
		r.Get("/:title/publish", PublishPost)
		r.Post("/new", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/search", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Group("/user", func(r martini.Router) {

		r.Get("", ProtectedPage, ReadUser)
		//r.Post("/delete", strict.ContentType("application/x-www-form-urlencoded"), ProtectedPage, binding.Form(Person{}), DeleteUser)

		r.Get("/register", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/register", nil)
		})
		r.Post("/register", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), binding.ErrorHandler, CreateUser)

		r.Get("/login", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/login", nil)
		})
		r.Post("/login", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), LoginUser)
		r.Get("/logout", LogoutUser)

	})

	m.Group("/api", func(r martini.Router) {

		r.Get("", func(res render.Render) {
			res.HTML(200, "api/index", nil)
		})
		r.Get("/users", ReadUsers)
		r.Get("/user/:id", ReadUser)
		//r.Delete("/user", DeleteUser)
		r.Post("/user", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, CreateUser)
		r.Post("/user/login", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, LoginUser)
		r.Get("/user/logout", LogoutUser)

		r.Get("/posts", ReadPosts)
		r.Get("/post/:title", ReadPost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Get("/post/:title/publish")
		r.Post("/post/:title/edit", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/post/:title/delete", DeletePost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/post/search/:query", strict.ContentType("application/json"), binding.Json(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
	m.Run()

	log.Println("Vertigo started")
}
<commit_msg>import cookie hash from env<commit_after>package main

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/gzip"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessions"
	"github.com/martini-contrib/strict"
	"html"
	"html/template"
	"log"
<<<<<<< HEAD
=======
	"os"
>>>>>>> 0ff12af... import cookie hash from env
	"time"
)

func main() {

	helpers := template.FuncMap{
		// Unescape unescapes and parses HTML from database objects.
		// Used in templates such as "/post/display.tmpl"
		"unescape": func(s string) template.HTML {
			return template.HTML(html.UnescapeString(s))
		},
		// Title renders post name as a page title.
		// Otherwise it defaults to Vertigo.
		"title": func(t interface{}) string {
			post, exists := t.(Post)
			if exists {
				return post.Title
			}
			return "Vertigo"
		},
		// Date helper returns unix date as more readable one in string format.
		"date": func(d int64) string {
			return time.Unix(d, 0).String()
		},
	}

	m := martini.Classic()
<<<<<<< HEAD
	store := sessions.NewCookieStore([]byte("heartbleed"))
=======
	store := sessions.NewCookieStore([]byte(os.Getenv("vertigo_hash")))
>>>>>>> 0ff12af... import cookie hash from env
	m.Use(sessions.Sessions("user", store))
	m.Use(middleware())
	m.Use(strict.Strict)
	m.Use(gzip.All())
	m.Use(render.Renderer(render.Options{
		Layout: "layout",
		Funcs:  []template.FuncMap{helpers}, // Specify helper function maps for templates to access.
	}))

	m.Get("/", Homepage)

	m.Group("/feeds", func(r martini.Router) {
		r.Get("", func(res render.Render) {
			res.Redirect("/feeds/rss", 302)
		})
		r.Get("/atom", ReadFeed)
		r.Get("/rss", ReadFeed)
	})

	m.Group("/post", func(r martini.Router) {

		// Please note that `/new` route has to be before the `/:title` route. Otherwise the program will try
		// to fetch for Post named "new".
		// For now I'll keep it this way to streamline route naming.
		r.Get("/new", ProtectedPage, func(res render.Render) {
			res.HTML(200, "post/new", nil)
		})
		r.Get("/:title", ReadPost)
		r.Get("/:title/edit", EditPost)
		r.Post("/:title/edit", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/:title/delete", DeletePost)
		r.Get("/:title/publish", PublishPost)
		r.Post("/new", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/search", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Group("/user", func(r martini.Router) {

		r.Get("", ProtectedPage, ReadUser)
		//r.Post("/delete", strict.ContentType("application/x-www-form-urlencoded"), ProtectedPage, binding.Form(Person{}), DeleteUser)

		r.Get("/register", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/register", nil)
		})
		r.Post("/register", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), binding.ErrorHandler, CreateUser)

		r.Get("/login", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/login", nil)
		})
		r.Post("/login", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), LoginUser)
		r.Get("/logout", LogoutUser)

	})

	m.Group("/api", func(r martini.Router) {

		r.Get("", func(res render.Render) {
			res.HTML(200, "api/index", nil)
		})
		r.Get("/users", ReadUsers)
		r.Get("/user/:id", ReadUser)
		//r.Delete("/user", DeleteUser)
		r.Post("/user", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, CreateUser)
		r.Post("/user/login", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, LoginUser)
		r.Get("/user/logout", LogoutUser)

		r.Get("/posts", ReadPosts)
		r.Get("/post/:title", ReadPost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Get("/post/:title/publish")
		r.Post("/post/:title/edit", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/post/:title/delete", DeletePost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/post/search/:query", strict.ContentType("application/json"), binding.Json(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
	m.Run()

	log.Println("Vertigo started")
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/mithrandie/csvq/lib/action"
	"github.com/mithrandie/csvq/lib/cmd"
	"github.com/mithrandie/csvq/lib/query"

	"github.com/urfave/cli"
)

var version = "v0.6.1"

func main() {
	cli.AppHelpTemplate = appHHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate

	app := cli.NewApp()

	app.Name = "csvq"
	app.Usage = "SQL like query language for csv"
	app.ArgsUsage = "[\"query\"|\"statements\"|argument]"
	app.Version = version

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "delimiter, d",
			Usage: "field delimiter. Default is \",\" for csv files, \"\\t\" for tsv files.",
		},
		cli.StringFlag{
			Name:  "encoding, e",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "line-break, l",
			Value: "LF",
			Usage: "line break. one of: CRLF|LF|CR",
		},
		cli.StringFlag{
			Name:  "timezone, z",
			Value: "Local",
			Usage: "default timezone. \"Local\", \"UTC\" or a timezone name(e.g. \"America/Los_Angeles\")",
		},
		cli.StringFlag{
			Name:  "repository, r",
			Usage: "directory path where files are located",
		},
		cli.StringFlag{
			Name:  "source, s",
			Usage: "load query from `FILE`",
		},
		cli.StringFlag{
			Name:  "datetime-format, t",
			Usage: "set datetime format to parse strings",
		},
		cli.BoolFlag{
			Name:  "no-header, n",
			Usage: "import the first line as a record",
		},
		cli.BoolFlag{
			Name:  "without-null, a",
			Usage: "parse empty fields as empty strings",
		},
		cli.StringFlag{
			Name:  "write-encoding, E",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "out, o",
			Usage: "write output to `FILE`",
		},
		cli.StringFlag{
			Name:  "format, f",
			Usage: "output format. one of: CSV|TSV|JSON|TEXT",
		},
		cli.StringFlag{
			Name:  "write-delimiter, D",
			Usage: "field delimiter for CSV",
		},
		cli.BoolFlag{
			Name:  "without-header, N",
			Usage: "when the file format is specified as CSV or TSV, write without the header line",
		},
		cli.IntFlag{
			Name:  "cpu, p",
			Value: 1,
			Usage: "number of cpu cores to be used. 1 - number of cpu cores",
		},
		cli.BoolFlag{
			Name:  "stats, x",
			Usage: "show execution time and memory statistics",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "fields",
			Usage:     "Show fields in a file",
			ArgsUsage: "CSV_FILE_PATH",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "fields")
					return cli.NewExitError("table is not specified", 1)
				}

				table := c.Args().First()

				err := action.ShowFields(table)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "calc",
			Usage:     "Calculate a value from stdin",
			ArgsUsage: "\"expression\"",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "calc")
					return cli.NewExitError("expression is empty", 1)
				}

				expr := c.Args().First()
				err := action.Calc(expr)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		return setFlags(c)
	}

	app.Action = func(c *cli.Context) error {
		queryString, err := readQuery(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return cli.NewExitError(err.Error(), 1)
		}

		if err = action.Run(queryString, cmd.GetFlags().Source); err != nil {
			code := 1
			if apperr, ok := err.(query.AppError); ok {
				code = apperr.GetCode()
			}
			return cli.NewExitError(err.Error(), code)
		}

		return nil
	}

	app.Run(os.Args)
}

func readQuery(c *cli.Context) (string, error) {
	var queryString string

	flags := cmd.GetFlags()
	if 0 < len(flags.Source) {
		fp, err := os.Open(flags.Source)
		if err != nil {
			return queryString, err
		}
		defer fp.Close()

		buf, err := ioutil.ReadAll(fp)
		if err != nil {
			return queryString, err
		}
		queryString = string(buf)

	} else {
		if c.NArg() != 1 {
			return queryString, errors.New("query is empty")
		}
		queryString = c.Args().First()
	}

	return queryString, nil
}

func setFlags(c *cli.Context) error {
	if err := cmd.SetDelimiter(c.GlobalString("delimiter")); err != nil {
		return err
	}
	if err := cmd.SetEncoding(c.GlobalString("encoding")); err != nil {
		return err
	}
	if err := cmd.SetLineBreak(c.String("line-break")); err != nil {
		return err
	}
	if err := cmd.SetLocation(c.String("timezone")); err != nil {
		return err
	}
	if err := cmd.SetRepository(c.GlobalString("repository")); err != nil {
		return err
	}
	if err := cmd.SetSource(c.GlobalString("source")); err != nil {
		return err
	}
	cmd.SetDatetimeFormat(c.GlobalString("datetime-format"))
	cmd.SetNoHeader(c.GlobalBool("no-header"))
	cmd.SetWithoutNull(c.GlobalBool("without-null"))

	if err := cmd.SetWriteEncoding(c.GlobalString("write-encoding")); err != nil {
		return err
	}
	if err := cmd.SetOut(c.GlobalString("out")); err != nil {
		return err
	}
	if err := cmd.SetFormat(c.GlobalString("format")); err != nil {
		return err
	}
	if err := cmd.SetWriteDelimiter(c.GlobalString("write-delimiter")); err != nil {
		return err
	}
	cmd.SetWithoutHeader(c.GlobalBool("without-header"))

	cmd.SetCPU(c.GlobalInt("cpu"))
	cmd.SetStats(c.GlobalBool("stats"))

	return nil
}
<commit_msg>Update version for Release v0.6.2<commit_after>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"github.com/mithrandie/csvq/lib/action"
	"github.com/mithrandie/csvq/lib/cmd"
	"github.com/mithrandie/csvq/lib/query"

	"github.com/urfave/cli"
)

var version = "v0.6.2"

func main() {
	cli.AppHelpTemplate = appHHelpTemplate
	cli.CommandHelpTemplate = commandHelpTemplate

	app := cli.NewApp()

	app.Name = "csvq"
	app.Usage = "SQL like query language for csv"
	app.ArgsUsage = "[\"query\"|\"statements\"|argument]"
	app.Version = version

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "delimiter, d",
			Usage: "field delimiter. Default is \",\" for csv files, \"\\t\" for tsv files.",
		},
		cli.StringFlag{
			Name:  "encoding, e",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "line-break, l",
			Value: "LF",
			Usage: "line break. one of: CRLF|LF|CR",
		},
		cli.StringFlag{
			Name:  "timezone, z",
			Value: "Local",
			Usage: "default timezone. \"Local\", \"UTC\" or a timezone name(e.g. \"America/Los_Angeles\")",
		},
		cli.StringFlag{
			Name:  "repository, r",
			Usage: "directory path where files are located",
		},
		cli.StringFlag{
			Name:  "source, s",
			Usage: "load query from `FILE`",
		},
		cli.StringFlag{
			Name:  "datetime-format, t",
			Usage: "set datetime format to parse strings",
		},
		cli.BoolFlag{
			Name:  "no-header, n",
			Usage: "import the first line as a record",
		},
		cli.BoolFlag{
			Name:  "without-null, a",
			Usage: "parse empty fields as empty strings",
		},
		cli.StringFlag{
			Name:  "write-encoding, E",
			Value: "UTF8",
			Usage: "file encoding. one of: UTF8|SJIS",
		},
		cli.StringFlag{
			Name:  "out, o",
			Usage: "write output to `FILE`",
		},
		cli.StringFlag{
			Name:  "format, f",
			Usage: "output format. one of: CSV|TSV|JSON|TEXT",
		},
		cli.StringFlag{
			Name:  "write-delimiter, D",
			Usage: "field delimiter for CSV",
		},
		cli.BoolFlag{
			Name:  "without-header, N",
			Usage: "when the file format is specified as CSV or TSV, write without the header line",
		},
		cli.IntFlag{
			Name:  "cpu, p",
			Value: 1,
			Usage: "number of cpu cores to be used. 1 - number of cpu cores",
		},
		cli.BoolFlag{
			Name:  "stats, x",
			Usage: "show execution time and memory statistics",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:      "fields",
			Usage:     "Show fields in a file",
			ArgsUsage: "CSV_FILE_PATH",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "fields")
					return cli.NewExitError("table is not specified", 1)
				}

				table := c.Args().First()

				err := action.ShowFields(table)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
		{
			Name:      "calc",
			Usage:     "Calculate a value from stdin",
			ArgsUsage: "\"expression\"",
			Action: func(c *cli.Context) error {
				if c.NArg() != 1 {
					cli.ShowCommandHelp(c, "calc")
					return cli.NewExitError("expression is empty", 1)
				}

				expr := c.Args().First()
				err := action.Calc(expr)
				if err != nil {
					return cli.NewExitError(err.Error(), 1)
				}

				return nil
			},
		},
	}

	app.Before = func(c *cli.Context) error {
		return setFlags(c)
	}

	app.Action = func(c *cli.Context) error {
		queryString, err := readQuery(c)
		if err != nil {
			cli.ShowAppHelp(c)
			return cli.NewExitError(err.Error(), 1)
		}

		if err = action.Run(queryString, cmd.GetFlags().Source); err != nil {
			code := 1
			if apperr, ok := err.(query.AppError); ok {
				code = apperr.GetCode()
			}
			return cli.NewExitError(err.Error(), code)
		}

		return nil
	}

	app.Run(os.Args)
}

func readQuery(c *cli.Context) (string, error) {
	var queryString string

	flags := cmd.GetFlags()
	if 0 < len(flags.Source) {
		fp, err := os.Open(flags.Source)
		if err != nil {
			return queryString, err
		}
		defer fp.Close()

		buf, err := ioutil.ReadAll(fp)
		if err != nil {
			return queryString, err
		}
		queryString = string(buf)

	} else {
		if c.NArg() != 1 {
			return queryString, errors.New("query is empty")
		}
		queryString = c.Args().First()
	}

	return queryString, nil
}

func setFlags(c *cli.Context) error {
	if err := cmd.SetDelimiter(c.GlobalString("delimiter")); err != nil {
		return err
	}
	if err := cmd.SetEncoding(c.GlobalString("encoding")); err != nil {
		return err
	}
	if err := cmd.SetLineBreak(c.String("line-break")); err != nil {
		return err
	}
	if err := cmd.SetLocation(c.String("timezone")); err != nil {
		return err
	}
	if err := cmd.SetRepository(c.GlobalString("repository")); err != nil {
		return err
	}
	if err := cmd.SetSource(c.GlobalString("source")); err != nil {
		return err
	}
	cmd.SetDatetimeFormat(c.GlobalString("datetime-format"))
	cmd.SetNoHeader(c.GlobalBool("no-header"))
	cmd.SetWithoutNull(c.GlobalBool("without-null"))

	if err := cmd.SetWriteEncoding(c.GlobalString("write-encoding")); err != nil {
		return err
	}
	if err := cmd.SetOut(c.GlobalString("out")); err != nil {
		return err
	}
	if err := cmd.SetFormat(c.GlobalString("format")); err != nil {
		return err
	}
	if err := cmd.SetWriteDelimiter(c.GlobalString("write-delimiter")); err != nil {
		return err
	}
	cmd.SetWithoutHeader(c.GlobalBool("without-header"))

	cmd.SetCPU(c.GlobalInt("cpu"))
	cmd.SetStats(c.GlobalBool("stats"))

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"github.com/ehalpern/go-mysql-elasticsearch/river"
	"github.com/juju/errors"
	"fmt"
)

var configFile = flag.String("config", "./etc/river.toml", "replication config file")
var serviceOp = flag.String("service", "", "install|remove|[re]start|stop|status")
var dbHost = flag.String("db_host", "", "DB host and port")
var dbUser = flag.String("db_user", "", "DB user")
var dbPass = flag.String("db_pass", "", "DB password")
var dbSlaveId = flag.Int("db_slave_id", 0, "MySQL slave id")
var esHost = flag.String("es_host", "", "Elasticsearch host and port")
var esMaxActions = flag.Int("es_max_actions", 0, "maximum elasticsearch bulk update size")
var dataDir = flag.String("data_dir", "", "path do store data")

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	flag.Parse()

	if serviceOp != "" {
		s := NewService()
		var status string
		var err error

		switch serviceOp {
		case "install":
			status, err = s.Install("-config", configFile)
		case "remove":
			status, err = s.Remove()
		case "start":
			status, err = s.Start()
		case "stop":
			status, err = s.Stop()
		case "status":
			status, err = s.Status()
		default:
			err = flag.Usage()
		}
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
		os.Exit(1)
	}

	cfg, err := river.NewConfigWithFile(*configFile)
	if err != nil {
		println(errors.ErrorStack(err))
		return
	}

	if len(*dbHost) > 0 {
		cfg.DbHost = *dbHost
	}
	if len(*dbUser) > 0 {
		cfg.DbUser = *dbUser
	}
	if len(*dbPass) > 0 {
		cfg.DbPassword = *dbPass
	}
	if *dbSlaveId > 0 {
		cfg.DbSlaveID = uint32(*dbSlaveId)
	}
	if len(*esHost) > 0 {
		cfg.EsHost = *esHost
	}
	if len(*dataDir) > 0 {
		cfg.DataDir = *dataDir
	}
	if *esMaxActions > 0 {
		cfg.EsMaxActions = *esMaxActions
	}

	r, err := river.NewRiver(cfg)
	if err != nil {
		println(errors.ErrorStack(err))
		return
	}

	if err = r.Run(); err != nil {
		println(errors.ErrorStack(err))
	}

	<-interrupt
	r.Close()
}
<commit_msg>Fix command line parsing bug<commit_after>package main

import (
	"flag"
	"os"
	"os/signal"
	"runtime"
	"syscall"

	"github.com/ehalpern/go-mysql-elasticsearch/river"
	"github.com/juju/errors"
	"fmt"
)

var configFile = flag.String("config", "./etc/river.toml", "replication config file")
var serviceOp = flag.String("service", "", "install|remove|[re]start|stop|status")
var dbHost = flag.String("db_host", "", "DB host and port")
var dbUser = flag.String("db_user", "", "DB user")
var dbPass = flag.String("db_pass", "", "DB password")
var dbSlaveId = flag.Int("db_slave_id", 0, "MySQL slave id")
var esHost = flag.String("es_host", "", "Elasticsearch host and port")
var esMaxActions = flag.Int("es_max_actions", 0, "maximum elasticsearch bulk update size")
var dataDir = flag.String("data_dir", "", "path do store data")

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

	flag.Parse()

	if serviceOp != "" {
		s := NewService()
		var status string
		var err error

		switch *serviceOp {
		case "install":
			status, err = s.Install("-config", configFile)
		case "remove":
			status, err = s.Remove()
		case "start":
			status, err = s.Start()
		case "stop":
			status, err = s.Stop()
		case "status":
			status, err = s.Status()
		default:
			err = flag.Usage()
		}
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
		os.Exit(1)
	}

	cfg, err := river.NewConfigWithFile(*configFile)
	if err != nil {
		println(errors.ErrorStack(err))
		return
	}

	if len(*dbHost) > 0 {
		cfg.DbHost = *dbHost
	}
	if len(*dbUser) > 0 {
		cfg.DbUser = *dbUser
	}
	if len(*dbPass) > 0 {
		cfg.DbPassword = *dbPass
	}
	if *dbSlaveId > 0 {
		cfg.DbSlaveID = uint32(*dbSlaveId)
	}
	if len(*esHost) > 0 {
		cfg.EsHost = *esHost
	}
	if len(*dataDir) > 0 {
		cfg.DataDir = *dataDir
	}
	if *esMaxActions > 0 {
		cfg.EsMaxActions = *esMaxActions
	}

	r, err := river.NewRiver(cfg)
	if err != nil {
		println(errors.ErrorStack(err))
		return
	}

	if err = r.Run(); err != nil {
		println(errors.ErrorStack(err))
	}

	<-interrupt
	r.Close()
}
<|endoftext|>