<commit_before>package main

import (
	"errors"
	"github.com/go-redis/redis"
	"github.com/mmcdole/gofeed/rss"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func parseRssURL(url string) (*rss.Feed, error) {
	fp := rss.Parser{}

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	if resp != nil {
		defer func() {
			ce := resp.Body.Close()
			if ce != nil {
				err = ce
			}
		}()
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}

	return fp.Parse(resp.Body)
}

func bgmTrack(id string, ttl int) {
	rssURL := "https://bgm.tv/feed/user/" + id + "/timeline"
	if ttl < 10 {
		ttl = 10
	}
	logger.Debug(rssURL, ttl)
	keyLock := "bgm_" + id + "_lock"
	keyLast := "bgm_" + id + "_last"
	i := 1
	for {
		err := redisClient.Get(keyLock).Err()
		if err == nil {
			i = 1
			continue
		} else if err != nil && err != redis.Nil {
			logger.Error("get lock", err)
			time.Sleep(time.Duration(i) * time.Second)
			i += int(i/2.0) + 1
			continue
		}

		if redisClient.Set(keyLock, 0, 10*time.Second).Err() != nil {
			logger.Error("set lock first", err)
		}

		rss, err := parseRssURL(rssURL)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
			i += int(i/2.0) + 1
			continue
		}
		last, err := redisClient.Get(keyLast).Int64()
		if err != nil {
			logger.Error("get last", err)
			last = 0
		}
		var latest int64
		for _, item := range rss.Items {
			if item.GUID == nil {
				continue
			}
			tokens := strings.Split(item.GUID.Value, "/")
			guid := tokens[len(tokens)-1]
			id, err := strconv.ParseInt(guid, 10, 64)
			if err != nil {
				logger.Error("guid:", item.GUID.Value)
				continue
			}
			if id > latest {
				latest = id
			}
			if last == 0 {
				last = id
				break
			}
			if id <= last {
				break
			}
			logger.Info(item.Title)
			emoji := emojiBangumi[string([]rune(item.Title)[0:2])]
			des := strings.Split(item.Description, `"`)
			var desURL string
			if len(des) > 2 {
				desURL = des[1]
			}
			go twitterBot.Client.Statuses.Update(emoji+" "+item.Title+" "+desURL+" #Bangumi", nil)
		}
		if redisClient.Set(keyLast, latest, 0).Err() != nil {
			logger.Error("set last", err)
		}
		if redisClient.Set(keyLock, 0, time.Duration(ttl)*time.Second).Err() != nil {
			logger.Error("set lock", err)
		}
		time.Sleep(1 * time.Second)
	}
}
<commit_msg>log sent<commit_after>package main

import (
	"errors"
	"github.com/go-redis/redis"
	"github.com/mmcdole/gofeed/rss"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func parseRssURL(url string) (*rss.Feed, error) {
	fp := rss.Parser{}

	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	if resp != nil {
		defer func() {
			ce := resp.Body.Close()
			if ce != nil {
				err = ce
			}
		}()
	}
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, errors.New(resp.Status)
	}

	return fp.Parse(resp.Body)
}

