<commit_before>package vptree

import (
	"container/heap"
	"math"
	"math/rand"
)

type node struct {
	Item      interface{}
	Threshold float64
	Left      *node
	Right     *node
}

type heapItem struct {
	Item interface{}
	Dist float64
}

type Metric func(a, b interface{}) float64

type VPTree struct {
	root           *node
	tau            float64
	distanceMetric Metric
}

func New(metric Metric, items []interface{}) (t *VPTree) {
	t = &VPTree{
		distanceMetric: metric,
	}
	t.root = t.buildFromPoints(items)
	return
}

func (vp *VPTree) Search(target interface{}, k int) (results []interface{}, distances []float64) {
	h := make(priorityQueue, 0, k)

	vp.tau = math.MaxFloat64
	vp.search(vp.root, target, k, &h)

	for h.Len() > 0 {
		hi := h.Pop()
		results = append(results, hi.(*heapItem).Item)
		distances = append(distances, hi.(*heapItem).Dist)
	}

	// Reverse results and distances, because we popped them from the heap
	// in large-to-small order
	for i, j := 0, len(results)-1; i < j; i, j = i+1, j-1 {
		results[i], results[j] = results[j], results[i]
		distances[i], distances[j] = distances[j], distances[i]
	}

	return
}

func (vp *VPTree) buildFromPoints(items []interface{}) (n *node) {
	if len(items) == 0 {
		return nil
	}

	n = &node{}

	// Take a random item out of the items slice and make it this node's item
	idx := rand.Intn(len(items))
	n.Item = items[idx]
	items[idx], items = items[len(items)-1], items[:len(items)-1]

	if len(items) > 0 {
		// Now partition the items into two equal-sized sets, one
		// closer to the node's item than the median, and one farther
		// away.
		median := len(items) / 2
		pivotDist := vp.distanceMetric(items[median], n.Item)

		left := 0
		right := len(items) - 1

		for left < right {
			for vp.distanceMetric(items[left], n.Item) < pivotDist {
				left += 1
			}
			for vp.distanceMetric(items[right], n.Item) > pivotDist {
				right -= 1
			}
			if left <= right {
				items[left], items[right] = items[right], items[left]
				left += 1
				right -= 1
			}
		}

		n.Threshold = vp.distanceMetric(items[median], n.Item)
		n.Left = vp.buildFromPoints(items[:median])
		n.Right = vp.buildFromPoints(items[median:])
	}
	return
}

func (vp *VPTree) search(n *node, target interface{}, k int, h *priorityQueue) {
	if n == nil {
		return
	}

	dist := vp.distanceMetric(n.Item, target)

	if dist < vp.tau {
		if h.Len() == k {
			heap.Pop(h)
		}
		heap.Push(h, &heapItem{n.Item, dist})
		if h.Len() == k {
			vp.tau = h.Top().(*heapItem).Dist
		}
	}

	if n.Left == nil && n.Right == nil {
		return
	}

	if dist < n.Threshold {
		if dist-vp.tau <= n.Threshold {
			vp.search(n.Left, target, k, h)
		}

		if dist+vp.tau >= n.Threshold {
			vp.search(n.Right, target, k, h)
		}
	} else {
		if dist+vp.tau >= n.Threshold {
			vp.search(n.Right, target, k, h)
		}

		if dist-vp.tau <= n.Threshold {
			vp.search(n.Left, target, k, h)
		}
	}
}
<commit_msg>Fix stupid bug: Was using h.Pop() instead of heap.Pop(&h)<commit_after>package vptree

import (
	"container/heap"
	"math"
	"math/rand"
)

type node struct {
	Item      interface{}
	Threshold float64
	Left      *node
	Right     *node
}

type heapItem struct {
	Item interface{}
	Dist float64
}

type Metric func(a, b interface{}) float64

type VPTree struct {
	root           *node
	tau            float64
	distanceMetric Metric
}

func New(metric Metric, items []interface{}) (t *VPTree) {
	t = &VPTree{
		distanceMetric: metric,
	}
	t.root = t.buildFromPoints(items)
	return
}

func (vp *VPTree) Search(target interface{}, k int) (results []interface{}, distances []float64) {
	h := make(priorityQueue, 0, k)

	vp.tau = math.MaxFloat64
	vp.search(vp.root, target, k, &h)

	for h.Len() > 0 {
		hi := heap.Pop(&h)
		results = append(results, hi.(*heapItem).Item)
		distances = append(distances, hi.(*heapItem).Dist)
	}

	// Reverse results and distances, because we popped them from the heap
	// in large-to-small order
	for i, j := 0, len(results)-1; i < j; i, j = i+1, j-1 {
		results[i], results[j] = results[j], results[i]
		distances[i], distances[j] = distances[j], distances[i]
	}

	return
}

func (vp *VPTree) buildFromPoints(items []interface{}) (n *node) {
	if len(items) == 0 {
		return nil
	}

	n = &node{}

	// Take a random item out of the items slice and make it this node's item
	idx := rand.Intn(len(items))
	n.Item = items[idx]
	items[idx], items = items[len(items)-1], items[:len(items)-1]

	if len(items) > 0 {
		// Now partition the items into two equal-sized sets, one
		// closer to the node's item than the median, and one farther
		// away.
		median := len(items) / 2
		pivotDist := vp.distanceMetric(items[median], n.Item)

		left := 0
		right := len(items) - 1

		for left < right {
			for vp.distanceMetric(items[left], n.Item) < pivotDist {
				left += 1
			}
			for vp.distanceMetric(items[right], n.Item) > pivotDist {
				right -= 1
			}
			if left <= right {
				items[left], items[right] = items[right], items[left]
				left += 1
				right -= 1
			}
		}

		n.Threshold = vp.distanceMetric(items[median], n.Item)
		n.Left = vp.buildFromPoints(items[:median])
		n.Right = vp.buildFromPoints(items[median:])
	}
	return
}

