<commit_before>package main

import (
	"flag"
	"fmt"
	"path/filepath"
	"syscall"
	"unsafe"
)

const defaultSocketType = "tcp"

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")

	proc_get_module_file_name = kernel32.NewProc("GetModuleFileNameW")
)

// Full path of the current executable
func get_executable_filename() string {
	b := make([]uint16, syscall.MAX_PATH)
	ret, _, err := syscall.Syscall(proc_get_module_file_name.Addr(), 3,
		0, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)))
	if int(ret) == 0 {
		panic(fmt.Sprintf("GetModuleFileNameW : err %d", int(err)))
	}
	return syscall.UTF16ToString(b)
}
<commit_msg>gocode: remove unused imports<commit_after>package main

import (
	"fmt"
	"syscall"
	"unsafe"
)

const defaultSocketType = "tcp"

var (
	kernel32 = syscall.NewLazyDLL("kernel32.dll")

	proc_get_module_file_name = kernel32.NewProc("GetModuleFileNameW")
)

// Full path of the current executable
func get_executable_filename() string {
	b := make([]uint16, syscall.MAX_PATH)
	ret, _, err := syscall.Syscall(proc_get_module_file_name.Addr(), 3,
		0, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)))
	if int(ret) == 0 {
		panic(fmt.Sprintf("GetModuleFileNameW : err %d", int(err)))
	}
	return syscall.UTF16ToString(b)
}
<|endoftext|>


<commit_before><commit_msg>Avoid goroutine from closing over range param<commit_after><|endoftext|>


<commit_before><commit_msg>hotfix: resp.body.close() outside if statement<commit_after><|endoftext|>


<commit_before>package bdefault

import (
	"fmt"

	"github.com/nyxtom/broadcast/server"
)

type DefaultBackend struct {
	server.Backend

	app *server.BroadcastServer
}

var PONG = "PONG"

func (b *DefaultBackend) ping(data interface{}, client server.ProtocolClient) error {
	client.WriteString(PONG)
	client.Flush()
	return nil
}

func (b *DefaultBackend) info(data interface{}, client server.ProtocolClient) error {
	status, _ := b.app.Status()
	client.WriteJson(status)
	client.Flush()
	return nil
}

func (b *DefaultBackend) help(data interface{}, client server.ProtocolClient) error {
	help, _ := b.app.Help()
	client.WriteJson(help)
	client.Flush()
	return nil
}

func (b *DefaultBackend) echo(data interface{}, client server.ProtocolClient) error {
	d, okInterface := data.([]interface{})
	if okInterface {
		if len(d) == 0 {
			client.WriteString("")
			client.Flush()
			return nil
		} else {
			if len(d) == 1 {
				fmt.Printf("%v", d[0])
				client.WriteInterface(d[0])
			} else {
				client.WriteArray(d)
			}
			client.Flush()
			return nil
		}
	} else {
		b, _ := data.([][]byte)
		if len(b) == 0 {
			client.WriteString("")
			client.Flush()
			return nil
		} else {
			if len(b) == 1 {
				client.WriteString(string(b[0]))
			} else {
				for _, v := range b {
					client.WriteString(string(v))
				}
			}
			client.Flush()
			return nil
		}
	}
}

func RegisterBackend(app *server.BroadcastServer) (server.Backend, error) {
	backend := new(DefaultBackend)
	app.RegisterCommand(server.Command{"PING", "Pings the server for a response", "", false}, backend.ping)
	app.RegisterCommand(server.Command{"ECHO", "Echos back a message sent", "ECHO \"hello world\"", false}, backend.echo)
	app.RegisterCommand(server.Command{"INFO", "Current server status and information", "", false}, backend.info)
	app.RegisterCommand(server.Command{"CMDS", "List of available commands supported by the server", "", false}, backend.help)
	backend.app = app
	return backend, nil
}

func (b *DefaultBackend) Load() error {
	return nil
}

func (b *DefaultBackend) Unload() error {
	return nil
}
<commit_msg>Ensuring all arguments are echo out as a single response (i.e. ECHO hello world)<commit_after>package bdefault

import (
	"fmt"
	"strings"

	"github.com/nyxtom/broadcast/server"
)

type DefaultBackend struct {
	server.Backend

	app *server.BroadcastServer
}

var PONG = "PONG"

func (b *DefaultBackend) ping(data interface{}, client server.ProtocolClient) error {
	client.WriteString(PONG)
	client.Flush()
	return nil
}

func (b *DefaultBackend) info(data interface{}, client server.ProtocolClient) error {
	status, _ := b.app.Status()
	client.WriteJson(status)
	client.Flush()
	return nil
}

func (b *DefaultBackend) help(data interface{}, client server.ProtocolClient) error {
	help, _ := b.app.Help()
	client.WriteJson(help)
	client.Flush()
	return nil
}

func (b *DefaultBackend) echo(data interface{}, client server.ProtocolClient) error {
	d, okInterface := data.([]interface{})
	if okInterface {
		if len(d) == 0 {
			client.WriteString("")
			client.Flush()
			return nil
		} else {
			if len(d) == 1 {
				fmt.Printf("%v", d[0])
				client.WriteInterface(d[0])
			} else {
				client.WriteArray(d)
			}
			client.Flush()
			return nil
		}
	} else {
		b, _ := data.([][]byte)
		if len(b) == 0 {
			client.WriteString("")
			client.Flush()
			return nil
		} else {
			if len(b) == 1 {
				client.WriteString(string(b[0]))
			} else {
				s := make([]string, len(b))
				for i, k := range b {
					s[i] = string(k)
				}
				client.WriteString(strings.Join(s, " "))
			}
			client.Flush()
			return nil
		}
	}
}

func RegisterBackend(app *server.BroadcastServer) (server.Backend, error) {
	backend := new(DefaultBackend)
	app.RegisterCommand(server.Command{"PING", "Pings the server for a response", "", false}, backend.ping)
	app.RegisterCommand(server.Command{"ECHO", "Echos back a message sent", "ECHO \"hello world\"", false}, backend.echo)
	app.RegisterCommand(server.Command{"INFO", "Current server status and information", "", false}, backend.info)
	app.RegisterCommand(server.Command{"CMDS", "List of available commands supported by the server", "", false}, backend.help)
	backend.app = app
	return backend, nil
}

func (b *DefaultBackend) Load() error {
	return nil
}

func (b *DefaultBackend) Unload() error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/bwmarrin/discordgo"

	"github.com/nelsonleduc/calmanbot/cache"
	"github.com/nelsonleduc/calmanbot/handlers"
	"github.com/nelsonleduc/calmanbot/handlers/models"
	"github.com/nelsonleduc/calmanbot/service/discord"
)

// Variables used for command line parameters
var (
	token          string
	discordService discord.DSService
	statusOptions  []statusTuple
)

type statusTuple struct {
	status   string
	gameType discordgo.GameType
}

func init() {
	token = os.Getenv("discord_token")
	discordService = discord.DSService{}
	statusOptions = []statusTuple{
		statusTuple{"to some sick beats", discordgo.GameTypeListening},
		statusTuple{"shit that doesn't suck yo", discordgo.GameTypeGame},
		statusTuple{"something I guess?", discordgo.GameTypeWatching},
		statusTuple{"whatever Zach thinks is good", discordgo.GameTypeGame},
		statusTuple{"to Zach ask \"Could this game get any worse?\"", discordgo.GameTypeListening},
		statusTuple{"nothing, I have no games :(", discordgo.GameTypeGame},
		statusTuple{"these l33t skillz", discordgo.GameTypeWatching},
		statusTuple{"to Alexa play Despacito", discordgo.GameTypeListening},
	}
}

func randomStatus(excluding statusTuple) statusTuple {
	choice := excluding
	for choice == excluding {
		idx := rand.Intn(len(statusOptions))
		choice = statusOptions[idx]
	}
	return choice
}

func postStatus(s *discordgo.Session, statusTuple statusTuple) {
	log.Printf("[Tick] Setting status \"%+v\"\n", statusTuple)
	s.UpdateStatusComplex(discordgo.UpdateStatusData{
		IdleSince: nil,
		Game: &discordgo.Game{
			Name: statusTuple.status,
			Type: statusTuple.gameType,
			URL:  "",
		},
		AFK:    false,
		Status: "online"})
}