func bgmTrack(id string, ttl int) {
	rssURL := "https://bgm.tv/feed/user/" + id + "/timeline"
	if ttl < 10 {
		ttl = 10
	}
	logger.Debug(rssURL, ttl)
	keyLock := "bgm_" + id + "_lock"
	keyLast := "bgm_" + id + "_last"
	i := 1
	for {
		err := redisClient.Get(keyLock).Err()
		if err == nil {
			i = 1
			continue
		} else if err != nil && err != redis.Nil {
			logger.Error("get lock", err)
			time.Sleep(time.Duration(i) * time.Second)
			i += int(i/2.0) + 1
			continue
		}

		if redisClient.Set(keyLock, 0, 10*time.Second).Err() != nil {
			logger.Error("set lock first", err)
		}

		rss, err := parseRssURL(rssURL)
		if err != nil {
			logger.Error(err)
			time.Sleep(time.Duration(i) * time.Second)
			i += int(i/2.0) + 1
			continue
		}
		last, err := redisClient.Get(keyLast).Int64()
		if err != nil {
			logger.Error("get last", err)
			last = 0
		}
		var latest int64
		for _, item := range rss.Items {
			if item.GUID == nil {
				continue
			}
			tokens := strings.Split(item.GUID.Value, "/")
			guid := tokens[len(tokens)-1]
			id, err := strconv.ParseInt(guid, 10, 64)
			if err != nil {
				logger.Error("guid:", item.GUID.Value)
				continue
			}
			if id > latest {
				latest = id
			}
			if last == 0 {
				last = id
				break
			}
			if id <= last {
				break
			}
			emoji := emojiBangumi[string([]rune(item.Title)[0:2])]
			des := strings.Split(item.Description, `"`)
			var desURL string
			if len(des) > 2 {
				desURL = des[1]
			}
			text := emoji + " " + item.Title + " " + desURL + " #Bangumi"
			logger.Info(text)
			go twitterBot.Client.Statuses.Update(text, nil)
		}
		if redisClient.Set(keyLast, latest, 0).Err() != nil {
			logger.Error("set last", err)
		}
		if redisClient.Set(keyLock, 0, time.Duration(ttl)*time.Second).Err() != nil {
			logger.Error("set lock", err)
		}
		time.Sleep(1 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"strconv"
	"sync"
	"time"

	"github.com/davecheney/gpio"
	"github.com/paypal/gatt"
)

// These bytes are sent over BLE
const UNLOCKED byte = 0x01
const NOTIFYING byte = 0x02

// Car represents a car
type Car struct {
	Auth *Auth

	mu          sync.Mutex
	Pin         gpio.Pin
	isUnlocked  bool
	isNotifying bool
	notifier    gatt.Notifier
}

// NewCar creates a new instance of the Car type
func NewCar(pin gpio.Pin, auth *Auth) *Car {
	return &Car{
		Pin:         pin,
		Auth:        auth,
		isUnlocked:  false,
		isNotifying: true,
	}
}

// HandleWrite will lock or unlock the car
func (c *Car) HandleWrite(r gatt.Request, data []byte) (status byte) {
	if !c.Auth.IsAuthenticated() {
		log.Println("You are not authenticated...")
		return gatt.StatusUnexpectedError
	}

	if len(data) < 1 {
		log.Println("Invalid data")
		return gatt.StatusUnexpectedError
	}

	// Pull the lever, Kronk!
	if data[0]&UNLOCKED == 0 {
		log.Println("--- Locking car")
		c.Lock()
	} else {
		log.Println("+++ Unlocking car")
		c.Unlock()
	}

	return gatt.StatusSuccess
}

// HandleRead reports the current status of the car
func (c *Car) HandleRead(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
	c.writeStatus(resp)
}

// HandleNotify sends the current  status of the car to the central every two
// seconds
func (c *Car) HandleNotify(r gatt.Request, n gatt.Notifier) {
	c.mu.Lock()
	c.notifier = n
	c.mu.Unlock()

	go func() {
		for !n.Done() {

			c.mu.Lock()
			isNotifying := c.isNotifying
			c.mu.Unlock()

			if isNotifying {
				c.writeStatus(n)
			}

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

// Unlock unlocks the car
func (c *Car) Unlock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if !c.isUnlocked {
		if c.Pin != nil {
			c.Pin.Set()
		}
		c.isUnlocked = true
	}
}

// Lock locks the car
func (c *Car) Lock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.isUnlocked {
		if c.Pin != nil {
			c.Pin.Clear()
		}
		c.isUnlocked = false
	}
}

func (c *Car) ToggleNotifications(status bool) {
	c.mu.Lock()
	c.isNotifying = status
	notifier := c.notifier
	c.mu.Unlock()

	if notifier == nil {
		log.Println("No connection")
		return
	}

	if status {
		log.Println("Enabling notifications")
	} else {
		log.Println("Stopping notifications")
	}

	c.writeStatus(notifier)
}

func (c *Car) Reset() {
	c.mu.Lock()
	c.notifier = nil
	c.mu.Unlock()
}

func (c *Car) writeStatus(w io.Writer) {
	status := byte(0)

	c.mu.Lock()
	if c.isUnlocked {
		status |= UNLOCKED
	}
	if c.isNotifying {
		status |= NOTIFYING
	}
	c.mu.Unlock()

	log.Println(strconv.FormatInt(int64(status), 2))

	w.Write([]byte{status})
}
<commit_msg>Print status as hex<commit_after>package main

import (
	"io"
	"log"
	"sync"
	"time"

	"github.com/davecheney/gpio"
	"github.com/paypal/gatt"
)

// These bytes are sent over BLE
const UNLOCKED byte = 0x01
const NOTIFYING byte = 0x02

// Car represents a car
type Car struct {
	Auth *Auth

	mu          sync.Mutex
	Pin         gpio.Pin
	isUnlocked  bool
	isNotifying bool
	notifier    gatt.Notifier
}

// NewCar creates a new instance of the Car type
func NewCar(pin gpio.Pin, auth *Auth) *Car {
	return &Car{
		Pin:         pin,
		Auth:        auth,
		isUnlocked:  false,
		isNotifying: true,
	}
}

// HandleWrite will lock or unlock the car
func (c *Car) HandleWrite(r gatt.Request, data []byte) (status byte) {
	if !c.Auth.IsAuthenticated() {
		log.Println("You are not authenticated...")
		return gatt.StatusUnexpectedError
	}

	if len(data) < 1 {
		log.Println("Invalid data")
		return gatt.StatusUnexpectedError
	}

	// Pull the lever, Kronk!
	if data[0]&UNLOCKED == 0 {
		log.Println("--- Locking car")
		c.Lock()
	} else {
		log.Println("+++ Unlocking car")
		c.Unlock()
	}

	return gatt.StatusSuccess
}

// HandleRead reports the current status of the car
func (c *Car) HandleRead(resp gatt.ReadResponseWriter, req *gatt.ReadRequest) {
	c.writeStatus(resp)
}

// HandleNotify sends the current  status of the car to the central every two
// seconds
func (c *Car) HandleNotify(r gatt.Request, n gatt.Notifier) {
	c.mu.Lock()
	c.notifier = n
	c.mu.Unlock()

	go func() {
		for !n.Done() {

			c.mu.Lock()
			isNotifying := c.isNotifying
			c.mu.Unlock()

			if isNotifying {
				c.writeStatus(n)
			}

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

// Unlock unlocks the car
func (c *Car) Unlock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if !c.isUnlocked {
		if c.Pin != nil {
			c.Pin.Set()
		}
		c.isUnlocked = true
	}
}

// Lock locks the car
func (c *Car) Lock() {
	c.mu.Lock()
	defer c.mu.Unlock()

	if c.isUnlocked {
		if c.Pin != nil {
			c.Pin.Clear()
		}
		c.isUnlocked = false
	}
}

func (c *Car) ToggleNotifications(status bool) {
	c.mu.Lock()
	c.isNotifying = status
	notifier := c.notifier
	c.mu.Unlock()

	if notifier == nil {
		log.Println("No connection")
		return
	}

	if status {
		log.Println("Enabling notifications")
	} else {
		log.Println("Stopping notifications")
	}

	c.writeStatus(notifier)
}

func (c *Car) Reset() {
	c.mu.Lock()
	c.notifier = nil
	c.mu.Unlock()
}

func (c *Car) writeStatus(w io.Writer) {
	status := byte(0)

	c.mu.Lock()
	if c.isUnlocked {
		status |= UNLOCKED
	}
	if c.isNotifying {
		status |= NOTIFYING
	}
	c.mu.Unlock()

	log.Printf("%x", status)

	w.Write([]byte{status})
}
<|endoftext|>


<commit_before>package cec

import(
	"log"
	"time"
	"strings"
)

type Device struct {
	OSDName string
	Vendor string
	LogicalAddress int
	ActiveSource bool
	PowerStatus string
	PhysicalAddress string
}

var logicalNames = []string{ "TV", "Recording", "Recording2", "Tuner",
	"Playback","Audio", "Tuner2", "Tuner3",
	"Playback2", "Recording3", "Tuner4", "Playback3",
	"Reserved", "Reserved2", "Free", "Broadcast" }

var vendorList = map[uint64]string{ 0x000039:"Toshiba", 0x0000F0:"Samsung",
	0x0005CD:"Denon", 0x000678:"Marantz", 0x000982:"Loewe", 0x0009B0:"Onkyo",
	0x000CB8:"Medion", 0x000CE7:"Toshiba", 0x001582:"Pulse Eight",
	0x0020C7:"Akai", 0x002467:"Aoc", 0x008045:"Panasonic", 0x00903E:"Philips",
	0x009053:"Daewoo", 0x00A0DE:"Yamaha", 0x00D0D5:"Grundig",
	0x00E036:"Pioneer", 0x00E091:"LG", 0x08001F:"Sharp", 0x080046:"Sony",
	0x18C086:"Broadcom", 0x6B746D:"Vizio", 0x8065E9:"Benq",
	0x9C645E:"Harman Kardon" }

func Open(name string, deviceName string) {
	var config CECConfiguration
	config.DeviceName = deviceName

	if er := cecInit(config); er != nil {
		log.Println(er)
		return
	}

	adapter, er := getAdapter(name)
	if er != nil {
		log.Println(er)
		return
	}

	er = openAdapter(adapter)
	if er != nil {
		log.Println(er)
		return
	}
}

func Key(address int, key int) {
	er := KeyPress(address, key)
	if er != nil {
		log.Println(er)
		return
	}
	time.Sleep(10 * time.Millisecond)
	er = KeyRelease(address)
	if er != nil {
		log.Println(er)
		return
	}
}

func List() map[string]Device {
	devices := make(map[string]Device)

	active_devices := GetActiveDevices()

	for address, active := range active_devices {
		if (active) {
			var dev Device

			dev.LogicalAddress = address
			dev.PhysicalAddress = GetDevicePhysicalAddress(address)
			dev.OSDName = GetDeviceOSDName(address)
			dev.PowerStatus = GetDevicePowerStatus(address)
			dev.ActiveSource = IsActiveSource(address)
			dev.Vendor = GetVendorById(GetDeviceVendorId(address))

			devices[logicalNames[address]] = dev
		}
	}
	return devices
}

func removeSeparators(in string) string {
        // remove separators (":", "-", " ", "_")
        out := strings.Map(func(r rune) rune {
                if strings.IndexRune(":-_ ", r) < 0 {
                        return r
                }
                return -1
        }, in)

	return(out)
}

func GetLogicalAddressByName(name string) int {
	name = removeSeparators(name)
	l := len(name)

	if name[l-1] == '1' {
		name = name[:l-1]
	}

	name = strings.ToLower(name)

	for i:=0; i<16; i++ {
		if strings.ToLower(logicalNames[i]) == name {
			return i
		}
	}

	if name == "unregistered" {
		return 15
	}

	return -1
}

func GetLogicalNameByAddress(addr int) string {
	return logicalNames[addr]
}

func GetVendorById(id uint64) string {
	return vendorList[id]
}
<commit_msg>support keys by name<commit_after>package cec

import(
	"log"
	"time"
	"strings"
)

type Device struct {
	OSDName string
	Vendor string
	LogicalAddress int
	ActiveSource bool
	PowerStatus string
	PhysicalAddress string
}

var logicalNames = []string{ "TV", "Recording", "Recording2", "Tuner",
	"Playback","Audio", "Tuner2", "Tuner3",
	"Playback2", "Recording3", "Tuner4", "Playback3",
	"Reserved", "Reserved2", "Free", "Broadcast" }

var vendorList = map[uint64]string{ 0x000039:"Toshiba", 0x0000F0:"Samsung",
	0x0005CD:"Denon", 0x000678:"Marantz", 0x000982:"Loewe", 0x0009B0:"Onkyo",
	0x000CB8:"Medion", 0x000CE7:"Toshiba", 0x001582:"Pulse Eight",
	0x0020C7:"Akai", 0x002467:"Aoc", 0x008045:"Panasonic", 0x00903E:"Philips",
	0x009053:"Daewoo", 0x00A0DE:"Yamaha", 0x00D0D5:"Grundig",
	0x00E036:"Pioneer", 0x00E091:"LG", 0x08001F:"Sharp", 0x080046:"Sony",
	0x18C086:"Broadcom", 0x6B746D:"Vizio", 0x8065E9:"Benq",
	0x9C645E:"Harman Kardon" }

var keyList = map[int]string{ 0x00:"Select", 0x01:"Up", 0x02:"Down", 0x03:"Left",
	0x04:"Right", 0x05:"RightUp", 0x06:"RightDown", 0x07:"LeftUp",
	0x08:"LeftDown", 0x09:"RootMenu", 0x0A:"SetupMenu", 0x0B:"ContentsMenu",
	0x0C:"FavoriteMenu", 0x0D:"Exit", 0x20:"0", 0x21:"1", 0x22:"2", 0x23:"3",
	0x24:"4", 0x25:"5", 0x26:"6", 0x27:"7", 0x28:"8", 0x29:"9", 0x2A:"Dot",
	0x2B:"Enter", 0x2C:"Clear", 0x2F:"NextFavorite", 0x30:"ChannelUp",
	0x31:"ChannelDown", 0x32:"PreviousChannel", 0x33:"SoundSelect",
	0x34:"InputSelect", 0x35:"DisplayInformation", 0x36:"Help",
	0x37:"PageUp", 0x38:"PageDown", 0x40:"Power", 0x41:"VolumeUp",
	0x42:"VolumeDown", 0x43:"Mute", 0x44:"Play", 0x45:"Stop", 0x46:"Pause",
	0x47:"Record", 0x48:"Rewind", 0x49:"FastForward", 0x4A:"Eject",
	0x4B:"Forward", 0x4C:"Backward", 0x4D:"StopRecord", 0x4E:"PauseRecord",
	0x50:"Angle", 0x51:"SubPicture", 0x52:"VideoOnDemand",
	0x53:"ElectronicProgramGuide", 0x54:"TimerProgramming",
	0x55:"InitialConfiguration", 0x60:"PlayFunction", 0x61:"PausePlay",
	0x62:"RecordFunction", 0x63:"PauseRecordFunction",
	0x64:"StopFunction", 0x65:"Mute",
	0x66:"RestoreVolume", 0x67:"Tune", 0x68:"SelectMedia",
	0x69:"SelectAvInput", 0x6A:"SelectAudioInput", 0x6B:"PowerToggle",
	0x6C:"PowerOff", 0x6D:"PowerOn", 0x71:"Blue", 0X72:"Red", 0x73:"Green",
	0x74:"Yellow", 0x75:"F5", 0x76:"Data", 0x91:"AnReturn",
	0x96:"Max" }

func Open(name string, deviceName string) {
	var config CECConfiguration
	config.DeviceName = deviceName

	if er := cecInit(config); er != nil {
		log.Println(er)
		return
	}

	adapter, er := getAdapter(name)
	if er != nil {
		log.Println(er)
		return
	}

	er = openAdapter(adapter)
	if er != nil {
		log.Println(er)
		return
	}
}

func Key(address int, key string) {
	keycode := GetKeyCodeByName(key)
	er := KeyPress(address, keycode)
	if er != nil {
		log.Println(er)
		return
	}
	time.Sleep(10 * time.Millisecond)
	er = KeyRelease(address)
	if er != nil {
		log.Println(er)
		return
	}
}

func List() map[string]Device {
	devices := make(map[string]Device)

	active_devices := GetActiveDevices()

	for address, active := range active_devices {
		if (active) {
			var dev Device

			dev.LogicalAddress = address
			dev.PhysicalAddress = GetDevicePhysicalAddress(address)
			dev.OSDName = GetDeviceOSDName(address)
			dev.PowerStatus = GetDevicePowerStatus(address)
			dev.ActiveSource = IsActiveSource(address)
			dev.Vendor = GetVendorById(GetDeviceVendorId(address))

			devices[logicalNames[address]] = dev
		}
	}
	return devices
}

func removeSeparators(in string) string {
        // remove separators (":", "-", " ", "_")
        out := strings.Map(func(r rune) rune {
                if strings.IndexRune(":-_ ", r) < 0 {
                        return r
                }
                return -1
        }, in)

	return(out)
}

func GetKeyCodeByName(name string) int {
	name = removeSeparators(name)
	name = strings.ToLower(name)

	for code, value := range keyList {
		if strings.ToLower(value) == name {
			return code
		}
	}

	return -1
}

func GetLogicalAddressByName(name string) int {
	name = removeSeparators(name)
	l := len(name)

	if name[l-1] == '1' {
		name = name[:l-1]
	}

	name = strings.ToLower(name)

	for i:=0; i<16; i++ {
		if strings.ToLower(logicalNames[i]) == name {
			return i
		}
	}

	if name == "unregistered" {
		return 15
	}

	return -1
}

func GetLogicalNameByAddress(addr int) string {
	return logicalNames[addr]
}

func GetVendorById(id uint64) string {
	return vendorList[id]
}
<|endoftext|>


<commit_before>package cfg

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
)

func StringSlice(str string, split ...string) []string {
	sp := ","
	if len(split) > 0 {
		sp = split[0]
	}
	out := strings.Split(str, sp)
	for k, v := range out {
		out[k] = strings.TrimSpace(v)
	}
	return out
}

func IntSlice(str string, split ...string) ([]int, error) {
	var err error
	sp := ","
	if len(split) > 0 {
		sp = split[0]
	}
	temp := strings.Split(str, sp)
	out := make([]int, len(temp))
	for k, v := range temp {
		v = strings.TrimSpace(v)
		out[k], err = strconv.Atoi(v)
		if err != nil {
			break
		}
	}

	return out, err
}

func ParseFile(path string) (map[string]string, error) {
	var buffer bytes.Buffer
	if _, err := os.Stat(path); err != nil {
		return nil, err
	}
	fl, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer fl.Close()
	_, err = io.Copy(&buffer, fl)
	if err != nil {
		return nil, err
	}
	m, err := parse(&buffer)
	if err != nil {
		return nil, errors.New(path + " :: " + err.Error())
	}
	return m, nil
}

func ParseString(val string) (map[string]string, error) {
	var buffer bytes.Buffer
	_, err := buffer.WriteString(val)
	if err != nil {
		return nil, err
	}
	return parse(&buffer)
}

func parse(buf *bytes.Buffer) (map[string]string, error) {
	b2 := new(bytes.Buffer)
	convnl(buf, b2)
	buf = b2
	buf.WriteRune('\n')
	insideVar := false
	var varName bytes.Buffer
	var varVal bytes.Buffer
	b := bufio.NewReader(buf)
	lc := 0
	mp := make(map[string]string, 0)
	for {
		l, e := b.ReadString('\n')
		if e != nil {
			break
		} else {
			a := []rune(l)
			if a[0] == '#' && !insideVar {
				continue
			}
			for i := 0; i < len(a); i++ {
				if !insideVar {
					switch a[i] {
					case '=':
						if varName.Len() < 1 {
							return nil, errors.New("Syntax error at line " + strconv.Itoa(lc) + " (" + strconv.Itoa(i) + "): " + l)
						}
						insideVar = true
					case '\\', '\'', '"', '#', '^', '&':
						return nil, errors.New("Syntax error at line " + strconv.Itoa(lc) + " (" + strconv.Itoa(i) + "): " + l)
					default:
						varName.WriteRune(a[i])
					}
				} else {
					if i == len(a)-1 {
						// last char is always a \n
						insideVar = false
						if i > 0 {
							if a[i-1] == '\\' {
								varVal.WriteRune('\n')
								insideVar = true
							}
						}
						continue
					}
					//TODO: parse "\" better
					if a[i] == '\\' {
						if i > 0 {
							if a[i-1] == '\\' {
								varVal.WriteRune(a[i])
							}
						}
					} else {
						varVal.WriteRune(a[i])
					}
				}
			}
			lc++
			if !insideVar {
				v00 := varName.String()
				v01 := varVal.String()
				//fmt.Println("v00", v00, "v01", v01)
				mp[strings.TrimSpace(v00)] = strings.Trim(v01, " ")
				varName.Truncate(0)
				varVal.Truncate(0)
			}
		}

	}
	return mp, nil
}

func convnl(input io.Reader, output io.Writer) {
	r := bufio.NewReader(input)
	w := bufio.NewWriter(output)
	var prev rune
	for {
		cur, _, err := r.ReadRune()
		fmt.Print(string(cur))
		if err != nil {
			if prev == '\r' {
				w.WriteRune(prev)
			}
			break
		}
		if cur == '\r' {
			if prev == '\r' {
				w.WriteRune(prev)
			}
			prev = cur
			continue
		}
		if cur != '\n' && prev == '\r' {
			w.WriteRune(prev)
		}
		prev = cur
		w.WriteRune(cur)
	}
	w.Flush()
}
<commit_msg>removed println<commit_after>package cfg

import (
	"bufio"
	"bytes"
	"errors"
	"io"
	"os"
	"strconv"
	"strings"
)

func StringSlice(str string, split ...string) []string {
	sp := ","
	if len(split) > 0 {
		sp = split[0]
	}
	out := strings.Split(str, sp)
	for k, v := range out {
		out[k] = strings.TrimSpace(v)
	}
	return out
}

func IntSlice(str string, split ...string) ([]int, error) {
	var err error
	sp := ","
	if len(split) > 0 {
		sp = split[0]
	}
	temp := strings.Split(str, sp)
	out := make([]int, len(temp))
	for k, v := range temp {
		v = strings.TrimSpace(v)
		out[k], err = strconv.Atoi(v)
		if err != nil {
			break
		}
	}

	return out, err
}

func ParseFile(path string) (map[string]string, error) {
	var buffer bytes.Buffer
	if _, err := os.Stat(path); err != nil {
		return nil, err
	}
	fl, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer fl.Close()
	_, err = io.Copy(&buffer, fl)
	if err != nil {
		return nil, err
	}
	m, err := parse(&buffer)
	if err != nil {
		return nil, errors.New(path + " :: " + err.Error())
	}
	return m, nil
}

func ParseString(val string) (map[string]string, error) {
	var buffer bytes.Buffer
	_, err := buffer.WriteString(val)
	if err != nil {
		return nil, err
	}
	return parse(&buffer)
}

func parse(buf *bytes.Buffer) (map[string]string, error) {
	b2 := new(bytes.Buffer)
	convnl(buf, b2)
	buf = b2
	buf.WriteRune('\n')
	insideVar := false
	var varName bytes.Buffer
	var varVal bytes.Buffer
	b := bufio.NewReader(buf)
	lc := 0
	mp := make(map[string]string, 0)
	for {
		l, e := b.ReadString('\n')
		if e != nil {
			break
		} else {
			a := []rune(l)
			if a[0] == '#' && !insideVar {
				continue
			}
			for i := 0; i < len(a); i++ {
				if !insideVar {
					switch a[i] {
					case '=':
						if varName.Len() < 1 {
							return nil, errors.New("Syntax error at line " + strconv.Itoa(lc) + " (" + strconv.Itoa(i) + "): " + l)
						}
						insideVar = true
					case '\\', '\'', '"', '#', '^', '&':
						return nil, errors.New("Syntax error at line " + strconv.Itoa(lc) + " (" + strconv.Itoa(i) + "): " + l)
					default:
						varName.WriteRune(a[i])
					}
				} else {
					if i == len(a)-1 {
						// last char is always a \n
						insideVar = false
						if i > 0 {
							if a[i-1] == '\\' {
								varVal.WriteRune('\n')
								insideVar = true
							}
						}
						continue
					}
					//TODO: parse "\" better
					if a[i] == '\\' {
						if i > 0 {
							if a[i-1] == '\\' {
								varVal.WriteRune(a[i])
							}
						}
					} else {
						varVal.WriteRune(a[i])
					}
				}
			}
			lc++
			if !insideVar {
				v00 := varName.String()
				v01 := varVal.String()
				//fmt.Println("v00", v00, "v01", v01)
				mp[strings.TrimSpace(v00)] = strings.Trim(v01, " ")
				varName.Truncate(0)
				varVal.Truncate(0)
			}
		}

	}
	return mp, nil
}

func convnl(input io.Reader, output io.Writer) {
	r := bufio.NewReader(input)
	w := bufio.NewWriter(output)
	var prev rune
	for {
		cur, _, err := r.ReadRune()
		if err != nil {
			if prev == '\r' {
				w.WriteRune(prev)
			}
			break
		}
		if cur == '\r' {
			if prev == '\r' {
				w.WriteRune(prev)
			}
			prev = cur
			continue
		}
		if cur != '\n' && prev == '\r' {
			w.WriteRune(prev)
		}
		prev = cur
		w.WriteRune(cur)
	}
	w.Flush()
}
<|endoftext|>


<commit_before>// Photobomb conducts workflow tests triggered by requests to its web server.
package main

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

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/dysolution/espsdk"
	"github.com/dysolution/sleepwalker"
)

func main() {
	app := cli.NewApp()
	app.Name = NAME
	app.Version = VERSION
	app.Usage = "test workflows for the Getty Images ESP API"
	app.Author = "Jordan Peterson"
	app.Email = "dysolution@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "enable debug output",
		},
		cli.StringFlag{
			Name:   "key, k",
			Usage:  "your ESP API key",
			EnvVar: "ESP_API_KEY",
		},
		cli.StringFlag{
			Name:   "secret",
			Usage:  "your ESP API secret",
			EnvVar: "ESP_API_SECRET",
		},
		cli.StringFlag{
			Name:   "username, u",
			Usage:  "your ESP username",
			EnvVar: "ESP_USERNAME",
		},
		cli.StringFlag{
			Name:   "password, p",
			Usage:  "your ESP password",
			EnvVar: "ESP_PASSWORD",
		},
		cli.StringFlag{
			Name:   "token, t",
			Usage:  "use an existing OAuth2 token",
			EnvVar: "ESP_TOKEN",
		},
		cli.StringFlag{
			Name:   "s3-bucket, b",
			Value:  "oregon",
			Usage:  "nearest S3 bucket = [germany|ireland|oregon|singapore|tokyo|virginia]",
			EnvVar: "S3_BUCKET",
		},
		cli.StringFlag{
			Name:   "format, f",
			Value:  "json",
			Usage:  "[json|ascii]",
			EnvVar: "PHOTOBOMB_OUTPUT_FORMAT",
		},
		cli.DurationFlag{
			Name:        "warning-threshold, w",
			Value:       time.Duration(200 * time.Millisecond),
			Usage:       "output WARN log messages for response times above this, e.g., 200ms",
			EnvVar:      "PHOTOBOMB_WARNING_THRESHOLD",
			Destination: &warningThreshold,
		},
		cli.StringFlag{
			Name:   "config, c",
			Value:  "config.json",
			Usage:  "file containing configuration (try running \"example\")",
			EnvVar: "PHOTOBOMB_CONFIG",
		},
	}
	app.Before = func(c *cli.Context) error {
		client = sleepwalker.GetClient(
			c.String("key"),
			c.String("secret"),
			c.String("username"),
			c.String("password"),
			espsdk.OAuthEndpoint,
			espsdk.ESPAPIRoot,
			log,
		)
		log.Debugf("client, created from environment: %v", client)

		if c.Bool("debug") == true {
			log.Level = logrus.DebugLevel
		} else {
			log.Level = logrus.InfoLevel
		}

		token = sleepwalker.Token(c.String("token"))

		if strings.ToLower(c.String("format")) == "json" {
			log.Formatter = &logrus.JSONFormatter{}
		}

		config = loadConfig(c.String("config"))
		configJSON, err := json.Marshal(config)
		tableFlip(err)
		log.Debugf("configuration: %s", configJSON)

		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:  "config",
			Usage: "print a JSON representation of the config",
			Action: func(c *cli.Context) {
				out, err := json.MarshalIndent(config, "", "    ")
				tableFlip(err)
				fmt.Printf("%s\n", out)
			},
		},
		{
			Name:  "example",
			Usage: "print an example JSON configuration",
			Action: func(c *cli.Context) {
				out, err := json.MarshalIndent(ExampleConfig(), "", "    ")
				tableFlip(err)
				fmt.Printf("%s\n", out)
			},
		},
	}
	app.Action = func(c *cli.Context) { httpd() }

	app.Run(os.Args)
}
<commit_msg>feat: allow specifying attack interval on CLI<commit_after>// Photobomb conducts workflow tests triggered by requests to its web server.
package main

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

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/dysolution/espsdk"
	"github.com/dysolution/sleepwalker"
)