func (vp *VPTree) search(n *node, target interface{}, k int, h *priorityQueue) {
	if n == nil {
		return
	}

	dist := vp.distanceMetric(n.Item, target)

	if dist < vp.tau {
		if h.Len() == k {
			heap.Pop(h)
		}
		heap.Push(h, &heapItem{n.Item, dist})
		if h.Len() == k {
			vp.tau = h.Top().(*heapItem).Dist
		}
	}

	if n.Left == nil && n.Right == nil {
		return
	}

	if dist < n.Threshold {
		if dist-vp.tau <= n.Threshold {
			vp.search(n.Left, target, k, h)
		}

		if dist+vp.tau >= n.Threshold {
			vp.search(n.Right, target, k, h)
		}
	} else {
		if dist+vp.tau >= n.Threshold {
			vp.search(n.Right, target, k, h)
		}

		if dist-vp.tau <= n.Threshold {
			vp.search(n.Left, target, k, h)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/rthornton128/goncurses"
)

func addStringAt(window *goncurses.Window, content string, ypos int, xpos int) {
	window.Move(ypos, xpos)
	addString(window, content)
}

func addString(window *goncurses.Window, content string) {
	var currentChar goncurses.Char
	allChars := []rune(content)[:]
	for i := range allChars {
		currentChar = goncurses.Char(allChars[i])
		window.AddChar(currentChar)
	}
}

func drawHeader(username string) {
	panic("Not implemented")
}

func initScreen() []*goncurses.Window {
	stdscr, err := goncurses.Init()
	goncurses.Echo(false)
	goncurses.NewLines(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	windows := make([]*goncurses.Window, 3)
	/* Order is from top to bottom for the slice */

	if goncurses.HasColors() == false {
		fmt.Fprintf(os.Stderr, "W: Console does not support color")
	}

	SIZE_Y, SIZE_X = stdscr.MaxYX()

	/* Create header window */
	headerWindow, err := goncurses.NewWindow(1, SIZE_X, 0, 0)
	fatalErrorCheck(err)
	windows[0] = headerWindow

	/* The second window being the main timeline window */
	timelineWindow, err := goncurses.NewWindow(SIZE_Y-3, SIZE_X, 1, 0)
	fatalErrorCheck(err)
	timelineWindow.ScrollOk(true)
	windows[1] = timelineWindow

	/* And the final command window */
	commandWindow, err := goncurses.NewWindow(2, SIZE_X, SIZE_Y-2, 0)
	fatalErrorCheck(err)
	commandWindow.Keypad(true) /* Will allow us to use the keypad in the console */
	fatalErrorCheck(err)
	windows[2] = commandWindow

	/* And finally, create a goroutine and a channel for when the terminal is resized */
	resizeChannel := make(chan os.Signal)
	signal.Notify(resizeChannel, syscall.SIGWINCH)
	go onResize(resizeChannel)

	return windows
}

func onResize(resizeChannel chan os.Signal) {
	for {
		<-resizeChannel
		/* do resizing stuff */
	}
}
<commit_msg>Window manager now holds the pointers to the windows instead of just returning them<commit_after>package main

import (
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/rthornton128/goncurses"
)

var (
	HeaderWindow  *goncurses.Window
	MainWindow    *goncurses.Window
	CommandWindow *goncurses.Window
)

func addStringAt(window *goncurses.Window, content string, ypos int, xpos int) {
	window.Move(ypos, xpos)
	addString(window, content)
}

func addString(window *goncurses.Window, content string) {
	var currentChar goncurses.Char
	allChars := []rune(content)[:]
	for i := range allChars {
		currentChar = goncurses.Char(allChars[i])
		window.AddChar(currentChar)
	}
}

func drawHeader(username string) {
	panic("Not implemented")
}

func initScreen() {
	stdscr, err := goncurses.Init()
	goncurses.Echo(false)
	goncurses.NewLines(true)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	if goncurses.HasColors() == false {
		fmt.Fprintf(os.Stderr, "W: Console does not support color")
	}

	SIZE_Y, SIZE_X = stdscr.MaxYX()

	/* Create header window */
	HeaderWindow, err := goncurses.NewWindow(1, SIZE_X, 0, 0)
	fatalErrorCheck(err)

	/* The second window being the main timeline window */
	MainWindow, err := goncurses.NewWindow(SIZE_Y-3, SIZE_X, 1, 0)
	fatalErrorCheck(err)
	MainWindow.ScrollOk(true)

	/* And the final command window */
	CommandWindow, err := goncurses.NewWindow(2, SIZE_X, SIZE_Y-2, 0)
	fatalErrorCheck(err)
	CommandWindow.Keypad(true) /* Will allow us to use the keypad in the console */
	fatalErrorCheck(err)

	/* And finally, create a goroutine and a channel for when the terminal is resized */
	resizeChannel := make(chan os.Signal)
	signal.Notify(resizeChannel, syscall.SIGWINCH)
	go onResize(resizeChannel)
}

func onResize(resizeChannel chan os.Signal) {
	for {
		<-resizeChannel
		/* do resizing stuff */
	}
}
<|endoftext|>


<commit_before>package registry

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

	docker "github.com/fsouza/go-dockerclient"
	"github.com/garyburd/redigo/redis"
)

type ServiceRegistration struct {
	Name          string    `json:"NAME",omitempty`
	ExternalIP    string    `json:"EXTERNAL_IP",omitempty`
	ExternalPort  string    `json:"EXTERNAL_PORT",omitempty`
	InternalIP    string    `json:"INTERNAL_IP",omitempty`
	InternalPort  string    `json:"INTERNAL_PORT",omitempty`
	ContainerID   string    `json:"CONTAINER_ID"`
	ContainerName string    `json:"CONTAINER_NAME"`
	Image         string    `json:"IMAGE",omitempty`
	StartedAt     time.Time `json:"STARTED_AT"`
	Expires       time.Time `json:"-"`
	Path          string    `json:"-"`
	VirtualHosts  []string  `json:"VIRTUAL_HOSTS"`
	Port          string    `json:"PORT"`
}

func (s *ServiceRegistration) Equals(other ServiceRegistration) bool {
	return s.ExternalIP == other.ExternalIP &&
		s.ExternalPort == other.ExternalPort &&
		s.InternalIP == other.InternalIP &&
		s.InternalPort == other.InternalPort
}

func (s *ServiceRegistration) addr(ip, port string) string {
	if ip != "" && port != "" {
		return fmt.Sprint(ip, ":", port)
	}
	return ""

}
func (s *ServiceRegistration) ExternalAddr() string {
	return s.addr(s.ExternalIP, s.ExternalPort)
}

func (s *ServiceRegistration) InternalAddr() string {
	return s.addr(s.InternalIP, s.InternalPort)
}

func (r *ServiceRegistry) RegisterService(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {
	registrationPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	serviceRegistration := r.newServiceRegistration(container)
	serviceRegistration.Name = serviceConfig.Name

	vhosts := serviceConfig.Env()["VIRTUAL_HOST"]
	serviceRegistration.VirtualHosts = strings.Split(vhosts, ",")

	serviceRegistration.Port = serviceConfig.Env()["GALAXY_PORT"]

	jsonReg, err := json.Marshal(serviceRegistration)
	if err != nil {
		return nil, err
	}

	conn := r.redisPool.Get()
	defer conn.Close()

	// TODO: use a compare-and-swap SCRIPT
	_, err = conn.Do("HMSET", registrationPath, "location", jsonReg)
	if err != nil {
		return nil, err
	}

	_, err = conn.Do("EXPIRE", registrationPath, r.TTL)
	if err != nil {
		return nil, err
	}
	serviceRegistration.Expires = time.Now().UTC().Add(time.Duration(r.TTL) * time.Second)

	return serviceRegistration, nil
}

func (r *ServiceRegistry) UnRegisterService(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {

	registrationPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	conn := r.redisPool.Get()
	defer conn.Close()

	registration, err := r.GetServiceRegistration(container, serviceConfig)
	if err != nil {
		return registration, err
	}

	_, err = conn.Do("DEL", registrationPath)
	if err != nil {
		return registration, err
	}

	return registration, nil
}

func (r *ServiceRegistry) GetServiceRegistration(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {

	regPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	existingRegistration := ServiceRegistration{
		Path: regPath,
	}

	conn := r.redisPool.Get()
	defer conn.Close()

	val, err := conn.Do("HGET", regPath, "location")

	if err != nil {
		return nil, err
	}

	if val != nil {
		location, err := redis.Bytes(val, err)
		err = json.Unmarshal(location, &existingRegistration)
		if err != nil {
			return nil, err
		}

		expires, err := redis.Int(conn.Do("TTL", regPath))
		if err != nil {
			return nil, err
		}
		existingRegistration.Expires = time.Now().UTC().Add(time.Duration(expires) * time.Second)
		return &existingRegistration, nil
	}

	return nil, nil
}

func (r *ServiceRegistry) IsRegistered(container *docker.Container, serviceConfig *ServiceConfig) (bool, error) {

	reg, err := r.GetServiceRegistration(container, serviceConfig)
	return reg != nil, err
}

// TODO: get all ServiceRegistrations
func (r *ServiceRegistry) ListRegistrations() ([]ServiceRegistration, error) {
	conn := r.redisPool.Get()
	defer conn.Close()

	// TODO: convert to scan
	keys, err := redis.Strings(conn.Do("KEYS", path.Join(r.Env, "*", "hosts", "*", "*")))
	if err != nil {
		return nil, err
	}

	var regList []ServiceRegistration
	for _, key := range keys {

		val, err := redis.Bytes(conn.Do("HGET", key, "location"))
		if err != nil {
			return nil, err
		}

		svcReg := ServiceRegistration{
			Name: path.Base(key),
		}
		err = json.Unmarshal(val, &svcReg)
		if err != nil {
			return nil, err
		}

		svcReg.Path = key

		regList = append(regList, svcReg)
	}

	return regList, nil
}
<commit_msg>fix malformed struct tags<commit_after>package registry

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

	docker "github.com/fsouza/go-dockerclient"
	"github.com/garyburd/redigo/redis"
)

type ServiceRegistration struct {
	Name          string    `json:"NAME,omitempty"`
	ExternalIP    string    `json:"EXTERNAL_IP,omitempty"`
	ExternalPort  string    `json:"EXTERNAL_PORT,omitempty"`
	InternalIP    string    `json:"INTERNAL_IP,omitempty"`
	InternalPort  string    `json:"INTERNAL_PORT,omitempty"`
	ContainerID   string    `json:"CONTAINER_ID"`
	ContainerName string    `json:"CONTAINER_NAME"`
	Image         string    `json:"IMAGE,omitempty"`
	StartedAt     time.Time `json:"STARTED_AT"`
	Expires       time.Time `json:"-"`
	Path          string    `json:"-"`
	VirtualHosts  []string  `json:"VIRTUAL_HOSTS"`
	Port          string    `json:"PORT"`
}

func (s *ServiceRegistration) Equals(other ServiceRegistration) bool {
	return s.ExternalIP == other.ExternalIP &&
		s.ExternalPort == other.ExternalPort &&
		s.InternalIP == other.InternalIP &&
		s.InternalPort == other.InternalPort
}

func (s *ServiceRegistration) addr(ip, port string) string {
	if ip != "" && port != "" {
		return fmt.Sprint(ip, ":", port)
	}
	return ""

}
func (s *ServiceRegistration) ExternalAddr() string {
	return s.addr(s.ExternalIP, s.ExternalPort)
}

func (s *ServiceRegistration) InternalAddr() string {
	return s.addr(s.InternalIP, s.InternalPort)
}

func (r *ServiceRegistry) RegisterService(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {
	registrationPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	serviceRegistration := r.newServiceRegistration(container)
	serviceRegistration.Name = serviceConfig.Name

	vhosts := serviceConfig.Env()["VIRTUAL_HOST"]
	serviceRegistration.VirtualHosts = strings.Split(vhosts, ",")

	serviceRegistration.Port = serviceConfig.Env()["GALAXY_PORT"]

	jsonReg, err := json.Marshal(serviceRegistration)
	if err != nil {
		return nil, err
	}

	conn := r.redisPool.Get()
	defer conn.Close()

	// TODO: use a compare-and-swap SCRIPT
	_, err = conn.Do("HMSET", registrationPath, "location", jsonReg)
	if err != nil {
		return nil, err
	}

	_, err = conn.Do("EXPIRE", registrationPath, r.TTL)
	if err != nil {
		return nil, err
	}
	serviceRegistration.Expires = time.Now().UTC().Add(time.Duration(r.TTL) * time.Second)

	return serviceRegistration, nil
}

func (r *ServiceRegistry) UnRegisterService(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {

	registrationPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	conn := r.redisPool.Get()
	defer conn.Close()

	registration, err := r.GetServiceRegistration(container, serviceConfig)
	if err != nil {
		return registration, err
	}

	_, err = conn.Do("DEL", registrationPath)
	if err != nil {
		return registration, err
	}

	return registration, nil
}

func (r *ServiceRegistry) GetServiceRegistration(container *docker.Container, serviceConfig *ServiceConfig) (*ServiceRegistration, error) {

	regPath := path.Join(r.Env, r.Pool, "hosts", r.ensureHostname(), serviceConfig.Name)

	existingRegistration := ServiceRegistration{
		Path: regPath,
	}

	conn := r.redisPool.Get()
	defer conn.Close()

	val, err := conn.Do("HGET", regPath, "location")

	if err != nil {
		return nil, err
	}

	if val != nil {
		location, err := redis.Bytes(val, err)
		err = json.Unmarshal(location, &existingRegistration)
		if err != nil {
			return nil, err
		}

		expires, err := redis.Int(conn.Do("TTL", regPath))
		if err != nil {
			return nil, err
		}
		existingRegistration.Expires = time.Now().UTC().Add(time.Duration(expires) * time.Second)
		return &existingRegistration, nil
	}

	return nil, nil
}

func (r *ServiceRegistry) IsRegistered(container *docker.Container, serviceConfig *ServiceConfig) (bool, error) {

	reg, err := r.GetServiceRegistration(container, serviceConfig)
	return reg != nil, err
}

// TODO: get all ServiceRegistrations
func (r *ServiceRegistry) ListRegistrations() ([]ServiceRegistration, error) {
	conn := r.redisPool.Get()
	defer conn.Close()

	// TODO: convert to scan
	keys, err := redis.Strings(conn.Do("KEYS", path.Join(r.Env, "*", "hosts", "*", "*")))
	if err != nil {
		return nil, err
	}

	var regList []ServiceRegistration
	for _, key := range keys {

		val, err := redis.Bytes(conn.Do("HGET", key, "location"))
		if err != nil {
			return nil, err
		}

		svcReg := ServiceRegistration{
			Name: path.Base(key),
		}
		err = json.Unmarshal(val, &svcReg)
		if err != nil {
			return nil, err
		}

		svcReg.Path = key

		regList = append(regList, svcReg)
	}

	return regList, nil
}
<|endoftext|>


<commit_before>package tests

import (
	"errors"
	"log"
	"time"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	bitfinex "github.com/bitfinexcom/bitfinex-api-go/v2"
	"github.com/bitfinexcom/bitfinex-api-go/v2/websocket"
)

type listener struct {
	infoEvents           chan *websocket.InfoEvent
	authEvents           chan *websocket.AuthEvent
	ticks                chan *bitfinex.Ticker
	subscriptionEvents   chan *websocket.SubscribeEvent
	unsubscriptionEvents chan *websocket.UnsubscribeEvent
	walletUpdates        chan *wallet.Update
	balanceUpdates       chan *bitfinex.BalanceUpdate
	walletSnapshot       chan *wallet.Snapshot
	positionSnapshot     chan *bitfinex.PositionSnapshot
	notifications        chan *bitfinex.Notification
	positions            chan *bitfinex.PositionUpdate
	tradeUpdates         chan *bitfinex.TradeExecutionUpdate
	tradeExecutions      chan *bitfinex.TradeExecution
	cancels              chan *bitfinex.OrderCancel
	marginBase           chan *bitfinex.MarginInfoBase
	marginUpdate         chan *bitfinex.MarginInfoUpdate
	funding              chan *bitfinex.FundingInfo
	orderNew             chan *bitfinex.OrderNew
	orderUpdate          chan *bitfinex.OrderUpdate
	errors               chan error
}

func newListener() *listener {
	return &listener{
		infoEvents:           make(chan *websocket.InfoEvent, 10),
		authEvents:           make(chan *websocket.AuthEvent, 10),
		ticks:                make(chan *bitfinex.Ticker, 10),
		subscriptionEvents:   make(chan *websocket.SubscribeEvent, 10),
		unsubscriptionEvents: make(chan *websocket.UnsubscribeEvent, 10),
		walletUpdates:        make(chan *wallet.Update, 10),
		balanceUpdates:       make(chan *bitfinex.BalanceUpdate, 10),
		walletSnapshot:       make(chan *wallet.Snapshot, 10),
		positionSnapshot:     make(chan *bitfinex.PositionSnapshot, 10),
		errors:               make(chan error, 10),
		notifications:        make(chan *bitfinex.Notification, 10),
		positions:            make(chan *bitfinex.PositionUpdate, 10),
		tradeUpdates:         make(chan *bitfinex.TradeExecutionUpdate, 10),
		tradeExecutions:      make(chan *bitfinex.TradeExecution, 10),
		cancels:              make(chan *bitfinex.OrderCancel, 10),
		marginBase:           make(chan *bitfinex.MarginInfoBase, 10),
		marginUpdate:         make(chan *bitfinex.MarginInfoUpdate, 10),
		orderNew:             make(chan *bitfinex.OrderNew, 10),
		orderUpdate:          make(chan *bitfinex.OrderUpdate, 10),
		funding:              make(chan *bitfinex.FundingInfo, 10),
	}
}

func (l *listener) nextInfoEvent() (*websocket.InfoEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.infoEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for InfoEvent")
	}
}

func (l *listener) nextAuthEvent() (*websocket.AuthEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.authEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for AuthEvent")
	}
}

func (l *listener) nextWalletUpdate() (*wallet.Update, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.walletUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for WalletUpdate")
	}
}

func (l *listener) nextBalanceUpdate() (*bitfinex.BalanceUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.balanceUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for BalanceUpdate")
	}
}

func (l *listener) nextWalletSnapshot() (*wallet.Snapshot, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.walletSnapshot:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for WalletSnapshot")
	}
}

func (l *listener) nextPositionSnapshot() (*bitfinex.PositionSnapshot, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.positionSnapshot:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for PositionSnapshot")
	}
}