func CreateWebhook() {
	log.Println("Creating discord webhook")

	// Create a new Discord session using the provided bot token.
	dg, err := discordgo.New("Bot " + token)
	if err != nil {
		log.Fatalln("error creating Discord session,", err)
		return
	}

	// Register the messageCreate func as a callback for MessageCreate events.
	dg.AddHandler(messageCreate)

	// Open a websocket connection to Discord and begin listening.
	err = dg.Open()
	if err != nil {
		log.Fatalln("error opening connection,", err)
		return
	}

	go func() {
		status := randomStatus(statusTuple{})
		postStatus(dg, status)
		c := time.Tick(30 * time.Minute)
		for range c {
			status = randomStatus(status)
			postStatus(dg, status)
		}
	}()
}

// This function will be called (due to AddHandler above) every time a new
// message is created on any channel that the autenticated bot has access to.
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	// Ignore all messages created by the bot itself
	// This isn't required in this specific example but it's a good practice.
	if m.Author.ID == s.State.User.ID {
		return
	}

	message := discordService.MessageFromSessionAndMessage(s, m.Message)
	monitor, _ := discordService.ServiceMonitor()
	cache := cache.NewSmartCache(monitor)

	handlers.HandleCalman(message, discordService, cache, models.PostGresRepo())
}
<commit_msg>Add more quotes<commit_after>package main

import (
	"log"
	"math/rand"
	"os"
	"time"

	"github.com/bwmarrin/discordgo"

	"github.com/nelsonleduc/calmanbot/cache"
	"github.com/nelsonleduc/calmanbot/handlers"
	"github.com/nelsonleduc/calmanbot/handlers/models"
	"github.com/nelsonleduc/calmanbot/service/discord"
)

// Variables used for command line parameters
var (
	token          string
	discordService discord.DSService
	statusOptions  []statusTuple
)

type statusTuple struct {
	status   string
	gameType discordgo.GameType
}

func init() {
	token = os.Getenv("discord_token")
	discordService = discord.DSService{}
	statusOptions = []statusTuple{
		statusTuple{"to some sick beats", discordgo.GameTypeListening},
		statusTuple{"shit that doesn't suck yo", discordgo.GameTypeGame},
		statusTuple{"something I guess?", discordgo.GameTypeWatching},
		statusTuple{"whatever Zach thinks is good", discordgo.GameTypeGame},
		statusTuple{"to Zach ask \"Could this game get any worse?\"", discordgo.GameTypeListening},
		statusTuple{"nothing, I have no games :(", discordgo.GameTypeGame},
		statusTuple{"these l33t skillz", discordgo.GameTypeWatching},
		statusTuple{"to Alexa play Despacito", discordgo.GameTypeListening},
		statusTuple{"Jeff Goldblum movies for quotes", discordgo.GameTypeWatching},
		statusTuple{"jet fuel not melt steel beams", discordgo.GameTypeWatching},
		statusTuple{"steel beams melt jet fuel", discordgo.GameTypeWatching},
		statusTuple{"Gazorpazorpfield", discordgo.GameTypeWatching},
		statusTuple{"Star Citizen (it's totally out!)", discordgo.GameTypeGame},
	}
}

func randomStatus(excluding statusTuple) statusTuple {
	choice := excluding
	for choice == excluding {
		idx := rand.Intn(len(statusOptions))
		choice = statusOptions[idx]
	}
	return choice
}

func postStatus(s *discordgo.Session, statusTuple statusTuple) {
	log.Printf("[Tick] Setting status \"%+v\"\n", statusTuple)
	s.UpdateStatusComplex(discordgo.UpdateStatusData{
		IdleSince: nil,
		Game: &discordgo.Game{
			Name: statusTuple.status,
			Type: statusTuple.gameType,
			URL:  "",
		},
		AFK:    false,
		Status: "online"})
}

func CreateWebhook() {
	log.Println("Creating discord webhook")

	// Create a new Discord session using the provided bot token.
	dg, err := discordgo.New("Bot " + token)
	if err != nil {
		log.Fatalln("error creating Discord session,", err)
		return
	}

	// Register the messageCreate func as a callback for MessageCreate events.
	dg.AddHandler(messageCreate)

	// Open a websocket connection to Discord and begin listening.
	err = dg.Open()
	if err != nil {
		log.Fatalln("error opening connection,", err)
		return
	}

	go func() {
		status := randomStatus(statusTuple{})
		postStatus(dg, status)
		c := time.Tick(30 * time.Minute)
		for range c {
			status = randomStatus(status)
			postStatus(dg, status)
		}
	}()
}

// This function will be called (due to AddHandler above) every time a new
// message is created on any channel that the autenticated bot has access to.
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	// Ignore all messages created by the bot itself
	// This isn't required in this specific example but it's a good practice.
	if m.Author.ID == s.State.User.ID {
		return
	}

	message := discordService.MessageFromSessionAndMessage(s, m.Message)
	monitor, _ := discordService.ServiceMonitor()
	cache := cache.NewSmartCache(monitor)

	handlers.HandleCalman(message, discordService, cache, models.PostGresRepo())
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains high level helper functions and easy entry points for the
// entire discordgo package.  These functions are beling developed and are very
// experimental at this point.  They will most likley change so please use the
// low level functions if that's a problem.

// Package discordgo provides Discord binding for Go
package discordgo

import (
	"fmt"
	"reflect"
)

// VERSION of Discordgo, follows Symantic Versioning. (http://semver.org/)
const VERSION = "0.12.0"

// New creates a new Discord session and will automate some startup
// tasks if given enough information to do so.  Currently you can pass zero
// arguments and it will return an empty Discord session.
// There are 3 ways to call New:
//     With a single auth token - All requests will use the token blindly,
//         no verification of the token will be done and requests may fail.
//     With an email and password - Discord will sign in with the provided
//         credentials.
//     With an email, password and auth token - Discord will verify the auth
//         token, if it is invalid it will sign in with the provided
//         credentials. This is the Discord recommended way to sign in.
func New(args ...interface{}) (s *Session, err error) {

	// Create an empty Session interface.
	s = &Session{
		State:                  NewState(),
		StateEnabled:           true,
		Compress:               true,
		ShouldReconnectOnError: true,
	}

	// If no arguments are passed return the empty Session interface.
	if args == nil {
		return
	}

	// Variables used below when parsing func arguments
	var auth, pass string

	// Parse passed arguments
	for _, arg := range args {

		switch v := arg.(type) {

		case []string:
			if len(v) > 3 {
				err = fmt.Errorf("Too many string parameters provided.")
				return
			}

			// First string is either token or username
			if len(v) > 0 {
				auth = v[0]
			}

			// If second string exists, it must be a password.
			if len(v) > 1 {
				pass = v[1]
			}

			// If third string exists, it must be an auth token.
			if len(v) > 2 {
				s.Token = v[2]
			}

		case string:
			// First string must be either auth token or username.
			// Second string must be a password.
			// Only 2 input strings are supported.

			if auth == "" {
				auth = v
			} else if pass == "" {
				pass = v
			} else if s.Token == "" {
				s.Token = v
			} else {
				err = fmt.Errorf("Too many string parameters provided.")
				return
			}

			//		case Config:
			// TODO: Parse configuration struct

		default:
			err = fmt.Errorf("Unsupported parameter type provided.")
			return
		}
	}

	// If only one string was provided, assume it is an auth token.
	// Otherwise get auth token from Discord, if a token was specified
	// Discord will verify it for free, or log the user in if it is
	// invalid.
	if pass == "" {
		s.Token = auth
	} else {
		err = s.Login(auth, pass)
		if err != nil || s.Token == "" {
			err = fmt.Errorf("Unable to fetch discord authentication token. %v", err)
			return
		}
	}

	// The Session is now able to have RestAPI methods called on it.
	// It is recommended that you now call Open() so that events will trigger.

	return
}