func main() {
	app := cli.NewApp()
	app.Name = NAME
	app.Version = VERSION
	app.Usage = "test workflows for the Getty Images ESP API"
	app.Author = "Jordan Peterson"
	app.Email = "dysolution@gmail.com"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "debug, D",
			Usage: "enable debug output",
		},
		cli.StringFlag{
			Name:   "key, k",
			Usage:  "your ESP API key",
			EnvVar: "ESP_API_KEY",
		},
		cli.StringFlag{
			Name:   "secret",
			Usage:  "your ESP API secret",
			EnvVar: "ESP_API_SECRET",
		},
		cli.StringFlag{
			Name:   "username, u",
			Usage:  "your ESP username",
			EnvVar: "ESP_USERNAME",
		},
		cli.StringFlag{
			Name:   "password, p",
			Usage:  "your ESP password",
			EnvVar: "ESP_PASSWORD",
		},
		cli.StringFlag{
			Name:   "token, t",
			Usage:  "use an existing OAuth2 token",
			EnvVar: "ESP_TOKEN",
		},
		cli.StringFlag{
			Name:   "s3-bucket, b",
			Value:  "oregon",
			Usage:  "nearest S3 bucket = [germany|ireland|oregon|singapore|tokyo|virginia]",
			EnvVar: "S3_BUCKET",
		},
		cli.StringFlag{
			Name:   "format, f",
			Value:  "json",
			Usage:  "[json|ascii]",
			EnvVar: "PHOTOBOMB_OUTPUT_FORMAT",
		},
		cli.DurationFlag{
			Name:   "attack-interval, i",
			Value:  time.Duration(5 * time.Second),
			Usage:  "wait this long between attacks, (minimum 1s)",
			EnvVar: "PHOTOBOMB_ATTACK_INTERVAL",
		},
		cli.DurationFlag{
			Name:        "warning-threshold, w",
			Value:       time.Duration(200 * time.Millisecond),
			Usage:       "output WARN log messages for response times above this, e.g., 200ms",
			EnvVar:      "PHOTOBOMB_WARNING_THRESHOLD",
			Destination: &warningThreshold,
		},
		cli.StringFlag{
			Name:   "config, c",
			Value:  "config.json",
			Usage:  "file containing configuration (try running \"example\")",
			EnvVar: "PHOTOBOMB_CONFIG",
		},
	}
	app.Before = func(c *cli.Context) error {
		client = sleepwalker.GetClient(
			c.String("key"),
			c.String("secret"),
			c.String("username"),
			c.String("password"),
			espsdk.OAuthEndpoint,
			espsdk.ESPAPIRoot,
			log,
		)
		log.Debugf("client, created from environment: %v", client)

		if c.Bool("debug") == true {
			log.Level = logrus.DebugLevel
		} else {
			log.Level = logrus.InfoLevel
		}

		token = sleepwalker.Token(c.String("token"))

		if strings.ToLower(c.String("format")) == "json" {
			log.Formatter = &logrus.JSONFormatter{}
		}

		cliInterval := int(c.Duration("attack-interval") / time.Duration(1*time.Second))
		if cliInterval != 0 {
			interval = cliInterval
		}

		config = loadConfig(c.String("config"))
		configJSON, err := json.Marshal(config)
		tableFlip(err)
		log.Debugf("configuration: %s", configJSON)

		return nil
	}
	app.Commands = []cli.Command{
		{
			Name:  "config",
			Usage: "print a JSON representation of the config",
			Action: func(c *cli.Context) {
				out, err := json.MarshalIndent(config, "", "    ")
				tableFlip(err)
				fmt.Printf("%s\n", out)
			},
		},
		{
			Name:  "example",
			Usage: "print an example JSON configuration",
			Action: func(c *cli.Context) {
				out, err := json.MarshalIndent(ExampleConfig(), "", "    ")
				tableFlip(err)
				fmt.Printf("%s\n", out)
			},
		},
	}
	app.Action = func(c *cli.Context) { httpd() }

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

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

	pubsub "google.golang.org/api/pubsub/v1"

	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "blocks-gcs-proxy"
	app.Usage = "github.com/groovenauts/blocks-gcs-proxy"
	app.Version = VERSION

	configFlag := cli.StringFlag{
		Name:  "config, c",
		Usage: "Load configuration from `FILE`",
	}
	app.Flags = []cli.Flag{
		configFlag,
	}

	app.Commands = []cli.Command{
		{
			Name:  "check",
			Usage: "Check config file is valid",
			Action: func(c *cli.Context) error {
				LoadAndSetupProcessConfig(c)
				fmt.Println("OK")
				return nil
			},
			Flags: []cli.Flag{
				configFlag,
			},
		},
		{
			Name:  "download",
			Usage: "Download the files from GCS to downloads directory",
			Action: func(c *cli.Context) error {
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				config.Command.Downloaders = c.Int("downloaders")
				config.Job.Sustainer = &JobSustainerConfig{
					Disabled: true,
				}
				p := setupProcess(config)
				p.setup()
				files := []interface{}{}
				for _, arg := range c.Args() {
					files = append(files, arg)
				}
				job := &Job{
					config:              config.Command,
					downloads_dir:       c.String("downloads_dir"),
					remoteDownloadFiles: files,
					storage:             p.storage,
				}
				err := job.setupDownloadFiles()
				if err != nil {
					return err
				}
				err = job.downloadFiles()
				return err
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "downloads_dir, d",
					Usage: "Path to the directory which has bucket_name/path/to/file",
				},
				cli.IntFlag{
					Name:  "downloaders, n",
					Usage: "Number of downloaders",
					Value: 6,
				},
			},
		},
		{
			Name:  "upload",
			Usage: "Upload the files under uploads directory",
			Action: func(c *cli.Context) error {
				fmt.Printf("Uploading files\n")
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				config.Command.Uploaders = c.Int("uploaders")
				config.Job.Sustainer = &JobSustainerConfig{
					Disabled: true,
				}
				p := setupProcess(config)
				p.setup()
				job := &Job{
					config:      config.Command,
					uploads_dir: c.String("uploads_dir"),
					storage:     p.storage,
				}
				fmt.Printf("Uploading files under %v\n", job.uploads_dir)
				err := job.uploadFiles()
				return err
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "uploads_dir, d",
					Usage: "Path to the directory which has bucket_name/path/to/file",
				},
				cli.IntFlag{
					Name:  "uploaders, n",
					Usage: "Number of uploaders",
					Value: 6,
				},
			},
		},

		{
			Name:  "exec",
			Usage: "Execute job without download nor upload",
			Action: func(c *cli.Context) error {
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				msg_file := c.String("message")
				workspace := c.String("workspace")

				type Msg struct {
					Attributes map[string]string `json:"attributes"`
					Data       string            `json:"data"`
				}
				var msg Msg

				data, err := ioutil.ReadFile(msg_file)
				if err != nil {
					fmt.Printf("Error to read file %v because of %v\n", msg_file, err)
					os.Exit(1)
				}

				err = json.Unmarshal(data, &msg)
				if err != nil {
					fmt.Printf("Error to parse json file %v because of %v\n", msg_file, err)
					os.Exit(1)
				}

				job := &Job{
					workspace: workspace,
					config:    config.Command,
					message: &JobMessage{
						raw: &pubsub.ReceivedMessage{
							AckId: "DummyAckId",
							Message: &pubsub.PubsubMessage{
								Attributes:  msg.Attributes,
								Data:        msg.Data,
								MessageId:   "DummyMessageId",
								PublishTime: time.Now().Format(time.RFC3339),
							},
						},
					},
				}
				fmt.Printf("Executing job %v\n", job.workspace)
				err = job.uploadFiles()
				return err
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "message, m",
					Usage: "Path to the message json file which has attributes and data",
				},
				cli.StringFlag{
					Name:  "workspace, w",
					Usage: "Path to workspace directory which has downloads and uploads",
				},
			},
		},
	}

	app.Action = run

	app.Run(os.Args)
}

