<commit_before>// Copyright (c) 2012 krepa098 (krepa098 at gmail dot com)
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose, including commercial applications,
// and to alter it and redistribute it freely, subject to the following restrictions:
// 	1.	The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
//		If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
// 	2. 	Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// 	3. 	This notice may not be removed or altered from any source distribution.

package gosfml2

// #include <SFML/Window/Window.h>
// #include <stdlib.h>
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		CONSTS
/////////////////////////////////////

const (
	StyleNone         = 0                                        ///< No border / title bar (this flag and all others are mutually exclusive)
	StyleTitlebar     = 1 << 0                                   ///< Title bar + fixed border
	StyleResize       = 1 << 1                                   ///< Titlebar + resizable border + maximize button
	StyleClose        = 1 << 2                                   ///< Titlebar + close button
	StyleFullscreen   = 1 << 3                                   ///< Fullscreen mode (this flag and all others are mutually exclusive)
	StyleDefaultStyle = StyleTitlebar | StyleResize | StyleClose ///< Default window style
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Window struct {
	cptr *C.sfWindow
}

/////////////////////////////////////
///		INTERFACES
/////////////////////////////////////

// Window and RenderWindow are SystemWindows
type SystemWindow interface {
	SetVSyncEnabled(bool)
	SetFramerateLimit(uint)
	SetJoystickThreshold(float32)
	SetKeyRepeatEnabled(bool)
	Display()
	IsOpen() bool
	Close()
	SetTitle(string)
	SetIcon(uint, uint, []byte) error
	SetMouseCursorVisible(bool)
	SetActive(bool) bool
}

//TEST
var _ SystemWindow = &RenderWindow{}
var _ SystemWindow = &Window{}

/////////////////////////////////////
///		FUNCTIONS
/////////////////////////////////////

// Construct a new window
//
// 	videoMode:       Video mode to use
// 	title:           Title of the window
// 	style:           Window style
// 	contextSettings: Creation settings (pass nil to use default values)
func NewWindow(videoMode VideoMode, title string, style int, contextSettings *ContextSettings) (window *Window) {
	//string conversion
	utf32 := append([]int32(title), 0)

	//convert contextSettings to C
	cs := contextSettings.toCPtr()
	defer C.free(unsafe.Pointer(cs))

	//create the window
	window = &Window{C.sfWindow_createUnicode(videoMode.toC(), (*C.sfUint32)(unsafe.Pointer(&utf32[0])), C.sfUint32(style), cs)}

	//GC cleanup
	runtime.SetFinalizer(window, (*Window).Destroy)

	return window
}

// Get the creation settings of a window
func (this *Window) GetSettings() (settings ContextSettings) {
	settings.fromC(C.sfWindow_getSettings(this.cptr))
	return
}

// Change the size of the rendering region of a window
//
// 	size: New size, in pixels
func (this *Window) SetSize(size Vector2u) {
	C.sfWindow_setSize(this.cptr, size.toC())
}

// Get the size of the rendering region of a window
func (this *Window) GetSize() Vector2u {
	size := C.sfWindow_getSize(this.cptr)
	return Vector2u{uint(size.x), uint(size.y)}
}

// Change the position of a window on screen
//
// Only works for top-level windows
//
// 	pos: New position, in pixels
func (this *Window) SetPosition(pos Vector2i) {
	C.sfWindow_setPosition(this.cptr, pos.toC())
}

// Get the position of a render window
func (this *Window) GetPosition() (pos Vector2i) {
	pos.fromC(C.sfWindow_getPosition(this.cptr))
	return
}

// Tell whether or not a window is opened
func (this *Window) IsOpen() bool {
	return sfBool2Go(C.sfWindow_isOpen(this.cptr))
}

// Close a window (but doesn't destroy the internal data)
func (this *Window) Close() {
	C.sfWindow_close(this.cptr)
}

// Destroy an existing window
func (this *Window) Destroy() {
	C.sfWindow_destroy(this.cptr)
	this.cptr = nil
}

// Get the event on top of event queue of a window, if any, and pop it
//
// returns nil if there are no events left.
func (this *Window) PollEvent() Event {
	cEvent := C.sfEvent{}
	hasEvent := C.sfWindow_pollEvent(this.cptr, &cEvent)

	if hasEvent != 0 {
		return handleEvent(&cEvent)
	}
	return nil
}

// Wait for an event and return it
func (this *Window) WaitEvent() Event {
	cEvent := C.sfEvent{}
	hasError := C.sfWindow_waitEvent(this.cptr, &cEvent)

	if hasError != 0 {
		return handleEvent(&cEvent)
	}
	return nil
}

// Change the title of a window
//
// 	title: New title
func (this *Window) SetTitle(title string) {
	utf32 := append([]int32(title), 0)

	C.sfWindow_setUnicodeTitle(this.cptr, (*C.sfUint32)(unsafe.Pointer(&utf32[0])))
}

// Change a window's icon
//
// 	width:  Icon's width, in pixels
// 	height: Icon's height, in pixels
// 	pixels: Slice of pixels, format must be RGBA 32 bits
func (this *Window) SetIcon(width, height uint, data []byte) error {
	if len(data) > 0 {
		C.sfWindow_setIcon(this.cptr, C.uint(width), C.uint(height), (*C.sfUint8)(&data[0]))
		return nil
	}
	return errors.New("SetIcon: no data")
}

// Limit the framerate to a maximum fixed frequency for a window
//
// 	limit: Framerate limit, in frames per seconds (use 0 to disable limit)
func (this *Window) SetFramerateLimit(limit uint) {
	C.sfWindow_setFramerateLimit(this.cptr, C.uint(limit))
}

///Change the joystick threshold, ie. the value below which no move event will be generated
//
// threshold: New threshold, in range [0, 100]
func (this *Window) SetJoystickThreshold(threshold float32) {
	C.sfWindow_setJoystickThreshold(this.cptr, C.float(threshold))
}

// Enable or disable automatic key-repeat
//
// If key repeat is enabled, you will receive repeated
// KeyPress events while keeping a key pressed. If it is disabled,
// you will only get a single event when the key is pressed.
//
// Key repeat is enabled by default.
func (this *Window) SetKeyRepeatEnabled(enabled bool) {
	C.sfWindow_setKeyRepeatEnabled(this.cptr, goBool2C(enabled))
}

// Display a window on screen
func (this *Window) Display() {
	C.sfWindow_display(this.cptr)
}

// Enable / disable vertical synchronization on a window
//
// 	enabled: true to enable v-sync, false to deactivate
func (this *Window) SetVSyncEnabled(enabled bool) {
	C.sfWindow_setVerticalSyncEnabled(this.cptr, goBool2C(enabled))
}

// Activate or deactivate a window as the current target for rendering
//
// 	active: true to activate, false to deactivate
//
// return True if operation was successful, false otherwise
func (this *Window) SetActive(active bool) bool {
	return sfBool2Go(C.sfWindow_setActive(this.cptr, goBool2C(active)))
}

// Show or hide the mouse cursor on a render window
//
// 	visible: true to show, false to hide
func (this *Window) SetMouseCursorVisible(visible bool) {
	C.sfWindow_setMouseCursorVisible(this.cptr, goBool2C(visible))
}
<commit_msg>StyleDefaultStyle -> StyleDefault<commit_after>// Copyright (c) 2012 krepa098 (krepa098 at gmail dot com)
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose, including commercial applications,
// and to alter it and redistribute it freely, subject to the following restrictions:
// 	1.	The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
//		If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
// 	2. 	Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
// 	3. 	This notice may not be removed or altered from any source distribution.

package gosfml2

// #include <SFML/Window/Window.h>
// #include <stdlib.h>
import "C"

import (
	"errors"
	"runtime"
	"unsafe"
)

/////////////////////////////////////
///		CONSTS
/////////////////////////////////////

const (
	StyleNone       = 0                                        ///< No border / title bar (this flag and all others are mutually exclusive)
	StyleTitlebar   = 1 << 0                                   ///< Title bar + fixed border
	StyleResize     = 1 << 1                                   ///< Titlebar + resizable border + maximize button
	StyleClose      = 1 << 2                                   ///< Titlebar + close button
	StyleFullscreen = 1 << 3                                   ///< Fullscreen mode (this flag and all others are mutually exclusive)
	StyleDefault    = StyleTitlebar | StyleResize | StyleClose ///< Default window style
)

/////////////////////////////////////
///		STRUCTS
/////////////////////////////////////

type Window struct {
	cptr *C.sfWindow
}

/////////////////////////////////////
///		INTERFACES
/////////////////////////////////////

// Window and RenderWindow are SystemWindows
type SystemWindow interface {
	SetVSyncEnabled(bool)
	SetFramerateLimit(uint)
	SetJoystickThreshold(float32)
	SetKeyRepeatEnabled(bool)
	Display()
	IsOpen() bool
	Close()
	SetTitle(string)
	SetIcon(uint, uint, []byte) error
	SetMouseCursorVisible(bool)
	SetActive(bool) bool
}

//TEST
var _ SystemWindow = &RenderWindow{}
var _ SystemWindow = &Window{}

/////////////////////////////////////
///		FUNCTIONS
/////////////////////////////////////

// Construct a new window
//
// 	videoMode:       Video mode to use
// 	title:           Title of the window
// 	style:           Window style
// 	contextSettings: Creation settings (pass nil to use default values)
func NewWindow(videoMode VideoMode, title string, style int, contextSettings *ContextSettings) (window *Window) {
	//string conversion
	utf32 := append([]int32(title), 0)

	//convert contextSettings to C
	cs := contextSettings.toCPtr()
	defer C.free(unsafe.Pointer(cs))

	//create the window
	window = &Window{C.sfWindow_createUnicode(videoMode.toC(), (*C.sfUint32)(unsafe.Pointer(&utf32[0])), C.sfUint32(style), cs)}

	//GC cleanup
	runtime.SetFinalizer(window, (*Window).Destroy)

	return window
}

// Get the creation settings of a window
func (this *Window) GetSettings() (settings ContextSettings) {
	settings.fromC(C.sfWindow_getSettings(this.cptr))
	return
}

// Change the size of the rendering region of a window
//
// 	size: New size, in pixels
func (this *Window) SetSize(size Vector2u) {
	C.sfWindow_setSize(this.cptr, size.toC())
}

// Get the size of the rendering region of a window
func (this *Window) GetSize() Vector2u {
	size := C.sfWindow_getSize(this.cptr)
	return Vector2u{uint(size.x), uint(size.y)}
}

// Change the position of a window on screen
//
// Only works for top-level windows
//
// 	pos: New position, in pixels
func (this *Window) SetPosition(pos Vector2i) {
	C.sfWindow_setPosition(this.cptr, pos.toC())
}

// Get the position of a render window
func (this *Window) GetPosition() (pos Vector2i) {
	pos.fromC(C.sfWindow_getPosition(this.cptr))
	return
}

// Tell whether or not a window is opened
func (this *Window) IsOpen() bool {
	return sfBool2Go(C.sfWindow_isOpen(this.cptr))
}

// Close a window (but doesn't destroy the internal data)
func (this *Window) Close() {
	C.sfWindow_close(this.cptr)
}

// Destroy an existing window
func (this *Window) Destroy() {
	C.sfWindow_destroy(this.cptr)
	this.cptr = nil
}

// Get the event on top of event queue of a window, if any, and pop it
//
// returns nil if there are no events left.
func (this *Window) PollEvent() Event {
	cEvent := C.sfEvent{}
	hasEvent := C.sfWindow_pollEvent(this.cptr, &cEvent)

	if hasEvent != 0 {
		return handleEvent(&cEvent)
	}
	return nil
}

// Wait for an event and return it
func (this *Window) WaitEvent() Event {
	cEvent := C.sfEvent{}
	hasError := C.sfWindow_waitEvent(this.cptr, &cEvent)

	if hasError != 0 {
		return handleEvent(&cEvent)
	}
	return nil
}

// Change the title of a window
//
// 	title: New title
func (this *Window) SetTitle(title string) {
	utf32 := append([]int32(title), 0)

	C.sfWindow_setUnicodeTitle(this.cptr, (*C.sfUint32)(unsafe.Pointer(&utf32[0])))
}

// Change a window's icon
//
// 	width:  Icon's width, in pixels
// 	height: Icon's height, in pixels
// 	pixels: Slice of pixels, format must be RGBA 32 bits
func (this *Window) SetIcon(width, height uint, data []byte) error {
	if len(data) > 0 {
		C.sfWindow_setIcon(this.cptr, C.uint(width), C.uint(height), (*C.sfUint8)(&data[0]))
		return nil
	}
	return errors.New("SetIcon: no data")
}

// Limit the framerate to a maximum fixed frequency for a window
//
// 	limit: Framerate limit, in frames per seconds (use 0 to disable limit)
func (this *Window) SetFramerateLimit(limit uint) {
	C.sfWindow_setFramerateLimit(this.cptr, C.uint(limit))
}

///Change the joystick threshold, ie. the value below which no move event will be generated
//
// threshold: New threshold, in range [0, 100]
func (this *Window) SetJoystickThreshold(threshold float32) {
	C.sfWindow_setJoystickThreshold(this.cptr, C.float(threshold))
}

// Enable or disable automatic key-repeat
//
// If key repeat is enabled, you will receive repeated
// KeyPress events while keeping a key pressed. If it is disabled,
// you will only get a single event when the key is pressed.
//
// Key repeat is enabled by default.
func (this *Window) SetKeyRepeatEnabled(enabled bool) {
	C.sfWindow_setKeyRepeatEnabled(this.cptr, goBool2C(enabled))
}

// Display a window on screen
func (this *Window) Display() {
	C.sfWindow_display(this.cptr)
}

// Enable / disable vertical synchronization on a window
//
// 	enabled: true to enable v-sync, false to deactivate
func (this *Window) SetVSyncEnabled(enabled bool) {
	C.sfWindow_setVerticalSyncEnabled(this.cptr, goBool2C(enabled))
}

// Activate or deactivate a window as the current target for rendering
//
// 	active: true to activate, false to deactivate
//
// return True if operation was successful, false otherwise
func (this *Window) SetActive(active bool) bool {
	return sfBool2Go(C.sfWindow_setActive(this.cptr, goBool2C(active)))
}

// Show or hide the mouse cursor on a render window
//
// 	visible: true to show, false to hide
func (this *Window) SetMouseCursorVisible(visible bool) {
	C.sfWindow_setMouseCursorVisible(this.cptr, goBool2C(visible))
}
<|endoftext|>


<commit_before>/*
Tiny web server to handle slack outgoing webhook and push the data to resque
*/
package main

import (
	"fmt"
	"net/http"
	"net/url"
	"encoding/json"
	"strings"
	"github.com/fzzy/radix/redis"
)

// some default global variable
var (
	PORT string = ":8765"
	API_PATH string = "/api"
	REDIS string = "localhost:6379"
	CLASS string = "SlackOPS"
	QUEUE string = "slackops"
)

func main() {
	// connect to redis and add queue
	rcon, err := redis.Dial("tcp", REDIS)
	if err != nil {
		fmt.Println("error:", err)
	}
	rcon.Cmd("SADD", "resque:queues", QUEUE)
	rcon.Close()

	// start web app
	http.HandleFunc(API_PATH, apiHandler)
	http.ListenAndServe(PORT, nil)
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
	type Response struct {
		Text string `json:"text"`
	}

	type Job struct {
		Class string `json:"class"`
		Vars map[string]string `json:"vars"`
	}

	body := make([]byte, r.ContentLength)

	// accept only POST
	if r.Method == "POST" {
		// make connection to redis
		rcon, err := redis.Dial("tcp", REDIS)
		if err != nil {
			fmt.Println("error:", err)
		}

		// read and parse request body content
		r.Body.Read(body)
		data, err := url.ParseQuery(string(body))
		if err != nil {
			fmt.Println("error:", err)
		}

		// create job
		job := Job{
			Class: CLASS,
			Vars: map[string]string {
			"request": strings.TrimPrefix(data.Get("text"), data.Get("trigger_word")),
			"user": data.Get("user_name"),
			"channel": data.Get("channel_name"),
			"timestamp": data.Get("timestamp"),
			},
		}
		jjob, err := json.Marshal(job)
		if err != nil {
			fmt.Println("error:", err)
		}
		// push job to resque
		queue := "resque:queue:" + QUEUE
		rcon.Cmd("RPUSH", queue, string(jjob))
		rcon.Close()

		// response to slack
		res := Response{
			Text: "@" + data.Get("user_name") + ": " + strings.TrimPrefix(data.Get("text"), "slackops: "),
		}
		jres, err := json.Marshal(res)
		if err != nil {
			fmt.Println("error:", err)
		}
		w.Header().Set("Content-type", "application/json")
		fmt.Fprintf(w, string(jres))
	}
}
<commit_msg>Vars -> Args<commit_after>/*
Tiny web server to handle slack outgoing webhook and push the data to resque
*/
package main

import (
	"fmt"
	"net/http"
	"net/url"
	"encoding/json"
	"strings"
	"github.com/fzzy/radix/redis"
)

// some default global variable
var (
	PORT string = ":8765"
	API_PATH string = "/api"
	REDIS string = "localhost:6379"
	CLASS string = "SlackOPS"
	QUEUE string = "slackops"
)

func main() {
	// connect to redis and add queue
	rcon, err := redis.Dial("tcp", REDIS)
	if err != nil {
		fmt.Println("error:", err)
	}
	rcon.Cmd("SADD", "resque:queues", QUEUE)
	rcon.Close()

	// start web app
	http.HandleFunc(API_PATH, apiHandler)
	http.ListenAndServe(PORT, nil)
}

func apiHandler(w http.ResponseWriter, r *http.Request) {
	type Response struct {
		Text string `json:"text"`
	}

	type Job struct {
		Class string `json:"class"`
		Args map[string]string `json:"args"`
	}

	body := make([]byte, r.ContentLength)

	// accept only POST
	if r.Method == "POST" {
		// make connection to redis
		rcon, err := redis.Dial("tcp", REDIS)
		if err != nil {
			fmt.Println("error:", err)
		}

		// read and parse request body content
		r.Body.Read(body)
		data, err := url.ParseQuery(string(body))
		if err != nil {
			fmt.Println("error:", err)
		}

		// create job
		job := Job{
			Class: CLASS,
			Args: map[string]string {
			"request": strings.TrimPrefix(data.Get("text"), data.Get("trigger_word")),
			"user": data.Get("user_name"),
			"channel": data.Get("channel_name"),
			"timestamp": data.Get("timestamp"),
			},
		}
		jjob, err := json.Marshal(job)
		if err != nil {
			fmt.Println("error:", err)
		}
		// push job to resque
		queue := "resque:queue:" + QUEUE
		rcon.Cmd("RPUSH", queue, string(jjob))
		rcon.Close()

		// response to slack
		res := Response{
			Text: "@" + data.Get("user_name") + ": " + strings.TrimPrefix(data.Get("text"), "slackops: "),
		}
		jres, err := json.Marshal(res)
		if err != nil {
			fmt.Println("error:", err)
		}
		w.Header().Set("Content-type", "application/json")
		fmt.Fprintf(w, string(jres))
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

// GraphNodeDestroyer must be implemented by nodes that destroy resources.
type GraphNodeDestroyer interface {
	dag.Vertex

	// ResourceAddr is the address of the resource that is being
	// destroyed by this node. If this returns nil, then this node
	// is not destroying anything.
	DestroyAddr() *ResourceAddress
}

// GraphNodeCreator must be implemented by nodes that create OR update resources.
type GraphNodeCreator interface {
	// ResourceAddr is the address of the resource being created or updated
	CreateAddr() *ResourceAddress
}

// DestroyEdgeTransformer is a GraphTransformer that creates the proper
// references for destroy resources. Destroy resources are more complex
// in that they must be depend on the destruction of resources that
// in turn depend on the CREATION of the node being destroy.
//
// That is complicated. Visually:
//
//   B_d -> A_d -> A -> B
//
// Notice that A destroy depends on B destroy, while B create depends on
// A create. They're inverted. This must be done for example because often
// dependent resources will block parent resources from deleting. Concrete
// example: VPC with subnets, the VPC can't be deleted while there are
// still subnets.
type DestroyEdgeTransformer struct {
	// Module and State are only needed to look up dependencies in
	// any way possible. Either can be nil if not availabile.
	Module *module.Tree
	State  *State
}

func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
	log.Printf("[TRACE] DestroyEdgeTransformer: Beginning destroy edge transformation...")

	// Build a map of what is being destroyed (by address string) to
	// the list of destroyers. In general there will only be one destroyer
	// but to make it more robust we support multiple.
	destroyers := make(map[string][]GraphNodeDestroyer)
	for _, v := range g.Vertices() {
		dn, ok := v.(GraphNodeDestroyer)
		if !ok {
			continue
		}

		addr := dn.DestroyAddr()
		if addr == nil {
			continue
		}

		key := addr.String()
		log.Printf(
			"[TRACE] DestroyEdgeTransformer: %s destroying %q",
			dag.VertexName(dn), key)
		destroyers[key] = append(destroyers[key], dn)
	}

	// If we aren't destroying anything, there will be no edges to make
	// so just exit early and avoid future work.
	if len(destroyers) == 0 {
		return nil
	}

	// Go through and connect creators to destroyers. Going along with
	// our example, this makes: A_d => A
	for _, v := range g.Vertices() {
		cn, ok := v.(GraphNodeCreator)
		if !ok {
			continue
		}

		addr := cn.CreateAddr()
		if addr == nil {
			continue
		}

		key := addr.String()
		ds := destroyers[key]
		if len(ds) == 0 {
			continue
		}

		for _, d := range ds {
			// For illustrating our example
			a_d := d.(dag.Vertex)
			a := v

			log.Printf(
				"[TRACE] DestroyEdgeTransformer: connecting creator/destroyer: %s, %s",
				dag.VertexName(a), dag.VertexName(a_d))

			g.Connect(&DestroyEdge{S: a, T: a_d})
		}
	}

	// This is strange but is the easiest way to get the dependencies
	// of a node that is being destroyed. We use another graph to make sure
	// the resource is in the graph and ask for references. We have to do this
	// because the node that is being destroyed may NOT be in the graph.
	//
	// Example: resource A is force new, then destroy A AND create A are
	// in the graph. BUT if resource A is just pure destroy, then only
	// destroy A is in the graph, and create A is not.
	steps := []GraphTransformer{
		&OutputTransformer{Module: t.Module},
		&AttachResourceConfigTransformer{Module: t.Module},
		&AttachStateTransformer{State: t.State},
		&ReferenceTransformer{},
	}

	// Go through all the nodes being destroyed and create a graph.
	// The resulting graph is only of things being CREATED. For example,
	// following our example, the resulting graph would be:
	//
	//   A, B (with no edges)
	//
	var tempG Graph
	var tempDestroyed []dag.Vertex
	for d, _ := range destroyers {
		// d is what is being destroyed. We parse the resource address
		// which it came from it is a panic if this fails.
		addr, err := ParseResourceAddress(d)
		if err != nil {
			panic(err)
		}

		// This part is a little bit weird but is the best way to
		// find the dependencies we need to: build a graph and use the
		// attach config and state transformers then ask for references.
		node := &NodeAbstractResource{Addr: addr}
		tempG.Add(node)
		tempDestroyed = append(tempDestroyed, node)
	}

	// Run the graph transforms so we have the information we need to
	// build references.
	for _, s := range steps {
		if err := s.Transform(&tempG); err != nil {
			return err
		}
	}

	log.Printf("[TRACE] DestroyEdgeTransformer: reference graph: %s", tempG.String())

	// Go through all the nodes in the graph and determine what they
	// depend on.
	for _, v := range tempDestroyed {
		// Find all descendents of this to determine the edges we'll depend on
		vs, err := tempG.Ancestors(v)
		if err != nil {
			return err
		}

		refs := make([]dag.Vertex, 0, vs.Len())
		for _, raw := range vs.List() {
			refs = append(refs, raw.(dag.Vertex))
		}

		log.Printf(
			"[TRACE] DestroyEdgeTransformer: creation node %q references %v",
			dag.VertexName(v), refs)

		// If we have no references, then we won't need to do anything
		if len(refs) == 0 {
			continue
		}

		// Get the destroy node for this. In the example of our struct,
		// we are currently at B and we're looking for B_d.
		rn, ok := v.(GraphNodeResource)
		if !ok {
			continue
		}

		addr := rn.ResourceAddr()
		if addr == nil {
			continue
		}

		dns := destroyers[addr.String()]

		// We have dependencies, check if any are being destroyed
		// to build the list of things that we must depend on!
		//
		// In the example of the struct, if we have:
		//
		//   B_d => A_d => A => B
		//
		// Then at this point in the algorithm we started with B_d,
		// we built B (to get dependencies), and we found A. We're now looking
		// to see if A_d exists.
		var depDestroyers []dag.Vertex
		for _, v := range refs {
			rn, ok := v.(GraphNodeResource)
			if !ok {
				continue
			}

			addr := rn.ResourceAddr()
			if addr == nil {
				continue
			}

			key := addr.String()
			if ds, ok := destroyers[key]; ok {
				for _, d := range ds {
					depDestroyers = append(depDestroyers, d.(dag.Vertex))
					log.Printf(
						"[TRACE] DestroyEdgeTransformer: destruction of %q depends on %s",
						key, dag.VertexName(d))
				}
			}
		}

		// Go through and make the connections. Use the variable
		// names "a_d" and "b_d" to reference our example.
		for _, a_d := range dns {
			for _, b_d := range depDestroyers {
				if b_d != a_d {
					g.Connect(dag.BasicEdge(b_d, a_d))
				}
			}
		}
	}

	return nil
}
<commit_msg>terraform: fix typo<commit_after>package terraform

import (
	"log"

	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

// GraphNodeDestroyer must be implemented by nodes that destroy resources.
type GraphNodeDestroyer interface {
	dag.Vertex

	// ResourceAddr is the address of the resource that is being
	// destroyed by this node. If this returns nil, then this node
	// is not destroying anything.
	DestroyAddr() *ResourceAddress
}

// GraphNodeCreator must be implemented by nodes that create OR update resources.
type GraphNodeCreator interface {
	// ResourceAddr is the address of the resource being created or updated
	CreateAddr() *ResourceAddress
}

// DestroyEdgeTransformer is a GraphTransformer that creates the proper
// references for destroy resources. Destroy resources are more complex
// in that they must be depend on the destruction of resources that
// in turn depend on the CREATION of the node being destroy.
//
// That is complicated. Visually:
//
//   B_d -> A_d -> A -> B
//
// Notice that A destroy depends on B destroy, while B create depends on
// A create. They're inverted. This must be done for example because often
// dependent resources will block parent resources from deleting. Concrete
// example: VPC with subnets, the VPC can't be deleted while there are
// still subnets.
type DestroyEdgeTransformer struct {
	// Module and State are only needed to look up dependencies in
	// any way possible. Either can be nil if not availabile.
	Module *module.Tree
	State  *State
}

func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
	log.Printf("[TRACE] DestroyEdgeTransformer: Beginning destroy edge transformation...")

	// Build a map of what is being destroyed (by address string) to
	// the list of destroyers. In general there will only be one destroyer
	// but to make it more robust we support multiple.
	destroyers := make(map[string][]GraphNodeDestroyer)
	for _, v := range g.Vertices() {
		dn, ok := v.(GraphNodeDestroyer)
		if !ok {
			continue
		}

		addr := dn.DestroyAddr()
		if addr == nil {
			continue
		}

		key := addr.String()
		log.Printf(
			"[TRACE] DestroyEdgeTransformer: %s destroying %q",
			dag.VertexName(dn), key)
		destroyers[key] = append(destroyers[key], dn)
	}

	// If we aren't destroying anything, there will be no edges to make
	// so just exit early and avoid future work.
	if len(destroyers) == 0 {
		return nil
	}

	// Go through and connect creators to destroyers. Going along with
	// our example, this makes: A_d => A
	for _, v := range g.Vertices() {
		cn, ok := v.(GraphNodeCreator)
		if !ok {
			continue
		}

		addr := cn.CreateAddr()
		if addr == nil {
			continue
		}

		key := addr.String()
		ds := destroyers[key]
		if len(ds) == 0 {
			continue
		}

		for _, d := range ds {
			// For illustrating our example
			a_d := d.(dag.Vertex)
			a := v

			log.Printf(
				"[TRACE] DestroyEdgeTransformer: connecting creator/destroyer: %s, %s",
				dag.VertexName(a), dag.VertexName(a_d))

			g.Connect(&DestroyEdge{S: a, T: a_d})
		}
	}

	// This is strange but is the easiest way to get the dependencies
	// of a node that is being destroyed. We use another graph to make sure
	// the resource is in the graph and ask for references. We have to do this
	// because the node that is being destroyed may NOT be in the graph.
	//
	// Example: resource A is force new, then destroy A AND create A are
	// in the graph. BUT if resource A is just pure destroy, then only
	// destroy A is in the graph, and create A is not.
	steps := []GraphTransformer{
		&OutputTransformer{Module: t.Module},
		&AttachResourceConfigTransformer{Module: t.Module},
		&AttachStateTransformer{State: t.State},
		&ReferenceTransformer{},
	}

	// Go through all the nodes being destroyed and create a graph.
	// The resulting graph is only of things being CREATED. For example,
	// following our example, the resulting graph would be:
	//
	//   A, B (with no edges)
	//
	var tempG Graph
	var tempDestroyed []dag.Vertex
	for d, _ := range destroyers {
		// d is what is being destroyed. We parse the resource address
		// which it came from it is a panic if this fails.
		addr, err := ParseResourceAddress(d)
		if err != nil {
			panic(err)
		}

		// This part is a little bit weird but is the best way to
		// find the dependencies we need to: build a graph and use the
		// attach config and state transformers then ask for references.
		node := &NodeAbstractResource{Addr: addr}
		tempG.Add(node)
		tempDestroyed = append(tempDestroyed, node)
	}

	// Run the graph transforms so we have the information we need to
	// build references.
	for _, s := range steps {
		if err := s.Transform(&tempG); err != nil {
			return err
		}
	}

	log.Printf("[TRACE] DestroyEdgeTransformer: reference graph: %s", tempG.String())

	// Go through all the nodes in the graph and determine what they
	// depend on.
	for _, v := range tempDestroyed {
		// Find all ancestors of this to determine the edges we'll depend on
		vs, err := tempG.Ancestors(v)
		if err != nil {
			return err
		}

		refs := make([]dag.Vertex, 0, vs.Len())
		for _, raw := range vs.List() {
			refs = append(refs, raw.(dag.Vertex))
		}

		log.Printf(
			"[TRACE] DestroyEdgeTransformer: creation node %q references %v",
			dag.VertexName(v), refs)

		// If we have no references, then we won't need to do anything
		if len(refs) == 0 {
			continue
		}

		// Get the destroy node for this. In the example of our struct,
		// we are currently at B and we're looking for B_d.
		rn, ok := v.(GraphNodeResource)
		if !ok {
			continue
		}

		addr := rn.ResourceAddr()
		if addr == nil {
			continue
		}

		dns := destroyers[addr.String()]

		// We have dependencies, check if any are being destroyed
		// to build the list of things that we must depend on!
		//
		// In the example of the struct, if we have:
		//
		//   B_d => A_d => A => B
		//
		// Then at this point in the algorithm we started with B_d,
		// we built B (to get dependencies), and we found A. We're now looking
		// to see if A_d exists.
		var depDestroyers []dag.Vertex
		for _, v := range refs {
			rn, ok := v.(GraphNodeResource)
			if !ok {
				continue
			}

			addr := rn.ResourceAddr()
			if addr == nil {
				continue
			}

			key := addr.String()
			if ds, ok := destroyers[key]; ok {
				for _, d := range ds {
					depDestroyers = append(depDestroyers, d.(dag.Vertex))
					log.Printf(
						"[TRACE] DestroyEdgeTransformer: destruction of %q depends on %s",
						key, dag.VertexName(d))
				}
			}
		}

		// Go through and make the connections. Use the variable
		// names "a_d" and "b_d" to reference our example.
		for _, a_d := range dns {
			for _, b_d := range depDestroyers {
				if b_d != a_d {
					g.Connect(dag.BasicEdge(b_d, a_d))
				}
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The golex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lex

import (
	"bytes"
	"fmt"
	"go/token"
	"io"
	"os"
)

// BOM handling modes which can be set by the BOMMode Option. Default is BOMIgnoreFirst.
const (
	BOMError       = iota // BOM is an error anywhere.
	BOMIgnoreFirst        // Skip BOM if at beginning, report as error if anywhere else.
	BOMPassAll            // No special handling of BOM.
	BOMPassFirst          // No special handling of BOM if at beginning, report as error if anywhere else.
)

const (
	NonASCII = 0x80 // DefaultRuneClass returns NonASCII for non ASCII runes.
	RuneEOF  = -1   // Distinct from any valid Unicode rune value.
)

// DefaultRuneClass returns the character class of r. If r is an ASCII code
// then its class equals the ASCII code. Any other rune is of class NonASCII.
//
// DefaultRuneClass is the default implementation Lexer will use to convert
// runes (21 bit entities) to scanner classes (8 bit entities).
//
// Non ASCII aware lexical analyzers will typically use their own
// categorization function. To assign such custom function use the RuneClass
// option.
func DefaultRuneClass(r rune) int {
	if r >= 0 && r < 0x80 {
		return int(r)
	}

	return NonASCII
}

// Char represents a rune and its position.
type Char struct {
	Rune rune
	pos  int32
}

// NewChar returns a new Char value.
func NewChar(pos token.Pos, r rune) Char { return Char{pos: int32(pos), Rune: r} }

// IsValid reports whether c is not a zero Char.
func (c Char) IsValid() bool { return c.Pos().IsValid() }

// Pos returns the token.Pos associated with c.
func (c Char) Pos() token.Pos { return token.Pos(c.pos) }

// Lexer suports golex[0] generated lexical analyzers.
type Lexer struct {
	File      *token.File             // The *token.File passed to New.
	First     Char                    // First remembers the lookahead char when Rule0 was invoked.
	Last      Char                    // Last remembers the last Char returned by Next.
	Prev      Char                    // Prev remembers the Char previous to Last.
	bomMode   int                     // See the BOM* constants.
	bytesBuf  bytes.Buffer            // Used by TokenBytes.
	classf    func(rune) int          //
	errorf    func(token.Pos, string) //
	lookahead Char                    // Lookahead if non zero.
	mark      int                     // Longest match marker.
	off       int                     // Used for File.AddLine.
	src       io.RuneReader           // Lexer input.
	tokenBuf  []Char                  // Lexeme collector.
	ungetBuf  []Char                  // Unget buffer.
}

// New returns a new *Lexer. The result can be amended using opts.
//
// Non Unicode Input
//
// To consume sources in other encodings and still have exact position
// information, pass an io.RuneReader which returns the next input character
// reencoded as an Unicode rune but returns the size (number of bytes used to
// encode it) of the original character, not the size of its UTF-8
// representation after converted to an Unicode rune.  Size is the second
// returned value of io.RuneReader.ReadRune method[4].
func New(file *token.File, src io.RuneReader, opts ...Option) (*Lexer, error) {
	r := &Lexer{
		File:    file,
		bomMode: BOMIgnoreFirst,
		classf:  DefaultRuneClass,
		src:     src,
	}
	r.errorf = r.defaultErrorf
	for _, o := range opts {
		if err := o(r); err != nil {
			return nil, err
		}
	}
	return r, nil
}

// Abort handles the situation when the scanner does not successfully recognize
// any token or when an attempt to find the longest match "overruns" from an
// accepting state only to never reach an accepting state again. In the first
// case the scanner was never in an accepting state since last call to Rule0
// and then (true, previousLookahead rune) is returned, effectively consuming a
// single Char token, avoiding scanner stall.  Otherwise there was at least one
// accepting scanner state marked using Mark. In this case Abort rollbacks the
// lexer state to the marked state and returns (false, 0). The scanner must
// then execute a prescribed goto statement. For example:
//
//	%yyc c
//	%yyn c = l.Next()
//	%yym l.Mark()
//
//	%{
//	package foo
//
//	import (...)
//
//	type lexer struct {
//		*lex.Lexer
//		...
//	}
//
//	func newLexer(...) *lexer {
//		return &lexer{
//			lex.NewLexer(...),
//			...
//		}
//	}
//
//	func (l *lexer) scan() int {
//	        c := l.Enter()
//	%}
//
//	... more lex defintions
//
//	%%
//
//	        c = l.Rule0()
//
//	... lex rules
//
//	%%
//
//		if c, ok := l.Abort(); ok {
//			return c
//		}
//
//		goto yyAction
//	}
func (l *Lexer) Abort() (int, bool) {
	if l.mark >= 0 {
		if len(l.tokenBuf) > l.mark {
			l.Unget(l.lookahead)
			for i := len(l.tokenBuf) - 1; i >= l.mark; i-- {
				l.Unget(l.tokenBuf[i])
			}
		}
		l.tokenBuf = l.tokenBuf[:l.mark]
		return 0, false
	}

	switch n := len(l.tokenBuf); n {
	case 0: // [] z
		c := l.lookahead
		l.Next()
		return int(c.Rune), true
	case 1: // [a] z
		return int(l.tokenBuf[0].Rune), true
	default: // [a, b, ...], z
		c := l.tokenBuf[0]   // a
		l.Unget(l.lookahead) // z
		for i := n - 1; i > 1; i-- {
			l.Unget(l.tokenBuf[i]) // ...
		}
		l.lookahead = l.tokenBuf[1] // b
		l.tokenBuf = l.tokenBuf[:1]
		return int(c.Rune), true
	}
}

func (l *Lexer) class() int { return l.classf(l.lookahead.Rune) }

func (l *Lexer) defaultErrorf(pos token.Pos, msg string) {
	l.Error(fmt.Sprintf("%v: %v", l.File.Position(pos), msg))
}

// Enter ensures the lexer has a valid lookahead Char and returns its class.
// Typical use in an .l file
//
//	func (l *lexer) scan() lex.Char {
//		c := l.Enter()
//		...
func (l *Lexer) Enter() int {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.class()
}

// Error Implements yyLexer[2] by printing the msg to stderr.
func (l *Lexer) Error(msg string) {
	fmt.Fprintf(os.Stderr, "%s\n", msg)
}

// Lookahead returns the current lookahead.
func (l *Lexer) Lookahead() Char {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.lookahead
}

// Mark records the current state of scanner as accepting. It implements the
// golex macro %yym. Typical usage in an .l file:
//
//	%yym l.Mark()
func (l *Lexer) Mark() { l.mark = len(l.tokenBuf) }

func (l *Lexer) next() int {
	const bom = '\ufeff'

	if c := l.lookahead; c.IsValid() {
		l.tokenBuf = append(l.tokenBuf, c)
	}
	if n := len(l.ungetBuf); n != 0 {
		l.lookahead = l.ungetBuf[n-1]
		l.ungetBuf = l.ungetBuf[:n-1]
		return l.class()
	}

	if l.src == nil {
		return RuneEOF
	}

	var r rune
	var sz int
	var err error
	var pos token.Pos
again:
	r, sz, err = l.src.ReadRune()
	off0 := l.off
	pos = l.File.Pos(l.off)
	l.off += sz
	if err != nil {
		l.src = nil
		r = RuneEOF
		if err != io.EOF {
			l.errorf(pos, err.Error())
		}
	}

	if r == bom {
		switch l.bomMode {
		default:
			fallthrough
		case BOMIgnoreFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		case BOMPassAll:
			// nop
		case BOMPassFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
				goto again
			}
		case BOMError:
			switch {
			case off0 == 0:
				l.errorf(pos, "unicode (UTF-8) BOM at beginnig of file")
			default:
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		}
	}

	l.lookahead = NewChar(pos, r)
	if r == '\n' {
		l.File.AddLine(l.off)
	}
	return l.class()
}

// Next advances the scanner for one rune and returns the respective character
// class of the new lookahead.  Typical usage in an .l file:
//
//	%yyn c = l.Next()
func (l *Lexer) Next() int {
	l.Prev = l.Last
	r := l.next()
	l.Last = l.lookahead
	return r
}

// Offset returns the current reading offset of the lexer's source.
func (l *Lexer) Offset() int { return l.off }

// Rule0 initializes the scanner state before the attempt to recognize a token
// starts. The token collecting buffer is cleared.  Rule0 records the current
// lookahead in l.First and returns its class.  Typical usage in an .l file:
//
//	... lex definitions
//
//	%%
//
//		c := l.Rule0()
//
//	first-pattern-regexp
func (l *Lexer) Rule0() int {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	l.First = l.lookahead
	l.mark = -1
	if len(l.tokenBuf) > 1<<18 { //DONE constant tuned
		l.tokenBuf = nil
	} else {
		l.tokenBuf = l.tokenBuf[:0]
	}
	return l.class()
}

// Token returns the currently collected token chars. The result is R/O.
func (l *Lexer) Token() []Char { return l.tokenBuf }

// TokenBytes returns the UTF-8 encoding of Token. If builder is not nil then
// it's called instead to build the encoded token byte value into the buffer
// passed to it.
//
// The Result is R/O.
func (l *Lexer) TokenBytes(builder func(*bytes.Buffer)) []byte {
	if len(l.bytesBuf.Bytes()) < 1<<18 { //DONE constant tuned
		l.bytesBuf.Reset()
	} else {
		l.bytesBuf = bytes.Buffer{}
	}
	switch {
	case builder != nil:
		builder(&l.bytesBuf)
	default:
		for _, c := range l.Token() {
			l.bytesBuf.WriteRune(c.Rune)
		}
	}
	return l.bytesBuf.Bytes()
}

// Unget unreads all chars in c.
func (l *Lexer) Unget(c ...Char) {
	for _, c := range c {
		l.ungetBuf = append(l.ungetBuf, c)
	}
	l.lookahead = Char{} // Must invalidate lookahead.
}

// Option is a function which can be passed as an optional argument to New.
type Option func(*Lexer) error

// BOMMode option selects how the lexer handles BOMs. See the BOM* constants for details.
func BOMMode(mode int) Option {
	return func(l *Lexer) error {
		l.bomMode = mode
		return nil
	}
}

// ErrorFunc option sets a function called when an, for example I/O error,
// occurs.  The default is to call Error with the position and message already
// formated as a string.
func ErrorFunc(f func(token.Pos, string)) Option {
	return func(l *Lexer) error {
		l.errorf = f
		return nil
	}
}

// RuneClass option sets the function used to convert runes to character
// classes.
func RuneClass(f func(rune) int) Option {
	return func(l *Lexer) error {
		l.classf = f
		return nil
	}
}
<commit_msg>lex: Introduce alternative lexer input: CharReader.<commit_after>// Copyright (c) 2015 The golex Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lex

import (
	"bytes"
	"fmt"
	"go/token"
	"io"
	"os"
)

// BOM handling modes which can be set by the BOMMode Option. Default is BOMIgnoreFirst.
const (
	BOMError       = iota // BOM is an error anywhere.
	BOMIgnoreFirst        // Skip BOM if at beginning, report as error if anywhere else.
	BOMPassAll            // No special handling of BOM.
	BOMPassFirst          // No special handling of BOM if at beginning, report as error if anywhere else.
)

const (
	NonASCII = 0x80 // DefaultRuneClass returns NonASCII for non ASCII runes.
	RuneEOF  = -1   // Distinct from any valid Unicode rune value.
)

// DefaultRuneClass returns the character class of r. If r is an ASCII code
// then its class equals the ASCII code. Any other rune is of class NonASCII.
//
// DefaultRuneClass is the default implementation Lexer will use to convert
// runes (21 bit entities) to scanner classes (8 bit entities).
//
// Non ASCII aware lexical analyzers will typically use their own
// categorization function. To assign such custom function use the RuneClass
// option.
func DefaultRuneClass(r rune) int {
	if r >= 0 && r < 0x80 {
		return int(r)
	}

	return NonASCII
}

// Char represents a rune and its position.
type Char struct {
	Rune rune
	pos  int32
}

// NewChar returns a new Char value.
func NewChar(pos token.Pos, r rune) Char { return Char{pos: int32(pos), Rune: r} }

// IsValid reports whether c is not a zero Char.
func (c Char) IsValid() bool { return c.Pos().IsValid() }

// Pos returns the token.Pos associated with c.
func (c Char) Pos() token.Pos { return token.Pos(c.pos) }

// CharReader is a RuneReader providing additionally explicit position
// information by returning a Char instead of a rune as its first result.
type CharReader interface {
	ReadChar() (c Char, size int, err error)
}

// Lexer suports golex[0] generated lexical analyzers.
type Lexer struct {
	File      *token.File             // The *token.File passed to New.
	First     Char                    // First remembers the lookahead char when Rule0 was invoked.
	Last      Char                    // Last remembers the last Char returned by Next.
	Prev      Char                    // Prev remembers the Char previous to Last.
	bomMode   int                     // See the BOM* constants.
	bytesBuf  bytes.Buffer            // Used by TokenBytes.
	charSrc   CharReader              // Lexer alternative input.
	classf    func(rune) int          //
	errorf    func(token.Pos, string) //
	lookahead Char                    // Lookahead if non zero.
	mark      int                     // Longest match marker.
	off       int                     // Used for File.AddLine.
	src       io.RuneReader           // Lexer input.
	tokenBuf  []Char                  // Lexeme collector.
	ungetBuf  []Char                  // Unget buffer.
}

// New returns a new *Lexer. The result can be amended using opts.
//
// Non Unicode Input
//
// To consume sources in other encodings and still have exact position
// information, pass an io.RuneReader which returns the next input character
// reencoded as an Unicode rune but returns the size (number of bytes used to
// encode it) of the original character, not the size of its UTF-8
// representation after converted to an Unicode rune.  Size is the second
// returned value of io.RuneReader.ReadRune method[4].
//
// When src optionally implements CharReader its ReadChar method is used
// instead of io.ReadRune.
func New(file *token.File, src io.RuneReader, opts ...Option) (*Lexer, error) {
	r := &Lexer{
		File:    file,
		bomMode: BOMIgnoreFirst,
		classf:  DefaultRuneClass,
		src:     src,
	}
	if x, ok := src.(CharReader); ok {
		r.charSrc = x
	}
	r.errorf = r.defaultErrorf
	for _, o := range opts {
		if err := o(r); err != nil {
			return nil, err
		}
	}
	return r, nil
}

// Abort handles the situation when the scanner does not successfully recognize
// any token or when an attempt to find the longest match "overruns" from an
// accepting state only to never reach an accepting state again. In the first
// case the scanner was never in an accepting state since last call to Rule0
// and then (true, previousLookahead rune) is returned, effectively consuming a
// single Char token, avoiding scanner stall.  Otherwise there was at least one
// accepting scanner state marked using Mark. In this case Abort rollbacks the
// lexer state to the marked state and returns (false, 0). The scanner must
// then execute a prescribed goto statement. For example:
//
//	%yyc c
//	%yyn c = l.Next()
//	%yym l.Mark()
//
//	%{
//	package foo
//
//	import (...)
//
//	type lexer struct {
//		*lex.Lexer
//		...
//	}
//
//	func newLexer(...) *lexer {
//		return &lexer{
//			lex.NewLexer(...),
//			...
//		}
//	}
//
//	func (l *lexer) scan() int {
//	        c := l.Enter()
//	%}
//
//	... more lex defintions
//
//	%%
//
//	        c = l.Rule0()
//
//	... lex rules
//
//	%%
//
//		if c, ok := l.Abort(); ok {
//			return c
//		}
//
//		goto yyAction
//	}
func (l *Lexer) Abort() (int, bool) {
	if l.mark >= 0 {
		if len(l.tokenBuf) > l.mark {
			l.Unget(l.lookahead)
			for i := len(l.tokenBuf) - 1; i >= l.mark; i-- {
				l.Unget(l.tokenBuf[i])
			}
		}
		l.tokenBuf = l.tokenBuf[:l.mark]
		return 0, false
	}

	switch n := len(l.tokenBuf); n {
	case 0: // [] z
		c := l.lookahead
		l.Next()
		return int(c.Rune), true
	case 1: // [a] z
		return int(l.tokenBuf[0].Rune), true
	default: // [a, b, ...], z
		c := l.tokenBuf[0]   // a
		l.Unget(l.lookahead) // z
		for i := n - 1; i > 1; i-- {
			l.Unget(l.tokenBuf[i]) // ...
		}
		l.lookahead = l.tokenBuf[1] // b
		l.tokenBuf = l.tokenBuf[:1]
		return int(c.Rune), true
	}
}

func (l *Lexer) class() int { return l.classf(l.lookahead.Rune) }

func (l *Lexer) defaultErrorf(pos token.Pos, msg string) {
	l.Error(fmt.Sprintf("%v: %v", l.File.Position(pos), msg))
}

// Enter ensures the lexer has a valid lookahead Char and returns its class.
// Typical use in an .l file
//
//	func (l *lexer) scan() lex.Char {
//		c := l.Enter()
//		...
func (l *Lexer) Enter() int {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.class()
}

// Error Implements yyLexer[2] by printing the msg to stderr.
func (l *Lexer) Error(msg string) {
	fmt.Fprintf(os.Stderr, "%s\n", msg)
}

// Lookahead returns the current lookahead.
func (l *Lexer) Lookahead() Char {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	return l.lookahead
}

// Mark records the current state of scanner as accepting. It implements the
// golex macro %yym. Typical usage in an .l file:
//
//	%yym l.Mark()
func (l *Lexer) Mark() { l.mark = len(l.tokenBuf) }

func (l *Lexer) next() int {
	const bom = '\ufeff'

	if c := l.lookahead; c.IsValid() {
		l.tokenBuf = append(l.tokenBuf, c)
	}
	if n := len(l.ungetBuf); n != 0 {
		l.lookahead = l.ungetBuf[n-1]
		l.ungetBuf = l.ungetBuf[:n-1]
		return l.class()
	}

	if l.src == nil {
		return RuneEOF
	}

	var r rune
	var sz int
	var err error
	var pos token.Pos
	var c Char
again:
	off0 := l.off
	switch cs := l.charSrc; {
	case cs != nil:
		c, sz, err = cs.ReadChar()
		r = c.Rune
		pos = c.Pos()
	default:
		r, sz, err = l.src.ReadRune()
		pos = l.File.Pos(l.off)
	}
	l.off += sz
	if err != nil {
		l.src = nil
		r = RuneEOF
		if err != io.EOF {
			l.errorf(pos, err.Error())
		}
	}

	if r == bom {
		switch l.bomMode {
		default:
			fallthrough
		case BOMIgnoreFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		case BOMPassAll:
			// nop
		case BOMPassFirst:
			if off0 != 0 {
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
				goto again
			}
		case BOMError:
			switch {
			case off0 == 0:
				l.errorf(pos, "unicode (UTF-8) BOM at beginnig of file")
			default:
				l.errorf(pos, "unicode (UTF-8) BOM in middle of file")
			}
			goto again
		}
	}

	l.lookahead = NewChar(pos, r)
	if r == '\n' {
		l.File.AddLine(l.off)
	}
	return l.class()
}

// Next advances the scanner for one rune and returns the respective character
// class of the new lookahead.  Typical usage in an .l file:
//
//	%yyn c = l.Next()
func (l *Lexer) Next() int {
	l.Prev = l.Last
	r := l.next()
	l.Last = l.lookahead
	return r
}

// Offset returns the current reading offset of the lexer's source.
func (l *Lexer) Offset() int { return l.off }

// Rule0 initializes the scanner state before the attempt to recognize a token
// starts. The token collecting buffer is cleared.  Rule0 records the current
// lookahead in l.First and returns its class.  Typical usage in an .l file:
//
//	... lex definitions
//
//	%%
//
//		c := l.Rule0()
//
//	first-pattern-regexp
func (l *Lexer) Rule0() int {
	if !l.lookahead.IsValid() {
		l.Next()
	}
	l.First = l.lookahead
	l.mark = -1
	if len(l.tokenBuf) > 1<<18 { //DONE constant tuned
		l.tokenBuf = nil
	} else {
		l.tokenBuf = l.tokenBuf[:0]
	}
	return l.class()
}

// Token returns the currently collected token chars. The result is R/O.
func (l *Lexer) Token() []Char { return l.tokenBuf }

// TokenBytes returns the UTF-8 encoding of Token. If builder is not nil then
// it's called instead to build the encoded token byte value into the buffer
// passed to it.
//
// The Result is R/O.
func (l *Lexer) TokenBytes(builder func(*bytes.Buffer)) []byte {
	if len(l.bytesBuf.Bytes()) < 1<<18 { //DONE constant tuned
		l.bytesBuf.Reset()
	} else {
		l.bytesBuf = bytes.Buffer{}
	}
	switch {
	case builder != nil:
		builder(&l.bytesBuf)
	default:
		for _, c := range l.Token() {
			l.bytesBuf.WriteRune(c.Rune)
		}
	}
	return l.bytesBuf.Bytes()
}

// Unget unreads all chars in c.
func (l *Lexer) Unget(c ...Char) {
	for _, c := range c {
		l.ungetBuf = append(l.ungetBuf, c)
	}
	l.lookahead = Char{} // Must invalidate lookahead.
}

// Option is a function which can be passed as an optional argument to New.
type Option func(*Lexer) error

// BOMMode option selects how the lexer handles BOMs. See the BOM* constants for details.
func BOMMode(mode int) Option {
	return func(l *Lexer) error {
		l.bomMode = mode
		return nil
	}
}

// ErrorFunc option sets a function called when an, for example I/O error,
// occurs.  The default is to call Error with the position and message already
// formated as a string.
func ErrorFunc(f func(token.Pos, string)) Option {
	return func(l *Lexer) error {
		l.errorf = f
		return nil
	}
}

// RuneClass option sets the function used to convert runes to character
// classes.
func RuneClass(f func(rune) int) Option {
	return func(l *Lexer) error {
		l.classf = f
		return nil
	}
}
<|endoftext|>


<commit_before>package instrumentedsql

import (
	"database/sql"
	"context"
	"log"

	"github.com/go-sql-driver/mysql"
	"github.com/ExpansiveWorlds/instrumentedsql/google"
	"github.com/ExpansiveWorlds/instrumentedsql/opentracing"
)

// WrapDriverGoogle demonstrates how to call wrapDriver and register a new driver.
// This example uses MySQL and google tracing to illustrate this
func ExampleWrapDriver_google() {
	logger := func(ctx context.Context, msg string, keyvals ...interface{}) {
		log.Printf("%s %v", msg, keyvals)
	}

	sql.Register("instrumented-mysql", WrapDriver(mysql.MySQLDriver{}, WithTracer(google.NewTracer()), WithLogger(NewFuncLogger(logger))))
	db, err := sql.Open("instrumented-mysql", "connString")

	// Proceed to handle connection errors and use the database as usual
	_, _ = db, err
}

// WrapDriverOpentracing demonstrates how to call wrapDriver and register a new driver.
// This example uses MySQL and opentracing to illustrate this
func ExampleWrapDriver_opentracing() {
	logger := func(ctx context.Context, msg string, keyvals ...interface{}) {
		log.Printf("%s %v", msg, keyvals)
	}

	sql.Register("instrumented-mysql", WrapDriver(mysql.MySQLDriver{}, WithTracer(opentracing.NewTracer()), WithLogger(NewFuncLogger(logger))))
	db, err := sql.Open("instrumented-mysql", "connString")

	// Proceed to handle connection errors and use the database as usual
	_, _ = db, err
}
<commit_msg>Add an example with just logging and no tracing<commit_after>package instrumentedsql

import (
	"database/sql"
	"context"
	"log"

	"github.com/go-sql-driver/mysql"
	"github.com/ExpansiveWorlds/instrumentedsql/google"
	"github.com/ExpansiveWorlds/instrumentedsql/opentracing"
)

// WrapDriverGoogle demonstrates how to call wrapDriver and register a new driver.
// This example uses MySQL and google tracing to illustrate this
func ExampleWrapDriver_google() {
	logger := func(ctx context.Context, msg string, keyvals ...interface{}) {
		log.Printf("%s %v", msg, keyvals)
	}

	sql.Register("instrumented-mysql", WrapDriver(mysql.MySQLDriver{}, WithTracer(google.NewTracer()), WithLogger(NewFuncLogger(logger))))
	db, err := sql.Open("instrumented-mysql", "connString")

	// Proceed to handle connection errors and use the database as usual
	_, _ = db, err
}

// WrapDriverOpentracing demonstrates how to call wrapDriver and register a new driver.
// This example uses MySQL and opentracing to illustrate this
func ExampleWrapDriver_opentracing() {
	logger := func(ctx context.Context, msg string, keyvals ...interface{}) {
		log.Printf("%s %v", msg, keyvals)
	}

	sql.Register("instrumented-mysql", WrapDriver(mysql.MySQLDriver{}, WithTracer(opentracing.NewTracer()), WithLogger(NewFuncLogger(logger))))
	db, err := sql.Open("instrumented-mysql", "connString")

	// Proceed to handle connection errors and use the database as usual
	_, _ = db, err
}

// WrapDriverJustLogging demonstrates how to call wrapDriver and register a new driver.
// This example uses MySQL, but does not trace, but merely logs all calls
func ExampleWrapDriver_justLogging() {
	logger := func(ctx context.Context, msg string, keyvals ...interface{}) {
		log.Printf("%s %v", msg, keyvals)
	}

	sql.Register("instrumented-mysql", WrapDriver(mysql.MySQLDriver{}, WithLogger(NewFuncLogger(logger))))
}<|endoftext|>


<commit_before>package cheshire

import (
	"bufio"
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"sync"
)

type WebsocketWriter struct {
	conn       *websocket.Conn
	writerLock sync.Mutex
}

func (this *WebsocketWriter) Write(response *Response) (int, error) {
	json, err := json.Marshal(response)
	if err != nil {
		//TODO: uhh, do something..
		log.Print(err)
	}
	// log.Println("writing ", string(json))
	defer this.writerLock.Unlock()
	this.writerLock.Lock()
	bytes, err := this.conn.Write(json)
	return bytes, err
}

func (this *WebsocketWriter) Type() string {
	return "websocket"
}

type WebsocketController struct {
	Conf         *ControllerConfig
	Handler      websocket.Handler
	serverConfig *ServerConfig
}

func (wc WebsocketController) Config() *ControllerConfig {
	return wc.Conf
}
func (wc WebsocketController) HandleRequest(txn *Txn) {
	//do nothing, this should never be called.
	log.Println("ERROR! Websocket Controller HandleRequest should never execute")
}

func NewWebsocketController(route string, config *ServerConfig) *WebsocketController {
	ws := &WebsocketController{
		Conf : NewControllerConfig(route),
		serverConfig : config,
	}
	ws.Handler = websocket.Handler(func(con *websocket.Conn) { ws.HandleWCConnection(con) })
	return ws
}

// implements the HttpHijacker interface so we can handle the request directly.
func (this *WebsocketController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	this.Handler.ServeHTTP(writer, req)
}

func (this *WebsocketController) HandleWCConnection(ws *websocket.Conn) {
	// Uhh, guessing we are already in a go routine..
	log.Print("CONNECT!")

	defer ws.Close()
	// log.Print("CONNECT!")
	// conn.writer = bufio.NewWriter(conn.conn)

	dec := json.NewDecoder(bufio.NewReader(ws))
	writer := &WebsocketWriter{conn: ws}
	for {
		var req Request
		err := dec.Decode(&req)

		if err == io.EOF {
			log.Print(err)
			break
		} else if err != nil {
			log.Print(err)
			break
		}
		log.Print(req)
		log.Print(req.Uri())
		controller := this.serverConfig.Router.Match(req.Method(), req.Uri())

		log.Print("GOT CONTROLLER ")
		log.Print(controller)

		go HandleRequest(&req, writer, controller, this.serverConfig)
	}
	log.Print("DISCONNECT!")
}
<commit_msg>remove some egregious logging<commit_after>package cheshire

import (
	"bufio"
	"code.google.com/p/go.net/websocket"
	"encoding/json"
	"io"
	"log"
	"net/http"
	"sync"
)

type WebsocketWriter struct {
	conn       *websocket.Conn
	writerLock sync.Mutex
}

func (this *WebsocketWriter) Write(response *Response) (int, error) {
	json, err := json.Marshal(response)
	if err != nil {
		//TODO: uhh, do something..
		log.Print(err)
	}
	// log.Println("writing ", string(json))
	defer this.writerLock.Unlock()
	this.writerLock.Lock()
	bytes, err := this.conn.Write(json)
	return bytes, err
}

func (this *WebsocketWriter) Type() string {
	return "websocket"
}

type WebsocketController struct {
	Conf         *ControllerConfig
	Handler      websocket.Handler
	serverConfig *ServerConfig
}

func (wc WebsocketController) Config() *ControllerConfig {
	return wc.Conf
}
func (wc WebsocketController) HandleRequest(txn *Txn) {
	//do nothing, this should never be called.
	log.Println("ERROR! Websocket Controller HandleRequest should never execute")
}

func NewWebsocketController(route string, config *ServerConfig) *WebsocketController {
	ws := &WebsocketController{
		Conf : NewControllerConfig(route),
		serverConfig : config,
	}
	ws.Handler = websocket.Handler(func(con *websocket.Conn) { ws.HandleWCConnection(con) })
	return ws
}

// implements the HttpHijacker interface so we can handle the request directly.
func (this *WebsocketController) HttpHijack(writer http.ResponseWriter, req *http.Request, serverConfig *ServerConfig) {
	this.Handler.ServeHTTP(writer, req)
}

func (this *WebsocketController) HandleWCConnection(ws *websocket.Conn) {
	// Uhh, guessing we are already in a go routine..
	log.Print("CONNECT!")

	defer ws.Close()
	// log.Print("CONNECT!")
	// conn.writer = bufio.NewWriter(conn.conn)

	dec := json.NewDecoder(bufio.NewReader(ws))
	writer := &WebsocketWriter{conn: ws}
	for {
		var req Request
		err := dec.Decode(&req)

		if err == io.EOF {
			log.Print(err)
			break
		} else if err != nil {
			log.Print(err)
			break
		}
		controller := this.serverConfig.Router.Match(req.Method(), req.Uri())
		go HandleRequest(&req, writer, controller, this.serverConfig)
	}
	log.Print("DISCONNECT!")
}
<|endoftext|>


<commit_before>package sms

import (
	"fmt"
	"github.com/kevinburke/twilio-go"
	"strings"
	"time"
)

type TwilioSMS struct {
	To string
	Body string
}

func GenerateTwilioErrorSMS(errs []error, service string) []*TwilioSMS {

	var smsArr []*TwilioSMS
	for _, recipient := range conf.To {

		var lines = []string{
			"Dear Admin,",
			"An error with the service " + strings.ToUpper(service) + " occurred:",
			"Timestamp: " + time.Now().Format(timestampFormat),
		}
		if len(errs) > 0 {
			lines = append(lines, "Errors: ")
			for _, e := range errs {
				lines = append(lines, e.Error())
			}
		}
		smsArr = append(smsArr, &TwilioSMS{
			To:      recipient,
			Body: strings.Join(lines, "\n"),
		})
	}

	return smsArr
}

func GenerateTwilioResolvedSMS(service string) []*TwilioSMS {

	var smsArr []*TwilioSMS
	for _, recipient := range conf.To {

		var lines = []string{
			"Dear Admin,",
			"service " + strings.ToUpper(service) + " is back to normal operation",
			"Timestamp: " + time.Now().Format(timestampFormat),
		}
		smsArr = append(smsArr, &TwilioSMS{
			To:      recipient,
			Body: strings.Join(lines, "\n"),
		})
	}

	return smsArr
}

func SendTwilioSMS(sms []*TwilioSMS) {

	client := twilio.NewClient(conf.TwilioSID, conf.TwilioToken, nil)
	for _, s := range sms {

		// Send a message
		_, err := client.Messages.SendMessage(conf.From, s.To, s.Body, nil)
		if err != nil {
			fmt.Println(err)
		}
		//fmt.Println(msg.Status)
	}
}
<commit_msg>update log message for failed twilio sms<commit_after>package sms

import (
	"github.com/kevinburke/twilio-go"
	"log"
	"strings"
	"time"
)

type TwilioSMS struct {
	To string
	Body string
}

func GenerateTwilioErrorSMS(errs []error, service string) []*TwilioSMS {

	var smsArr []*TwilioSMS
	for _, recipient := range conf.To {

		var lines = []string{
			"Dear Admin,",
			"An error with the service " + strings.ToUpper(service) + " occurred:",
			"Timestamp: " + time.Now().Format(timestampFormat),
		}
		if len(errs) > 0 {
			lines = append(lines, "Errors: ")
			for _, e := range errs {
				lines = append(lines, e.Error())
			}
		}
		smsArr = append(smsArr, &TwilioSMS{
			To:      recipient,
			Body: strings.Join(lines, "\n"),
		})
	}

	return smsArr
}

func GenerateTwilioResolvedSMS(service string) []*TwilioSMS {

	var smsArr []*TwilioSMS
	for _, recipient := range conf.To {

		var lines = []string{
			"Dear Admin,",
			"service " + strings.ToUpper(service) + " is back to normal operation",
			"Timestamp: " + time.Now().Format(timestampFormat),
		}
		smsArr = append(smsArr, &TwilioSMS{
			To:      recipient,
			Body: strings.Join(lines, "\n"),
		})
	}

	return smsArr
}

func SendTwilioSMS(sms []*TwilioSMS) {

	client := twilio.NewClient(conf.TwilioSID, conf.TwilioToken, nil)
	for _, s := range sms {

		// Send a message
		_, err := client.Messages.SendMessage(conf.From, s.To, s.Body, nil)
		if err != nil {
			log.Println("sending twilio sms failed:", err)
		}
		//fmt.Println(msg.Status)
	}
}
<|endoftext|>


<commit_before>package disruptor

type Writer struct {
	previous      int64
	gate          int64
	writerCursor  *Cursor
	ringSize      int64
	readerBarrier Barrier
}

func NewWriter(writerCursor *Cursor, ringSize int32, readerBarrier Barrier) *Writer {
	if !isPowerOfTwo(ringSize) {
		panic("The ring size must be a power of two, e.g. 2, 4, 8, 16, 32, 64, etc.")
	}

	return &Writer{
		previous:      writerCursor.Load(), // show the Go runtime that the cursor is actually used
		gate:          writerCursor.Load(), // and that it should not be optimized away
		writerCursor:  writerCursor,
		ringSize:      int64(ringSize),
		readerBarrier: readerBarrier,
	}
}

func isPowerOfTwo(value int32) bool {
	return value > 0 && (value&(value-1)) == 0
}

func (this *Writer) Reserve(items int64) int64 {
	next := this.previous + items
	wrap := next - this.ringSize

	if wrap > this.gate {
		min := this.readerBarrier.Load() // TODO: the most expensive call
		if wrap > min {
			return Gating
		}

		this.gate = min
	}

	this.previous = next
	return next
}
<commit_msg>Completed TODO.<commit_after>package disruptor

type Writer struct {
	previous      int64
	gate          int64
	writerCursor  *Cursor
	ringSize      int64
	readerBarrier Barrier
}

func NewWriter(writerCursor *Cursor, ringSize int32, readerBarrier Barrier) *Writer {
	if !isPowerOfTwo(ringSize) {
		panic("The ring size must be a power of two, e.g. 2, 4, 8, 16, 32, 64, etc.")
	}

	return &Writer{
		previous:      writerCursor.Load(), // show the Go runtime that the cursor is actually used
		gate:          writerCursor.Load(), // and that it should not be optimized away
		writerCursor:  writerCursor,
		ringSize:      int64(ringSize),
		readerBarrier: readerBarrier,
	}
}

func isPowerOfTwo(value int32) bool {
	return value > 0 && (value&(value-1)) == 0
}

func (this *Writer) Reserve(items int64) int64 {
	next := this.previous + items
	wrap := next - this.ringSize

	if wrap > this.gate {
		min := this.readerBarrier.Load()
		if wrap > min {
			return Gating
		}

		this.gate = min
	}

	this.previous = next
	return next
}
<|endoftext|>


<commit_before>package logger

import (
	"io"
	"os"
)

type ioWriterMsgWriter struct {
	w io.Writer
}

func (iw *ioWriterMsgWriter) Write(msg Msg) error {
	_, err := iw.w.Write(msg.Bytes())
	return err
}

func (iw *ioWriterMsgWriter) Close() error {
	return nil
}

// Error ouput, usefull for testing.
var stderr io.Writer = os.Stderr

// NewConsole creates a new logger that writes to error output (os.Stderr).
func NewConsole(name string) (*Logger, error) {
	mw := &ioWriterMsgWriter{stderr}
	return New(name, mw)
}

<commit_msg>Add NewWriter<commit_after>package logger

import (
	"io"
	"os"
)

type ioWriterMsgWriter struct {
	w io.Writer
}

func (iw *ioWriterMsgWriter) Write(msg Msg) error {
	_, err := iw.w.Write(msg.Bytes())
	return err
}

func (iw *ioWriterMsgWriter) Close() error {
	return nil
}

// NewWriter creates a new logger that writes to the given io.Writer.
func NewWriter(name string, w io.Writer) (*Logger, error) {
	mw := &ioWriterMsgWriter{w}
	return New(name, mw)
}

// Error ouput, usefull for testing.
var stderr io.Writer = os.Stderr

// NewConsole creates a new logger that writes to error output (os.Stderr).
func NewConsole(name string) (*Logger, error) {
	return NewWriter(name, stderr)
}
<|endoftext|>


<commit_before>package quicktemplate

import (
	"fmt"
	"io"
	"strconv"
	"sync"
)

// Writer implements auxiliary writer used by quicktemplate functions.
//
// Use AcquireWriter for creating new writers.
type Writer struct {
	e QWriter
	n QWriter
}

// W returns the underlying writer passed to AcquireWriter.
func (qw *Writer) W() io.Writer {
	return qw.n.w
}

// E returns QWriter with enabled html escaping.
func (qw *Writer) E() *QWriter {
	return &qw.e
}

// N returns QWriter without html escaping.
func (qw *Writer) N() *QWriter {
	return &qw.n
}

// AcquireWriter returns new writer from the pool.
//
// Return unneeded writer to the pool by calling ReleaseWriter
// in order to reduce memory allocations.
func AcquireWriter(w io.Writer) *Writer {
	v := writerPool.Get()
	if v == nil {
		v = &Writer{}
	}
	qw := v.(*Writer)
	qw.e.w = acquireHTMLEscapeWriter(w)
	qw.n.w = w
	return qw
}

// ReleaseWriter returns the writer to the pool.
//
// Do not access released writer, otherwise data races may occur.
func ReleaseWriter(qw *Writer) {
	releaseHTMLEscapeWriter(qw.e.w)
	qw.e.w = nil
	qw.n.w = nil
	writerPool.Put(qw)
}

var writerPool sync.Pool

// QWriter is auxiliary writer used by Writer.
type QWriter struct {
	w io.Writer
}

// S writes s to w.
func (w *QWriter) S(s string) {
	w.w.Write(unsafeStrToBytes(s))
}

// Z writes z to w.
func (w *QWriter) Z(z []byte) {
	w.w.Write(z)
}

// SZ is a synonym to Z.
func (w *QWriter) SZ(z []byte) {
	w.w.Write(z)
}

// D writes n to w.
func (w *QWriter) D(n int) {
	writeQuick(w.w, func(dst []byte) []byte {
		return strconv.AppendInt(dst, int64(n), 10)
	})
}

// F writes f to w.
func (w *QWriter) F(f float64) {
	w.FPrec(f, -1)
}

// FPrec writes f to w using the given floating point precision.
func (w *QWriter) FPrec(f float64, prec int) {
	writeQuick(w.w, func(dst []byte) []byte {
		return strconv.AppendFloat(dst, f, 'f', prec, 64)
	})
}

// Q writes quoted json-safe s to w.
func (w *QWriter) Q(s string) {
	ww := w.w
	ww.Write(strQuote)
	writeJSONString(w.w, s)
	ww.Write(strQuote)
}

var strQuote = []byte(`"`)

// QZ writes quoted json-safe z to w.
func (w *QWriter) QZ(z []byte) {
	w.Q(unsafeBytesToStr(z))
}

// J writes json-safe s to w.
//
// Unlike Q it doesn't qoute resulting s.
func (w *QWriter) J(s string) {
	writeJSONString(w.w, s)
}

// JZ writes json-safe z to w.
//
// Unlike Q it doesn't qoute resulting z.
func (w *QWriter) JZ(z []byte) {
	w.J(unsafeBytesToStr(z))
}

// V writes v to w.
func (w *QWriter) V(v interface{}) {
	fmt.Fprintf(w.w, "%v", v)
}

// U writes url-encoded s to w.
func (w *QWriter) U(s string) {
	writeQuick(w.w, func(dst []byte) []byte {
		return appendURLEncode(dst, s)
	})
}

// UZ writes url-encoded z to w.
func (w *QWriter) UZ(z []byte) {
	w.U(unsafeBytesToStr(z))
}

func writeQuick(w io.Writer, f func(dst []byte) []byte) {
	bb, ok := w.(*ByteBuffer)
	if !ok {
		bb = AcquireByteBuffer()
	}
	bb.B = f(bb.B)
	if !ok {
		w.Write(bb.B)
		ReleaseByteBuffer(bb)
	}
}
<commit_msg>Stop sending data to the writer after the first error returned from it<commit_after>package quicktemplate

import (
	"fmt"
	"io"
	"strconv"
	"sync"
)

// Writer implements auxiliary writer used by quicktemplate functions.
//
// Use AcquireWriter for creating new writers.
type Writer struct {
	e QWriter
	n QWriter
}

// W returns the underlying writer passed to AcquireWriter.
func (qw *Writer) W() io.Writer {
	return qw.n.w
}

// E returns QWriter with enabled html escaping.
func (qw *Writer) E() *QWriter {
	return &qw.e
}

// N returns QWriter without html escaping.
func (qw *Writer) N() *QWriter {
	return &qw.n
}

// AcquireWriter returns new writer from the pool.
//
// Return unneeded writer to the pool by calling ReleaseWriter
// in order to reduce memory allocations.
func AcquireWriter(w io.Writer) *Writer {
	v := writerPool.Get()
	if v == nil {
		v = &Writer{}
	}
	qw := v.(*Writer)
	qw.e.w = acquireHTMLEscapeWriter(w)
	qw.n.w = w
	return qw
}

// ReleaseWriter returns the writer to the pool.
//
// Do not access released writer, otherwise data races may occur.
func ReleaseWriter(qw *Writer) {
	releaseHTMLEscapeWriter(qw.e.w)
	qw.e.Reset()
	qw.n.Reset()
	writerPool.Put(qw)
}

var writerPool sync.Pool

// QWriter is auxiliary writer used by Writer.
type QWriter struct {
	w   io.Writer
	err error
}

// Write implements io.Writer.
func (w *QWriter) Write(p []byte) (int, error) {
	if w.err != nil {
		return 0, w.err
	}
	n, err := w.w.Write(p)
	if err != nil {
		w.err = err
	}
	return n, err
}

// Reset resets QWriter to the original state.
func (w *QWriter) Reset() {
	w.w = nil
	w.err = nil
}

// S writes s to w.
func (w *QWriter) S(s string) {
	w.Write(unsafeStrToBytes(s))
}

// Z writes z to w.
func (w *QWriter) Z(z []byte) {
	w.Write(z)
}

// SZ is a synonym to Z.
func (w *QWriter) SZ(z []byte) {
	w.Write(z)
}

// D writes n to w.
func (w *QWriter) D(n int) {
	w.writeQuick(func(dst []byte) []byte {
		return strconv.AppendInt(dst, int64(n), 10)
	})
}

// F writes f to w.
func (w *QWriter) F(f float64) {
	w.FPrec(f, -1)
}

// FPrec writes f to w using the given floating point precision.
func (w *QWriter) FPrec(f float64, prec int) {
	w.writeQuick(func(dst []byte) []byte {
		return strconv.AppendFloat(dst, f, 'f', prec, 64)
	})
}

// Q writes quoted json-safe s to w.
func (w *QWriter) Q(s string) {
	w.Write(strQuote)
	writeJSONString(w, s)
	w.Write(strQuote)
}

var strQuote = []byte(`"`)

// QZ writes quoted json-safe z to w.
func (w *QWriter) QZ(z []byte) {
	w.Q(unsafeBytesToStr(z))
}

// J writes json-safe s to w.
//
// Unlike Q it doesn't qoute resulting s.
func (w *QWriter) J(s string) {
	writeJSONString(w, s)
}

// JZ writes json-safe z to w.
//
// Unlike Q it doesn't qoute resulting z.
func (w *QWriter) JZ(z []byte) {
	w.J(unsafeBytesToStr(z))
}

// V writes v to w.
func (w *QWriter) V(v interface{}) {
	fmt.Fprintf(w, "%v", v)
}

// U writes url-encoded s to w.
func (w *QWriter) U(s string) {
	w.writeQuick(func(dst []byte) []byte {
		return appendURLEncode(dst, s)
	})
}

// UZ writes url-encoded z to w.
func (w *QWriter) UZ(z []byte) {
	w.U(unsafeBytesToStr(z))
}

func (w *QWriter) writeQuick(f func(dst []byte) []byte) {
	if w.err != nil {
		return
	}
	bb, ok := w.w.(*ByteBuffer)
	if !ok {
		bb = AcquireByteBuffer()
	}
	bb.B = f(bb.B)
	if !ok {
		w.Write(bb.B)
		ReleaseByteBuffer(bb)
	}
}
<|endoftext|>


<commit_before>// Package snapshotgc implements garbage collection of contents that are no longer referenced through snapshots.
package snapshotgc

import (
	"context"
	"sync"
	"time"

	"github.com/pkg/errors"

	"github.com/kopia/kopia/fs"
	"github.com/kopia/kopia/internal/stats"
	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/repo/content"
	"github.com/kopia/kopia/repo/logging"
	"github.com/kopia/kopia/repo/maintenance"
	"github.com/kopia/kopia/repo/manifest"
	"github.com/kopia/kopia/repo/object"
	"github.com/kopia/kopia/snapshot"
	"github.com/kopia/kopia/snapshot/snapshotfs"
)

var log = logging.Module("snapshotgc")

func findInUseContentIDs(ctx context.Context, rep repo.Repository, used *sync.Map) error {
	ids, err := snapshot.ListSnapshotManifests(ctx, rep, nil, nil)
	if err != nil {
		return errors.Wrap(err, "unable to list snapshot manifest IDs")
	}

	manifests, err := snapshot.LoadSnapshots(ctx, rep, ids)
	if err != nil {
		return errors.Wrap(err, "unable to load manifest IDs")
	}

	w := snapshotfs.NewTreeWalker(snapshotfs.TreeWalkerOptions{
		EntryCallback: func(ctx context.Context, entry fs.Entry, oid object.ID, entryPath string) error {
			contentIDs, err := rep.VerifyObject(ctx, oid)
			if err != nil {
				return errors.Wrapf(err, "error verifying %v", oid)
			}

			for _, cid := range contentIDs {
				used.Store(cid, nil)
			}

			return nil
		},
	})
	defer w.Close()

	log(ctx).Infof("Looking for active contents...")

	for _, m := range manifests {
		root, err := snapshotfs.SnapshotRoot(rep, m)
		if err != nil {
			return errors.Wrap(err, "unable to get snapshot root")
		}

		if err := w.Process(ctx, root, ""); err != nil {
			return errors.Wrap(err, "error processing snapshot root")
		}
	}

	return nil
}

// Run performs garbage collection on all the snapshots in the repository.
func Run(ctx context.Context, rep repo.DirectRepositoryWriter, gcDelete bool, safety maintenance.SafetyParameters, maintenanceStartTime time.Time) (Stats, error) {
	var st Stats

	err := maintenance.ReportRun(ctx, rep, maintenance.TaskSnapshotGarbageCollection, nil, func() error {
		if err := runInternal(ctx, rep, gcDelete, safety, maintenanceStartTime, &st); err != nil {
			return err
		}

		l := log(ctx)

		l.Infof("GC found %v unused contents (%v bytes)", st.UnusedCount, units.BytesStringBase2(st.UnusedBytes))
		l.Infof("GC found %v unused contents that are too recent to delete (%v bytes)", st.TooRecentCount, units.BytesStringBase2(st.TooRecentBytes))
		l.Infof("GC found %v in-use contents (%v bytes)", st.InUseCount, units.BytesStringBase2(st.InUseBytes))
		l.Infof("GC found %v in-use system-contents (%v bytes)", st.SystemCount, units.BytesStringBase2(st.SystemBytes))

		if st.UnusedCount > 0 && !gcDelete {
			return errors.Errorf("Not deleting because 'gcDelete' was not set")
		}

		return nil
	})

	return st, errors.Wrap(err, "error running snapshot gc")
}

func runInternal(ctx context.Context, rep repo.DirectRepositoryWriter, gcDelete bool, safety maintenance.SafetyParameters, maintenanceStartTime time.Time, st *Stats) error {
	var (
		used sync.Map

		unused, inUse, system, tooRecent, undeleted stats.CountSum
	)

	if err := findInUseContentIDs(ctx, rep, &used); err != nil {
		return errors.Wrap(err, "unable to find in-use content ID")
	}

	log(ctx).Infof("Looking for unreferenced contents...")

	// Ensure that the iteration includes deleted contents, so those can be
	// undeleted (recovered).
	err := rep.ContentReader().IterateContents(ctx, content.IterateOptions{IncludeDeleted: true}, func(ci content.Info) error {
		if manifest.ContentPrefix == ci.GetContentID().Prefix() {
			system.Add(int64(ci.GetPackedLength()))
			return nil
		}

		if _, ok := used.Load(ci.GetContentID()); ok {
			if ci.GetDeleted() {
				if err := rep.ContentManager().UndeleteContent(ctx, ci.GetContentID()); err != nil {
					return errors.Wrapf(err, "Could not undelete referenced content: %v", ci)
				}
				undeleted.Add(int64(ci.GetPackedLength()))
			}

			inUse.Add(int64(ci.GetPackedLength()))

			return nil
		}

		if maintenanceStartTime.Sub(ci.Timestamp()) < safety.MinContentAgeSubjectToGC {
			log(ctx).Debugf("recent unreferenced content %v (%v bytes, modified %v)", ci.GetContentID(), ci.GetPackedLength(), ci.Timestamp())
			tooRecent.Add(int64(ci.GetPackedLength()))

			return nil
		}

		log(ctx).Debugf("unreferenced %v (%v bytes, modified %v)", ci.GetContentID(), ci.GetPackedLength(), ci.Timestamp())
		cnt, totalSize := unused.Add(int64(ci.GetPackedLength()))

		if gcDelete {
			if err := rep.ContentManager().DeleteContent(ctx, ci.GetContentID()); err != nil {
				return errors.Wrap(err, "error deleting content")
			}
		}

		if cnt%100000 == 0 {
			log(ctx).Infof("... found %v unused contents so far (%v bytes)", cnt, units.BytesStringBase2(totalSize))
			if gcDelete {
				if err := rep.Flush(ctx); err != nil {
					return errors.Wrap(err, "flush error")
				}
			}
		}

		return nil
	})

	st.UnusedCount, st.UnusedBytes = unused.Approximate()
	st.InUseCount, st.InUseBytes = inUse.Approximate()
	st.SystemCount, st.SystemBytes = system.Approximate()
	st.TooRecentCount, st.TooRecentBytes = tooRecent.Approximate()
	st.UndeletedCount, st.UndeletedBytes = undeleted.Approximate()

	if err != nil {
		return errors.Wrap(err, "error iterating contents")
	}

	return errors.Wrap(rep.Flush(ctx), "flush error")
}
<commit_msg>fix(cli): content sizes are already suffixed, so 'bytes' in the string is redundant (#2209)<commit_after>// Package snapshotgc implements garbage collection of contents that are no longer referenced through snapshots.
package snapshotgc

import (
	"context"
	"sync"
	"time"

	"github.com/pkg/errors"

	"github.com/kopia/kopia/fs"
	"github.com/kopia/kopia/internal/stats"
	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/repo"
	"github.com/kopia/kopia/repo/content"
	"github.com/kopia/kopia/repo/logging"
	"github.com/kopia/kopia/repo/maintenance"
	"github.com/kopia/kopia/repo/manifest"
	"github.com/kopia/kopia/repo/object"
	"github.com/kopia/kopia/snapshot"
	"github.com/kopia/kopia/snapshot/snapshotfs"
)

var log = logging.Module("snapshotgc")

func findInUseContentIDs(ctx context.Context, rep repo.Repository, used *sync.Map) error {
	ids, err := snapshot.ListSnapshotManifests(ctx, rep, nil, nil)
	if err != nil {
		return errors.Wrap(err, "unable to list snapshot manifest IDs")
	}

	manifests, err := snapshot.LoadSnapshots(ctx, rep, ids)
	if err != nil {
		return errors.Wrap(err, "unable to load manifest IDs")
	}

	w := snapshotfs.NewTreeWalker(snapshotfs.TreeWalkerOptions{
		EntryCallback: func(ctx context.Context, entry fs.Entry, oid object.ID, entryPath string) error {
			contentIDs, err := rep.VerifyObject(ctx, oid)
			if err != nil {
				return errors.Wrapf(err, "error verifying %v", oid)
			}

			for _, cid := range contentIDs {
				used.Store(cid, nil)
			}

			return nil
		},
	})
	defer w.Close()

	log(ctx).Infof("Looking for active contents...")

	for _, m := range manifests {
		root, err := snapshotfs.SnapshotRoot(rep, m)
		if err != nil {
			return errors.Wrap(err, "unable to get snapshot root")
		}

		if err := w.Process(ctx, root, ""); err != nil {
			return errors.Wrap(err, "error processing snapshot root")
		}
	}

	return nil
}

// Run performs garbage collection on all the snapshots in the repository.
func Run(ctx context.Context, rep repo.DirectRepositoryWriter, gcDelete bool, safety maintenance.SafetyParameters, maintenanceStartTime time.Time) (Stats, error) {
	var st Stats

	err := maintenance.ReportRun(ctx, rep, maintenance.TaskSnapshotGarbageCollection, nil, func() error {
		if err := runInternal(ctx, rep, gcDelete, safety, maintenanceStartTime, &st); err != nil {
			return err
		}

		l := log(ctx)

		l.Infof("GC found %v unused contents (%v)", st.UnusedCount, units.BytesStringBase2(st.UnusedBytes))
		l.Infof("GC found %v unused contents that are too recent to delete (%v)", st.TooRecentCount, units.BytesStringBase2(st.TooRecentBytes))
		l.Infof("GC found %v in-use contents (%v)", st.InUseCount, units.BytesStringBase2(st.InUseBytes))
		l.Infof("GC found %v in-use system-contents (%v)", st.SystemCount, units.BytesStringBase2(st.SystemBytes))

		if st.UnusedCount > 0 && !gcDelete {
			return errors.Errorf("Not deleting because 'gcDelete' was not set")
		}

		return nil
	})

	return st, errors.Wrap(err, "error running snapshot gc")
}

func runInternal(ctx context.Context, rep repo.DirectRepositoryWriter, gcDelete bool, safety maintenance.SafetyParameters, maintenanceStartTime time.Time, st *Stats) error {
	var (
		used sync.Map

		unused, inUse, system, tooRecent, undeleted stats.CountSum
	)

	if err := findInUseContentIDs(ctx, rep, &used); err != nil {
		return errors.Wrap(err, "unable to find in-use content ID")
	}

	log(ctx).Infof("Looking for unreferenced contents...")

	// Ensure that the iteration includes deleted contents, so those can be
	// undeleted (recovered).
	err := rep.ContentReader().IterateContents(ctx, content.IterateOptions{IncludeDeleted: true}, func(ci content.Info) error {
		if manifest.ContentPrefix == ci.GetContentID().Prefix() {
			system.Add(int64(ci.GetPackedLength()))
			return nil
		}

		if _, ok := used.Load(ci.GetContentID()); ok {
			if ci.GetDeleted() {
				if err := rep.ContentManager().UndeleteContent(ctx, ci.GetContentID()); err != nil {
					return errors.Wrapf(err, "Could not undelete referenced content: %v", ci)
				}
				undeleted.Add(int64(ci.GetPackedLength()))
			}

			inUse.Add(int64(ci.GetPackedLength()))

			return nil
		}

		if maintenanceStartTime.Sub(ci.Timestamp()) < safety.MinContentAgeSubjectToGC {
			log(ctx).Debugf("recent unreferenced content %v (%v bytes, modified %v)", ci.GetContentID(), ci.GetPackedLength(), ci.Timestamp())
			tooRecent.Add(int64(ci.GetPackedLength()))

			return nil
		}

		log(ctx).Debugf("unreferenced %v (%v bytes, modified %v)", ci.GetContentID(), ci.GetPackedLength(), ci.Timestamp())
		cnt, totalSize := unused.Add(int64(ci.GetPackedLength()))

		if gcDelete {
			if err := rep.ContentManager().DeleteContent(ctx, ci.GetContentID()); err != nil {
				return errors.Wrap(err, "error deleting content")
			}
		}

		if cnt%100000 == 0 {
			log(ctx).Infof("... found %v unused contents so far (%v bytes)", cnt, units.BytesStringBase2(totalSize))
			if gcDelete {
				if err := rep.Flush(ctx); err != nil {
					return errors.Wrap(err, "flush error")
				}
			}
		}

		return nil
	})

	st.UnusedCount, st.UnusedBytes = unused.Approximate()
	st.InUseCount, st.InUseBytes = inUse.Approximate()
	st.SystemCount, st.SystemBytes = system.Approximate()
	st.TooRecentCount, st.TooRecentBytes = tooRecent.Approximate()
	st.UndeletedCount, st.UndeletedBytes = undeleted.Approximate()

	if err != nil {
		return errors.Wrap(err, "error iterating contents")
	}

	return errors.Wrap(rep.Flush(ctx), "flush error")
}
<|endoftext|>


<commit_before>// Copyright © 2016 Patrick Young <patrick.mckendree.young@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package cmd

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"sync"

	"github.com/spf13/cobra"
	"github.com/youngpm/gbdx"
)

func orderLocation(cmd *cobra.Command, args []string) (err error) {
	// Read catalog ids from stdin (line seperated)  if given no arguments.
	if len(args) == 0 {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			args = append(args, scanner.Text())
		}
	}

	// We do things concurrently, so make a channel for returning
	// responses on and one to use as a counting semaphore.
	type orderResponse struct {
		order *gbdx.Order
		err   error
	}
	ch := make(chan orderResponse)
	sema := make(chan struct{}, 10) // Max concurrent requests.
	quit := make(chan struct{})
	defer close(quit)

	// Aquire an Api.
	api, err := apiFromConfig()
	if err != nil {
		return err
	}

	// Place the order concurrently in batches of 100.
	var n sync.WaitGroup
	for i := 0; i < len(args); i += 100 {
		j := i + 100
		if j > len(args) {
			j = len(args)
		}

		n.Add(1)
		go func(a []string) {
			defer n.Done()

			select {
			case sema <- struct{}{}:
			case <-quit:
				return
			}

			var o orderResponse
			o.order, o.err = api.OrderLocation(a...)
			<-sema
			ch <- o
		}(args[i:j])
	}

	// Close ch once all goroutines have returned.
	go func() {
		n.Wait()
		close(ch)
	}()

	var orders Orders
	for resp := range ch {

		// On error, send quit signal and drain the channel.
		if resp.err != nil {
			quit <- struct{}{}
			go func() {
				for range ch {
					// Drain any stragglers.
				}
			}()
			return resp.err
		}

		orders.Append(resp.order)
	}

	result, err := json.Marshal(orders)
	if err != nil {
		return err
	}
	fmt.Printf("%s\n", result)

	return nil
}

var orderLocationCmd = &cobra.Command{
	Use:   "location [CATIDs]",
	Short: "Check the location of GBDX catalog IDs",
	Long: `Check the location of GBDX catalog IDs

Pass the catalog ids in space delimited arguments to check multiple
catalog ids, or if given no arguments, passed in delimited by newlines via
stdin.

A useful command to run to see how many strips might be ordered is
something like

  cat file-of-cids.txt | gbdxcli order location | jq '.acquisitions[].state' | sort | uniq -c

which will return a count of "delivered" and "not_found", the latter
would be ordered if you were to submit those catalog ids.
`,
	RunE: orderLocation}

func init() {
	orderCmd.AddCommand(orderLocationCmd)
}
<commit_msg>Update order location docs.<commit_after>// Copyright © 2016 Patrick Young <patrick.mckendree.young@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package cmd

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"sync"

	"github.com/spf13/cobra"
	"github.com/youngpm/gbdx"
)

func orderLocation(cmd *cobra.Command, args []string) (err error) {
	// Read catalog ids from stdin (line seperated)  if given no arguments.
	if len(args) == 0 {
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			args = append(args, scanner.Text())
		}
	}

	// We do things concurrently, so make a channel for returning
	// responses on and one to use as a counting semaphore.
	type orderResponse struct {
		order *gbdx.Order
		err   error
	}
	ch := make(chan orderResponse)
	sema := make(chan struct{}, 10) // Max concurrent requests.
	quit := make(chan struct{})
	defer close(quit)

	// Aquire an Api.
	api, err := apiFromConfig()
	if err != nil {
		return err
	}

	// Place the order concurrently in batches of 100.
	var n sync.WaitGroup
	for i := 0; i < len(args); i += 100 {
		j := i + 100
		if j > len(args) {
			j = len(args)
		}

		n.Add(1)
		go func(a []string) {
			defer n.Done()

			select {
			case sema <- struct{}{}:
			case <-quit:
				return
			}

			var o orderResponse
			o.order, o.err = api.OrderLocation(a...)
			<-sema
			ch <- o
		}(args[i:j])
	}

	// Close ch once all goroutines have returned.
	go func() {
		n.Wait()
		close(ch)
	}()

	var orders Orders
	for resp := range ch {

		// On error, send quit signal and drain the channel.
		if resp.err != nil {
			quit <- struct{}{}
			go func() {
				for range ch {
					// Drain any stragglers.
				}
			}()
			return resp.err
		}

		orders.Append(resp.order)
	}

	result, err := json.Marshal(orders.Acquisitions)
	if err != nil {
		return err
	}
	fmt.Printf("%s\n", result)

	return nil
}

var orderLocationCmd = &cobra.Command{
	Use:   "location [CATIDs]",
	Short: "Check the location of GBDX catalog IDs",
	Long: `Check the location of GBDX catalog IDs

Pass the catalog ids in space delimited arguments to check multiple
catalog ids, or if given no arguments, passed in delimited by newlines via
stdin.

A useful command to run to see how many strips might be ordered is
something like

  cat file-of-cids.txt | gbdxcli order location | jq '.[].state' | sort | uniq -c

which will return a count of "delivered" and "not_found", the latter
would be ordered if you were to submit those catalog ids.
`,
	RunE: orderLocation}

func init() {
	orderCmd.AddCommand(orderLocationCmd)
}
<|endoftext|>