// validateHandler takes an event handler func, and returns the type of event.
// eg.
//     Session.validateHandler(func (s *discordgo.Session, m *discordgo.MessageCreate))
//     will return the reflect.Type of *discordgo.MessageCreate
func (s *Session) validateHandler(handler interface{}) reflect.Type {

	handlerType := reflect.TypeOf(handler)

	if handlerType.NumIn() != 2 {
		panic("Unable to add event handler, handler must be of the type func(*discordgo.Session, *discordgo.EventType).")
	}

	if handlerType.In(0) != reflect.TypeOf(s) {
		panic("Unable to add event handler, first argument must be of type *discordgo.Session.")
	}

	eventType := handlerType.In(1)

	// Support handlers of type interface{}, this is a special handler, which is triggered on every event.
	if eventType.Kind() == reflect.Interface {
		eventType = nil
	}

	return eventType
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the interface fires.
// eventToInterface in events.go has a list of all the Discord WSAPI events
// and their respective interface.
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {

	s.initialize()

	eventType := s.validateHandler(handler)

	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	h := reflect.ValueOf(handler)

	s.handlers[eventType] = append(s.handlers[eventType], h)

	// This must be done as we need a consistent reference to the
	// reflected value, otherwise a RemoveHandler method would have
	// been nice.
	return func() {
		s.handlersMu.Lock()
		defer s.handlersMu.Unlock()

		handlers := s.handlers[eventType]
		for i, v := range handlers {
			if h == v {
				s.handlers[eventType] = append(handlers[:i], handlers[i+1:]...)
				return
			}
		}
	}
}

// handle calls any handlers that match the event type and any handlers of
// interface{}.
func (s *Session) handle(event interface{}) {

	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	if s.handlers == nil {
		return
	}

	handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}

	if handlers, ok := s.handlers[nil]; ok {
		for _, handler := range handlers {
			handler.Call(handlerParameters)
		}
	}

	if handlers, ok := s.handlers[reflect.TypeOf(event)]; ok {
		for _, handler := range handlers {
			handler.Call(handlerParameters)
		}
	}
}

// initialize adds all internal handlers and state tracking handlers.
func (s *Session) initialize() {

	s.handlersMu.Lock()
	if s.handlers != nil {
		s.handlersMu.Unlock()
		return
	}

	s.handlers = map[interface{}][]reflect.Value{}
	s.handlersMu.Unlock()

	s.AddHandler(s.onReady)
	s.AddHandler(s.onVoiceServerUpdate)
	s.AddHandler(s.onVoiceStateUpdate)
	s.AddHandler(s.State.onInterface)
}

// onReady handles the ready event.
func (s *Session) onReady(se *Session, r *Ready) {

	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
}
<commit_msg>Bump version to 0.12.1<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains high level helper functions and easy entry points for the
// entire discordgo package.  These functions are beling developed and are very
// experimental at this point.  They will most likley change so please use the
// low level functions if that's a problem.

// Package discordgo provides Discord binding for Go
package discordgo

import (
	"fmt"
	"reflect"
)

// VERSION of Discordgo, follows Symantic Versioning. (http://semver.org/)
const VERSION = "0.12.1"

// New creates a new Discord session and will automate some startup
// tasks if given enough information to do so.  Currently you can pass zero
// arguments and it will return an empty Discord session.
// There are 3 ways to call New:
//     With a single auth token - All requests will use the token blindly,
//         no verification of the token will be done and requests may fail.
//     With an email and password - Discord will sign in with the provided
//         credentials.
//     With an email, password and auth token - Discord will verify the auth
//         token, if it is invalid it will sign in with the provided
//         credentials. This is the Discord recommended way to sign in.
func New(args ...interface{}) (s *Session, err error) {

	// Create an empty Session interface.
	s = &Session{
		State:                  NewState(),
		StateEnabled:           true,
		Compress:               true,
		ShouldReconnectOnError: true,
	}

	// If no arguments are passed return the empty Session interface.
	if args == nil {
		return
	}

	// Variables used below when parsing func arguments
	var auth, pass string

	// Parse passed arguments
	for _, arg := range args {

		switch v := arg.(type) {

		case []string:
			if len(v) > 3 {
				err = fmt.Errorf("Too many string parameters provided.")
				return
			}

			// First string is either token or username
			if len(v) > 0 {
				auth = v[0]
			}

			// If second string exists, it must be a password.
			if len(v) > 1 {
				pass = v[1]
			}

			// If third string exists, it must be an auth token.
			if len(v) > 2 {
				s.Token = v[2]
			}

		case string:
			// First string must be either auth token or username.
			// Second string must be a password.
			// Only 2 input strings are supported.

			if auth == "" {
				auth = v
			} else if pass == "" {
				pass = v
			} else if s.Token == "" {
				s.Token = v
			} else {
				err = fmt.Errorf("Too many string parameters provided.")
				return
			}

			//		case Config:
			// TODO: Parse configuration struct

		default:
			err = fmt.Errorf("Unsupported parameter type provided.")
			return
		}
	}

	// If only one string was provided, assume it is an auth token.
	// Otherwise get auth token from Discord, if a token was specified
	// Discord will verify it for free, or log the user in if it is
	// invalid.
	if pass == "" {
		s.Token = auth
	} else {
		err = s.Login(auth, pass)
		if err != nil || s.Token == "" {
			err = fmt.Errorf("Unable to fetch discord authentication token. %v", err)
			return
		}
	}

	// The Session is now able to have RestAPI methods called on it.
	// It is recommended that you now call Open() so that events will trigger.

	return
}

// validateHandler takes an event handler func, and returns the type of event.
// eg.
//     Session.validateHandler(func (s *discordgo.Session, m *discordgo.MessageCreate))
//     will return the reflect.Type of *discordgo.MessageCreate
func (s *Session) validateHandler(handler interface{}) reflect.Type {

	handlerType := reflect.TypeOf(handler)

	if handlerType.NumIn() != 2 {
		panic("Unable to add event handler, handler must be of the type func(*discordgo.Session, *discordgo.EventType).")
	}

	if handlerType.In(0) != reflect.TypeOf(s) {
		panic("Unable to add event handler, first argument must be of type *discordgo.Session.")
	}

	eventType := handlerType.In(1)

	// Support handlers of type interface{}, this is a special handler, which is triggered on every event.
	if eventType.Kind() == reflect.Interface {
		eventType = nil
	}

	return eventType
}

// AddHandler allows you to add an event handler that will be fired anytime
// the Discord WSAPI event that matches the interface fires.
// eventToInterface in events.go has a list of all the Discord WSAPI events
// and their respective interface.
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
// The return value of this method is a function, that when called will remove the
// event handler.
func (s *Session) AddHandler(handler interface{}) func() {

	s.initialize()

	eventType := s.validateHandler(handler)

	s.handlersMu.Lock()
	defer s.handlersMu.Unlock()

	h := reflect.ValueOf(handler)

	s.handlers[eventType] = append(s.handlers[eventType], h)

	// This must be done as we need a consistent reference to the
	// reflected value, otherwise a RemoveHandler method would have
	// been nice.
	return func() {
		s.handlersMu.Lock()
		defer s.handlersMu.Unlock()

		handlers := s.handlers[eventType]
		for i, v := range handlers {
			if h == v {
				s.handlers[eventType] = append(handlers[:i], handlers[i+1:]...)
				return
			}
		}
	}
}

// handle calls any handlers that match the event type and any handlers of
// interface{}.
func (s *Session) handle(event interface{}) {

	s.handlersMu.RLock()
	defer s.handlersMu.RUnlock()

	if s.handlers == nil {
		return
	}

	handlerParameters := []reflect.Value{reflect.ValueOf(s), reflect.ValueOf(event)}

	if handlers, ok := s.handlers[nil]; ok {
		for _, handler := range handlers {
			handler.Call(handlerParameters)
		}
	}

	if handlers, ok := s.handlers[reflect.TypeOf(event)]; ok {
		for _, handler := range handlers {
			handler.Call(handlerParameters)
		}
	}
}

// initialize adds all internal handlers and state tracking handlers.
func (s *Session) initialize() {

	s.handlersMu.Lock()
	if s.handlers != nil {
		s.handlersMu.Unlock()
		return
	}

	s.handlers = map[interface{}][]reflect.Value{}
	s.handlersMu.Unlock()

	s.AddHandler(s.onReady)
	s.AddHandler(s.onVoiceServerUpdate)
	s.AddHandler(s.onVoiceStateUpdate)
	s.AddHandler(s.State.onInterface)
}