func run(c *cli.Context) error {
	config := LoadAndSetupProcessConfig(c)
	p := setupProcess(config)

	err := p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func setupProcess(config *ProcessConfig) *Process {
	p := &Process{config: config}
	err := p.setup()
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}
	return p
}

func LoadAndSetupProcessConfig(c *cli.Context) *ProcessConfig {
	path := configPath(c)
	config, err := LoadProcessConfig(path)
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", path, err)
		os.Exit(1)
	}
	err = config.setup(os.Args[1:])
	if err != nil {
		fmt.Printf("Error to setup %v cause of %v\n", path, err)
		os.Exit(1)
	}
	return config
}

func configPath(c *cli.Context) string {
	r := c.String("config")
	if r == "" {
		r = "./config.json"
	}
	return r
}
<commit_msg>:+1: Add Options to execute job locally<commit_after>package main

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

	pubsub "google.golang.org/api/pubsub/v1"

	"github.com/urfave/cli"
)

func main() {
	app := cli.NewApp()
	app.Name = "blocks-gcs-proxy"
	app.Usage = "github.com/groovenauts/blocks-gcs-proxy"
	app.Version = VERSION

	configFlag := cli.StringFlag{
		Name:  "config, c",
		Usage: "Load configuration from `FILE`",
	}
	app.Flags = []cli.Flag{
		configFlag,
	}

	app.Commands = []cli.Command{
		{
			Name:  "check",
			Usage: "Check config file is valid",
			Action: func(c *cli.Context) error {
				LoadAndSetupProcessConfig(c)
				fmt.Println("OK")
				return nil
			},
			Flags: []cli.Flag{
				configFlag,
			},
		},
		{
			Name:  "download",
			Usage: "Download the files from GCS to downloads directory",
			Action: func(c *cli.Context) error {
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				config.Command.Downloaders = c.Int("downloaders")
				config.Job.Sustainer = &JobSustainerConfig{
					Disabled: true,
				}
				p := setupProcess(config)
				p.setup()
				files := []interface{}{}
				for _, arg := range c.Args() {
					files = append(files, arg)
				}
				job := &Job{
					config:              config.Command,
					downloads_dir:       c.String("downloads_dir"),
					remoteDownloadFiles: files,
					storage:             p.storage,
				}
				err := job.setupDownloadFiles()
				if err != nil {
					return err
				}
				err = job.downloadFiles()
				return err
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "downloads_dir, d",
					Usage: "Path to the directory which has bucket_name/path/to/file",
				},
				cli.IntFlag{
					Name:  "downloaders, n",
					Usage: "Number of downloaders",
					Value: 6,
				},
			},
		},
		{
			Name:  "upload",
			Usage: "Upload the files under uploads directory",
			Action: func(c *cli.Context) error {
				fmt.Printf("Uploading files\n")
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				config.Command.Uploaders = c.Int("uploaders")
				config.Job.Sustainer = &JobSustainerConfig{
					Disabled: true,
				}
				p := setupProcess(config)
				p.setup()
				job := &Job{
					config:      config.Command,
					uploads_dir: c.String("uploads_dir"),
					storage:     p.storage,
				}
				fmt.Printf("Uploading files under %v\n", job.uploads_dir)
				err := job.uploadFiles()
				return err
			},
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "uploads_dir, d",
					Usage: "Path to the directory which has bucket_name/path/to/file",
				},
				cli.IntFlag{
					Name:  "uploaders, n",
					Usage: "Number of uploaders",
					Value: 6,
				},
			},
		},

		{
			Name:  "exec",
			Usage: "Execute job without download nor upload",
			Action: func(c *cli.Context) error {
				config := &ProcessConfig{}
				config.Log = &LogConfig{Level: "debug"}
				config.setup([]string{})
				msg_file := c.String("message")
				workspace := c.String("workspace")

				type Msg struct {
					Attributes  map[string]string `json:"attributes"`
					Data        string            `json:"data"`
					MessageId   string            `json:"messageId"`
					PublishTime string            `json:"publishTime"`
					AckId       string            `json:"ackId"`
				}
				var msg Msg

				data, err := ioutil.ReadFile(msg_file)
				if err != nil {
					fmt.Printf("Error to read file %v because of %v\n", msg_file, err)
					os.Exit(1)
				}

				err = json.Unmarshal(data, &msg)
				if err != nil {
					fmt.Printf("Error to parse json file %v because of %v\n", msg_file, err)
					os.Exit(1)
				}

				job := &Job{
					workspace: workspace,
					config:    config.Command,
					message: &JobMessage{
						raw: &pubsub.ReceivedMessage{
							AckId: msg.AckId,
							Message: &pubsub.PubsubMessage{
								Attributes: msg.Attributes,
								Data:       msg.Data,
								MessageId:  msg.MessageId,
								// PublishTime: time.Now().Format(time.RFC3339),
								PublishTime: msg.PublishTime,
							},
						},
					},
				}
				fmt.Printf("Executing job %v\n", job.workspace)
				err = job.uploadFiles()
				return err
			},
			Flags: []cli.Flag{
				configFlag,
				cli.StringFlag{
					Name:  "message, m",
					Usage: "Path to the message json file which has attributes and data",
				},
				cli.StringFlag{
					Name:  "workspace, w",
					Usage: "Path to workspace directory which has downloads and uploads",
				},
			},
		},
	}

	app.Action = run

	app.Run(os.Args)
}

func run(c *cli.Context) error {
	config := LoadAndSetupProcessConfig(c)
	p := setupProcess(config)

	err := p.run()
	if err != nil {
		fmt.Printf("Error to run cause of %v\n", err)
		os.Exit(1)
	}
	return nil
}

func setupProcess(config *ProcessConfig) *Process {
	p := &Process{config: config}
	err := p.setup()
	if err != nil {
		fmt.Printf("Error to setup Process cause of %v\n", err)
		os.Exit(1)
	}
	return p
}

func LoadAndSetupProcessConfig(c *cli.Context) *ProcessConfig {
	path := configPath(c)
	config, err := LoadProcessConfig(path)
	if err != nil {
		fmt.Printf("Error to load %v cause of %v\n", path, err)
		os.Exit(1)
	}
	err = config.setup(os.Args[1:])
	if err != nil {
		fmt.Printf("Error to setup %v cause of %v\n", path, err)
		os.Exit(1)
	}
	return config
}

func configPath(c *cli.Context) string {
	r := c.String("config")
	if r == "" {
		r = "./config.json"
	}
	return r
}
<|endoftext|>


<commit_before>// cli.go
//
// Everything related to command-line flag handling
//
// Copyright 2015 © by Ollivier Robert for the EEC
//

// Command-line Interface for fa-export
package main

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

var (
	// cli
	fVerbose       bool
	fOutput        string
	fEventType     string
	fFeedType      string
	fTimeout       int64
	fsTimeout      string
	fAutoRotate    bool
	fFeedBegin     string
	fFeedEnd       string
	fOverwrite     bool
	fUserName      string
	fDest          string
	fAirlineFilter string
	fIdentFilter   string
	fLatLongFilter string
	fAirportFilter string
	fHexid         string
	fPProf         bool
)

// my usage string
const (
	cliUsage = `
%s version %s
Usage: %s [-o FILE] [-d N(s|mn|h|d)][-f live|pitr|range [-B date [-E date]] [-v] [-u user]

       Filters (OR is implied if multiple):
          [-e type] [-F airline] [-I plane-ident] [-L lat/lon] [-P airport-glob]
       Output filter (not on theFA command line)
          [-X hexid]
`
)

// Redefine Usage
var Usage = func() {
	fmt.Fprintf(os.Stderr, cliUsage, os.Args[0], FA_VERSION, os.Args[0])
	flag.PrintDefaults()
}

// called by flag.Parse()
func init() {
	// cli
	flag.StringVar(&fsTimeout, "d", "", "Stop after N s/mn/h/days")
	flag.StringVar(&fEventType, "e", "", "Events to stream")
	flag.StringVar(&fFeedType, "f", "live", "Specify which feed we want")
	flag.StringVar(&fOutput, "o", "", "Specify output FILE.")
	flag.BoolVar(&fOverwrite, "O", false, "Overwrite existing file?")
	flag.BoolVar(&fPProf, "p", false, "Enable profiling")
	flag.StringVar(&fUserName, "u", "", "Username to connect with")
	flag.BoolVar(&fVerbose, "v", false, "Set verbose flag.")
	flag.BoolVar(&fAutoRotate, "A", false, "Autorotate output file")
	flag.StringVar(&fFeedBegin, "B", "", "Begin time for -f pitr|range")
	flag.StringVar(&fDest, "D", "", "Default destination (NOT IMPL)")
	flag.StringVar(&fFeedEnd, "E", "", "End time for -f range")
	flag.StringVar(&fAirlineFilter, "F", "", "Airline filter")
	flag.StringVar(&fIdentFilter, "I", "", "Aircraft Ident filter")
	flag.StringVar(&fLatLongFilter, "L", "", "Lat/Long filter")
	flag.StringVar(&fAirportFilter, "P", "", "Airport filter")
	flag.StringVar(&fHexid, "X", "", "Hexid output filter")
}
<commit_msg>Reformat the usage string.<commit_after>// cli.go
//
// Everything related to command-line flag handling
//
// Copyright 2015 © by Ollivier Robert for the EEC
//

// Command-line Interface for fa-export
package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
)

var (
	// cli
	fVerbose       bool
	fOutput        string
	fEventType     string
	fFeedType      string
	fTimeout       int64
	fsTimeout      string
	fAutoRotate    bool
	fFeedBegin     string
	fFeedEnd       string
	fOverwrite     bool
	fUserName      string
	fDest          string
	fAirlineFilter string
	fIdentFilter   string
	fLatLongFilter string
	fAirportFilter string
	fHexid         string
	fPProf         bool
)

// my usage string
const (
	cliUsage = `%s version %s

Usage: %s [-o FILE] [-d N(s|mn|h|d)][-f live|pitr|range [-B date [-E date]] [-v] [-u user]

       Filters (OR is implied if multiple):
          [-e type] [-F airline] [-I plane-ident] [-L lat/lon] [-P airport-glob]
       Output filter (not on theFA command line)
          [-X hexid]
`
)

// Redefine Usage
var Usage = func() {
	myName := filepath.Base(os.Args[0])
	fmt.Fprintf(os.Stderr, cliUsage, myName, FA_VERSION, myName)
	flag.PrintDefaults()
}

// called by flag.Parse()
func init() {
	// cli
	flag.StringVar(&fsTimeout, "d", "", "Stop after N s/mn/h/days")
	flag.StringVar(&fEventType, "e", "", "Events to stream")
	flag.StringVar(&fFeedType, "f", "live", "Specify which feed we want")
	flag.StringVar(&fOutput, "o", "", "Specify output FILE.")
	flag.BoolVar(&fOverwrite, "O", false, "Overwrite existing file?")
	flag.BoolVar(&fPProf, "p", false, "Enable profiling")
	flag.StringVar(&fUserName, "u", "", "Username to connect with")
	flag.BoolVar(&fVerbose, "v", false, "Set verbose flag.")
	flag.BoolVar(&fAutoRotate, "A", false, "Autorotate output file")
	flag.StringVar(&fFeedBegin, "B", "", "Begin time for -f pitr|range")
	flag.StringVar(&fDest, "D", "", "Default destination (NOT IMPL)")
	flag.StringVar(&fFeedEnd, "E", "", "End time for -f range")
	flag.StringVar(&fAirlineFilter, "F", "", "Airline filter")
	flag.StringVar(&fIdentFilter, "I", "", "Aircraft Ident filter")
	flag.StringVar(&fLatLongFilter, "L", "", "Lat/Long filter")
	flag.StringVar(&fAirportFilter, "P", "", "Airport filter")
	flag.StringVar(&fHexid, "X", "", "Hexid output filter")
}
<|endoftext|>


<commit_before>/*
Package supervisor provides supervisor trees for Go applications.

This package is a clean reimplementation of github.com/thejerf/suture, aiming
to be more Go idiomatic, thus less Erlang-like.

It is built on top of context package, with all of its advantages, namely the
possibility trickle down context-related values and cancellation signals.

TheJerf's blog post about Suture is a very good and helpful read to understand
how this package has been implemented.

http://www.jerf.org/iri/post/2930
*/
package supervisor // import "cirello.io/supervisor"

import (
	"fmt"
	"log"
	"math"
	"sync"
	"time"

	"golang.org/x/net/context"
)

// Service is the public interface expected by a Supervisor.
//
// This will be internally named after the result of fmt.Stringer, if available.
// Otherwise it will going to use an internal representation for the service
// name.
type Service interface {
	// Serve is called by a Supervisor to start the service. It expects the
	// service to honor the passed context and its lifetime. Observe
	// <-ctx.Done() and ctx.Err(). If the service is stopped by anything
	// but the Supervisor, it will get started again. Be careful with shared
	// state among restarts.
	Serve(ctx context.Context)
}