func (l *listener) nextSubscriptionEvent() (*websocket.SubscribeEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.subscriptionEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for SubscribeEvent")
	}
}

func (l *listener) nextUnsubscriptionEvent() (*websocket.UnsubscribeEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.unsubscriptionEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for UnsubscribeEvent")
	}
}

func (l *listener) nextTick() (*bitfinex.Ticker, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.ticks:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for Ticker")
	}
}

func (l *listener) nextNotification() (*bitfinex.Notification, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.notifications:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for Notification")
	}
}

func (l *listener) nextTradeExecution() (*bitfinex.TradeExecution, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.tradeExecutions:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for TradeExecution")
	}
}

func (l *listener) nextPositionUpdate() (*bitfinex.PositionUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.positions:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for PositionUpdate")
	}
}

func (l *listener) nextTradeUpdate() (*bitfinex.TradeExecutionUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.tradeUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for TradeUpdate")
	}
}

func (l *listener) nextOrderCancel() (*bitfinex.OrderCancel, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.cancels:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderCancel")
	}
}

func (l *listener) nextMarginInfoBase() (*bitfinex.MarginInfoBase, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.marginBase:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for MarginInfoBase")
	}
}

func (l *listener) nextMarginInfoUpdate() (*bitfinex.MarginInfoUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.marginUpdate:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for MarginInfoUpdate")
	}
}

func (l *listener) nextFundingInfo() (*bitfinex.FundingInfo, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.funding:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for FundingInfo")
	}
}

func (l *listener) nextOrderNew() (*bitfinex.OrderNew, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.orderNew:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderNew")
	}
}

func (l *listener) nextOrderUpdate() (*bitfinex.OrderUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.orderUpdate:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderUpdate")
	}
}

// strongly types messages and places them into a channel
func (l *listener) run(ch <-chan interface{}) {
	go func() {
		// nolint:megacheck
		for {
			select {
			case msg := <-ch:
				if msg == nil {
					return
				}
				// remove threading guarantees when mulitplexing into channels
				log.Printf("[DEBUG] WsService -> WsClient: %#v", msg)
				switch msg.(type) {
				case error:
					l.errors <- msg.(error)
				case *bitfinex.Ticker:
					l.ticks <- msg.(*bitfinex.Ticker)
				case *websocket.InfoEvent:
					l.infoEvents <- msg.(*websocket.InfoEvent)
				case *websocket.SubscribeEvent:
					l.subscriptionEvents <- msg.(*websocket.SubscribeEvent)
				case *websocket.UnsubscribeEvent:
					l.unsubscriptionEvents <- msg.(*websocket.UnsubscribeEvent)
				case *websocket.AuthEvent:
					l.authEvents <- msg.(*websocket.AuthEvent)
				case *wallet.Update:
					l.walletUpdates <- msg.(*wallet.Update)
				case *bitfinex.BalanceUpdate:
					l.balanceUpdates <- msg.(*bitfinex.BalanceUpdate)
				case *bitfinex.Notification:
					l.notifications <- msg.(*bitfinex.Notification)
				case *bitfinex.TradeExecutionUpdate:
					l.tradeUpdates <- msg.(*bitfinex.TradeExecutionUpdate)
				case *bitfinex.TradeExecution:
					l.tradeExecutions <- msg.(*bitfinex.TradeExecution)
				case *bitfinex.PositionUpdate:
					l.positions <- msg.(*bitfinex.PositionUpdate)
				case *bitfinex.OrderCancel:
					l.cancels <- msg.(*bitfinex.OrderCancel)
				case *bitfinex.MarginInfoBase:
					l.marginBase <- msg.(*bitfinex.MarginInfoBase)
				case *bitfinex.MarginInfoUpdate:
					l.marginUpdate <- msg.(*bitfinex.MarginInfoUpdate)
				case *bitfinex.OrderNew:
					l.orderNew <- msg.(*bitfinex.OrderNew)
				case *bitfinex.OrderUpdate:
					l.orderUpdate <- msg.(*bitfinex.OrderUpdate)
				case *bitfinex.FundingInfo:
					l.funding <- msg.(*bitfinex.FundingInfo)
				case *bitfinex.PositionSnapshot:
					l.positionSnapshot <- msg.(*bitfinex.PositionSnapshot)
				case *wallet.Snapshot:
					l.walletSnapshot <- msg.(*wallet.Snapshot)
				default:
					log.Printf("COULD NOT TYPE MSG ^")
				}
			}
		}
	}()
}
<commit_msg>tests/integration/v2/listener.go putting new Ticker and Position packages to work<commit_after>package tests

import (
	"errors"
	"log"
	"time"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/position"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/ticker"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/wallet"
	bitfinex "github.com/bitfinexcom/bitfinex-api-go/v2"
	"github.com/bitfinexcom/bitfinex-api-go/v2/websocket"
)

type listener struct {
	infoEvents           chan *websocket.InfoEvent
	authEvents           chan *websocket.AuthEvent
	ticks                chan *ticker.Ticker
	subscriptionEvents   chan *websocket.SubscribeEvent
	unsubscriptionEvents chan *websocket.UnsubscribeEvent
	walletUpdates        chan *wallet.Update
	balanceUpdates       chan *bitfinex.BalanceUpdate
	walletSnapshot       chan *wallet.Snapshot
	positionSnapshot     chan *position.Snapshot
	notifications        chan *bitfinex.Notification
	positions            chan *position.Update
	tradeUpdates         chan *bitfinex.TradeExecutionUpdate
	tradeExecutions      chan *bitfinex.TradeExecution
	cancels              chan *bitfinex.OrderCancel
	marginBase           chan *bitfinex.MarginInfoBase
	marginUpdate         chan *bitfinex.MarginInfoUpdate
	funding              chan *bitfinex.FundingInfo
	orderNew             chan *bitfinex.OrderNew
	orderUpdate          chan *bitfinex.OrderUpdate
	errors               chan error
}

func newListener() *listener {
	return &listener{
		infoEvents:           make(chan *websocket.InfoEvent, 10),
		authEvents:           make(chan *websocket.AuthEvent, 10),
		ticks:                make(chan *ticker.Ticker, 10),
		subscriptionEvents:   make(chan *websocket.SubscribeEvent, 10),
		unsubscriptionEvents: make(chan *websocket.UnsubscribeEvent, 10),
		walletUpdates:        make(chan *wallet.Update, 10),
		balanceUpdates:       make(chan *bitfinex.BalanceUpdate, 10),
		walletSnapshot:       make(chan *wallet.Snapshot, 10),
		positionSnapshot:     make(chan *position.Snapshot, 10),
		errors:               make(chan error, 10),
		notifications:        make(chan *bitfinex.Notification, 10),
		positions:            make(chan *position.Update, 10),
		tradeUpdates:         make(chan *bitfinex.TradeExecutionUpdate, 10),
		tradeExecutions:      make(chan *bitfinex.TradeExecution, 10),
		cancels:              make(chan *bitfinex.OrderCancel, 10),
		marginBase:           make(chan *bitfinex.MarginInfoBase, 10),
		marginUpdate:         make(chan *bitfinex.MarginInfoUpdate, 10),
		orderNew:             make(chan *bitfinex.OrderNew, 10),
		orderUpdate:          make(chan *bitfinex.OrderUpdate, 10),
		funding:              make(chan *bitfinex.FundingInfo, 10),
	}
}

func (l *listener) nextInfoEvent() (*websocket.InfoEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.infoEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for InfoEvent")
	}
}

func (l *listener) nextAuthEvent() (*websocket.AuthEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.authEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for AuthEvent")
	}
}

func (l *listener) nextWalletUpdate() (*wallet.Update, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.walletUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for WalletUpdate")
	}
}

func (l *listener) nextBalanceUpdate() (*bitfinex.BalanceUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.balanceUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for BalanceUpdate")
	}
}

func (l *listener) nextWalletSnapshot() (*wallet.Snapshot, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.walletSnapshot:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for WalletSnapshot")
	}
}

func (l *listener) nextPositionSnapshot() (*position.Snapshot, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.positionSnapshot:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for PositionSnapshot")
	}
}

func (l *listener) nextSubscriptionEvent() (*websocket.SubscribeEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.subscriptionEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for SubscribeEvent")
	}
}

func (l *listener) nextUnsubscriptionEvent() (*websocket.UnsubscribeEvent, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.unsubscriptionEvents:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for UnsubscribeEvent")
	}
}

func (l *listener) nextTick() (*ticker.Ticker, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.ticks:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for Ticker")
	}
}

func (l *listener) nextNotification() (*bitfinex.Notification, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.notifications:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for Notification")
	}
}

func (l *listener) nextTradeExecution() (*bitfinex.TradeExecution, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.tradeExecutions:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for TradeExecution")
	}
}

func (l *listener) nextPositionUpdate() (*position.Update, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.positions:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for PositionUpdate")
	}
}

func (l *listener) nextTradeUpdate() (*bitfinex.TradeExecutionUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.tradeUpdates:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for TradeUpdate")
	}
}

func (l *listener) nextOrderCancel() (*bitfinex.OrderCancel, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.cancels:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderCancel")
	}
}

func (l *listener) nextMarginInfoBase() (*bitfinex.MarginInfoBase, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.marginBase:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for MarginInfoBase")
	}
}

func (l *listener) nextMarginInfoUpdate() (*bitfinex.MarginInfoUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.marginUpdate:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for MarginInfoUpdate")
	}
}

func (l *listener) nextFundingInfo() (*bitfinex.FundingInfo, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.funding:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for FundingInfo")
	}
}

func (l *listener) nextOrderNew() (*bitfinex.OrderNew, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.orderNew:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderNew")
	}
}

func (l *listener) nextOrderUpdate() (*bitfinex.OrderUpdate, error) {
	timeout := make(chan bool)
	go func() {
		time.Sleep(time.Second * 2)
		close(timeout)
	}()
	select {
	case ev := <-l.orderUpdate:
		return ev, nil
	case <-timeout:
		return nil, errors.New("timed out waiting for OrderUpdate")
	}
}

// strongly types messages and places them into a channel
func (l *listener) run(ch <-chan interface{}) {
	go func() {
		// nolint:megacheck
		for {
			select {
			case msg := <-ch:
				if msg == nil {
					return
				}
				// remove threading guarantees when mulitplexing into channels
				log.Printf("[DEBUG] WsService -> WsClient: %#v", msg)
				switch msg.(type) {
				case error:
					l.errors <- msg.(error)
				case *ticker.Ticker:
					l.ticks <- msg.(*ticker.Ticker)
				case *websocket.InfoEvent:
					l.infoEvents <- msg.(*websocket.InfoEvent)
				case *websocket.SubscribeEvent:
					l.subscriptionEvents <- msg.(*websocket.SubscribeEvent)
				case *websocket.UnsubscribeEvent:
					l.unsubscriptionEvents <- msg.(*websocket.UnsubscribeEvent)
				case *websocket.AuthEvent:
					l.authEvents <- msg.(*websocket.AuthEvent)
				case *wallet.Update:
					l.walletUpdates <- msg.(*wallet.Update)
				case *bitfinex.BalanceUpdate:
					l.balanceUpdates <- msg.(*bitfinex.BalanceUpdate)
				case *bitfinex.Notification:
					l.notifications <- msg.(*bitfinex.Notification)
				case *bitfinex.TradeExecutionUpdate:
					l.tradeUpdates <- msg.(*bitfinex.TradeExecutionUpdate)
				case *bitfinex.TradeExecution:
					l.tradeExecutions <- msg.(*bitfinex.TradeExecution)
				case *position.Update:
					l.positions <- msg.(*position.Update)
				case *bitfinex.OrderCancel:
					l.cancels <- msg.(*bitfinex.OrderCancel)
				case *bitfinex.MarginInfoBase:
					l.marginBase <- msg.(*bitfinex.MarginInfoBase)
				case *bitfinex.MarginInfoUpdate:
					l.marginUpdate <- msg.(*bitfinex.MarginInfoUpdate)
				case *bitfinex.OrderNew:
					l.orderNew <- msg.(*bitfinex.OrderNew)
				case *bitfinex.OrderUpdate:
					l.orderUpdate <- msg.(*bitfinex.OrderUpdate)
				case *bitfinex.FundingInfo:
					l.funding <- msg.(*bitfinex.FundingInfo)
				case *position.Snapshot:
					l.positionSnapshot <- msg.(*position.Snapshot)
				case *wallet.Snapshot:
					l.walletSnapshot <- msg.(*wallet.Snapshot)
				default:
					log.Printf("COULD NOT TYPE MSG ^")
				}
			}
		}
	}()
}
<|endoftext|>