// onReady handles the ready event.
func (s *Session) onReady(se *Session, r *Ready) {

	go s.heartbeat(s.wsConn, s.listening, r.HeartbeatInterval)
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 assets

import (
	"bytes"
	"context"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"testing"
	"time"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"google.golang.org/api/iterator"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
	"google.golang.org/genproto/protobuf/field_mask"
)

var marksAssetName = ""

func getRandomAsset(client *securitycenter.Client, orgID string) (*securitycenterpb.Asset, error) {
	ctx := context.Background()
	req := &securitycenterpb.ListAssetsRequest{
		Parent: fmt.Sprintf("organizations/%s", orgID),
	}

	var randomAsset *securitycenterpb.Asset
	assetsCount := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("it.Next(): %v", err)
		}
		assetsCount++
		if rand.Float64() < 1.0/float64(assetsCount) {
			randomAsset = result.Asset
		}
	}
	return randomAsset, nil
}

func attemptLease(client *securitycenter.Client, asset *securitycenterpb.Asset, orgID string) error {
	const leaseExpirationKey = "LEASEKEY"
	now := time.Now().UnixNano()

	lease := asset.SecurityMarks.Marks[leaseExpirationKey]
	okToLease := true
	if lease != "" {
		i, err := strconv.ParseInt(lease, 10, 64)
		if err != nil {
			fmt.Printf("strconv.ParseInt(%v, 10, 64): %v", lease, err)
		}
		okToLease = now > i
	}
	if !okToLease {
		return fmt.Errorf("lease by another process still active for %s", asset.Name)
	}
	leaseTime := now + (60 * time.Second).Nanoseconds()
	leaseValue := strconv.FormatInt(leaseTime, 10)
	ctx := context.Background()
	_, err := client.UpdateSecurityMarks(ctx, &securitycenterpb.UpdateSecurityMarksRequest{
		// If not set or empty, all marks would be cleared before
		// adding the new marks below.
		UpdateMask: &field_mask.FieldMask{
			Paths: []string{
				fmt.Sprintf("marks.%s", leaseExpirationKey),
				"marks.key_a",
				"marks.key_b",
			},
		},
		SecurityMarks: &securitycenterpb.SecurityMarks{
			Name: fmt.Sprintf("%s/securityMarks", asset.Name),
			// Note keys correspond to the last part of each path.
			Marks: map[string]string{leaseExpirationKey: leaseValue},
		},
	})
	if err != nil {
		return fmt.Errorf("UpdateSecurityMarks: %v", err)
	}
	// Randomize wake-up in case we are in the edge case of two writes
	time.Sleep(time.Duration((100 * rand.Int63n(20))) * time.Millisecond)
	it := client.ListAssets(ctx, &securitycenterpb.ListAssetsRequest{
		Parent: fmt.Sprintf("organizations/%s", orgID),
		Filter: fmt.Sprintf(`name="%s"`, asset.Name),
	})

	result, err := it.Next()
	if err == iterator.Done {
		return fmt.Errorf("didn't find asset %s", asset.Name)
	}
	if err != nil {
		return fmt.Errorf("it.Next: %v", err)
	}
	asset = result.Asset

	if asset.SecurityMarks.Marks[leaseExpirationKey] != leaseValue {
		return fmt.Errorf("simultaneous write by another process for %s", asset.Name)
	}
	marksAssetName = asset.Name
	return nil
}

func initAssetForManipulation() error {
	orgID := os.Getenv("GCLOUD_ORGANIZATION")
	if orgID == "" {
		// Each test checks for GCLOUD_ORGANIZATION. Return nil so we see every skip.
		return nil
	}

	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %v", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	try := 0
	for try < 3 && marksAssetName == "" {
		try++
		asset, err := getRandomAsset(client, orgID)
		if err != nil {
			continue
		}
		if err := attemptLease(client, asset, orgID); err != nil {
			return fmt.Errorf("attemptLease: %s", asset.Name)
		}
	}
	if marksAssetName == "" {
		return fmt.Errorf("failed to set marksAssetName")
	}
	return nil
}

func setup(t *testing.T) string {
	orgID := os.Getenv("GCLOUD_ORGANIZATION")
	if orgID == "" {
		t.Skip("GCLOUD_ORGANIZATION not set")
	} else if marksAssetName == "" {
		t.Fatalf("marksAssetName wasn't initialized.")
	}
	return orgID
}

func TestMain(m *testing.M) {
	if err := initAssetForManipulation(); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize assets test environment: %v", err)
		return
	}
	rand.Seed(time.Now().UTC().UnixNano())
	code := m.Run()
	os.Exit(code)
}

func TestListAllAssets(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllAssets(buf, orgID)
	if err != nil {
		t.Fatalf("listAllAssets(%s) failed: %v", orgID, err)
	}

	want := 59
	got := strings.Count(buf.String(), "\n")
	if got < want {
		t.Errorf("listAllAssets(%s) Not enough results: %d Want >= %d", orgID, got, want)
	}
}

func TestListAllProjectAssets(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllProjectAssets(buf, orgID)
	if err != nil {
		t.Fatalf("listAllAssets(%s) failed: %v", orgID, err)
	}
	want := 3
	got := strings.Count(buf.String(), "\n")
	if got != want {
		t.Errorf("listAllAssets(%s) Unexpected number of results: %d Want: %d", orgID, got, want)
	}
}

func TestListAllProjectAssetsAtTime(t *testing.T) {
	orgID := setup(t)
	buf := new(bytes.Buffer)
	var nothingInstant = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)

	err := listAllProjectAssetsAtTime(buf, orgID, nothingInstant)

	if err != nil {
		t.Fatalf("listAllProjectAssetsAtTime(%s, %v) failed: %v", orgID, nothingInstant, err)
	}

	got := strings.Count(buf.String(), "\n")
	if got != 0 {
		t.Errorf("listAllProjectAssetsAtTime(%s, %v) Results not 0: %d", orgID, nothingInstant, got)
	}

	buf.Truncate(0)
	var somethingInstant = time.Date(2019, 3, 15, 0, 0, 0, 0, time.UTC)
	err = listAllProjectAssetsAtTime(buf, orgID, somethingInstant)
	if err != nil {
		t.Fatalf("listAllProjectAssetsAtTime(%s, %v) failed: %v", orgID, somethingInstant, err)
	}
	want := 3
	got = strings.Count(buf.String(), "\n")
	if got != want {
		t.Errorf("listAllProjectAssetsAtTime(%s, %v) Unexpected number of projects: %d Want: %d", orgID, somethingInstant, got, want)
	}
}

func TestListAllProjectAssetsAndStateChanges(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllProjectAssetsAndStateChanges(buf, orgID)
	if err != nil {
		t.Fatalf("listAllProjectAssetsAndStateChanges(%s) failed: %v", orgID, err)
	}
	got := strings.Count(buf.String(), "\n")
	want := 3
	if got != want {
		t.Errorf("listAllProjectAssetsAndStateChanges(%s) Unexpected number of results: %d Want: %d", orgID, got, want)
	}
}

func TestAddSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := deleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for addSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	err = addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("addSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if want := "key_a = value_a"; !strings.Contains(got, want) {
		t.Errorf("addSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

	if want := "key_b = value_b"; !strings.Contains(got, want) {
		t.Errorf("addSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

}

func TestDeleteSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for deleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}
	buf.Truncate(0)

	err = deleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("deleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if dont_want := "key_a = value_a"; strings.Contains(got, dont_want) {
		t.Errorf("deleteSecurityMarks(%s) got: %s dont_want %s", marksAssetName, got, dont_want)
	}

	if dont_want := "key_b = value_b"; strings.Contains(got, dont_want) {
		t.Errorf("deleteSecurityMarks(%s) got: %s dont_want %s", marksAssetName, got, dont_want)
	}
}

func TestAddDeleteSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for addDeleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}
	buf.Truncate(0)

	err = addDeleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("addDeleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if want := "key_a = new_value_a"; !strings.Contains(got, want) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

	if dont_want := "key_b = value_b"; strings.Contains(got, dont_want) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s dont_want %s", marksAssetName, got, dont_want)
	}
}

func TestListWithSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for ListWithSecurityMarks(%s) failed %v", orgID, err)
	}

	err = listAssetsWithMarks(buf, orgID)

	if err != nil {
		t.Fatalf("listAssetsWithMarks(%s) failed %v", orgID, err)
	}

	got := buf.String()
	if !strings.Contains(got, marksAssetName) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s want %s", orgID, got, marksAssetName)
	}
}
<commit_msg>securitycenter/asset: skip broken test, small style fixes (#1377)<commit_after>// Copyright 2019 Google LLC
//
// 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
//
//     https://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 assets

import (
	"bytes"
	"context"
	"fmt"
	"math/rand"
	"os"
	"strconv"
	"strings"
	"testing"
	"time"

	securitycenter "cloud.google.com/go/securitycenter/apiv1"
	"google.golang.org/api/iterator"
	securitycenterpb "google.golang.org/genproto/googleapis/cloud/securitycenter/v1"
	"google.golang.org/genproto/protobuf/field_mask"
)

var marksAssetName = ""

func getRandomAsset(client *securitycenter.Client, orgID string) (*securitycenterpb.Asset, error) {
	ctx := context.Background()
	req := &securitycenterpb.ListAssetsRequest{
		Parent: fmt.Sprintf("organizations/%s", orgID),
	}

	var randomAsset *securitycenterpb.Asset
	assetsCount := 0
	it := client.ListAssets(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, fmt.Errorf("it.Next(): %v", err)
		}
		assetsCount++
		if rand.Float64() < 1.0/float64(assetsCount) {
			randomAsset = result.Asset
		}
	}
	return randomAsset, nil
}

func attemptLease(client *securitycenter.Client, asset *securitycenterpb.Asset, orgID string) error {
	const leaseExpirationKey = "LEASEKEY"
	now := time.Now().UnixNano()

	lease := asset.SecurityMarks.Marks[leaseExpirationKey]
	okToLease := true
	if lease != "" {
		i, err := strconv.ParseInt(lease, 10, 64)
		if err != nil {
			fmt.Printf("strconv.ParseInt(%v, 10, 64): %v", lease, err)
		}
		okToLease = now > i
	}
	if !okToLease {
		return fmt.Errorf("lease by another process still active for %s", asset.Name)
	}
	leaseTime := now + (60 * time.Second).Nanoseconds()
	leaseValue := strconv.FormatInt(leaseTime, 10)
	ctx := context.Background()
	_, err := client.UpdateSecurityMarks(ctx, &securitycenterpb.UpdateSecurityMarksRequest{
		// If not set or empty, all marks would be cleared before
		// adding the new marks below.
		UpdateMask: &field_mask.FieldMask{
			Paths: []string{
				fmt.Sprintf("marks.%s", leaseExpirationKey),
				"marks.key_a",
				"marks.key_b",
			},
		},
		SecurityMarks: &securitycenterpb.SecurityMarks{
			Name: fmt.Sprintf("%s/securityMarks", asset.Name),
			// Note keys correspond to the last part of each path.
			Marks: map[string]string{leaseExpirationKey: leaseValue},
		},
	})
	if err != nil {
		return fmt.Errorf("UpdateSecurityMarks: %v", err)
	}
	// Randomize wake-up in case we are in the edge case of two writes
	time.Sleep(time.Duration((100 * rand.Int63n(20))) * time.Millisecond)
	it := client.ListAssets(ctx, &securitycenterpb.ListAssetsRequest{
		Parent: fmt.Sprintf("organizations/%s", orgID),
		Filter: fmt.Sprintf(`name="%s"`, asset.Name),
	})

	result, err := it.Next()
	if err == iterator.Done {
		return fmt.Errorf("didn't find asset %s", asset.Name)
	}
	if err != nil {
		return fmt.Errorf("it.Next: %v", err)
	}
	asset = result.Asset

	if asset.SecurityMarks.Marks[leaseExpirationKey] != leaseValue {
		return fmt.Errorf("simultaneous write by another process for %s", asset.Name)
	}
	marksAssetName = asset.Name
	return nil
}

func initAssetForManipulation() error {
	orgID := os.Getenv("GCLOUD_ORGANIZATION")
	if orgID == "" {
		// Each test checks for GCLOUD_ORGANIZATION. Return nil so we see every skip.
		return nil
	}

	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %v", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	try := 0
	for try < 3 && marksAssetName == "" {
		try++
		asset, err := getRandomAsset(client, orgID)
		if err != nil {
			continue
		}
		if err := attemptLease(client, asset, orgID); err != nil {
			return fmt.Errorf("attemptLease: %s", asset.Name)
		}
	}
	if marksAssetName == "" {
		return fmt.Errorf("failed to set marksAssetName")
	}
	return nil
}

func setup(t *testing.T) string {
	orgID := os.Getenv("GCLOUD_ORGANIZATION")
	if orgID == "" {
		t.Skip("GCLOUD_ORGANIZATION not set")
	} else if marksAssetName == "" {
		t.Fatalf("marksAssetName wasn't initialized.")
	}
	return orgID
}

func TestMain(m *testing.M) {
	if err := initAssetForManipulation(); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to initialize assets test environment: %v\n", err)
		return
	}
	rand.Seed(time.Now().UTC().UnixNano())
	code := m.Run()
	os.Exit(code)
}

func TestListAllAssets(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllAssets(buf, orgID)
	if err != nil {
		t.Fatalf("listAllAssets(%s) failed: %v", orgID, err)
	}

	want := 59
	got := strings.Count(buf.String(), "\n")
	if got < want {
		t.Errorf("listAllAssets(%s) Not enough results: %d Want >= %d", orgID, got, want)
	}
}

func TestListAllProjectAssets(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllProjectAssets(buf, orgID)
	if err != nil {
		t.Fatalf("listAllAssets(%s) failed: %v", orgID, err)
	}
	want := 3
	got := strings.Count(buf.String(), "\n")
	if got != want {
		t.Errorf("listAllAssets(%s) Unexpected number of results: %d Want: %d", orgID, got, want)
	}
}

func TestListAllProjectAssetsAtTime(t *testing.T) {
	t.Skip("https://github.com/GoogleCloudPlatform/golang-samples/issues/1375")
	orgID := setup(t)
	buf := new(bytes.Buffer)
	var nothingInstant = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)

	err := listAllProjectAssetsAtTime(buf, orgID, nothingInstant)

	if err != nil {
		t.Fatalf("listAllProjectAssetsAtTime(%s, %v) failed: %v", orgID, nothingInstant, err)
	}

	got := strings.Count(buf.String(), "\n")
	if got != 0 {
		t.Errorf("listAllProjectAssetsAtTime(%s, %v) Results not 0: %d", orgID, nothingInstant, got)
	}

	buf.Reset()
	var somethingInstant = time.Date(2019, 3, 15, 0, 0, 0, 0, time.UTC)
	err = listAllProjectAssetsAtTime(buf, orgID, somethingInstant)
	if err != nil {
		t.Fatalf("listAllProjectAssetsAtTime(%s, %v) failed: %v", orgID, somethingInstant, err)
	}
	want := 3
	got = strings.Count(buf.String(), "\n")
	if got != want {
		t.Errorf("listAllProjectAssetsAtTime(%s, %v) Unexpected number of projects: %d Want: %d", orgID, somethingInstant, got, want)
	}
}

func TestListAllProjectAssetsAndStateChanges(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := listAllProjectAssetsAndStateChanges(buf, orgID)
	if err != nil {
		t.Fatalf("listAllProjectAssetsAndStateChanges(%s) failed: %v", orgID, err)
	}
	got := strings.Count(buf.String(), "\n")
	want := 3
	if got != want {
		t.Errorf("listAllProjectAssetsAndStateChanges(%s) Unexpected number of results: %d Want: %d", orgID, got, want)
	}
}

func TestAddSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := deleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for addSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	err = addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("addSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if want := "key_a = value_a"; !strings.Contains(got, want) {
		t.Errorf("addSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

	if want := "key_b = value_b"; !strings.Contains(got, want) {
		t.Errorf("addSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

}

func TestDeleteSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for deleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}
	buf.Reset()

	err = deleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("deleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if dontWant := "key_a = value_a"; strings.Contains(got, dontWant) {
		t.Errorf("deleteSecurityMarks(%s) got: %s dont want %q", marksAssetName, got, dontWant)
	}

	if dontWant := "key_b = value_b"; strings.Contains(got, dontWant) {
		t.Errorf("deleteSecurityMarks(%s) got: %s dont want %q", marksAssetName, got, dontWant)
	}
}

func TestAddDeleteSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for addDeleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}
	buf.Reset()

	err = addDeleteSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("addDeleteSecurityMarks(%s) failed %v", marksAssetName, err)
	}

	got := buf.String()
	if want := "key_a = new_value_a"; !strings.Contains(got, want) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s want %s", marksAssetName, got, want)
	}

	if dontWant := "key_b = value_b"; strings.Contains(got, dontWant) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s dont want %q", marksAssetName, got, dontWant)
	}
}

func TestListWithSecurityMarks(t *testing.T) {
	buf := new(bytes.Buffer)
	orgID := setup(t)
	err := addSecurityMarks(buf, marksAssetName)
	if err != nil {
		t.Fatalf("Setup for ListWithSecurityMarks(%s) failed %v", orgID, err)
	}

	err = listAssetsWithMarks(buf, orgID)

	if err != nil {
		t.Fatalf("listAssetsWithMarks(%s) failed %v", orgID, err)
	}

	got := buf.String()
	if !strings.Contains(got, marksAssetName) {
		t.Errorf("addDeleteSecurityMarks(%s) got: %s want %s", orgID, got, marksAssetName)
	}
}
<|endoftext|>


<commit_before>// Package virtualmachine provides a client for Virtual Machines.
package virtualmachine

import (
	"encoding/xml"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/management"
)

const (
	azureDeploymentListURL   = "services/hostedservices/%s/deployments"
	azureDeploymentURL       = "services/hostedservices/%s/deployments/%s"
	deleteAzureDeploymentURL = "services/hostedservices/%s/deployments/%s?comp=media"
	azureAddRoleURL          = "services/hostedservices/%s/deployments/%s/roles"
	azureRoleURL             = "services/hostedservices/%s/deployments/%s/roles/%s"
	azureOperationsURL       = "services/hostedservices/%s/deployments/%s/roleinstances/%s/Operations"
	azureRoleSizeListURL     = "rolesizes"

	errParamNotSpecified = "Parameter %s is not specified."
)

//NewClient is used to instantiate a new VirtualMachineClient from an Azure client
func NewClient(client management.Client) VirtualMachineClient {
	return VirtualMachineClient{client: client}
}

// CreateDeploymentOptions can be used to create a customized deployement request
type CreateDeploymentOptions struct {
	DNSServers         []DNSServer
	LoadBalancers      []LoadBalancer
	ReservedIPName     string
	VirtualNetworkName string
}

// CreateDeployment creates a deployment and then creates a virtual machine
// in the deployment based on the specified configuration.
//
// https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx
func (vm VirtualMachineClient) CreateDeployment(
	role Role,
	cloudServiceName string,
	options CreateDeploymentOptions) (management.OperationID, error) {

	req := DeploymentRequest{
		Name:               role.RoleName,
		DeploymentSlot:     "Production",
		Label:              role.RoleName,
		RoleList:           []Role{role},
		DNSServers:         options.DNSServers,
		LoadBalancers:      options.LoadBalancers,
		ReservedIPName:     options.ReservedIPName,
		VirtualNetworkName: options.VirtualNetworkName,
	}

	data, err := xml.Marshal(req)
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureDeploymentListURL, cloudServiceName)
	return vm.client.SendAzurePostRequest(requestURL, data)
}

//https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx
func (vm VirtualMachineClient) GetDeployment(cloudServiceName, deploymentName string) (DeploymentResponse, error) {
	var deployment DeploymentResponse
	if cloudServiceName == "" {
		return deployment, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return deployment, fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	requestURL := fmt.Sprintf(azureDeploymentURL, cloudServiceName, deploymentName)
	response, azureErr := vm.client.SendAzureGetRequest(requestURL)
	if azureErr != nil {
		return deployment, azureErr
	}

	err := xml.Unmarshal(response, &deployment)
	return deployment, err
}

func (vm VirtualMachineClient) DeleteDeployment(cloudServiceName, deploymentName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}

	requestURL := fmt.Sprintf(deleteAzureDeploymentURL, cloudServiceName, deploymentName)
	return vm.client.SendAzureDeleteRequest(requestURL)
}

func (vm VirtualMachineClient) GetRole(cloudServiceName, deploymentName, roleName string) (*Role, error) {
	if cloudServiceName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "roleName")
	}

	role := new(Role)

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	response, azureErr := vm.client.SendAzureGetRequest(requestURL)
	if azureErr != nil {
		return nil, azureErr
	}

	err := xml.Unmarshal(response, role)
	if err != nil {
		return nil, err
	}

	return role, nil
}

// AddRole adds a Virtual Machine to a deployment of Virtual Machines, where role name = VM name
// See https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx
func (vm VirtualMachineClient) AddRole(cloudServiceName string, deploymentName string, role Role) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}

	data, err := xml.Marshal(PersistentVMRole{Role: role})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureAddRoleURL, cloudServiceName, deploymentName)
	return vm.client.SendAzurePostRequest(requestURL, data)
}

// UpdateRole updates the configuration of the specified virtual machine
// See https://msdn.microsoft.com/en-us/library/azure/jj157187.aspx
func (vm VirtualMachineClient) UpdateRole(cloudServiceName, deploymentName, roleName string, role Role) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	data, err := xml.Marshal(PersistentVMRole{Role: role})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePutRequest(requestURL, "text/xml", data)
}

func (vm VirtualMachineClient) StartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	startRoleOperationBytes, err := xml.Marshal(StartRoleOperation{
		OperationType: "StartRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, startRoleOperationBytes)
}

func (vm VirtualMachineClient) ShutdownRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	shutdownRoleOperationBytes, err := xml.Marshal(ShutdownRoleOperation{
		OperationType: "ShutdownRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, shutdownRoleOperationBytes)
}

func (vm VirtualMachineClient) RestartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	restartRoleOperationBytes, err := xml.Marshal(RestartRoleOperation{
		OperationType: "RestartRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, restartRoleOperationBytes)
}

func (vm VirtualMachineClient) DeleteRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzureDeleteRequest(requestURL)
}

func (vm VirtualMachineClient) GetRoleSizeList() (RoleSizeList, error) {
	roleSizeList := RoleSizeList{}

	response, err := vm.client.SendAzureGetRequest(azureRoleSizeListURL)
	if err != nil {
		return roleSizeList, err
	}

	err = xml.Unmarshal(response, &roleSizeList)
	return roleSizeList, err
}

// CaptureRole captures a VM role. If reprovisioningConfigurationSet is non-nil,
// the VM role is redeployed after capturing the image, otherwise, the original
// VM role is deleted.
//
// NOTE: an image resulting from this operation shows up in
// osimage.GetImageList() as images with Category "User".
func (vm VirtualMachineClient) CaptureRole(cloudServiceName, deploymentName, roleName, imageName, imageLabel string,
	reprovisioningConfigurationSet *ConfigurationSet) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	if reprovisioningConfigurationSet != nil &&
		!(reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeLinuxProvisioning ||
			reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeWindowsProvisioning) {
		return "", fmt.Errorf("ConfigurationSet type can only be WindowsProvisioningConfiguration or LinuxProvisioningConfiguration")
	}

	operation := CaptureRoleOperation{
		OperationType:             "CaptureRoleOperation",
		PostCaptureAction:         PostCaptureActionReprovision,
		ProvisioningConfiguration: reprovisioningConfigurationSet,
		TargetImageLabel:          imageLabel,
		TargetImageName:           imageName,
	}
	if reprovisioningConfigurationSet == nil {
		operation.PostCaptureAction = PostCaptureActionDelete
	}

	data, err := xml.Marshal(operation)
	if err != nil {
		return "", err
	}

	return vm.client.SendAzurePostRequest(fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName), data)
}
<commit_msg>https://github.com/hashicorp/terraform/issues/3568<commit_after>// Package virtualmachine provides a client for Virtual Machines.
package virtualmachine

import (
	"encoding/xml"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/management"
)