// Supervisor is the basic datastructure responsible for offering a supervisor
// tree. It implements Service, therefore it can be nested if necessary. When
// passing the Supervisor around, remind to do it as reference (&supervisor).
type Supervisor struct {
	// Name for this supervisor tree, used for logging.
	Name string

	// FailureDecay is the timespan on which the current failure count will
	// be halved.
	FailureDecay float64

	// FailureThreshold is the maximum accepted number of failures, after
	// decay adjustment, that shall trigger the back-off wait.
	FailureThreshold float64

	// Backoff is the wait duration when hit threshold.
	Backoff time.Duration

	// Log is a replaceable function used for overall logging
	Log func(interface{})

	ready sync.Once

	addedService    chan struct{}
	startedServices chan struct{}

	runningServices sync.WaitGroup

	servicesMu sync.Mutex
	services   map[string]Service

	cancelationsMu sync.Mutex
	cancelations   map[string]context.CancelFunc

	backoffMu sync.Mutex
	backoff   map[string]*backoff

	runningMu sync.Mutex
}

func (s *Supervisor) String() string {
	return s.Name
}

func (s *Supervisor) prepare() {
	s.ready.Do(func() {
		if s.Name == "" {
			s.Name = "supervisor"
		}
		s.addedService = make(chan struct{}, 1)
		s.backoff = make(map[string]*backoff)
		s.cancelations = make(map[string]context.CancelFunc)
		s.services = make(map[string]Service)
		s.startedServices = make(chan struct{}, 1)

		if s.Log == nil {
			s.Log = func(msg interface{}) {
				log.Printf("%s: %v", s.Name, msg)
			}
		}
		if s.FailureDecay == 0 {
			s.FailureDecay = 30
		}
		if s.FailureThreshold == 0 {
			s.FailureThreshold = 5
		}
		if s.Backoff == 0 {
			s.Backoff = 15 * time.Second
		}
	})
}

// Add inserts into the Supervisor tree a new service. If the Supervisor is
// already started, it will start it automatically.
func (s *Supervisor) Add(service Service) {
	s.prepare()

	name := fmt.Sprintf("%s", service)

	s.servicesMu.Lock()
	s.backoffMu.Lock()
	s.backoff[name] = &backoff{}
	s.services[name] = service
	s.backoffMu.Unlock()
	s.servicesMu.Unlock()

	select {
	case s.addedService <- struct{}{}:
	default:
	}
}

// Remove stops the service in the Supervisor tree and remove from it.
func (s *Supervisor) Remove(name string) {
	s.prepare()

	s.servicesMu.Lock()
	defer s.servicesMu.Unlock()
	if _, ok := s.services[name]; !ok {
		return
	}

	s.cancelationsMu.Lock()
	defer s.cancelationsMu.Unlock()
	if c, ok := s.cancelations[name]; ok {
		delete(s.cancelations, name)
		c()
	}
}

// Serve starts the Supervisor tree. It can be started only once at a time. If
// stopped (canceled), it can be restarted. In case of concurrent calls, it will
// hang until the current call is completed.
func (s *Supervisor) Serve(ctx context.Context) {
	s.prepare()

	s.runningMu.Lock()
	s.serve(ctx)
	s.runningMu.Unlock()
}

// Services return a list of services
func (s *Supervisor) Services() map[string]Service {
	svclist := make(map[string]Service)
	s.servicesMu.Lock()
	for k, v := range s.services {
		svclist[k] = v
	}
	s.servicesMu.Unlock()
	return svclist
}

// Cancelations return a list of services names and their cancellation calls
func (s *Supervisor) Cancelations() map[string]context.CancelFunc {
	svclist := make(map[string]context.CancelFunc)
	s.cancelationsMu.Lock()
	for k, v := range s.cancelations {
		svclist[k] = v
	}
	s.cancelationsMu.Unlock()
	return svclist
}

func (s *Supervisor) startServices(ctx context.Context) {
	s.startAllServices(ctx)
	select {
	case s.startedServices <- struct{}{}:
	default:
	}
}

func (s *Supervisor) serve(ctx context.Context) {
	select {
	case <-s.addedService:
	default:
	}
	s.startServices(ctx)

	go func(ctx context.Context) {
		for {
			select {
			case <-s.addedService:
				s.startServices(ctx)

			case <-ctx.Done():
				return
			}
		}
	}(ctx)
	<-ctx.Done()

	s.runningServices.Wait()

	s.cancelationsMu.Lock()
	s.cancelations = make(map[string]context.CancelFunc)
	s.cancelationsMu.Unlock()
	return
}

func (s *Supervisor) startAllServices(ctx context.Context) {
	s.servicesMu.Lock()
	defer s.servicesMu.Unlock()
	s.cancelationsMu.Lock()
	defer s.cancelationsMu.Unlock()

	var wg sync.WaitGroup
	for name, svc := range s.services {
		if _, ok := s.cancelations[name]; ok {
			continue
		}

		intermediateCtx, cancel := context.WithCancel(ctx)
		s.cancelations[name] = cancel

		wg.Add(1)
		go func(name string, svc Service) {
			s.runningServices.Add(1)
			wg.Done()
			for {
				retry := func() (retry bool) {
					defer func() {
						if r := recover(); r != nil {
							s.Log(fmt.Sprintf("trapped panic: %v", r))
							retry = true
						}
					}()

					c, cancel := context.WithCancel(intermediateCtx)
					s.cancelationsMu.Lock()
					s.cancelations[name] = cancel
					s.cancelationsMu.Unlock()
					svc.Serve(c)

					select {
					case <-ctx.Done():
						return false
					default:
						return true
					}
				}()
				if retry {
					s.Log(fmt.Sprintf("restarting %s", name))
					s.backoffMu.Lock()
					b := s.backoff[name]
					s.backoffMu.Unlock()
					b.wait(s.FailureDecay, s.FailureThreshold, s.Backoff, func(msg interface{}) {
						s.Log(fmt.Sprintf("backoff %s: %v", name, msg))
					})
					continue
				}
				break
			}
			s.runningServices.Done()
		}(name, svc)
	}

	wg.Wait()
}

type backoff struct {
	lastfail time.Time
	failures float64
}

func (b *backoff) wait(failureDecay float64, threshold float64, backoffDur time.Duration, log func(str interface{})) {
	if b.lastfail.IsZero() {
		b.lastfail = time.Now()
		b.failures = 1.0
		return
	}

	b.failures++
	intervals := time.Since(b.lastfail).Seconds() / failureDecay
	b.failures = b.failures*math.Pow(.5, intervals) + 1

	if b.failures > threshold {
		log(backoffDur)
		time.Sleep(backoffDur)
	}
}
<commit_msg>Add comment to reveal the intention of the intermediate context<commit_after>/*
Package supervisor provides supervisor trees for Go applications.

This package is a clean reimplementation of github.com/thejerf/suture, aiming
to be more Go idiomatic, thus less Erlang-like.

It is built on top of context package, with all of its advantages, namely the
possibility trickle down context-related values and cancellation signals.

TheJerf's blog post about Suture is a very good and helpful read to understand
how this package has been implemented.

http://www.jerf.org/iri/post/2930
*/
package supervisor // import "cirello.io/supervisor"

import (
	"fmt"
	"log"
	"math"
	"sync"
	"time"

	"golang.org/x/net/context"
)

// Service is the public interface expected by a Supervisor.
//
// This will be internally named after the result of fmt.Stringer, if available.
// Otherwise it will going to use an internal representation for the service
// name.
type Service interface {
	// Serve is called by a Supervisor to start the service. It expects the
	// service to honor the passed context and its lifetime. Observe
	// <-ctx.Done() and ctx.Err(). If the service is stopped by anything
	// but the Supervisor, it will get started again. Be careful with shared
	// state among restarts.
	Serve(ctx context.Context)
}

// Supervisor is the basic datastructure responsible for offering a supervisor
// tree. It implements Service, therefore it can be nested if necessary. When
// passing the Supervisor around, remind to do it as reference (&supervisor).
type Supervisor struct {
	// Name for this supervisor tree, used for logging.
	Name string

	// FailureDecay is the timespan on which the current failure count will
	// be halved.
	FailureDecay float64

	// FailureThreshold is the maximum accepted number of failures, after
	// decay adjustment, that shall trigger the back-off wait.
	FailureThreshold float64

	// Backoff is the wait duration when hit threshold.
	Backoff time.Duration

	// Log is a replaceable function used for overall logging
	Log func(interface{})

	ready sync.Once

	addedService    chan struct{}
	startedServices chan struct{}

	runningServices sync.WaitGroup

	servicesMu sync.Mutex
	services   map[string]Service

	cancelationsMu sync.Mutex
	cancelations   map[string]context.CancelFunc

	backoffMu sync.Mutex
	backoff   map[string]*backoff

	runningMu sync.Mutex
}

func (s *Supervisor) String() string {
	return s.Name
}

func (s *Supervisor) prepare() {
	s.ready.Do(func() {
		if s.Name == "" {
			s.Name = "supervisor"
		}
		s.addedService = make(chan struct{}, 1)
		s.backoff = make(map[string]*backoff)
		s.cancelations = make(map[string]context.CancelFunc)
		s.services = make(map[string]Service)
		s.startedServices = make(chan struct{}, 1)

		if s.Log == nil {
			s.Log = func(msg interface{}) {
				log.Printf("%s: %v", s.Name, msg)
			}
		}
		if s.FailureDecay == 0 {
			s.FailureDecay = 30
		}
		if s.FailureThreshold == 0 {
			s.FailureThreshold = 5
		}
		if s.Backoff == 0 {
			s.Backoff = 15 * time.Second
		}
	})
}

// Add inserts into the Supervisor tree a new service. If the Supervisor is
// already started, it will start it automatically.
func (s *Supervisor) Add(service Service) {
	s.prepare()

	name := fmt.Sprintf("%s", service)

	s.servicesMu.Lock()
	s.backoffMu.Lock()
	s.backoff[name] = &backoff{}
	s.services[name] = service
	s.backoffMu.Unlock()
	s.servicesMu.Unlock()

	select {
	case s.addedService <- struct{}{}:
	default:
	}
}

// Remove stops the service in the Supervisor tree and remove from it.
func (s *Supervisor) Remove(name string) {
	s.prepare()

	s.servicesMu.Lock()
	defer s.servicesMu.Unlock()
	if _, ok := s.services[name]; !ok {
		return
	}

	s.cancelationsMu.Lock()
	defer s.cancelationsMu.Unlock()
	if c, ok := s.cancelations[name]; ok {
		delete(s.cancelations, name)
		c()
	}
}

// Serve starts the Supervisor tree. It can be started only once at a time. If
// stopped (canceled), it can be restarted. In case of concurrent calls, it will
// hang until the current call is completed.
func (s *Supervisor) Serve(ctx context.Context) {
	s.prepare()

	s.runningMu.Lock()
	s.serve(ctx)
	s.runningMu.Unlock()
}

// Services return a list of services
func (s *Supervisor) Services() map[string]Service {
	svclist := make(map[string]Service)
	s.servicesMu.Lock()
	for k, v := range s.services {
		svclist[k] = v
	}
	s.servicesMu.Unlock()
	return svclist
}

// Cancelations return a list of services names and their cancellation calls
func (s *Supervisor) Cancelations() map[string]context.CancelFunc {
	svclist := make(map[string]context.CancelFunc)
	s.cancelationsMu.Lock()
	for k, v := range s.cancelations {
		svclist[k] = v
	}
	s.cancelationsMu.Unlock()
	return svclist
}

func (s *Supervisor) startServices(ctx context.Context) {
	s.startAllServices(ctx)
	select {
	case s.startedServices <- struct{}{}:
	default:
	}
}

func (s *Supervisor) serve(ctx context.Context) {
	select {
	case <-s.addedService:
	default:
	}
	s.startServices(ctx)

	go func(ctx context.Context) {
		for {
			select {
			case <-s.addedService:
				s.startServices(ctx)

			case <-ctx.Done():
				return
			}
		}
	}(ctx)
	<-ctx.Done()

	s.runningServices.Wait()

	s.cancelationsMu.Lock()
	s.cancelations = make(map[string]context.CancelFunc)
	s.cancelationsMu.Unlock()
	return
}

func (s *Supervisor) startAllServices(ctx context.Context) {
	s.servicesMu.Lock()
	defer s.servicesMu.Unlock()
	s.cancelationsMu.Lock()
	defer s.cancelationsMu.Unlock()

	var wg sync.WaitGroup
	for name, svc := range s.services {
		if _, ok := s.cancelations[name]; ok {
			continue
		}

		// In the edge case that a service has been added, immediately
		// removed, but the service itself hasn't been started. This
		// intermediate context shall prevent a nil pointer in
		// Supervisor.Remove(), but also stops all the subsequent
		// service restarts. It might deserve a more elegant solution.
		intermediateCtx, cancel := context.WithCancel(ctx)
		s.cancelations[name] = cancel

		wg.Add(1)
		go func(name string, svc Service) {
			s.runningServices.Add(1)
			wg.Done()
			for {
				retry := func() (retry bool) {
					defer func() {
						if r := recover(); r != nil {
							s.Log(fmt.Sprintf("trapped panic: %v", r))
							retry = true
						}
					}()

					c, cancel := context.WithCancel(intermediateCtx)
					s.cancelationsMu.Lock()
					s.cancelations[name] = cancel
					s.cancelationsMu.Unlock()
					svc.Serve(c)

					select {
					case <-ctx.Done():
						return false
					default:
						return true
					}
				}()
				if retry {
					s.Log(fmt.Sprintf("restarting %s", name))
					s.backoffMu.Lock()
					b := s.backoff[name]
					s.backoffMu.Unlock()
					b.wait(s.FailureDecay, s.FailureThreshold, s.Backoff, func(msg interface{}) {
						s.Log(fmt.Sprintf("backoff %s: %v", name, msg))
					})
					continue
				}
				break
			}
			s.runningServices.Done()
		}(name, svc)
	}

	wg.Wait()
}