<commit_before>package auctionrunner

import (
	"os"
	"time"

	"github.com/cloudfoundry/gunk/timeprovider"

	"github.com/cloudfoundry-incubator/auction/auctiontypes"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/cloudfoundry/gunk/workpool"
)

type AuctionRunner interface {
	AddLRPStartAuction(models.LRPStartAuction)
	AddLRPStopAuction(models.LRPStopAuction)
}

type AuctionRunnerDelegate interface {
	FetchAuctionRepClients() (map[string]auctiontypes.AuctionRep, error)
	DistributedBatch(WorkResults)
}

type WorkResults struct {
	SuccessfulStarts []auctiontypes.StartAuction
	SuccessfulStops  []auctiontypes.StopAuction
	FailedStarts     []auctiontypes.StartAuction
	FailedStops      []auctiontypes.StopAuction
}

type auctionRunner struct {
	delegate     AuctionRunnerDelegate
	batch        *Batch
	timeProvider timeprovider.TimeProvider
	workPool     *workpool.WorkPool
	maxRetries   int
}

func New(delegate AuctionRunnerDelegate, timeProvider timeprovider.TimeProvider, maxRetries int, workPool *workpool.WorkPool) *auctionRunner {
	return &auctionRunner{
		delegate:     delegate,
		batch:        NewBatch(timeProvider),
		timeProvider: timeProvider,
		workPool:     workPool,
		maxRetries:   maxRetries,
	}
}

func (a *auctionRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	close(ready)

	var hasWork chan struct{}
	hasWork = a.batch.HasWork

	for {
		select {
		case <-hasWork:
			clients, err := a.delegate.FetchAuctionRepClients()
			if err != nil {
				time.Sleep(time.Second)
				hasWork = make(chan struct{}, 1)
				hasWork <- struct{}{}
				break
			}
			hasWork = a.batch.HasWork
			cells := FetchStateAndBuildCells(a.workPool, clients)
			startAuctions, stopAuctions := a.batch.DedupeAndDrain()
			workResults := DistributeWork(a.workPool, cells, a.timeProvider, startAuctions, stopAuctions)
			workResults = ResubmitFailedWork(a.batch, workResults, a.maxRetries)

			go a.delegate.DistributedBatch(workResults)
			//emit successfulStartAuctions and sucessfulStopAuctions to delegate
			//add failedStartAuctions to batch
		case <-signals:
			return nil
		}
	}
}

func (a *auctionRunner) AddLRPStartAuction(start models.LRPStartAuction) {
	a.batch.AddLRPStartAuction(start)
}

func (a *auctionRunner) AddLRPStopAuction(stop models.LRPStopAuction) {
	a.batch.AddLRPStopAuction(stop)
}
<commit_msg>bail early in auction runner if necessary<commit_after>package auctionrunner

import (
	"os"
	"time"

	"github.com/cloudfoundry/gunk/timeprovider"

	"github.com/cloudfoundry-incubator/auction/auctiontypes"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	"github.com/cloudfoundry/gunk/workpool"
)

type AuctionRunner interface {
	AddLRPStartAuction(models.LRPStartAuction)
	AddLRPStopAuction(models.LRPStopAuction)
}

type AuctionRunnerDelegate interface {
	FetchAuctionRepClients() (map[string]auctiontypes.AuctionRep, error)
	DistributedBatch(WorkResults)
}

type WorkResults struct {
	SuccessfulStarts []auctiontypes.StartAuction
	SuccessfulStops  []auctiontypes.StopAuction
	FailedStarts     []auctiontypes.StartAuction
	FailedStops      []auctiontypes.StopAuction
}

type auctionRunner struct {
	delegate     AuctionRunnerDelegate
	batch        *Batch
	timeProvider timeprovider.TimeProvider
	workPool     *workpool.WorkPool
	maxRetries   int
}

func New(delegate AuctionRunnerDelegate, timeProvider timeprovider.TimeProvider, maxRetries int, workPool *workpool.WorkPool) *auctionRunner {
	return &auctionRunner{
		delegate:     delegate,
		batch:        NewBatch(timeProvider),
		timeProvider: timeProvider,
		workPool:     workPool,
		maxRetries:   maxRetries,
	}
}

func (a *auctionRunner) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	close(ready)

	var hasWork chan struct{}
	hasWork = a.batch.HasWork

	for {
		select {
		case <-hasWork:
			clients, err := a.delegate.FetchAuctionRepClients()
			if err != nil {
				time.Sleep(time.Second)
				hasWork = make(chan struct{}, 1)
				hasWork <- struct{}{}
				break
			}
			hasWork = a.batch.HasWork
			cells := FetchStateAndBuildCells(a.workPool, clients)
			startAuctions, stopAuctions := a.batch.DedupeAndDrain()
			if len(startAuctions) == 0 && len(stopAuctions) == 0 {
				break
			}
			workResults := DistributeWork(a.workPool, cells, a.timeProvider, startAuctions, stopAuctions)
			workResults = ResubmitFailedWork(a.batch, workResults, a.maxRetries)

			go a.delegate.DistributedBatch(workResults)
		case <-signals:
			return nil
		}
	}
}

func (a *auctionRunner) AddLRPStartAuction(start models.LRPStartAuction) {
	a.batch.AddLRPStartAuction(start)
}

func (a *auctionRunner) AddLRPStopAuction(stop models.LRPStopAuction) {
	a.batch.AddLRPStopAuction(stop)
}
<|endoftext|>


<commit_before>package bitbucket

import (
	"code.cloudfoundry.org/lager"
	api "github.com/SHyx0rmZ/go-bitbucket/bitbucket"
	"github.com/concourse/atc/auth/verifier"
	"net/http"
)

type UserVerifier struct {
	users  []string
	client api.Client
}

func NewUserVerifier(client api.Client, users []string) verifier.Verifier {
	return UserVerifier{
		users: users,
	}
}

func (verifier UserVerifier) Verify(logger lager.Logger, c *http.Client) (bool, error) {
	currentUser, err := verifier.client.CurrentUser()
	if err != nil {
		logger.Error("failed-to-get-current-user", err)
		return false, err
	}

	for _, user := range verifier.users {
		if user == currentUser {
			return true, nil
		}
	}

	logger.Info("not-validated-user", lager.Data{
		"have": currentUser,
		"want": verifier.users,
	})

	return false, nil
}
<commit_msg>Set HTTP client in UserVerifier<commit_after>package bitbucket

import (
	"code.cloudfoundry.org/lager"
	api "github.com/SHyx0rmZ/go-bitbucket/bitbucket"
	"github.com/concourse/atc/auth/verifier"
	"net/http"
)

type UserVerifier struct {
	users  []string
	client api.Client
}

func NewUserVerifier(client api.Client, users []string) verifier.Verifier {
	return UserVerifier{
		users:  users,
		client: client,
	}
}

func (verifier UserVerifier) Verify(logger lager.Logger, c *http.Client) (bool, error) {
	verifier.client.SetHTTPClient(c)

	currentUser, err := verifier.client.CurrentUser()
	if err != nil {
		logger.Error("failed-to-get-current-user", err)
		return false, err
	}

	for _, user := range verifier.users {
		if user == currentUser {
			return true, nil
		}
	}

	logger.Info("not-validated-user", lager.Data{
		"have": currentUser,
		"want": verifier.users,
	})

	return false, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"
	"strings"
	"syscall"

	"github.com/lxc/lxd/shared"
)

func updateStoragePoolError(unchangeable []string, driverName string) error {
	return fmt.Errorf(`The %v properties cannot be changed for "%s" `+
		`storage pools`, unchangeable, driverName)
}

var changeableStoragePoolProperties = map[string][]string{
	"btrfs": {
		"rsync.bwlimit",
		"btrfs.mount_options"},

	"ceph": {
		"volume.block.filesystem",
		"volume.block.mount_options",
		"volume.size"},

	"dir": {
		"rsync.bwlimit"},

	"lvm": {
		"lvm.thinpool_name",
		"lvm.vg_name",
		"volume.block.filesystem",
		"volume.block.mount_options",
		"volume.size"},

	"zfs": {
		"rsync_bwlimit",
		"volume.zfs.remove_snapshots",
		"volume.zfs.use_refquota",
		"zfs.clone_copy"},
}

var storagePoolConfigKeys = map[string]func(value string) error{
	// valid drivers: btrfs
	// (Note, that we can't be smart in detecting mount options since a lot
	// of filesystems come with their own additional ones (e.g.
	// "user_subvol_rm_allowed" for btrfs or "zfsutils" for zfs). So
	// shared.IsAny() must do.)
	"btrfs.mount_options": shared.IsAny,

	// valid drivers: ceph
	"ceph.cluster_name":    shared.IsAny,
	"ceph.osd.force_reuse": shared.IsBool,
	"ceph.osd.pool_name":   shared.IsAny,
	"ceph.osd.pg_num": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},
	"ceph.rbd.clone_copy": shared.IsBool,
	"ceph.user.name":      shared.IsAny,

	// valid drivers: lvm
	"lvm.thinpool_name": shared.IsAny,
	"lvm.use_thinpool":  shared.IsBool,
	"lvm.vg_name":       shared.IsAny,

	// valid drivers: btrfs, lvm, zfs
	"size": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},

	// valid drivers: btrfs, dir, lvm, zfs
	"source": shared.IsAny,

	// Using it as an indicator whether we created the pool or are just
	// re-using it. Note that the valid drivers only list ceph for now. This
	// approach is however generalizable. It's just that we currently don't
	// really need it for the other drivers.
	// valid drivers: ceph
	"volatile.pool.pristine":  shared.IsAny,
	"volatile.initial_source": shared.IsAny,

	// valid drivers: ceph, lvm
	"volume.block.filesystem": func(value string) error {
		return shared.IsOneOf(value, []string{"btrfs", "ext4", "xfs"})
	},
	"volume.block.mount_options": shared.IsAny,

	// valid drivers: ceph, lvm
	"volume.size": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},

	// valid drivers: zfs
	"volume.zfs.remove_snapshots": shared.IsBool,
	"volume.zfs.use_refquota":     shared.IsBool,

	// valid drivers: zfs
	"zfs.clone_copy": shared.IsBool,
	"zfs.pool_name":  shared.IsAny,
	"rsync.bwlimit":  shared.IsAny,
}