const (
	azureDeploymentListURL   = "services/hostedservices/%s/deployments"
	azureDeploymentURL       = "services/hostedservices/%s/deployments/%s"
	azureListDeploymentsInSlotURL = "services/hostedservices/%s/deploymentslots/Production"
	deleteAzureDeploymentURL = "services/hostedservices/%s/deployments/%s?comp=media"
	azureAddRoleURL          = "services/hostedservices/%s/deployments/%s/roles"
	azureRoleURL             = "services/hostedservices/%s/deployments/%s/roles/%s"
	azureOperationsURL       = "services/hostedservices/%s/deployments/%s/roleinstances/%s/Operations"
	azureRoleSizeListURL     = "rolesizes"

	errParamNotSpecified = "Parameter %s is not specified."
)

//NewClient is used to instantiate a new VirtualMachineClient from an Azure client
func NewClient(client management.Client) VirtualMachineClient {
	return VirtualMachineClient{client: client}
}

// CreateDeploymentOptions can be used to create a customized deployement request
type CreateDeploymentOptions struct {
	DNSServers         []DNSServer
	LoadBalancers      []LoadBalancer
	ReservedIPName     string
	VirtualNetworkName string
}

// CreateDeployment creates a deployment and then creates a virtual machine
// in the deployment based on the specified configuration.
//
// https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx
func (vm VirtualMachineClient) CreateDeployment(
	role Role,
	cloudServiceName string,
	options CreateDeploymentOptions) (management.OperationID, error) {

	req := DeploymentRequest{
		Name:               role.RoleName,
		DeploymentSlot:     "Production",
		Label:              role.RoleName,
		RoleList:           []Role{role},
		DNSServers:         options.DNSServers,
		LoadBalancers:      options.LoadBalancers,
		ReservedIPName:     options.ReservedIPName,
		VirtualNetworkName: options.VirtualNetworkName,
	}

	data, err := xml.Marshal(req)
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureDeploymentListURL, cloudServiceName)
	return vm.client.SendAzurePostRequest(requestURL, data)
}

// GetDeploymentName queries an existing Azure cloud service for the name of the Deployment,
// if any, in its 'Production' slot (the only slot possible). If none exists, it returns empty
// string but no error
//
//https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx
func (vm VirtualMachineClient) GetDeploymentName(cloudServiceName string) (string, error) {
	var deployment DeploymentResponse
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	requestURL := fmt.Sprintf(azureListDeploymentsInSlotURL, cloudServiceName)
	response, err := vm.client.SendAzureGetRequest(requestURL)
	if err != nil {
		if management.IsResourceNotFoundError(err) {
			return "", nil
		} else {
			return "", err
		}
        }
	err = xml.Unmarshal(response, &deployment)
	if err != nil {
		return "", err
	}

	return deployment.Name, nil
}

func (vm VirtualMachineClient) GetDeployment(cloudServiceName, deploymentName string) (DeploymentResponse, error) {
	var deployment DeploymentResponse
	if cloudServiceName == "" {
		return deployment, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return deployment, fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	requestURL := fmt.Sprintf(azureDeploymentURL, cloudServiceName, deploymentName)
	response, azureErr := vm.client.SendAzureGetRequest(requestURL)
	if azureErr != nil {
		return deployment, azureErr
	}

	err := xml.Unmarshal(response, &deployment)
	return deployment, err
}

func (vm VirtualMachineClient) DeleteDeployment(cloudServiceName, deploymentName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}

	requestURL := fmt.Sprintf(deleteAzureDeploymentURL, cloudServiceName, deploymentName)
	return vm.client.SendAzureDeleteRequest(requestURL)
}

func (vm VirtualMachineClient) GetRole(cloudServiceName, deploymentName, roleName string) (*Role, error) {
	if cloudServiceName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return nil, fmt.Errorf(errParamNotSpecified, "roleName")
	}

	role := new(Role)

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	response, azureErr := vm.client.SendAzureGetRequest(requestURL)
	if azureErr != nil {
		return nil, azureErr
	}

	err := xml.Unmarshal(response, role)
	if err != nil {
		return nil, err
	}

	return role, nil
}

// AddRole adds a Virtual Machine to a deployment of Virtual Machines, where role name = VM name
// See https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx
func (vm VirtualMachineClient) AddRole(cloudServiceName string, deploymentName string, role Role) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}

	data, err := xml.Marshal(PersistentVMRole{Role: role})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureAddRoleURL, cloudServiceName, deploymentName)
	return vm.client.SendAzurePostRequest(requestURL, data)
}

// UpdateRole updates the configuration of the specified virtual machine
// See https://msdn.microsoft.com/en-us/library/azure/jj157187.aspx
func (vm VirtualMachineClient) UpdateRole(cloudServiceName, deploymentName, roleName string, role Role) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	data, err := xml.Marshal(PersistentVMRole{Role: role})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePutRequest(requestURL, "text/xml", data)
}

func (vm VirtualMachineClient) StartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	startRoleOperationBytes, err := xml.Marshal(StartRoleOperation{
		OperationType: "StartRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, startRoleOperationBytes)
}

func (vm VirtualMachineClient) ShutdownRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	shutdownRoleOperationBytes, err := xml.Marshal(ShutdownRoleOperation{
		OperationType: "ShutdownRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, shutdownRoleOperationBytes)
}

func (vm VirtualMachineClient) RestartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	restartRoleOperationBytes, err := xml.Marshal(RestartRoleOperation{
		OperationType: "RestartRoleOperation",
	})
	if err != nil {
		return "", err
	}

	requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzurePostRequest(requestURL, restartRoleOperationBytes)
}

func (vm VirtualMachineClient) DeleteRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName)
	return vm.client.SendAzureDeleteRequest(requestURL)
}

func (vm VirtualMachineClient) GetRoleSizeList() (RoleSizeList, error) {
	roleSizeList := RoleSizeList{}

	response, err := vm.client.SendAzureGetRequest(azureRoleSizeListURL)
	if err != nil {
		return roleSizeList, err
	}

	err = xml.Unmarshal(response, &roleSizeList)
	return roleSizeList, err
}

// CaptureRole captures a VM role. If reprovisioningConfigurationSet is non-nil,
// the VM role is redeployed after capturing the image, otherwise, the original
// VM role is deleted.
//
// NOTE: an image resulting from this operation shows up in
// osimage.GetImageList() as images with Category "User".
func (vm VirtualMachineClient) CaptureRole(cloudServiceName, deploymentName, roleName, imageName, imageLabel string,
	reprovisioningConfigurationSet *ConfigurationSet) (management.OperationID, error) {
	if cloudServiceName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName")
	}
	if deploymentName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "deploymentName")
	}
	if roleName == "" {
		return "", fmt.Errorf(errParamNotSpecified, "roleName")
	}

	if reprovisioningConfigurationSet != nil &&
		!(reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeLinuxProvisioning ||
			reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeWindowsProvisioning) {
		return "", fmt.Errorf("ConfigurationSet type can only be WindowsProvisioningConfiguration or LinuxProvisioningConfiguration")
	}

	operation := CaptureRoleOperation{
		OperationType:             "CaptureRoleOperation",
		PostCaptureAction:         PostCaptureActionReprovision,
		ProvisioningConfiguration: reprovisioningConfigurationSet,
		TargetImageLabel:          imageLabel,
		TargetImageName:           imageName,
	}
	if reprovisioningConfigurationSet == nil {
		operation.PostCaptureAction = PostCaptureActionDelete
	}

	data, err := xml.Marshal(operation)
	if err != nil {
		return "", err
	}

	return vm.client.SendAzurePostRequest(fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName), data)
}
<|endoftext|>


<commit_before>package doit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"strings"
	"text/tabwriter"

	"github.com/codegangsta/cli"
	"github.com/digitalocean/godo"
)

func displayOutput(c *cli.Context, item interface{}) error {
	output := c.GlobalString(ArgOutput)
	if len(output) < 1 {
		output = "text"
	}

	switch output {
	case "json":
		return writeJSON(item, c.App.Writer)
	case "text":
		return writeText(item, c.App.Writer)
	default:
		return fmt.Errorf("unknown output type")
	}
}