type backoff struct {
	lastfail time.Time
	failures float64
}

func (b *backoff) wait(failureDecay float64, threshold float64, backoffDur time.Duration, log func(str interface{})) {
	if b.lastfail.IsZero() {
		b.lastfail = time.Now()
		b.failures = 1.0
		return
	}

	b.failures++
	intervals := time.Since(b.lastfail).Seconds() / failureDecay
	b.failures = b.failures*math.Pow(.5, intervals) + 1

	if b.failures > threshold {
		log(backoffDur)
		time.Sleep(backoffDur)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Jonathan Picques. All rights reserved.
// Use of this source code is governed by a MIT license
// The license can be found in the LICENSE file.

// The GoCSV package aims to provide easy CSV serialization and deserialization to the golang programming language

package gocsv

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"
)

// FailIfUnmatchedStructTags indicates whether it is considered an error when there is an unmatched
// struct tag.
var FailIfUnmatchedStructTags = false

// FailIfDoubleHeaderNames indicates whether it is considered an error when a header name is repeated
// in the csv header.
var FailIfDoubleHeaderNames = false

// ShouldAlignDuplicateHeadersWithStructFieldOrder indicates whether we should align duplicate CSV
// headers per their alignment in the struct definition.
var ShouldAlignDuplicateHeadersWithStructFieldOrder = false

// TagSeparator defines seperator string for multiple csv tags in struct fields
var TagSeparator = ","

// --------------------------------------------------------------------------
// CSVWriter used to format CSV

var selfCSVWriter = DefaultCSVWriter

// DefaultCSVWriter is the default CSV writer used to format CSV (cf. csv.NewWriter)
func DefaultCSVWriter(out io.Writer) *csv.Writer {
	writer := csv.NewWriter(out)

	// As only one rune can be defined as a CSV separator, we are going to trim
	// the custom tag separator and use the first rune.
	if runes := []rune(strings.TrimSpace(TagSeparator)); len(runes) > 0 {
		writer.Comma = runes[0]
	}

	return writer
}

// SetCSVWriter sets the CSV writer used to format CSV.
func SetCSVWriter(csvWriter func(io.Writer) *csv.Writer) {
	selfCSVWriter = csvWriter
}

func getCSVWriter(out io.Writer) *csv.Writer {
	return selfCSVWriter(out)
}

// --------------------------------------------------------------------------
// CSVReader used to parse CSV

var selfCSVReader = DefaultCSVReader

// DefaultCSVReader is the default CSV reader used to parse CSV (cf. csv.NewReader)
func DefaultCSVReader(in io.Reader) *csv.Reader {
	return csv.NewReader(in)
}

// LazyCSVReader returns a lazy CSV reader, with LazyQuotes and TrimLeadingSpace.
func LazyCSVReader(in io.Reader) *csv.Reader {
	csvReader := csv.NewReader(in)
	csvReader.LazyQuotes = true
	csvReader.TrimLeadingSpace = true
	return csvReader
}

// SetCSVReader sets the CSV reader used to parse CSV.
func SetCSVReader(csvReader func(io.Reader) *csv.Reader) {
	selfCSVReader = csvReader
}

func getCSVReader(in io.Reader) *csv.Reader {
	return selfCSVReader(in)
}

// --------------------------------------------------------------------------
// Marshal functions

// MarshalFile saves the interface as CSV in the file.
func MarshalFile(in interface{}, file *os.File) (err error) {
	return Marshal(in, file)
}

// MarshalString returns the CSV string from the interface.
func MarshalString(in interface{}) (out string, err error) {
	bufferString := bytes.NewBufferString(out)
	if err := Marshal(in, bufferString); err != nil {
		return "", err
	}
	return bufferString.String(), nil
}

// MarshalBytes returns the CSV bytes from the interface.
func MarshalBytes(in interface{}) (out []byte, err error) {
	bufferString := bytes.NewBuffer(out)
	if err := Marshal(in, bufferString); err != nil {
		return nil, err
	}
	return bufferString.Bytes(), nil
}

// Marshal returns the CSV in writer from the interface.
func Marshal(in interface{}, out io.Writer) (err error) {
	writer := getCSVWriter(out)
	return writeTo(writer, in, false)
}

// Marshal returns the CSV in writer from the interface.
func MarshalWithoutHeaders(in interface{}, out io.Writer) (err error) {
	writer := getCSVWriter(out)
	return writeTo(writer, in, true)
}

// MarshalChan returns the CSV read from the channel.
func MarshalChan(c <-chan interface{}, out *csv.Writer) error {
	return writeFromChan(out, c)
}

// MarshalCSV returns the CSV in writer from the interface.
func MarshalCSV(in interface{}, out *csv.Writer) (err error) {
	return writeTo(out, in, false)
}

// --------------------------------------------------------------------------
// Unmarshal functions

// UnmarshalFile parses the CSV from the file in the interface.
func UnmarshalFile(in *os.File, out interface{}) (err error) {
	return Unmarshal(in, out)
}

// UnmarshalString parses the CSV from the string in the interface.
func UnmarshalString(in string, out interface{}) (err error) {
	return Unmarshal(strings.NewReader(in), out)
}

// UnmarshalBytes parses the CSV from the bytes in the interface.
func UnmarshalBytes(in []byte, out interface{}) (err error) {
	return Unmarshal(bytes.NewReader(in), out)
}

// Unmarshal parses the CSV from the reader in the interface.
func Unmarshal(in io.Reader, out interface{}) (err error) {
	return readTo(newDecoder(in), out)
}

// UnmarshalCSV parses the CSV from the reader in the interface.
func UnmarshalCSV(in CSVReader, out interface{}) error {
	return readTo(csvDecoder{in}, out)
}

// UnmarshalToChan parses the CSV from the reader and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalToChan(in io.Reader, c interface{}) error {
	fmt.Println("HELLO")
	if c == nil {
		return fmt.Errorf("goscv: channel is %v", c)
	}
	return readEach(newDecoder(in), c)
}

// UnmarshalStringToChan parses the CSV from the string and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalStringToChan(in string, c interface{}) error {
	return UnmarshalToChan(strings.NewReader(in), c)
}

// UnmarshalBytesToChan parses the CSV from the bytes and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalBytesToChan(in []byte, c interface{}) error {
	return UnmarshalToChan(bytes.NewReader(in), c)
}

// UnmarshalToCallback parses the CSV from the reader and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalToCallback(in io.Reader, f interface{}) (err error) {
	valueFunc := reflect.ValueOf(f)
	t := reflect.TypeOf(f)
	if t.NumIn() != 1 {
		return fmt.Errorf("the given function must have exactly one parameter")
	}
	c := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, t.In(0)), 0)
	go func() {
		err = UnmarshalToChan(in, c.Interface())
	}()
	for {
		if err != nil {
			return err
		}
		v, notClosed := c.Recv()
		if !notClosed || v.Interface() == nil {
			break
		}
		valueFunc.Call([]reflect.Value{v})
	}
	return
}

// UnmarshalBytesToCallback parses the CSV from the bytes and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalBytesToCallback(in []byte, f interface{}) (err error) {
	return UnmarshalToCallback(bytes.NewReader(in), f)
}

// UnmarshalStringToCallback parses the CSV from the string and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalStringToCallback(in string, c interface{}) (err error) {
	return UnmarshalToCallback(strings.NewReader(in), c)
}
<commit_msg>Removed debug.<commit_after>// Copyright 2014 Jonathan Picques. All rights reserved.
// Use of this source code is governed by a MIT license
// The license can be found in the LICENSE file.

// The GoCSV package aims to provide easy CSV serialization and deserialization to the golang programming language

package gocsv

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"reflect"
	"strings"
)

// FailIfUnmatchedStructTags indicates whether it is considered an error when there is an unmatched
// struct tag.
var FailIfUnmatchedStructTags = false

// FailIfDoubleHeaderNames indicates whether it is considered an error when a header name is repeated
// in the csv header.
var FailIfDoubleHeaderNames = false

// ShouldAlignDuplicateHeadersWithStructFieldOrder indicates whether we should align duplicate CSV
// headers per their alignment in the struct definition.
var ShouldAlignDuplicateHeadersWithStructFieldOrder = false

// TagSeparator defines seperator string for multiple csv tags in struct fields
var TagSeparator = ","

// --------------------------------------------------------------------------
// CSVWriter used to format CSV

var selfCSVWriter = DefaultCSVWriter

// DefaultCSVWriter is the default CSV writer used to format CSV (cf. csv.NewWriter)
func DefaultCSVWriter(out io.Writer) *csv.Writer {
	writer := csv.NewWriter(out)

	// As only one rune can be defined as a CSV separator, we are going to trim
	// the custom tag separator and use the first rune.
	if runes := []rune(strings.TrimSpace(TagSeparator)); len(runes) > 0 {
		writer.Comma = runes[0]
	}

	return writer
}

// SetCSVWriter sets the CSV writer used to format CSV.
func SetCSVWriter(csvWriter func(io.Writer) *csv.Writer) {
	selfCSVWriter = csvWriter
}

func getCSVWriter(out io.Writer) *csv.Writer {
	return selfCSVWriter(out)
}

// --------------------------------------------------------------------------
// CSVReader used to parse CSV

var selfCSVReader = DefaultCSVReader

// DefaultCSVReader is the default CSV reader used to parse CSV (cf. csv.NewReader)
func DefaultCSVReader(in io.Reader) *csv.Reader {
	return csv.NewReader(in)
}

// LazyCSVReader returns a lazy CSV reader, with LazyQuotes and TrimLeadingSpace.
func LazyCSVReader(in io.Reader) *csv.Reader {
	csvReader := csv.NewReader(in)
	csvReader.LazyQuotes = true
	csvReader.TrimLeadingSpace = true
	return csvReader
}

// SetCSVReader sets the CSV reader used to parse CSV.
func SetCSVReader(csvReader func(io.Reader) *csv.Reader) {
	selfCSVReader = csvReader
}

func getCSVReader(in io.Reader) *csv.Reader {
	return selfCSVReader(in)
}

// --------------------------------------------------------------------------
// Marshal functions

// MarshalFile saves the interface as CSV in the file.
func MarshalFile(in interface{}, file *os.File) (err error) {
	return Marshal(in, file)
}

// MarshalString returns the CSV string from the interface.
func MarshalString(in interface{}) (out string, err error) {
	bufferString := bytes.NewBufferString(out)
	if err := Marshal(in, bufferString); err != nil {
		return "", err
	}
	return bufferString.String(), nil
}

// MarshalBytes returns the CSV bytes from the interface.
func MarshalBytes(in interface{}) (out []byte, err error) {
	bufferString := bytes.NewBuffer(out)
	if err := Marshal(in, bufferString); err != nil {
		return nil, err
	}
	return bufferString.Bytes(), nil
}

// Marshal returns the CSV in writer from the interface.
func Marshal(in interface{}, out io.Writer) (err error) {
	writer := getCSVWriter(out)
	return writeTo(writer, in, false)
}

// Marshal returns the CSV in writer from the interface.
func MarshalWithoutHeaders(in interface{}, out io.Writer) (err error) {
	writer := getCSVWriter(out)
	return writeTo(writer, in, true)
}

// MarshalChan returns the CSV read from the channel.
func MarshalChan(c <-chan interface{}, out *csv.Writer) error {
	return writeFromChan(out, c)
}

// MarshalCSV returns the CSV in writer from the interface.
func MarshalCSV(in interface{}, out *csv.Writer) (err error) {
	return writeTo(out, in, false)
}

// --------------------------------------------------------------------------
// Unmarshal functions

// UnmarshalFile parses the CSV from the file in the interface.
func UnmarshalFile(in *os.File, out interface{}) (err error) {
	return Unmarshal(in, out)
}

// UnmarshalString parses the CSV from the string in the interface.
func UnmarshalString(in string, out interface{}) (err error) {
	return Unmarshal(strings.NewReader(in), out)
}

// UnmarshalBytes parses the CSV from the bytes in the interface.
func UnmarshalBytes(in []byte, out interface{}) (err error) {
	return Unmarshal(bytes.NewReader(in), out)
}

// Unmarshal parses the CSV from the reader in the interface.
func Unmarshal(in io.Reader, out interface{}) (err error) {
	return readTo(newDecoder(in), out)
}

// UnmarshalCSV parses the CSV from the reader in the interface.
func UnmarshalCSV(in CSVReader, out interface{}) error {
	return readTo(csvDecoder{in}, out)
}

// UnmarshalToChan parses the CSV from the reader and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalToChan(in io.Reader, c interface{}) error {
	if c == nil {
		return fmt.Errorf("goscv: channel is %v", c)
	}
	return readEach(newDecoder(in), c)
}