func storagePoolValidateConfig(name string, driver string, config map[string]string, oldConfig map[string]string) error {
	err := func(value string) error {
		return shared.IsOneOf(value, supportedStoragePoolDrivers)
	}(driver)
	if err != nil {
		return err
	}

	if driver == "lvm" {
		v, ok := config["lvm.use_thinpool"]
		if ok && !shared.IsTrue(v) && config["lvm.thinpool_name"] != "" {
			return fmt.Errorf("the key \"lvm.use_thinpool\" cannot be set to a false value when \"lvm.thinpool_name\" is set for LVM storage pools")
		}
	}

	v, ok := config["rsync.bwlimit"]
	if ok && v != "" {
		_, err := shared.ParseByteSizeString(v)
		if err != nil {
			return err
		}
	}

	// Check whether the config properties for the driver container sane
	// values.
	for key, val := range config {
		// Skip unchanged keys
		if oldConfig != nil && oldConfig[key] == val {
			continue
		}

		// User keys are not validated.
		if strings.HasPrefix(key, "user.") {
			continue
		}

		prfx := strings.HasPrefix
		if driver == "dir" || driver == "ceph" {
			if key == "size" {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		if driver != "lvm" && driver != "ceph" {
			if prfx(key, "lvm.") || prfx(key, "volume.block.") || key == "volume.size" {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		if driver != "zfs" {
			if prfx(key, "volume.zfs.") || prfx(key, "zfs.") {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		// Validate storage pool config keys.
		validator, ok := storagePoolConfigKeys[key]
		if !ok {
			return fmt.Errorf("Invalid storage pool configuration key: %s", key)
		}

		err := validator(val)
		if err != nil {
			return err
		}
	}

	return nil
}

func storagePoolFillDefault(name string, driver string, config map[string]string) error {
	if driver == "dir" || driver == "ceph" {
		if config["size"] != "" {
			return fmt.Errorf(`The "size" property does not apply `+
				`to %s storage pools`, driver)
		}
	} else {
		if config["size"] == "" {
			st := syscall.Statfs_t{}
			err := syscall.Statfs(shared.VarPath(), &st)
			if err != nil {
				return fmt.Errorf("Couldn't statfs %s: %s", shared.VarPath(), err)
			}

			/* choose 15 GB < x < 100GB, where x is 20% of the disk size */
			size := uint64(st.Frsize) * st.Blocks / (1024 * 1024 * 1024) / 5
			if size > 100 {
				size = 100
			}
			if size < 15 {
				size = 15
			}
			config["size"] = strconv.FormatUint(uint64(size), 10) + "GB"
		} else {
			_, err := shared.ParseByteSizeString(config["size"])
			if err != nil {
				return err
			}
		}
	}

	if driver == "lvm" {
		// We use thin pools per default.
		useThinpool := true
		if config["lvm.use_thinpool"] != "" {
			useThinpool = shared.IsTrue(config["lvm.use_thinpool"])
		}

		if useThinpool && config["lvm.thinpool_name"] == "" {
			// Unchangeable pool property: Set unconditionally.
			config["lvm.thinpool_name"] = "LXDThinPool"
		}
	}

	if driver == "btrfs" || driver == "ceph" || driver == "lvm" || driver == "zfs" {
		if config["volume.size"] != "" {
			_, err := shared.ParseByteSizeString(config["volume.size"])
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<commit_msg>lxd/storage: Fix validation of CEPH config<commit_after>package main

import (
	"fmt"
	"strconv"
	"strings"
	"syscall"

	"github.com/lxc/lxd/shared"
)

func updateStoragePoolError(unchangeable []string, driverName string) error {
	return fmt.Errorf(`The %v properties cannot be changed for "%s" `+
		`storage pools`, unchangeable, driverName)
}

var changeableStoragePoolProperties = map[string][]string{
	"btrfs": {
		"rsync.bwlimit",
		"btrfs.mount_options"},

	"ceph": {
		"volume.block.filesystem",
		"volume.block.mount_options",
		"volume.size"},

	"dir": {
		"rsync.bwlimit"},

	"lvm": {
		"lvm.thinpool_name",
		"lvm.vg_name",
		"volume.block.filesystem",
		"volume.block.mount_options",
		"volume.size"},

	"zfs": {
		"rsync_bwlimit",
		"volume.zfs.remove_snapshots",
		"volume.zfs.use_refquota",
		"zfs.clone_copy"},
}

var storagePoolConfigKeys = map[string]func(value string) error{
	// valid drivers: btrfs
	// (Note, that we can't be smart in detecting mount options since a lot
	// of filesystems come with their own additional ones (e.g.
	// "user_subvol_rm_allowed" for btrfs or "zfsutils" for zfs). So
	// shared.IsAny() must do.)
	"btrfs.mount_options": shared.IsAny,

	// valid drivers: ceph
	"ceph.cluster_name":    shared.IsAny,
	"ceph.osd.force_reuse": shared.IsBool,
	"ceph.osd.pool_name":   shared.IsAny,
	"ceph.osd.pg_num": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},
	"ceph.rbd.clone_copy": shared.IsBool,
	"ceph.user.name":      shared.IsAny,

	// valid drivers: lvm
	"lvm.thinpool_name": shared.IsAny,
	"lvm.use_thinpool":  shared.IsBool,
	"lvm.vg_name":       shared.IsAny,

	// valid drivers: btrfs, lvm, zfs
	"size": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},

	// valid drivers: btrfs, dir, lvm, zfs
	"source": shared.IsAny,

	// Using it as an indicator whether we created the pool or are just
	// re-using it. Note that the valid drivers only list ceph for now. This
	// approach is however generalizable. It's just that we currently don't
	// really need it for the other drivers.
	// valid drivers: ceph
	"volatile.pool.pristine":  shared.IsAny,
	"volatile.initial_source": shared.IsAny,

	// valid drivers: ceph, lvm
	"volume.block.filesystem": func(value string) error {
		return shared.IsOneOf(value, []string{"btrfs", "ext4", "xfs"})
	},
	"volume.block.mount_options": shared.IsAny,

	// valid drivers: ceph, lvm
	"volume.size": func(value string) error {
		if value == "" {
			return nil
		}

		_, err := shared.ParseByteSizeString(value)
		return err
	},

	// valid drivers: zfs
	"volume.zfs.remove_snapshots": shared.IsBool,
	"volume.zfs.use_refquota":     shared.IsBool,

	// valid drivers: zfs
	"zfs.clone_copy": shared.IsBool,
	"zfs.pool_name":  shared.IsAny,
	"rsync.bwlimit":  shared.IsAny,
}

func storagePoolValidateConfig(name string, driver string, config map[string]string, oldConfig map[string]string) error {
	err := func(value string) error {
		return shared.IsOneOf(value, supportedStoragePoolDrivers)
	}(driver)
	if err != nil {
		return err
	}

	if driver == "lvm" {
		v, ok := config["lvm.use_thinpool"]
		if ok && !shared.IsTrue(v) && config["lvm.thinpool_name"] != "" {
			return fmt.Errorf("the key \"lvm.use_thinpool\" cannot be set to a false value when \"lvm.thinpool_name\" is set for LVM storage pools")
		}
	}

	v, ok := config["rsync.bwlimit"]
	if ok && v != "" {
		_, err := shared.ParseByteSizeString(v)
		if err != nil {
			return err
		}
	}

	// Check whether the config properties for the driver container sane
	// values.
	for key, val := range config {
		// Skip unchanged keys
		if oldConfig != nil && oldConfig[key] == val {
			continue
		}

		// User keys are not validated.
		if strings.HasPrefix(key, "user.") {
			continue
		}

		prfx := strings.HasPrefix
		if driver == "dir" || driver == "ceph" {
			if key == "size" {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		if driver != "lvm" {
			if prfx(key, "lvm.") {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		if driver != "lvm" && driver != "ceph" {
			if prfx(key, "volume.block.") || key == "volume.size" {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		if driver != "zfs" {
			if prfx(key, "volume.zfs.") || prfx(key, "zfs.") {
				return fmt.Errorf("the key %s cannot be used with %s storage pools", key, strings.ToUpper(driver))
			}
		}

		// Validate storage pool config keys.
		validator, ok := storagePoolConfigKeys[key]
		if !ok {
			return fmt.Errorf("Invalid storage pool configuration key: %s", key)
		}

		err := validator(val)
		if err != nil {
			return err
		}
	}

	return nil
}

func storagePoolFillDefault(name string, driver string, config map[string]string) error {
	if driver == "dir" || driver == "ceph" {
		if config["size"] != "" {
			return fmt.Errorf(`The "size" property does not apply `+
				`to %s storage pools`, driver)
		}
	} else {
		if config["size"] == "" {
			st := syscall.Statfs_t{}
			err := syscall.Statfs(shared.VarPath(), &st)
			if err != nil {
				return fmt.Errorf("Couldn't statfs %s: %s", shared.VarPath(), err)
			}

			/* choose 15 GB < x < 100GB, where x is 20% of the disk size */
			size := uint64(st.Frsize) * st.Blocks / (1024 * 1024 * 1024) / 5
			if size > 100 {
				size = 100
			}
			if size < 15 {
				size = 15
			}
			config["size"] = strconv.FormatUint(uint64(size), 10) + "GB"
		} else {
			_, err := shared.ParseByteSizeString(config["size"])
			if err != nil {
				return err
			}
		}
	}

	if driver == "lvm" {
		// We use thin pools per default.
		useThinpool := true
		if config["lvm.use_thinpool"] != "" {
			useThinpool = shared.IsTrue(config["lvm.use_thinpool"])
		}

		if useThinpool && config["lvm.thinpool_name"] == "" {
			// Unchangeable pool property: Set unconditionally.
			config["lvm.thinpool_name"] = "LXDThinPool"
		}
	}

	if driver == "btrfs" || driver == "ceph" || driver == "lvm" || driver == "zfs" {
		if config["volume.size"] != "" {
			_, err := shared.ParseByteSizeString(config["volume.size"])
			if err != nil {
				return err
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package options

import (
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"path/filepath"
	"time"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/hashicorp/go-version"
)

var TERRAFORM_COMMANDS_WITH_SUBCOMMAND = []string{
	"debug",
	"force-unlock",
	"state",
}

const DEFAULT_MAX_FOLDERS_TO_CHECK = 100

// no limits on parallelism by default (limited by GOPROCS)
const DEFAULT_PARALLELISM = math.MaxInt32

// TERRAFORM_DEFAULT_PATH just takes terraform from the path
const TERRAFORM_DEFAULT_PATH = "terraform"

const TerragruntCacheDir = ".terragrunt-cache"

const DefaultTFDataDir = ".terraform"

// TerragruntOptions represents options that configure the behavior of the Terragrunt program
type TerragruntOptions struct {
	// Location of the Terragrunt config file
	TerragruntConfigPath string

	// Version of terragrunt
	TerragruntVersion *version.Version

	// Location of the terraform binary
	TerraformPath string

	// Current Terraform command being executed by Terragrunt
	TerraformCommand string

	// Original Terraform command being executed by Terragrunt. Used to track command evolution as terragrunt chains
	// different commands together. For example, when retrieving dependencies, terragrunt will change the
	// TerraformCommand to `output` to run `terraform output`, which loses the context of the original command that was
	// run to fetch the dependency. This is a problem when mock_outputs is configured and we only allow mocks to be
	// returned on specific commands.
	// NOTE: For `xxx-all` commands, this will be set to the Terraform command, which would be `xxx`. For example,
	// if you run `apply-all` (which is a terragrunt command), this variable will be set to `apply`.
	OriginalTerraformCommand string

	// Version of terraform (obtained by running 'terraform version')
	TerraformVersion *version.Version

	// Whether we should prompt the user for confirmation or always assume "yes"
	NonInteractive bool

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoInit bool

	// CLI args that are intended for Terraform (i.e. all the CLI args except the --terragrunt ones)
	TerraformCliArgs []string

	// The working directory in which to run Terraform
	WorkingDir string

	// The logger to use for all logging
	Logger *log.Logger

	// Environment variables at runtime
	Env map[string]string

	// Download Terraform configurations from the specified source location into a temporary folder and run
	// Terraform in that temporary folder
	Source string

	// If set to true, delete the contents of the temporary folder before downloading Terraform source code into it
	SourceUpdate bool

	// Download Terraform configurations specified in the Source parameter into this folder
	DownloadDir string

	// The ARN of an IAM Role to assume before running Terraform
	IamRole string

	// If set to true, continue running *-all commands even if a dependency has errors. This is mostly useful for 'output-all <some_variable>'. See https://github.com/gruntwork-io/terragrunt/issues/193
	IgnoreDependencyErrors bool

	// If set to true, ignore the dependency order when running *-all command.
	IgnoreDependencyOrder bool

	// If set to true, skip any external dependencies when running *-all commands
	IgnoreExternalDependencies bool

	// If set to true, apply all external dependencies when running *-all commands
	IncludeExternalDependencies bool

	// If you want stdout to go somewhere other than os.stdout
	Writer io.Writer

	// If you want stderr to go somewhere other than os.stderr
	ErrWriter io.Writer

	// When searching the directory tree, this is the max folders to check before exiting with an error. This is
	// exposed here primarily so we can set it to a low value at test time.
	MaxFoldersToCheck int

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoRetry bool

	// Maximum number of times to retry errors matching RetryableErrors
	MaxRetryAttempts int

	// Sleep is the duration in seconds to wait before retrying
	Sleep time.Duration

	// RetryableErrors is an array of regular expressions with RE2 syntax (https://github.com/google/re2/wiki/Syntax) that qualify for retrying
	RetryableErrors []string

	// Unix-style glob of directories to exclude when running *-all commands
	ExcludeDirs []string

	// Unix-style glob of directories to include when running *-all commands
	IncludeDirs []string

	// If set to true, do not include dependencies when processing IncludeDirs (unless they are in the included dirs)
	StrictInclude bool

	// Parallelism limits the number of commands to run concurrently during *-all commands
	Parallelism int

	// Enable check mode, by default it's disabled.
	Check bool

	// The file which hclfmt should be specifically run on
	HclFile string

	// A command that can be used to run Terragrunt with the given options. This is useful for running Terragrunt
	// multiple times (e.g. when spinning up a stack of Terraform modules). The actual command is normally defined
	// in the cli package, which depends on almost all other packages, so we declare it here so that other
	// packages can use the command without a direct reference back to the cli package (which would create a
	// circular dependency).
	RunTerragrunt func(*TerragruntOptions) error

	// True if terragrunt should run in debug mode, writing terragrunt-debug.tfvars to working folder to help
	// root-cause issues.
	Debug bool

	// Attributes to override in AWS provider nested within modules as part of the aws-provider-patch command. See that
	// command for more info.
	AwsProviderPatchOverrides map[string]string
}

// Create a new TerragruntOptions object with reasonable defaults for real usage
func NewTerragruntOptions(terragruntConfigPath string) (*TerragruntOptions, error) {
	logger := util.CreateLogger("")

	workingDir, downloadDir, err := DefaultWorkingAndDownloadDirs(terragruntConfigPath)
	if err != nil {
		return nil, errors.WithStackTrace(err)
	}

	return &TerragruntOptions{
		TerragruntConfigPath:        terragruntConfigPath,
		TerraformPath:               TERRAFORM_DEFAULT_PATH,
		OriginalTerraformCommand:    "",
		TerraformCommand:            "",
		AutoInit:                    true,
		NonInteractive:              false,
		TerraformCliArgs:            []string{},
		WorkingDir:                  workingDir,
		Logger:                      logger,
		Env:                         map[string]string{},
		Source:                      "",
		SourceUpdate:                false,
		DownloadDir:                 downloadDir,
		IgnoreDependencyErrors:      false,
		IgnoreDependencyOrder:       false,
		IgnoreExternalDependencies:  false,
		IncludeExternalDependencies: false,
		Writer:                      os.Stdout,
		ErrWriter:                   os.Stderr,
		MaxFoldersToCheck:           DEFAULT_MAX_FOLDERS_TO_CHECK,
		AutoRetry:                   true,
		MaxRetryAttempts:            DEFAULT_MAX_RETRY_ATTEMPTS,
		Sleep:                       DEFAULT_SLEEP,
		RetryableErrors:             util.CloneStringList(DEFAULT_RETRYABLE_ERRORS),
		ExcludeDirs:                 []string{},
		IncludeDirs:                 []string{},
		StrictInclude:               false,
		Parallelism:                 DEFAULT_PARALLELISM,
		Check:                       false,
		RunTerragrunt: func(terragruntOptions *TerragruntOptions) error {
			return errors.WithStackTrace(RunTerragruntCommandNotSet)
		},
	}, nil
}

// Get the default working and download directories for the given Terragrunt config path
func DefaultWorkingAndDownloadDirs(terragruntConfigPath string) (string, string, error) {
	workingDir := filepath.Dir(terragruntConfigPath)

	downloadDir, err := filepath.Abs(filepath.Join(workingDir, TerragruntCacheDir))
	if err != nil {
		return "", "", errors.WithStackTrace(err)
	}

	return filepath.ToSlash(workingDir), filepath.ToSlash(downloadDir), nil
}

// Create a new TerragruntOptions object with reasonable defaults for test usage
func NewTerragruntOptionsForTest(terragruntConfigPath string) (*TerragruntOptions, error) {
	opts, err := NewTerragruntOptions(terragruntConfigPath)

	if err != nil {
		logger := util.CreateLogger("")
		logger.Printf("error: %v\n", errors.WithStackTrace(err))
		return nil, err
	}

	opts.NonInteractive = true

	return opts, nil
}

// Create a copy of this TerragruntOptions, but with different values for the given variables. This is useful for
// creating a TerragruntOptions that behaves the same way, but is used for a Terraform module in a different folder.
func (terragruntOptions *TerragruntOptions) Clone(terragruntConfigPath string) *TerragruntOptions {
	workingDir := filepath.Dir(terragruntConfigPath)

	// Note that we clone lists and maps below as TerragruntOptions may be used and modified concurrently in the code
	// during xxx-all commands (e.g., apply-all, plan-all). See https://github.com/gruntwork-io/terragrunt/issues/367
	// for more info.
	return &TerragruntOptions{
		TerragruntConfigPath:        terragruntConfigPath,
		TerraformPath:               terragruntOptions.TerraformPath,
		OriginalTerraformCommand:    terragruntOptions.OriginalTerraformCommand,
		TerraformCommand:            terragruntOptions.TerraformCommand,
		TerraformVersion:            terragruntOptions.TerraformVersion,
		TerragruntVersion:           terragruntOptions.TerragruntVersion,
		AutoInit:                    terragruntOptions.AutoInit,
		NonInteractive:              terragruntOptions.NonInteractive,
		TerraformCliArgs:            util.CloneStringList(terragruntOptions.TerraformCliArgs),
		WorkingDir:                  workingDir,
		Logger:                      util.CreateLoggerWithWriter(terragruntOptions.ErrWriter, workingDir),
		Env:                         util.CloneStringMap(terragruntOptions.Env),
		Source:                      terragruntOptions.Source,
		SourceUpdate:                terragruntOptions.SourceUpdate,
		DownloadDir:                 terragruntOptions.DownloadDir,
		IamRole:                     terragruntOptions.IamRole,
		IgnoreDependencyErrors:      terragruntOptions.IgnoreDependencyErrors,
		IgnoreDependencyOrder:       terragruntOptions.IgnoreDependencyOrder,
		IgnoreExternalDependencies:  terragruntOptions.IgnoreExternalDependencies,
		IncludeExternalDependencies: terragruntOptions.IncludeExternalDependencies,
		Writer:                      terragruntOptions.Writer,
		ErrWriter:                   terragruntOptions.ErrWriter,
		MaxFoldersToCheck:           terragruntOptions.MaxFoldersToCheck,
		AutoRetry:                   terragruntOptions.AutoRetry,
		MaxRetryAttempts:            terragruntOptions.MaxRetryAttempts,
		Sleep:                       terragruntOptions.Sleep,
		RetryableErrors:             util.CloneStringList(terragruntOptions.RetryableErrors),
		ExcludeDirs:                 terragruntOptions.ExcludeDirs,
		IncludeDirs:                 terragruntOptions.IncludeDirs,
		Parallelism:                 terragruntOptions.Parallelism,
		StrictInclude:               terragruntOptions.StrictInclude,
		RunTerragrunt:               terragruntOptions.RunTerragrunt,
		AwsProviderPatchOverrides:   terragruntOptions.AwsProviderPatchOverrides,
	}
}

// Inserts the given argsToInsert after the terraform command argument, but before the remaining args
func (terragruntOptions *TerragruntOptions) InsertTerraformCliArgs(argsToInsert ...string) {

	commandLength := 1
	if util.ListContainsElement(TERRAFORM_COMMANDS_WITH_SUBCOMMAND, terragruntOptions.TerraformCliArgs[0]) {
		// Since these terraform commands require subcommands which may not always be properly passed by the user,
		// using util.Min to return the minimum to avoid potential out of bounds slice errors.
		commandLength = util.Min(2, len(terragruntOptions.TerraformCliArgs))
	}

	// Options must be inserted after command but before the other args
	// command is either 1 word or 2 words
	var args []string
	args = append(args, terragruntOptions.TerraformCliArgs[:commandLength]...)
	args = append(args, argsToInsert...)
	args = append(args, terragruntOptions.TerraformCliArgs[commandLength:]...)
	terragruntOptions.TerraformCliArgs = args
}

// Appends the given argsToAppend after the current TerraformCliArgs
func (terragruntOptions *TerragruntOptions) AppendTerraformCliArgs(argsToAppend ...string) {
	terragruntOptions.TerraformCliArgs = append(terragruntOptions.TerraformCliArgs, argsToAppend...)
}

// TerraformDataDir returns Terraform data directory (.terraform by default, overridden by $TF_DATA_DIR envvar)
func (terragruntOptions *TerragruntOptions) TerraformDataDir() string {
	if tfDataDir, ok := terragruntOptions.Env["TF_DATA_DIR"]; ok {
		return tfDataDir
	}
	return DefaultTFDataDir
}

// DataDir returns the Terraform data directory prepended with the working directory path,
// or just the Terraform data directory if it is an absolute path.
func (terragruntOptions *TerragruntOptions) DataDir() string {
	tfDataDir := terragruntOptions.TerraformDataDir()
	if filepath.IsAbs(tfDataDir) {
		return tfDataDir
	}
	return util.JoinPath(terragruntOptions.WorkingDir, tfDataDir)
}

// Custom error types

var RunTerragruntCommandNotSet = fmt.Errorf("The RunTerragrunt option has not been set on this TerragruntOptions object")
<commit_msg>Fix debug mode (#1503)<commit_after>package options

import (
	"fmt"
	"io"
	"log"
	"math"
	"os"
	"path/filepath"
	"time"

	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/hashicorp/go-version"
)

var TERRAFORM_COMMANDS_WITH_SUBCOMMAND = []string{
	"debug",
	"force-unlock",
	"state",
}

const DEFAULT_MAX_FOLDERS_TO_CHECK = 100

// no limits on parallelism by default (limited by GOPROCS)
const DEFAULT_PARALLELISM = math.MaxInt32

// TERRAFORM_DEFAULT_PATH just takes terraform from the path
const TERRAFORM_DEFAULT_PATH = "terraform"

const TerragruntCacheDir = ".terragrunt-cache"

const DefaultTFDataDir = ".terraform"

// TerragruntOptions represents options that configure the behavior of the Terragrunt program
type TerragruntOptions struct {
	// Location of the Terragrunt config file
	TerragruntConfigPath string

	// Version of terragrunt
	TerragruntVersion *version.Version

	// Location of the terraform binary
	TerraformPath string

	// Current Terraform command being executed by Terragrunt
	TerraformCommand string

	// Original Terraform command being executed by Terragrunt. Used to track command evolution as terragrunt chains
	// different commands together. For example, when retrieving dependencies, terragrunt will change the
	// TerraformCommand to `output` to run `terraform output`, which loses the context of the original command that was
	// run to fetch the dependency. This is a problem when mock_outputs is configured and we only allow mocks to be
	// returned on specific commands.
	// NOTE: For `xxx-all` commands, this will be set to the Terraform command, which would be `xxx`. For example,
	// if you run `apply-all` (which is a terragrunt command), this variable will be set to `apply`.
	OriginalTerraformCommand string

	// Version of terraform (obtained by running 'terraform version')
	TerraformVersion *version.Version

	// Whether we should prompt the user for confirmation or always assume "yes"
	NonInteractive bool

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoInit bool

	// CLI args that are intended for Terraform (i.e. all the CLI args except the --terragrunt ones)
	TerraformCliArgs []string

	// The working directory in which to run Terraform
	WorkingDir string

	// The logger to use for all logging
	Logger *log.Logger

	// Environment variables at runtime
	Env map[string]string

	// Download Terraform configurations from the specified source location into a temporary folder and run
	// Terraform in that temporary folder
	Source string

	// If set to true, delete the contents of the temporary folder before downloading Terraform source code into it
	SourceUpdate bool

	// Download Terraform configurations specified in the Source parameter into this folder
	DownloadDir string

	// The ARN of an IAM Role to assume before running Terraform
	IamRole string

	// If set to true, continue running *-all commands even if a dependency has errors. This is mostly useful for 'output-all <some_variable>'. See https://github.com/gruntwork-io/terragrunt/issues/193
	IgnoreDependencyErrors bool

	// If set to true, ignore the dependency order when running *-all command.
	IgnoreDependencyOrder bool

	// If set to true, skip any external dependencies when running *-all commands
	IgnoreExternalDependencies bool

	// If set to true, apply all external dependencies when running *-all commands
	IncludeExternalDependencies bool

	// If you want stdout to go somewhere other than os.stdout
	Writer io.Writer

	// If you want stderr to go somewhere other than os.stderr
	ErrWriter io.Writer

	// When searching the directory tree, this is the max folders to check before exiting with an error. This is
	// exposed here primarily so we can set it to a low value at test time.
	MaxFoldersToCheck int

	// Whether we should automatically run terraform init if necessary when executing other commands
	AutoRetry bool

	// Maximum number of times to retry errors matching RetryableErrors
	MaxRetryAttempts int

	// Sleep is the duration in seconds to wait before retrying
	Sleep time.Duration

	// RetryableErrors is an array of regular expressions with RE2 syntax (https://github.com/google/re2/wiki/Syntax) that qualify for retrying
	RetryableErrors []string

	// Unix-style glob of directories to exclude when running *-all commands
	ExcludeDirs []string

	// Unix-style glob of directories to include when running *-all commands
	IncludeDirs []string

	// If set to true, do not include dependencies when processing IncludeDirs (unless they are in the included dirs)
	StrictInclude bool

	// Parallelism limits the number of commands to run concurrently during *-all commands
	Parallelism int

	// Enable check mode, by default it's disabled.
	Check bool

	// The file which hclfmt should be specifically run on
	HclFile string

	// A command that can be used to run Terragrunt with the given options. This is useful for running Terragrunt
	// multiple times (e.g. when spinning up a stack of Terraform modules). The actual command is normally defined
	// in the cli package, which depends on almost all other packages, so we declare it here so that other
	// packages can use the command without a direct reference back to the cli package (which would create a
	// circular dependency).
	RunTerragrunt func(*TerragruntOptions) error

	// True if terragrunt should run in debug mode, writing terragrunt-debug.tfvars to working folder to help
	// root-cause issues.
	Debug bool

	// Attributes to override in AWS provider nested within modules as part of the aws-provider-patch command. See that
	// command for more info.
	AwsProviderPatchOverrides map[string]string
}

// Create a new TerragruntOptions object with reasonable defaults for real usage
func NewTerragruntOptions(terragruntConfigPath string) (*TerragruntOptions, error) {
	logger := util.CreateLogger("")

	workingDir, downloadDir, err := DefaultWorkingAndDownloadDirs(terragruntConfigPath)
	if err != nil {
		return nil, errors.WithStackTrace(err)
	}

	return &TerragruntOptions{
		TerragruntConfigPath:        terragruntConfigPath,
		TerraformPath:               TERRAFORM_DEFAULT_PATH,
		OriginalTerraformCommand:    "",
		TerraformCommand:            "",
		AutoInit:                    true,
		NonInteractive:              false,
		TerraformCliArgs:            []string{},
		WorkingDir:                  workingDir,
		Logger:                      logger,
		Env:                         map[string]string{},
		Source:                      "",
		SourceUpdate:                false,
		DownloadDir:                 downloadDir,
		IgnoreDependencyErrors:      false,
		IgnoreDependencyOrder:       false,
		IgnoreExternalDependencies:  false,
		IncludeExternalDependencies: false,
		Writer:                      os.Stdout,
		ErrWriter:                   os.Stderr,
		MaxFoldersToCheck:           DEFAULT_MAX_FOLDERS_TO_CHECK,
		AutoRetry:                   true,
		MaxRetryAttempts:            DEFAULT_MAX_RETRY_ATTEMPTS,
		Sleep:                       DEFAULT_SLEEP,
		RetryableErrors:             util.CloneStringList(DEFAULT_RETRYABLE_ERRORS),
		ExcludeDirs:                 []string{},
		IncludeDirs:                 []string{},
		StrictInclude:               false,
		Parallelism:                 DEFAULT_PARALLELISM,
		Check:                       false,
		RunTerragrunt: func(terragruntOptions *TerragruntOptions) error {
			return errors.WithStackTrace(RunTerragruntCommandNotSet)
		},
	}, nil
}

// Get the default working and download directories for the given Terragrunt config path
func DefaultWorkingAndDownloadDirs(terragruntConfigPath string) (string, string, error) {
	workingDir := filepath.Dir(terragruntConfigPath)

	downloadDir, err := filepath.Abs(filepath.Join(workingDir, TerragruntCacheDir))
	if err != nil {
		return "", "", errors.WithStackTrace(err)
	}

	return filepath.ToSlash(workingDir), filepath.ToSlash(downloadDir), nil
}

// Create a new TerragruntOptions object with reasonable defaults for test usage
func NewTerragruntOptionsForTest(terragruntConfigPath string) (*TerragruntOptions, error) {
	opts, err := NewTerragruntOptions(terragruntConfigPath)

	if err != nil {
		logger := util.CreateLogger("")
		logger.Printf("error: %v\n", errors.WithStackTrace(err))
		return nil, err
	}

	opts.NonInteractive = true

	return opts, nil
}

// Create a copy of this TerragruntOptions, but with different values for the given variables. This is useful for
// creating a TerragruntOptions that behaves the same way, but is used for a Terraform module in a different folder.
func (terragruntOptions *TerragruntOptions) Clone(terragruntConfigPath string) *TerragruntOptions {
	workingDir := filepath.Dir(terragruntConfigPath)

	// Note that we clone lists and maps below as TerragruntOptions may be used and modified concurrently in the code
	// during xxx-all commands (e.g., apply-all, plan-all). See https://github.com/gruntwork-io/terragrunt/issues/367
	// for more info.
	return &TerragruntOptions{
		TerragruntConfigPath:        terragruntConfigPath,
		TerraformPath:               terragruntOptions.TerraformPath,
		OriginalTerraformCommand:    terragruntOptions.OriginalTerraformCommand,
		TerraformCommand:            terragruntOptions.TerraformCommand,
		TerraformVersion:            terragruntOptions.TerraformVersion,
		TerragruntVersion:           terragruntOptions.TerragruntVersion,
		AutoInit:                    terragruntOptions.AutoInit,
		NonInteractive:              terragruntOptions.NonInteractive,
		TerraformCliArgs:            util.CloneStringList(terragruntOptions.TerraformCliArgs),
		WorkingDir:                  workingDir,
		Logger:                      util.CreateLoggerWithWriter(terragruntOptions.ErrWriter, workingDir),
		Env:                         util.CloneStringMap(terragruntOptions.Env),
		Source:                      terragruntOptions.Source,
		SourceUpdate:                terragruntOptions.SourceUpdate,
		DownloadDir:                 terragruntOptions.DownloadDir,
		Debug:                       terragruntOptions.Debug,
		IamRole:                     terragruntOptions.IamRole,
		IgnoreDependencyErrors:      terragruntOptions.IgnoreDependencyErrors,
		IgnoreDependencyOrder:       terragruntOptions.IgnoreDependencyOrder,
		IgnoreExternalDependencies:  terragruntOptions.IgnoreExternalDependencies,
		IncludeExternalDependencies: terragruntOptions.IncludeExternalDependencies,
		Writer:                      terragruntOptions.Writer,
		ErrWriter:                   terragruntOptions.ErrWriter,
		MaxFoldersToCheck:           terragruntOptions.MaxFoldersToCheck,
		AutoRetry:                   terragruntOptions.AutoRetry,
		MaxRetryAttempts:            terragruntOptions.MaxRetryAttempts,
		Sleep:                       terragruntOptions.Sleep,
		RetryableErrors:             util.CloneStringList(terragruntOptions.RetryableErrors),
		ExcludeDirs:                 terragruntOptions.ExcludeDirs,
		IncludeDirs:                 terragruntOptions.IncludeDirs,
		Parallelism:                 terragruntOptions.Parallelism,
		StrictInclude:               terragruntOptions.StrictInclude,
		RunTerragrunt:               terragruntOptions.RunTerragrunt,
		AwsProviderPatchOverrides:   terragruntOptions.AwsProviderPatchOverrides,
	}
}

// Inserts the given argsToInsert after the terraform command argument, but before the remaining args
func (terragruntOptions *TerragruntOptions) InsertTerraformCliArgs(argsToInsert ...string) {

	commandLength := 1
	if util.ListContainsElement(TERRAFORM_COMMANDS_WITH_SUBCOMMAND, terragruntOptions.TerraformCliArgs[0]) {
		// Since these terraform commands require subcommands which may not always be properly passed by the user,
		// using util.Min to return the minimum to avoid potential out of bounds slice errors.
		commandLength = util.Min(2, len(terragruntOptions.TerraformCliArgs))
	}

	// Options must be inserted after command but before the other args
	// command is either 1 word or 2 words
	var args []string
	args = append(args, terragruntOptions.TerraformCliArgs[:commandLength]...)
	args = append(args, argsToInsert...)
	args = append(args, terragruntOptions.TerraformCliArgs[commandLength:]...)
	terragruntOptions.TerraformCliArgs = args
}

// Appends the given argsToAppend after the current TerraformCliArgs
func (terragruntOptions *TerragruntOptions) AppendTerraformCliArgs(argsToAppend ...string) {
	terragruntOptions.TerraformCliArgs = append(terragruntOptions.TerraformCliArgs, argsToAppend...)
}

// TerraformDataDir returns Terraform data directory (.terraform by default, overridden by $TF_DATA_DIR envvar)
func (terragruntOptions *TerragruntOptions) TerraformDataDir() string {
	if tfDataDir, ok := terragruntOptions.Env["TF_DATA_DIR"]; ok {
		return tfDataDir
	}
	return DefaultTFDataDir
}

// DataDir returns the Terraform data directory prepended with the working directory path,
// or just the Terraform data directory if it is an absolute path.
func (terragruntOptions *TerragruntOptions) DataDir() string {
	tfDataDir := terragruntOptions.TerraformDataDir()
	if filepath.IsAbs(tfDataDir) {
		return tfDataDir
	}
	return util.JoinPath(terragruntOptions.WorkingDir, tfDataDir)
}

// Custom error types

var RunTerragruntCommandNotSet = fmt.Errorf("The RunTerragrunt option has not been set on this TerragruntOptions object")
<|endoftext|>


<commit_before>package feedloggr2

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"time"
)

func (app *App) updateAllFeeds(feeds []Item) []Feed {
	var updated []Feed
	sleep := time.Duration(feedTimeout) * time.Second
	for _, f := range feeds {
		items, sslDowngrade, err := app.updateSingleFeed(f)
		if err != nil {
			app.Log("Error: %s", err)
		}

		if len(items) > 0 || err != nil {
			updated = append(updated, Feed{
				Title:  f.Title,
				URL:    f.URL,
				Items:  items,
				BadSSL: sslDowngrade,
				Error:  err,
			})
		}
		time.Sleep(sleep)
	}
	sort.Slice(updated, func(i, j int) bool {
		return updated[i].Title < updated[j].Title
	})
	return updated
}

func (app *App) updateSingleFeed(feed Item) ([]Item, bool, error) {
	app.Log("Updating %s (%s)", feed.Title, feed.URL)
	b, sslDowngrade, err := app.downloadFeed(feed.URL)
	if err != nil {
		return nil, sslDowngrade, err
	}

	items, err := app.parseFeed(b)
	if err != nil {
		return nil, sslDowngrade, err
	}

	d := date(app.time)
	err = app.db.SaveItems(feed.URL, d, items)
	if err != nil {
		return nil, sslDowngrade, err
	}

	uniqe, err := app.db.GetItems(feed.URL, d)
	if err != nil {
		return nil, sslDowngrade, err
	}

	return uniqe, sslDowngrade, nil
}

func (app *App) downloadFeed(url string) (io.ReadCloser, bool, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, false, err
	}

	req.Header.Set("User-Agent", UserAgent)
	req.URL.Scheme = "https"
	res, err := app.httpClient.Do(req)
	if err == nil {
		return res.Body, false, nil
	}

	// Fallback to insecure connection with no ssl/tls
	req.URL.Scheme = "http"
	res, err = app.httpClient.Do(req)
	if err != nil {
		return nil, true, err
	}
	return res.Body, true, nil
}

func (app *App) parseFeed(b io.ReadCloser) ([]Item, error) {
	defer b.Close()
	feed, err := app.parser.Parse(b)
	if err != nil {
		return nil, err
	}

	var seen []string
	var items []Item
	num := min(len(feed.Items), maxItems)
	for _, i := range feed.Items[:num] {
		// Avoid items with duplicate names (/r/WorldNews ffs)
		if inList(i.Title, seen) {
			continue
		}
		seen = append(seen, i.Title)

		items = append(items, Item{
			Title: i.Title,
			URL:   i.Link,
		})
	}
	return items, nil
}

func (app *App) generatePage(feeds []Feed) ([]byte, error) {
	app.Log("Generating page...")
	buf := new(bytes.Buffer)
	err := app.tmpl.Execute(buf, map[string]interface{}{
		"CurrentDate": date(app.time),
		"PrevDate":    date(app.time.AddDate(0, 0, -1)),
		"NextDate":    date(app.time.AddDate(0, 0, 1)),
		"Feeds":       feeds,
	})
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (app *App) writePage(path string, b []byte) error {
	app.Log("Writing page to %s...", path)
	err := os.MkdirAll(filepath.Dir(path), 0744)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(path, b, 0644)
	if err != nil {
		return err
	}

	index := filepath.Join(app.Config.OutputPath, "index.html")
	err = os.Remove(index)
	if err != nil {
		// ignore error if the symlink doesn't exist already
		if !os.IsNotExist(err) {
			return err
		}
	}

	err = os.Symlink(filepath.Base(path), index)
	if err != nil {
		return err
	}
	return nil
}

func (app *App) writeStyleFile() error {
	path := filepath.Join(app.Config.OutputPath, "style.css")
	// With these flags we try to avoid overwriting an existing file
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644)
	if err != nil {
		if os.IsExist(err) {
			return nil
		}
		return err
	}

	defer f.Close()
	app.Log("Writing style file...")
	_, err = f.WriteString(tmplCSS)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Try to enforce SSL earlier<commit_after>package feedloggr2

import (
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

func (app *App) updateAllFeeds(feeds []Item) []Feed {
	var updated []Feed
	sleep := time.Duration(feedTimeout) * time.Second
	for _, f := range feeds {
		// Try to enforce SSL
		f.URL = strings.Replace(f.URL, "http://", "https://", -1)

		items, sslDowngrade, err := app.updateSingleFeed(f)
		if err != nil {
			app.Log("Error: %s", err)
		}
		if sslDowngrade {
			// Ops, no SSL here; redo
			f.URL = strings.Replace(f.URL, "https://", "http://", -1)
		}

		if len(items) > 0 || err != nil {
			updated = append(updated, Feed{
				Title:  f.Title,
				URL:    f.URL,
				Items:  items,
				BadSSL: sslDowngrade,
				Error:  err,
			})
		}
		time.Sleep(sleep)
	}
	sort.Slice(updated, func(i, j int) bool {
		return updated[i].Title < updated[j].Title
	})
	return updated
}

func (app *App) updateSingleFeed(feed Item) ([]Item, bool, error) {
	app.Log("Updating %s (%s)", feed.Title, feed.URL)
	b, sslDowngrade, err := app.downloadFeed(feed.URL)
	if err != nil {
		return nil, sslDowngrade, err
	}

	items, err := app.parseFeed(b)
	if err != nil {
		return nil, sslDowngrade, err
	}

	d := date(app.time)
	err = app.db.SaveItems(feed.URL, d, items)
	if err != nil {
		return nil, sslDowngrade, err
	}

	uniqe, err := app.db.GetItems(feed.URL, d)
	if err != nil {
		return nil, sslDowngrade, err
	}

	return uniqe, sslDowngrade, nil
}

func (app *App) downloadFeed(url string) (io.ReadCloser, bool, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, false, err
	}

	req.Header.Set("User-Agent", UserAgent)
	res, err := app.httpClient.Do(req)
	if err == nil {
		return res.Body, false, nil
	}

	// Fallback to insecure connection with no ssl/tls
	req.URL.Scheme = "http"
	res, err = app.httpClient.Do(req)
	if err != nil {
		return nil, true, err
	}
	return res.Body, true, nil
}

func (app *App) parseFeed(b io.ReadCloser) ([]Item, error) {
	defer b.Close()
	feed, err := app.parser.Parse(b)
	if err != nil {
		return nil, err
	}

	var seen []string
	var items []Item
	num := min(len(feed.Items), maxItems)
	for _, i := range feed.Items[:num] {
		// Avoid items with duplicate names (/r/WorldNews ffs)
		if inList(i.Title, seen) {
			continue
		}
		seen = append(seen, i.Title)

		items = append(items, Item{
			Title: i.Title,
			URL:   i.Link,
		})
	}
	return items, nil
}

func (app *App) generatePage(feeds []Feed) ([]byte, error) {
	app.Log("Generating page...")
	buf := new(bytes.Buffer)
	err := app.tmpl.Execute(buf, map[string]interface{}{
		"CurrentDate": date(app.time),
		"PrevDate":    date(app.time.AddDate(0, 0, -1)),
		"NextDate":    date(app.time.AddDate(0, 0, 1)),
		"Feeds":       feeds,
	})
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (app *App) writePage(path string, b []byte) error {
	app.Log("Writing page to %s...", path)
	err := os.MkdirAll(filepath.Dir(path), 0744)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(path, b, 0644)
	if err != nil {
		return err
	}

	index := filepath.Join(app.Config.OutputPath, "index.html")
	err = os.Remove(index)
	if err != nil {
		// ignore error if the symlink doesn't exist already
		if !os.IsNotExist(err) {
			return err
		}
	}

	err = os.Symlink(filepath.Base(path), index)
	if err != nil {
		return err
	}
	return nil
}

func (app *App) writeStyleFile() error {
	path := filepath.Join(app.Config.OutputPath, "style.css")
	// With these flags we try to avoid overwriting an existing file
	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644)
	if err != nil {
		if os.IsExist(err) {
			return nil
		}
		return err
	}

	defer f.Close()
	app.Log("Writing style file...")
	_, err = f.WriteString(tmplCSS)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


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

package cmd

import (
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/cilium/cilium/api/v1/models"
	pkg "github.com/cilium/cilium/pkg/client"

	"github.com/spf13/cobra"
)

// statusCmd represents the daemon_status command
var statusCmd = &cobra.Command{
	Use:   "status",
	Short: "Display status of daemon",
	Run: func(cmd *cobra.Command, args []string) {
		statusDaemon(cmd, args)
	},
}

func init() {
	rootCmd.AddCommand(statusCmd)
}

func statusDaemon(cmd *cobra.Command, args []string) {
	if resp, err := client.Daemon.GetHealthz(nil); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", pkg.Hint(err))
		os.Exit(1)
	} else {
		sr := resp.Payload
		w := tabwriter.NewWriter(os.Stdout, 2, 0, 3, ' ', 0)
		if sr.Kvstore != nil {
			fmt.Fprintf(w, "KVStore:\t%s\t%s\n", sr.Kvstore.State, sr.Kvstore.Msg)
		}
		if sr.ContainerRuntime != nil {
			fmt.Fprintf(w, "ContainerRuntime:\t%s\t%s\n",
				sr.ContainerRuntime.State, sr.ContainerRuntime.Msg)
		}
		if sr.Kubernetes != nil {
			fmt.Fprintf(w, "Kubernetes:\t%s\t%s\n", sr.Kubernetes.State, sr.Kubernetes.Msg)
		}
		if sr.Cilium != nil {
			fmt.Fprintf(w, "Cilium:\t%s\t%s\n", sr.Cilium.State, sr.Cilium.Msg)
		}

		if sr.IPAM != nil {
			fmt.Printf("Allocated IPv4 addresses:\n")
			for _, ipv4 := range sr.IPAM.IPV4 {
				fmt.Printf(" %s\n", ipv4)

			}
			fmt.Printf("Allocated IPv6 addresses:\n")
			for _, ipv6 := range sr.IPAM.IPV6 {
				fmt.Printf(" %s\n", ipv6)
			}
		}

		if nm := sr.NodeMonitor; nm != nil {
			fmt.Fprintf(w, "NodeMonitor:\tListening for events on %d CPUs with %dx%d of shared memory\n",
				nm.Cpus, nm.Npages, nm.Pagesize)
			if nm.Lost != 0 || nm.Unknown != 0 {
				fmt.Fprintf(w, "\t%d events lost, %d unknown notifications\n", nm.Lost, nm.Unknown)
			}
		} else {
			fmt.Fprintf(w, "NodeMonitor:\tDisabled\n")
		}

		w.Flush()

		if sr.Cilium != nil && sr.Cilium.State != models.StatusStateOk {
			os.Exit(1)
		} else {
			os.Exit(0)
		}
	}

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

package cmd

import (
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/cilium/cilium/api/v1/models"
	pkg "github.com/cilium/cilium/pkg/client"

	"github.com/spf13/cobra"
)

// statusCmd represents the daemon_status command
var statusCmd = &cobra.Command{
	Use:   "status",
	Short: "Display status of daemon",
	Run: func(cmd *cobra.Command, args []string) {
		statusDaemon(cmd, args)
	},
}

func init() {
	rootCmd.AddCommand(statusCmd)
}

func statusDaemon(cmd *cobra.Command, args []string) {
	if resp, err := client.Daemon.GetHealthz(nil); err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", pkg.Hint(err))
		os.Exit(1)
	} else {
		sr := resp.Payload
		w := tabwriter.NewWriter(os.Stdout, 2, 0, 3, ' ', 0)
		if sr.Kvstore != nil {
			fmt.Fprintf(w, "KVStore:\t%s\t%s\n", sr.Kvstore.State, sr.Kvstore.Msg)
		}
		if sr.ContainerRuntime != nil {
			fmt.Fprintf(w, "ContainerRuntime:\t%s\t%s\n",
				sr.ContainerRuntime.State, sr.ContainerRuntime.Msg)
		}
		if sr.Kubernetes != nil {
			fmt.Fprintf(w, "Kubernetes:\t%s\t%s\n", sr.Kubernetes.State, sr.Kubernetes.Msg)
		}
		if sr.Cilium != nil {
			fmt.Fprintf(w, "Cilium:\t%s\t%s\n", sr.Cilium.State, sr.Cilium.Msg)
		}

		if nm := sr.NodeMonitor; nm != nil {
			fmt.Fprintf(w, "NodeMonitor:\tListening for events on %d CPUs with %dx%d of shared memory\n",
				nm.Cpus, nm.Npages, nm.Pagesize)
			if nm.Lost != 0 || nm.Unknown != 0 {
				fmt.Fprintf(w, "\t%d events lost, %d unknown notifications\n", nm.Lost, nm.Unknown)
			}
		} else {
			fmt.Fprintf(w, "NodeMonitor:\tDisabled\n")
		}

		if sr.IPAM != nil {
			fmt.Fprintf(w, "Allocated IPv4 addresses:\n")
			for _, ipv4 := range sr.IPAM.IPV4 {
				fmt.Fprintf(w, " %s\n", ipv4)

			}
			fmt.Fprintf(w, "Allocated IPv6 addresses:\n")
			for _, ipv6 := range sr.IPAM.IPV6 {
				fmt.Fprintf(w, " %s\n", ipv6)
			}
		}

		w.Flush()

		if sr.Cilium != nil && sr.Cilium.State != models.StatusStateOk {
			os.Exit(1)
		} else {
			os.Exit(0)
		}
	}

}
<|endoftext|>