func writeJSON(item interface{}, w io.Writer) error {
	b, err := json.Marshal(item)
	if err != nil {
		return err
	}

	var out bytes.Buffer
	json.Indent(&out, b, "", "  ")
	_, err = out.WriteTo(w)
	return err
}

func writeText(item interface{}, w io.Writer) error {
	switch item.(type) {
	case *godo.Action:
		i := item.(*godo.Action)
		outputActions([]godo.Action{*i}, w)
	case []godo.Action:
		outputActions(item.([]godo.Action), w)
	case *godo.Domain:
		outputZone(item.(*godo.Domain), w)
	case *godo.Droplet:
		d := item.(*godo.Droplet)
		outputDroplets([]godo.Droplet{*d}, w)
	case []godo.Droplet:
		outputDroplets(item.([]godo.Droplet), w)
	case *godo.Image:
		i := item.(*godo.Image)
		outputImages([]godo.Image{*i}, w)
	case []godo.Image:
		outputImages(item.([]godo.Image), w)
	case *godo.Kernel:
		i := item.(*godo.Kernel)
		outputKernels([]godo.Kernel{*i}, w)
	case []godo.Kernel:
		outputKernels(item.([]godo.Kernel), w)
	case *godo.Key:
		i := item.(*godo.Key)
		outputSSHKeys([]godo.Key{*i}, w)
	case []godo.Key:
		outputSSHKeys(item.([]godo.Key), w)

	case []godo.Region:
		outputRegions(item.([]godo.Region), w)
	case []godo.Size:
		outputSizes(item.([]godo.Size), w)
	}

	return nil
}

func outputActions(list []godo.Action, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tStatus\tType\tStarted At\tCompleted At\tResource ID\tResource Type\tRegion")

	for _, a := range list {
		fmt.Fprintf(w, "")
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n",
			a.ID, a.Status, a.Type, a.StartedAt, a.CompletedAt, a.ResourceID, a.ResourceType, a.RegionSlug)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputDroplets(list []godo.Droplet, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tPublic IPv4\tMemory\tVCPUs\tDisk\tRegion\tImage\tStatus")

	for _, d := range list {
		ip := extractDropletPublicIP(&d)
		image := fmt.Sprintf("%s %s", d.Image.Distribution, d.Image.Name)
		fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\t%s\n",
			d.ID, d.Name, ip, d.Memory, d.Vcpus, d.Disk, d.Region.Slug, image, d.Status)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputImages(list []godo.Image, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tType\tDistribution\tSlug\tPublic\tRegions\tMin Disk")

	for _, i := range list {
		publicStatus := false
		if i.Public {
			publicStatus = true
		}

		regionList := strings.Join(i.Regions, ",")

		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%s\t%d\n",
			i.ID, i.Name, i.Type, i.Distribution, i.Slug, publicStatus, regionList, i.MinDiskSize)

	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputKernels(list []godo.Kernel, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tVersion")

	for _, k := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n", k.ID, k.Name, k.Version)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputRegions(list []godo.Region, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tName\tAvailable")

	for _, r := range list {
		fmt.Fprintf(w, "%s\t%s\t%t\n", r.Slug, r.Name, r.Available)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSizes(list []godo.Size, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tMemory\tVcpus\tDisk\tPrice Monthly\tPrice Hourly")

	for _, s := range list {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%0.2f\t%f\n",
			s.Slug, s.Memory, s.Vcpus, s.Disk, s.PriceMonthly, s.PriceHourly)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSSHKeys(list []godo.Key, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tFingerprint")

	for _, s := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n",
			s.ID, s.Name, s.Fingerprint)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputZone(domain *godo.Domain, out io.Writer) {
	fmt.Fprintln(out, domain.ZoneFile)
}
<commit_msg>remove region lists from image display<commit_after>package doit

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"text/tabwriter"

	"github.com/codegangsta/cli"
	"github.com/digitalocean/godo"
)

func displayOutput(c *cli.Context, item interface{}) error {
	output := c.GlobalString(ArgOutput)
	if len(output) < 1 {
		output = "text"
	}

	switch output {
	case "json":
		return writeJSON(item, c.App.Writer)
	case "text":
		return writeText(item, c.App.Writer)
	default:
		return fmt.Errorf("unknown output type")
	}
}

func writeJSON(item interface{}, w io.Writer) error {
	b, err := json.Marshal(item)
	if err != nil {
		return err
	}

	var out bytes.Buffer
	json.Indent(&out, b, "", "  ")
	_, err = out.WriteTo(w)
	return err
}

func writeText(item interface{}, w io.Writer) error {
	switch item.(type) {
	case *godo.Action:
		i := item.(*godo.Action)
		outputActions([]godo.Action{*i}, w)
	case []godo.Action:
		outputActions(item.([]godo.Action), w)
	case *godo.Domain:
		outputZone(item.(*godo.Domain), w)
	case *godo.Droplet:
		d := item.(*godo.Droplet)
		outputDroplets([]godo.Droplet{*d}, w)
	case []godo.Droplet:
		outputDroplets(item.([]godo.Droplet), w)
	case *godo.Image:
		i := item.(*godo.Image)
		outputImages([]godo.Image{*i}, w)
	case []godo.Image:
		outputImages(item.([]godo.Image), w)
	case *godo.Kernel:
		i := item.(*godo.Kernel)
		outputKernels([]godo.Kernel{*i}, w)
	case []godo.Kernel:
		outputKernels(item.([]godo.Kernel), w)
	case *godo.Key:
		i := item.(*godo.Key)
		outputSSHKeys([]godo.Key{*i}, w)
	case []godo.Key:
		outputSSHKeys(item.([]godo.Key), w)

	case []godo.Region:
		outputRegions(item.([]godo.Region), w)
	case []godo.Size:
		outputSizes(item.([]godo.Size), w)
	}

	return nil
}

func outputActions(list []godo.Action, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tStatus\tType\tStarted At\tCompleted At\tResource ID\tResource Type\tRegion")

	for _, a := range list {
		fmt.Fprintf(w, "")
		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%d\t%s\t%s\n",
			a.ID, a.Status, a.Type, a.StartedAt, a.CompletedAt, a.ResourceID, a.ResourceType, a.RegionSlug)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputDroplets(list []godo.Droplet, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tPublic IPv4\tMemory\tVCPUs\tDisk\tRegion\tImage\tStatus")

	for _, d := range list {
		ip := extractDropletPublicIP(&d)
		image := fmt.Sprintf("%s %s", d.Image.Distribution, d.Image.Name)
		fmt.Fprintf(w, "%d\t%s\t%s\t%d\t%d\t%d\t%s\t%s\t%s\n",
			d.ID, d.Name, ip, d.Memory, d.Vcpus, d.Disk, d.Region.Slug, image, d.Status)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputImages(list []godo.Image, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tType\tDistribution\tSlug\tPublic\tMin Disk")

	for _, i := range list {
		publicStatus := false
		if i.Public {
			publicStatus = true
		}

		fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t%t\t%d\n",
			i.ID, i.Name, i.Type, i.Distribution, i.Slug, publicStatus, i.MinDiskSize)

	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputKernels(list []godo.Kernel, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tVersion")

	for _, k := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n", k.ID, k.Name, k.Version)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputRegions(list []godo.Region, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tName\tAvailable")

	for _, r := range list {
		fmt.Fprintf(w, "%s\t%s\t%t\n", r.Slug, r.Name, r.Available)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSizes(list []godo.Size, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "Slug\tMemory\tVcpus\tDisk\tPrice Monthly\tPrice Hourly")

	for _, s := range list {
		fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%0.2f\t%f\n",
			s.Slug, s.Memory, s.Vcpus, s.Disk, s.PriceMonthly, s.PriceHourly)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputSSHKeys(list []godo.Key, out io.Writer) {
	w := new(tabwriter.Writer)
	w.Init(out, 0, 8, 1, '\t', 0)

	fmt.Fprintln(w, "ID\tName\tFingerprint")

	for _, s := range list {
		fmt.Fprintf(w, "%d\t%s\t%s\n",
			s.ID, s.Name, s.Fingerprint)
	}
	fmt.Fprintln(w)
	w.Flush()
}

func outputZone(domain *godo.Domain, out io.Writer) {
	fmt.Fprintln(out, domain.ZoneFile)
}
<|endoftext|>