// UnmarshalStringToChan parses the CSV from the string and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalStringToChan(in string, c interface{}) error {
	return UnmarshalToChan(strings.NewReader(in), c)
}

// UnmarshalBytesToChan parses the CSV from the bytes and send each value in the chan c.
// The channel must have a concrete type.
func UnmarshalBytesToChan(in []byte, c interface{}) error {
	return UnmarshalToChan(bytes.NewReader(in), c)
}

// UnmarshalToCallback parses the CSV from the reader and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalToCallback(in io.Reader, f interface{}) (err error) {
	valueFunc := reflect.ValueOf(f)
	t := reflect.TypeOf(f)
	if t.NumIn() != 1 {
		return fmt.Errorf("the given function must have exactly one parameter")
	}
	c := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, t.In(0)), 0)
	go func() {
		err = UnmarshalToChan(in, c.Interface())
	}()
	for {
		if err != nil {
			return err
		}
		v, notClosed := c.Recv()
		if !notClosed || v.Interface() == nil {
			break
		}
		valueFunc.Call([]reflect.Value{v})
	}
	return
}

// UnmarshalBytesToCallback parses the CSV from the bytes and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalBytesToCallback(in []byte, f interface{}) (err error) {
	return UnmarshalToCallback(bytes.NewReader(in), f)
}

// UnmarshalStringToCallback parses the CSV from the string and send each value to the given func f.
// The func must look like func(Struct).
func UnmarshalStringToCallback(in string, c interface{}) (err error) {
	return UnmarshalToCallback(strings.NewReader(in), c)
}
<|endoftext|>


<commit_before>package aspect

import (
	"fmt"
	"runtime"
	"strings"
	"testing"
)

// Declare schemas that can be used package-wide
var users = Table("users",
	Column("id", Integer{NotNull: true}),
	Column("name", String{Length: 32, NotNull: true}),
	Column("password", String{Length: 128}),
	PrimaryKey("id"),
)

type user struct {
	Id       int64  `db:"id"`
	Name     string `db:"name"`
	Password string `db:"password"`
}

var views = Table("views",
	Column("id", Integer{PrimaryKey: true}),
	Column("user_id", Integer{}),
	Column("url", String{}),
	Column("ip", String{}),
	Column("timestamp", Timestamp{}),
)

var edges = Table("edges",
	Column("a", Integer{}),
	Column("b", Integer{}),
	PrimaryKey("a", "b"),
)

var attrs = Table("attrs",
	Column("id", Integer{PrimaryKey: true}),
	Column("a", Integer{}),
	Column("b", Integer{}),
	Unique("a", "b"),
)

type edge struct {
	A int64 `db:"a"`
	B int64 `db:"b"`
}

// CallerInfo returns a string containing the file and line number of the
// assert call that failed.
// https://github.com/stretchr/testify/blob/master/assert/assertions.go
// Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
func CallerInfo() string {
	file := ""
	line := 0
	ok := false

	for i := 2; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		parts := strings.Split(file, "/")
		file = parts[len(parts)-1]

		// TODO Separate this file so break can be called on file name
		// dir := parts[len(parts)-2]
		// if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
		// 	break
		// }

		break
	}

	return fmt.Sprintf("%s:%d", file, line)
}

// A short test for testing that an SQL statement was compiled as expected
func expectedSQL(t *testing.T, stmt Compiles, expected string, p int) {
	// Get caller information in case of failure
	caller := CallerInfo()

	// Call both Compile and String
	params := Params()
	str := stmt.String()
	compiled, err := stmt.Compile(&defaultDialect{}, params)
	if err != nil {
		t.Error("%s: unexpected error from compile: %s", caller, err)
	}
	if compiled != expected {
		t.Errorf("%s: unexpected SQL: %s != %s", caller, compiled, expected)
	}
	if compiled != str {
		t.Errorf(
			"%s: compile %s should match the default string output %s",
			caller,
			compiled,
			str,
		)
	}
	if params.Len() != p {
		t.Errorf(
			"%s: unexpected number of parameters for %s: %d != %d",
			caller,
			expected,
			params.Len(),
			p,
		)
	}
}

func TestTableSchema(t *testing.T) {
	// Test table properties
	if users.Name != "users" {
		t.Errorf("unexpected Table name: '%s' != 'users'", users.Name)
	}
	if users.String() != "users" {
		t.Errorf("unexpected Table String output: %s != users", users.String())
	}

	// Test the accessor methods
	userId := users.C["id"]
	if userId.name != "id" {
		t.Errorf("Name of returned column was not 'id': '%s'", userId.name)
	}

	// A pointer to the column's table should have been added
	if userId.table != users {
		t.Errorf("Unexpected Table: %+v", userId.table)
	}

	// And primary key(s) should exist
	pk := users.PrimaryKey()
	if len(pk) != 1 && pk[0] != "id" {
		t.Errorf("unexpected primary key")
	}

	// Test improper schemas
	{
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when duplicate columns were created")
			}
		}()

		// A table can't have two columns with the same name
		Table("bad",
			Column("a", String{}),
			Column("a", String{}),
		)
	}

	{
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a column without a name was created")
			}
		}()

		// A column must have a name
		Table("bad",
			Column("", String{}),
		)
	}

	// Can't have primary keys without columns of the same name
	{
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a primary key without a corresponding column was created")
			}
		}()
		Table("bad",
			Column("okay", String{}),
			PrimaryKey("not"),
		)
	}

	// Can't have unique constraints without columns of the same name
	{
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a unique constraint without a corresponding column was created")
			}
		}()
		Table("bad",
			Column("okay", String{}),
			Unique("not"),
		)
	}
}

// Test the sql.SelectStmts generated by table.Select() and Select()
func TestTableSelect(t *testing.T) {
	// All three of these select statements should produce the same output
	x := `SELECT "users"."id", "users"."name", "users"."password" FROM "users"`
	expectedSQL(t, users.Select(), x, 0)
	expectedSQL(t, Select(users), x, 0)
	expectedSQL(
		t,
		Select(users.C["id"], users.C["name"], users.C["password"]),
		x,
		0,
	)

	// Select a column that doesn't exist
	stmt := Select(users.C["joined"])
	output, err := stmt.Compile(&defaultDialect{}, Params())
	if err != ErrNilSelect {
		t.Errorf("Improper SELECT should have generated an error")
	}
	if output != "" {
		t.Errorf("Unexpected output from an improper SELECT: %s", output)
	}
}

func TestTableSelectExcept(t *testing.T) {
	x := `SELECT "users"."id", "users"."name" FROM "users"`
	expectedSQL(t, users.SelectExcept(users.C["password"]), x, 0)
	expectedSQL(t, SelectExcept(users, users.C["password"]), x, 0)
}

// Test the InsertStmt generated by table.Insert()
func TestTableInsert(t *testing.T) {
	// An example user
	admin := user{1, "admin", "secret"}

	// Insert a single value into the table
	stmt := users.Insert(&admin)
	expectedSQL(
		t,
		stmt,
		`INSERT INTO "users" ("id", "name", "password") VALUES ($1, $2, $3)`,
		3,
	)
}

// Test DeleteStmt generated by table.Delete()
func TestTableDelete(t *testing.T) {
	// Delete the entire table
	expectedSQL(t, users.Delete(), `DELETE FROM "users"`, 0)

	// Delete using a conditional
	expectedSQL(
		t,
		users.Delete().Where(users.C["id"].Equals(1)),
		`DELETE FROM "users" WHERE "users"."id" = $1`,
		1,
	)
}

// Test UpdateStmt generated by table.Update()
func TestTableUpdate(t *testing.T) {
	expectedSQL(
		t,
		users.Update(Values{"name": "Jabroni"}),
		`UPDATE "users" SET "name" = $1`,
		1,
	)
}
<commit_msg>Testing coverage does not recognize scoped recovers unless they are in a function<commit_after>package aspect

import (
	"fmt"
	"runtime"
	"strings"
	"testing"
)

// Declare schemas that can be used package-wide
var users = Table("users",
	Column("id", Integer{NotNull: true}),
	Column("name", String{Length: 32, NotNull: true}),
	Column("password", String{Length: 128}),
	PrimaryKey("id"),
)

type user struct {
	Id       int64  `db:"id"`
	Name     string `db:"name"`
	Password string `db:"password"`
}

var views = Table("views",
	Column("id", Integer{PrimaryKey: true}),
	Column("user_id", Integer{}),
	Column("url", String{}),
	Column("ip", String{}),
	Column("timestamp", Timestamp{}),
)

var edges = Table("edges",
	Column("a", Integer{}),
	Column("b", Integer{}),
	PrimaryKey("a", "b"),
)

var attrs = Table("attrs",
	Column("id", Integer{PrimaryKey: true}),
	Column("a", Integer{}),
	Column("b", Integer{}),
	Unique("a", "b"),
)

type edge struct {
	A int64 `db:"a"`
	B int64 `db:"b"`
}

// CallerInfo returns a string containing the file and line number of the
// assert call that failed.
// https://github.com/stretchr/testify/blob/master/assert/assertions.go
// Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
func CallerInfo() string {
	file := ""
	line := 0
	ok := false

	for i := 2; ; i++ {
		_, file, line, ok = runtime.Caller(i)
		if !ok {
			return ""
		}
		parts := strings.Split(file, "/")
		file = parts[len(parts)-1]

		// TODO Separate this file so break can be called on file name
		// dir := parts[len(parts)-2]
		// if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" {
		// 	break
		// }

		break
	}

	return fmt.Sprintf("%s:%d", file, line)
}

// A short test for testing that an SQL statement was compiled as expected
func expectedSQL(t *testing.T, stmt Compiles, expected string, p int) {
	// Get caller information in case of failure
	caller := CallerInfo()

	// Call both Compile and String
	params := Params()
	str := stmt.String()
	compiled, err := stmt.Compile(&defaultDialect{}, params)
	if err != nil {
		t.Error("%s: unexpected error from compile: %s", caller, err)
	}
	if compiled != expected {
		t.Errorf("%s: unexpected SQL: %s != %s", caller, compiled, expected)
	}
	if compiled != str {
		t.Errorf(
			"%s: compile %s should match the default string output %s",
			caller,
			compiled,
			str,
		)
	}
	if params.Len() != p {
		t.Errorf(
			"%s: unexpected number of parameters for %s: %d != %d",
			caller,
			expected,
			params.Len(),
			p,
		)
	}
}

func TestTableSchema(t *testing.T) {
	// Test table properties
	if users.Name != "users" {
		t.Errorf("unexpected Table name: '%s' != 'users'", users.Name)
	}
	if users.String() != "users" {
		t.Errorf("unexpected Table String output: %s != users", users.String())
	}

	// Test the accessor methods
	userId := users.C["id"]
	if userId.name != "id" {
		t.Errorf("Name of returned column was not 'id': '%s'", userId.name)
	}

	// A pointer to the column's table should have been added
	if userId.table != users {
		t.Errorf("Unexpected Table: %+v", userId.table)
	}

	// And primary key(s) should exist
	pk := users.PrimaryKey()
	if len(pk) != 1 && pk[0] != "id" {
		t.Errorf("unexpected primary key")
	}

	// Test improper schemas
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when duplicate columns were created")
			}
		}()

		// A table can't have two columns with the same name
		Table("bad",
			Column("a", String{}),
			Column("a", String{}),
		)
	}()

	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a column without a name was created")
			}
		}()

		// A column must have a name
		Table("bad",
			Column("", String{}),
		)
	}()

	// Can't have primary keys without columns of the same name
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a primary key without a corresponding column was created")
			}
		}()
		Table("bad",
			Column("okay", String{}),
			PrimaryKey("not"),
		)
	}()

	// Can't have unique constraints without columns of the same name
	func() {
		defer func() {
			if panicked := recover(); panicked == nil {
				t.Errorf("table failed to panic when a unique constraint without a corresponding column was created")
			}
		}()
		Table("bad",
			Column("okay", String{}),
			Unique("not"),
		)
	}()
}

// Test the sql.SelectStmts generated by table.Select() and Select()
func TestTableSelect(t *testing.T) {
	// All three of these select statements should produce the same output
	x := `SELECT "users"."id", "users"."name", "users"."password" FROM "users"`
	expectedSQL(t, users.Select(), x, 0)
	expectedSQL(t, Select(users), x, 0)
	expectedSQL(
		t,
		Select(users.C["id"], users.C["name"], users.C["password"]),
		x,
		0,
	)

	// Select a column that doesn't exist
	stmt := Select(users.C["joined"])
	output, err := stmt.Compile(&defaultDialect{}, Params())
	if err != ErrNilSelect {
		t.Errorf("Improper SELECT should have generated an error")
	}
	if output != "" {
		t.Errorf("Unexpected output from an improper SELECT: %s", output)
	}
}

func TestTableSelectExcept(t *testing.T) {
	x := `SELECT "users"."id", "users"."name" FROM "users"`
	expectedSQL(t, users.SelectExcept(users.C["password"]), x, 0)
	expectedSQL(t, SelectExcept(users, users.C["password"]), x, 0)
}

// Test the InsertStmt generated by table.Insert()
func TestTableInsert(t *testing.T) {
	// An example user
	admin := user{1, "admin", "secret"}

	// Insert a single value into the table
	stmt := users.Insert(&admin)
	expectedSQL(
		t,
		stmt,
		`INSERT INTO "users" ("id", "name", "password") VALUES ($1, $2, $3)`,
		3,
	)
}

// Test DeleteStmt generated by table.Delete()
func TestTableDelete(t *testing.T) {
	// Delete the entire table
	expectedSQL(t, users.Delete(), `DELETE FROM "users"`, 0)

	// Delete using a conditional
	expectedSQL(
		t,
		users.Delete().Where(users.C["id"].Equals(1)),
		`DELETE FROM "users" WHERE "users"."id" = $1`,
		1,
	)
}

// Test UpdateStmt generated by table.Update()
func TestTableUpdate(t *testing.T) {
	expectedSQL(
		t,
		users.Update(Values{"name": "Jabroni"}),
		`UPDATE "users" SET "name" = $1`,
		1,
	)
}
<|endoftext|>


<commit_before>package qbit

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestTable(t *testing.T) {

	table := NewTable(
		"user",
		[]Column{
			NewColumn(
				"id",
				BigInt(),
				[]Constraint{
					PrimaryKey(),
				},
			),
			NewColumn(
				"email",
				VarChar(512),
				[]Constraint{
					Unique(),
					NotNull(),
				},
			),
			NewColumn(
				"bio",
				Text(),
				[]Constraint{
					NotNull(),
				},
			),
			NewColumn(
				"gender",
				Char(16),
				[]Constraint{
					Default("female"),
				},
			),
			NewColumn(
				"birth_date",
				Char(16),
				[]Constraint{
					NotNull(),
				},
			),
		},
		[]Constraint{},
	)

	q := fmt.Sprintf(`CREATE TABLE user(
	id BIGINT PRIMARY KEY,
	email VARCHAR(512) UNIQUE NOT NULL,
	bio TEXT NOT NULL,
	gender CHAR(16) DEFAULT %s,
	birth_date CHAR(16) NOT NULL
);`, "`female`")

	assert.Equal(t, table.Sql(), q)
}<commit_msg>remove PrimaryKey function in table test<commit_after>package qbit

import (
	"fmt"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestTable(t *testing.T) {

	table := NewTable(
		"user",
		[]Column{
			NewColumn(
				"id",
				BigInt(),
				[]Constraint{
//					PrimaryKey(),
				},
			),
			NewColumn(
				"email",
				VarChar(512),
				[]Constraint{
					Unique(),
					NotNull(),
				},
			),
			NewColumn(
				"bio",
				Text(),
				[]Constraint{
					NotNull(),
				},
			),
			NewColumn(
				"gender",
				Char(16),
				[]Constraint{
					Default("female"),
				},
			),
			NewColumn(
				"birth_date",
				Char(16),
				[]Constraint{
					NotNull(),
				},
			),
		},
		[]Constraint{},
	)

	q := fmt.Sprintf(`CREATE TABLE user(
	id BIGINT PRIMARY KEY,
	email VARCHAR(512) UNIQUE NOT NULL,
	bio TEXT NOT NULL,
	gender CHAR(16) DEFAULT %s,
	birth_date CHAR(16) NOT NULL
);`, "`female`")

	assert.Equal(t, table.Sql(), q)
}<|endoftext|>


<commit_before>package tei

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type Engine struct {
	ConfigFactory func(size int) ai.MinimaxConfig

	in  *bufio.Reader
	out io.Writer

	mm   *ai.MinimaxAI
	pos  *tak.Position
	size int
}

func NewEngine(in io.Reader, out io.Writer) *Engine {
	return &Engine{
		in:  bufio.NewReader(in),
		out: out,
	}
}

func (e *Engine) Run(ctx context.Context) error {
	for {
		line, err := e.in.ReadString('\n')
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		words := strings.Fields(line)
		switch words[0] {
		case "tei":
			fmt.Fprintln(e.out, "id name Taktician")
			fmt.Fprintln(e.out, "id author Nelson Elhage")
			fmt.Fprintln(e.out, "teiok")
		case "quit":
			break
		case "teinewgame":
			e.mm = nil
			e.pos = nil
			if len(words) > 1 {
				e.size, err = strconv.Atoi(words[1])
				if err != nil || e.size < 3 || e.size > 8 {
					return fmt.Errorf("Bad size: %s", words[1])
				}
			} else {
				e.size = 5
			}
			break
		case "position":
			e.pos, err = parsePosition(e.size, words)
			if err != nil {
				return fmt.Errorf("error parsing position: %w\n", err)
				break
			}
			break
		case "go":
			if err := e.analyze(ctx, words); err != nil {
				log.Printf("error in go: %v\n", err)
				break
			}
			break
		case "stop":
			break
		case "isready":
			fmt.Fprintln(e.out, "readyok")
		default:
			return fmt.Errorf("Unknown command: %q", line)
		}
	}
}

func parsePosition(size int, words []string) (*tak.Position, error) {
	var pos *tak.Position
	words = words[1:]
	if len(words) == 0 {
		return nil, errors.New("not enough arguments")
	}
	switch words[0] {
	case "startpos":
		words = words[1:]
		pos = tak.New(tak.Config{Size: size})
	case "tps":
		// tps A B C
		if len(words) < 4 {
			return nil, errors.New("position tps: not enough arguments")
		}
		var err error
		pos, err = ptn.ParseTPS(strings.Join(words[1:4], " "))
		if err != nil {
			return nil, fmt.Errorf("Parse TPS: %w", err)
		}
		words = words[4:]
		if pos.Size() != size {
			return nil, fmt.Errorf("tps has wrong size: got %d, configured for %d", pos.Size(), size)
		}
	default:
		return nil, fmt.Errorf("Unknown initial position: %q", words[0])
	}
	if len(words) == 0 {
		return pos, nil
	}
	if words[0] != "moves" {
		return nil, errors.New("position: expected `moves'")
	}
	words = words[1:]
	for _, w := range words {
		move, err := ptn.ParseMove(w)
		if err != nil {
			return nil, fmt.Errorf("Parse move %q: %w", w, err)
		}
		pos, err = pos.Move(move)
		if err != nil {
			return nil, fmt.Errorf("Move %q: %w", w, err)
		}
	}
	return pos, nil
}

func (e *Engine) analyze(ctx context.Context, words []string) error {
	if e.pos == nil {
		return errors.New("No position provided")
	}
	if e.mm == nil {
		var cfg ai.MinimaxConfig
		if e.ConfigFactory != nil {
			cfg = e.ConfigFactory(e.size)
		} else {
			cfg = ai.MinimaxConfig{
				Size: e.size,
			}
		}
		e.mm = ai.NewMinimax(cfg)
	}
	words = words[1:]
	if len(words) > 0 {
		if len(words) != 2 || words[0] != "movetime" {
			return fmt.Errorf("go: expected <movetime> N got: %q", words)
		}
		ms, err := strconv.ParseUint(words[1], 10, 64)
		if err != nil {
			return fmt.Errorf("bad ms: %v", words[1])
		}

		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, time.Duration(ms)*time.Millisecond)
		defer cancel()
	}

	pv, val, stats := e.mm.Analyze(ctx, e.pos)
	var pvs strings.Builder
	for _, m := range pv {
		pvs.WriteString(" ")
		pvs.WriteString(ptn.FormatMove(m))
	}
	fmt.Fprintf(e.out, "info depth %d time %d nodes %d score cp %d pv%s\n",
		stats.Depth,
		stats.Elapsed/time.Millisecond,
		stats.Visited,
		val,
		pvs.String(),
	)
	fmt.Fprintf(e.out, "bestmove %s\n", ptn.FormatMove(pv[0]))
	return nil
}
<commit_msg>Initial time control support for `taktician tei`<commit_after>package tei

import (
	"bufio"
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/nelhage/taktician/ai"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

type Engine struct {
	ConfigFactory func(size int) ai.MinimaxConfig

	in  *bufio.Reader
	out io.Writer

	mm   *ai.MinimaxAI
	pos  *tak.Position
	size int
}

func NewEngine(in io.Reader, out io.Writer) *Engine {
	return &Engine{
		in:  bufio.NewReader(in),
		out: out,
	}
}

func (e *Engine) Run(ctx context.Context) error {
	for {
		line, err := e.in.ReadString('\n')
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		words := strings.Fields(line)
		switch words[0] {
		case "tei":
			fmt.Fprintln(e.out, "id name Taktician")
			fmt.Fprintln(e.out, "id author Nelson Elhage")
			fmt.Fprintln(e.out, "teiok")
		case "quit":
			break
		case "teinewgame":
			e.mm = nil
			e.pos = nil
			if len(words) > 1 {
				e.size, err = strconv.Atoi(words[1])
				if err != nil || e.size < 3 || e.size > 8 {
					return fmt.Errorf("Bad size: %s", words[1])
				}
			} else {
				e.size = 5
			}
			break
		case "position":
			e.pos, err = parsePosition(e.size, words)
			if err != nil {
				return fmt.Errorf("error parsing position: %w\n", err)
			}
			break
		case "go":
			if err := e.analyze(ctx, words); err != nil {
				log.Printf("error in go: %v\n", err)
				break
			}
			break
		case "stop":
			break
		case "isready":
			fmt.Fprintln(e.out, "readyok")
		default:
			return fmt.Errorf("Unknown command: %q", line)
		}
	}
}

func parsePosition(size int, words []string) (*tak.Position, error) {
	var pos *tak.Position
	words = words[1:]
	if len(words) == 0 {
		return nil, errors.New("not enough arguments")
	}
	switch words[0] {
	case "startpos":
		words = words[1:]
		pos = tak.New(tak.Config{Size: size})
	case "tps":
		// tps A B C
		if len(words) < 4 {
			return nil, errors.New("position tps: not enough arguments")
		}
		var err error
		pos, err = ptn.ParseTPS(strings.Join(words[1:4], " "))
		if err != nil {
			return nil, fmt.Errorf("Parse TPS: %w", err)
		}
		words = words[4:]
		if pos.Size() != size {
			return nil, fmt.Errorf("tps has wrong size: got %d, configured for %d", pos.Size(), size)
		}
	default:
		return nil, fmt.Errorf("Unknown initial position: %q", words[0])
	}
	if len(words) == 0 {
		return pos, nil
	}
	if words[0] != "moves" {
		return nil, errors.New("position: expected `moves'")
	}
	words = words[1:]
	for _, w := range words {
		move, err := ptn.ParseMove(w)
		if err != nil {
			return nil, fmt.Errorf("Parse move %q: %w", w, err)
		}
		pos, err = pos.Move(move)
		if err != nil {
			return nil, fmt.Errorf("Move %q: %w", w, err)
		}
	}
	return pos, nil
}

func calcBudget(movetime time.Duration, gametime time.Duration, inc time.Duration) time.Duration {
	var budget time.Duration
	if gametime != 0 {
		budget = gametime/10 + inc
	}
	if movetime > 0 && (budget == 0 || movetime < budget) {
		budget = movetime
	}
	return budget
}

func (e *Engine) analyze(ctx context.Context, words []string) error {
	if e.pos == nil {
		return errors.New("No position provided")
	}
	if e.mm == nil {
		var cfg ai.MinimaxConfig
		if e.ConfigFactory != nil {
			cfg = e.ConfigFactory(e.size)
		} else {
			cfg = ai.MinimaxConfig{
				Size: e.size,
			}
		}
		e.mm = ai.NewMinimax(cfg)
	}
	words = words[1:]
	var movetime, wtime, winc, btime, binc time.Duration
	for len(words) > 0 {
		opt := words[0]
		if len(words) == 1 {
			return fmt.Errorf("go: %s: expected arg", opt)
		}
		arg := words[1]
		words = words[2:]
		var err error
		var ms uint64
		switch opt {
		case "movetime":
			ms, err = strconv.ParseUint(arg, 10, 64)
			movetime = time.Millisecond * time.Duration(ms)
		case "wtime":
			ms, err = strconv.ParseUint(arg, 10, 64)
			wtime = time.Millisecond * time.Duration(ms)
		case "btime":
			ms, err = strconv.ParseUint(arg, 10, 64)
			btime = time.Millisecond * time.Duration(ms)
		case "winc":
			ms, err = strconv.ParseUint(arg, 10, 64)
			winc = time.Millisecond * time.Duration(ms)
		case "binc":
			ms, err = strconv.ParseUint(arg, 10, 64)
			binc = time.Millisecond * time.Duration(ms)
		default:
			return fmt.Errorf("go: Unknown option: %s", opt)
		}
		if err != nil {
			return fmt.Errorf("go: %s: cannot parse value: %q", opt, arg)
		}
	}
	var tm, inc time.Duration
	if e.pos.ToMove() == tak.White {
		tm, inc = wtime, winc
	} else {
		tm, inc = btime, binc
	}

	if movetime > 0 || tm > 0 {
		budget := calcBudget(movetime, tm, inc)
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, budget)
		defer cancel()
	}

	pv, val, stats := e.mm.Analyze(ctx, e.pos)
	var pvs strings.Builder
	for _, m := range pv {
		pvs.WriteString(" ")
		pvs.WriteString(ptn.FormatMove(m))
	}
	fmt.Fprintf(e.out, "info depth %d time %d nodes %d score cp %d pv%s\n",
		stats.Depth,
		stats.Elapsed/time.Millisecond,
		stats.Visited,
		val,
		pvs.String(),
	)
	fmt.Fprintf(e.out, "bestmove %s\n", ptn.FormatMove(pv[0]))
	return nil
}
<|endoftext|>