<commit_before>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"sync"
	"time"
)

type Adminz struct {
	// keep track of killfile state
	running bool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	onresume func()

	// pause is called when the server is killed
	onpause func()

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool

	sync.Mutex

	// the various handlers are attached to serveMux or DefaultServeMux
	mux *http.ServeMux
}

// Creates a new Adminz "builder". Not safe to use until Start() is called.
func New() *Adminz {
	return &Adminz{}
}

func (a *Adminz) Resume() {
	a.Lock()
	defer a.Unlock()
	a.doResume()
}

// Internal helper to resume if stopped. MUST be called while holding a.Lock. Use a.Resume if not.
func (a *Adminz) doResume() {
	if !a.running {
		if a.onresume != nil {
			a.onresume()
		}
		a.running = true
	}
}

func (a *Adminz) ServeMux(mux *http.ServeMux) *Adminz {
	a.mux = mux
	return a
}

// Resume is called when the server is unkilled
func (a *Adminz) OnResume(resume func()) *Adminz {
	a.onresume = resume
	return a
}

// Pause the server if it is running and return true, otherwise no-op and return false.
func (a *Adminz) Pause() bool {
	a.Lock()
	defer a.Unlock()
	return a.doPause()
}

// Internal helper to pause if running. MUST be called while holding a.Lock. Use a.Pause if not.
func (a *Adminz) doPause() bool {
	was := a.running
	if a.running {
		if a.onpause != nil {
			a.onpause()
		}
		a.running = false
	}
	return was
}

// pause is called when the server is killed
func (a *Adminz) OnPause(pause func()) *Adminz {
	a.onpause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Start initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Start() *Adminz {
	if a.mux != nil {
		a.mux.HandleFunc("/healthz", a.healthzHandler)
		a.mux.HandleFunc("/servicez", a.ServicezHandler)
		a.mux.HandleFunc("/gc", a.gcHandler)
	} else {
		http.HandleFunc("/healthz", a.healthzHandler)
		http.HandleFunc("/servicez", a.ServicezHandler)
		http.HandleFunc("/gc", a.gcHandler)
	}

	log.Print("adminz registered")

	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		log.Print("Watching paths for killfile: ", a.killfilePaths)
		a.checkKillfiles()
		go a.killfileLoop()
	} else {
		log.Print("No killfiles being watched.")
	}

	return a
}

// Stops killfile checking
func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...int) []string {
	// the number of ports + the "all" killfile
	log.Print(ports)
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%d", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			if a.Pause() {
				log.Println("paused due to ", killfile)
			}
			return true
		}
	}
	a.Resume()
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		a.checkKillfiles()
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string

	if a.running && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
		log.Println("Healthz returning ", ret)
	}

	w.Write(([]byte)(ret))
}

type EmptyStruct struct {
}

func (a *Adminz) ServicezHandler(w http.ResponseWriter, r *http.Request) {
	var data interface{}

	if a.servicez != nil {
		data = a.servicez()
	} else {
		data = &EmptyStruct{}
	}

	bytes, err := json.Marshal(data)
	if err == nil {
		w.Header().Add("Content-Type", "text/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}

func (a *Adminz) gcHandler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats

	mb := uint64(1024 * 1024)
	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "Before")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	a.Lock()
	was := a.doPause()
	runtime.GC()
	if was {
		a.doResume()
	}
	a.Unlock()

	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "After")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	w.Write([]byte("OK"))
}
<commit_msg>use application/json as the adminz content type<commit_after>// Package adminz provides a simple set of adminz pages for administering
// a simple go server.
package adminz

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"runtime"
	"sync"
	"time"
)

type Adminz struct {
	// keep track of killfile state
	running bool

	// ticker that checks killfiles every 1 second
	killfileTicker *time.Ticker

	// list of killfilePaths to check
	killfilePaths []string

	// defaults to 1 second
	checkInterval time.Duration

	// generates data to return to /servicez endpoint. marshalled into json.
	servicez func() interface{}

	// resume is called when the server is unkilled
	onresume func()

	// pause is called when the server is killed
	onpause func()

	// healthy returns true iff the server is ready to respond to requests
	healthy func() bool

	sync.Mutex

	// the various handlers are attached to serveMux or DefaultServeMux
	mux *http.ServeMux
}

// Creates a new Adminz "builder". Not safe to use until Start() is called.
func New() *Adminz {
	return &Adminz{}
}

func (a *Adminz) Resume() {
	a.Lock()
	defer a.Unlock()
	a.doResume()
}

// Internal helper to resume if stopped. MUST be called while holding a.Lock. Use a.Resume if not.
func (a *Adminz) doResume() {
	if !a.running {
		if a.onresume != nil {
			a.onresume()
		}
		a.running = true
	}
}

func (a *Adminz) ServeMux(mux *http.ServeMux) *Adminz {
	a.mux = mux
	return a
}

// Resume is called when the server is unkilled
func (a *Adminz) OnResume(resume func()) *Adminz {
	a.onresume = resume
	return a
}

// Pause the server if it is running and return true, otherwise no-op and return false.
func (a *Adminz) Pause() bool {
	a.Lock()
	defer a.Unlock()
	return a.doPause()
}

// Internal helper to pause if running. MUST be called while holding a.Lock. Use a.Pause if not.
func (a *Adminz) doPause() bool {
	was := a.running
	if a.running {
		if a.onpause != nil {
			a.onpause()
		}
		a.running = false
	}
	return was
}

// pause is called when the server is killed
func (a *Adminz) OnPause(pause func()) *Adminz {
	a.onpause = pause
	return a
}

// healthy returns true iff the server is ready to respond to requests
func (a *Adminz) Healthy(healthy func() bool) *Adminz {
	a.healthy = healthy
	return a
}

// servicez generates data to return to /servicez endpoint. marshalled into
// json.
func (a *Adminz) Servicez(servicez func() interface{}) *Adminz {
	a.servicez = servicez
	return a
}

// Sets the list of killfilePaths to check.
func (a *Adminz) KillfilePaths(killfilePaths []string) *Adminz {
	a.killfilePaths = killfilePaths
	return a
}

// Sets frequency the killfile is checked. defaults every second
func (a *Adminz) KillfileInterval(interval time.Duration) *Adminz {
	a.checkInterval = interval
	return a
}

// Start initializes handlers and starts killfile checking. Make sure to
// remember to call this!
func (a *Adminz) Start() *Adminz {
	if a.mux != nil {
		a.mux.HandleFunc("/healthz", a.healthzHandler)
		a.mux.HandleFunc("/servicez", a.ServicezHandler)
		a.mux.HandleFunc("/gc", a.gcHandler)
	} else {
		http.HandleFunc("/healthz", a.healthzHandler)
		http.HandleFunc("/servicez", a.ServicezHandler)
		http.HandleFunc("/gc", a.gcHandler)
	}

	log.Print("adminz registered")

	if a.checkInterval == 0 {
		a.checkInterval = 1 * time.Second
	}
	a.killfileTicker = time.NewTicker(a.checkInterval)

	// start killfile checking loop
	if len(a.killfilePaths) > 0 {
		log.Print("Watching paths for killfile: ", a.killfilePaths)
		a.checkKillfiles()
		go a.killfileLoop()
	} else {
		log.Print("No killfiles being watched.")
	}

	return a
}

// Stops killfile checking
func (a *Adminz) Stop() {
	if a.killfileTicker != nil {
		a.killfileTicker.Stop()
	}
}

// Generates the standard set of killfiles. Pass these to KillfilePaths
func Killfiles(ports ...int) []string {
	// the number of ports + the "all" killfile
	log.Print(ports)
	var ret = make([]string, len(ports)+1)
	for i, port := range ports {
		ret[i] = fmt.Sprintf("/dev/shm/healthz/kill.%d", port)
	}
	ret[len(ports)] = "/dev/shm/healthz/kill.all"
	return ret
}

func (a *Adminz) checkKillfiles() bool {
	for _, killfile := range a.killfilePaths {
		file, err := os.Open(killfile)
		if file != nil && err == nil {
			file.Close()
			if a.Pause() {
				log.Println("paused due to ", killfile)
			}
			return true
		}
	}
	a.Resume()
	return false
}

func (a *Adminz) killfileLoop() {
	for _ = range a.killfileTicker.C {
		a.checkKillfiles()
	}
}

func (a *Adminz) healthzHandler(w http.ResponseWriter, r *http.Request) {
	// we are healthy iff:
	// we are not killed AND
	// a.healthy is unset (so we ignore it) OR
	// a.healthy() returns true
	var ret string

	if a.running && (a.healthy == nil || a.healthy()) {
		ret = "OK"
	} else {
		w.WriteHeader(http.StatusServiceUnavailable)
		ret = "Service Unavailable"
		log.Println("Healthz returning ", ret)
	}

	w.Write(([]byte)(ret))
}

type EmptyStruct struct {
}

func (a *Adminz) ServicezHandler(w http.ResponseWriter, r *http.Request) {
	var data interface{}

	if a.servicez != nil {
		data = a.servicez()
	} else {
		data = &EmptyStruct{}
	}

	bytes, err := json.Marshal(data)
	if err == nil {
		w.Header().Add("Content-Type", "application/json")
		// TODO I probably need to serialize reads to servicez as who knows what
		// people will put in that function
		w.Write(bytes)
	} else {
		http.Error(w, err.Error(), 500)
	}
}

func (a *Adminz) gcHandler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats

	mb := uint64(1024 * 1024)
	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "Before")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	a.Lock()
	was := a.doPause()
	runtime.GC()
	if was {
		a.doResume()
	}
	a.Unlock()

	runtime.ReadMemStats(&mem)
	fmt.Fprintln(w, "After")
	fmt.Fprintln(w, "\tAlloc\t", mem.Alloc/mb)
	fmt.Fprintln(w, "\tTotalAlloc:\t", mem.TotalAlloc/mb)
	fmt.Fprintln(w, "\tHeapAlloc:\t", mem.HeapAlloc/mb)
	fmt.Fprintln(w, "\tHeapSys:\t", mem.HeapSys/mb)
	fmt.Fprintln(w, "\tSys:\t", mem.Sys/mb)

	w.Write([]byte("OK"))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"log"
	"net/http"
	_ "net/http/pprof"
	"sync"

	"github.com/uber/tchannel/golang"
	"github.com/uber/tchannel/golang/raw"
	"golang.org/x/net/context"
)

var hostPort = flag.String("hostPort", "localhost:12345", "listening socket for the server")

func main() {
	// Sets up a listener for pprof.
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	ch, err := tchannel.NewChannel("bench-server", &tchannel.ChannelOptions{
		ProcessName: "bench-server",
	})
	if err != nil {
		log.Fatalf("NewChannel failed: %v", err)
	}

	handler := raw.Wrap(&kvHandler{vals: make(map[string]string)})
	ch.Register(handler, "get")
	ch.Register(handler, "set")

	if err := ch.ListenAndServe(*hostPort); err != nil {
		log.Fatalf("ListenAndServe failed: %v", err)
	}

	// Listen indefinitely.
	select {}
}

type kvHandler struct {
	mut  sync.RWMutex
	vals map[string]string
}

func (h *kvHandler) WithLock(write bool, f func()) {
	if write {
		h.mut.Lock()
	} else {
		h.mut.RLock()
	}

	f()

	if write {
		h.mut.Unlock()
	} else {
		h.mut.RUnlock()
	}
}

func (h *kvHandler) Get(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	var arg3 []byte
	h.WithLock(false /* write */, func() {
		arg3 = []byte(h.vals[string(args.Arg2)])
	})

	return &raw.Res{
		Arg3: arg3,
	}, nil
}

func (h *kvHandler) Set(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	h.WithLock(true /* write */, func() {
		h.vals[string(args.Arg2)] = string(args.Arg3)
	})
	return &raw.Res{}, nil
}

func (h *kvHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	switch args.Operation {
	case "get":
		return h.Get(ctx, args)
	case "put":
		return h.Set(ctx, args)
	default:
		return nil, errors.New("unknown operation")
	}
}

func (h *kvHandler) OnError(ctx context.Context, err error) {
	log.Fatalf("OnError %v", err)
}
<commit_msg>make go bench server work the same way as the node bench server<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"sync"

	"github.com/uber/tchannel/golang"
	"github.com/uber/tchannel/golang/raw"
	"golang.org/x/net/context"
)

var hostPort = flag.String("hostPort", "localhost:12345", "listening socket for the server")

func main() {
	flag.Parse()

	// Sets up a listener for pprof.
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	ch, err := tchannel.NewChannel("benchmark", &tchannel.ChannelOptions{
		ProcessName: "benchmark",
	})
	if err != nil {
		log.Fatalf("NewChannel failed: %v", err)
	}

	handler := raw.Wrap(&kvHandler{vals: make(map[string]string)})
	ch.Register(handler, "ping")
	ch.Register(handler, "get")
	ch.Register(handler, "set")

	if err := ch.ListenAndServe(*hostPort); err != nil {
		log.Fatalf("ListenAndServe failed: %v", err)
	}

	// Listen indefinitely.
	select {}
}

type kvHandler struct {
	mut  sync.RWMutex
	vals map[string]string
}

func (h *kvHandler) WithLock(write bool, f func()) {
	if write {
		h.mut.Lock()
	} else {
		h.mut.RLock()
	}

	f()

	if write {
		h.mut.Unlock()
	} else {
		h.mut.RUnlock()
	}
}

func (h *kvHandler) Ping(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	return &raw.Res{
		Arg2: []byte("pong"),
	}, nil
}

func (h *kvHandler) Get(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	var arg3 []byte
	h.WithLock(false /* write */, func() {
		arg3 = []byte(h.vals[string(args.Arg2)])
	})

	return &raw.Res{
		Arg2: []byte(fmt.Sprint(len(arg3))),
		Arg3: arg3,
	}, nil
}

func (h *kvHandler) Set(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	h.WithLock(true /* write */, func() {
		h.vals[string(args.Arg2)] = string(args.Arg3)
	})
	return &raw.Res{
		Arg2: []byte("ok"),
		Arg3: []byte("really ok"),
	}, nil
}

func (h *kvHandler) Handle(ctx context.Context, args *raw.Args) (*raw.Res, error) {
	switch args.Operation {
	case "ping":
		return h.Ping(ctx, args)
	case "get":
		return h.Get(ctx, args)
	case "put":
		return h.Set(ctx, args)
	default:
		return nil, errors.New("unknown operation")
	}
}

func (h *kvHandler) OnError(ctx context.Context, err error) {
	log.Fatalf("OnError %v", err)
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/promise.go                                     *
 *                                                        *
 * promise interface for Go.                              *
 *                                                        *
 * LastModified: Aug 11, 2015                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import "time"

// OnFulfilled is a function called when the Promise is fulfilled.
// This function has one argument, the fulfillment value.
type OnFulfilled func(interface{}) (interface{}, error)

// OnRejected is a function called when the Promise is rejected.
// This function has one argument, the rejection reason.
type OnRejected func(error) (interface{}, error)

// OnCompleted is a function called when the Promise is completed.
// This function has one argument,
// the fulfillment value when the Promise is fulfilled,
// or the rejection reason when the Promise is rejected.
type OnCompleted func(interface{}) (interface{}, error)

// OnfulfilledSideEffect is a function used as the argument of Promise.Tap
type OnfulfilledSideEffect func(interface{})

// TestFunc is a function used as the argument of Promise.Catch
type TestFunc func(error) bool

// Thenable is an interface that defines a Then method.
type Thenable interface {
	// Then method returns a Promise. It takes two arguments: callback functions
	// for the success and failure cases of the Promise.
	Then(onFulfilled OnFulfilled, onRejected ...OnRejected) Promise
}

// Promise is an interface of the JS Promise/A+ spec
// (https://promisesaplus.com/).
type Promise interface {
	Thenable

	// Catch handles errors emitted by this Promise.
	//
	// This is the asynchronous equivalent of a "catch" block.
	//
	// Returns a new Promise that will be completed with either the result of
	// this promise or the result of calling the onRejected callback.
	//
	// If this promise completes with a value, the returned promise completes
	// with the same value.
	//
	// If this promise completes with an error, then test is first called with
	// the error value.
	//
	// If test returns false, the error is not handled by this Catch, and the
	// returned promise completes with the same error and stack trace as this
	// promise.
	//
	// If test returns true, onRejected is called with the error and possibly
	// stack trace, and the returned promise is completed with the result of
	// this call in exactly the same way as for Then's onRejected.
	//
	// If test is omitted, it defaults to a function that always returns true.
	// The test function should not panic, but if it does, it is handled as if
	// the the onRejected function had panic.
	Catch(onRejected OnRejected, test ...TestFunc) Promise

	// Complete is the same way as Then(onCompleted, onCompleted)
	Complete(onCompleted OnCompleted) Promise

	// WhenComplete register a function to be called when the promise completes.
	//
	// The action function is called when this promise completes, whether it
	// does so with a value or with an error.
	//
	// If this promise completes with a value, the returned promise completes
	// with the same value.
	//
	// If this promise completes with an error, the returned promise completes
	// with the same error.
	//
	// The action function should not panic, but if it does, the returned promise completes with a PanicError.
	WhenComplete(action func()) Promise

	// Done is the same semantics as Then except that it don't return a Promise.
	// If the callback function (onFulfilled or onRejected) returns error or
	// panics, the application will be crashing.
	// The result of the callback function will be ignored.
	Done(onFulfilled OnFulfilled, onRejected ...OnRejected)

	// Fail is the same way as Done(nil, onRejected)
	Fail(onRejected OnRejected)

	// Always is the same way as Done(onCompleted, onCompleted)
	Always(onCompleted OnCompleted)

	// State return the current state of the Promise
	State() State

	// Resolve method returns a Promise object that is resolved with the given
	// value. If the value is a Thenable (i.e. has a Then method), the returned
	// promise will "follow" that Thenable, adopting its eventual state;
	// otherwise the returned promise will be fulfilled with the value.
	Resolve(value interface{})

	// Reject method returns a Promise object that is rejected with the given
	// reason.
	Reject(reason error)

	// Fill the promise with this promise if the promise is in PENDING state.
	// otherwise nothing to do.
	Fill(promise Promise)

	// Timeout create a new promise that will reject with a TimeoutError or a
	// custom reason after a timeout if promise does not fulfill or reject
	// beforehand.
	Timeout(duration time.Duration, reason ...error) Promise

	// Delay create a new promise that will, after duration delay, fulfill with
	// the same value as this promise. If this promise rejects, delayed promise
	// will be rejected immediately.
	Delay(duration time.Duration) Promise

	// Tap executes a function as a side effect when promise fulfills.
	//
	// It returns a new promise:
	// 1. If promise fulfills, onFulfilledSideEffect is executed:
	//     * If onFulfilledSideEffect returns successfully, the promise
	//       returned by tap fulfills with promise's original fulfillment
	//       value.
	//     * If onFulfilledSideEffect panics, the promise returned by tap
	//       rejects with the panic message as the reason.
	// 2. If promise rejects, onFulfilledSideEffect is not executed, and the
	//    promise returned by tap rejects with promise's rejection reason.
	Tap(onfulfilledSideEffect OnfulfilledSideEffect) Promise

	// Get the value and reason synchronously, if this promise in PENDING state.
	// this method will block the current goroutine.
	Get() (interface{}, error)
}
<commit_msg>Update document comments<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/promise.go                                     *
 *                                                        *
 * promise interface for Go.                              *
 *                                                        *
 * LastModified: Aug 11, 2015                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import "time"

// OnFulfilled is a function called when the Promise is fulfilled.
// This function has one argument, the fulfillment value.
type OnFulfilled func(interface{}) (interface{}, error)

// OnRejected is a function called when the Promise is rejected.
// This function has one argument, the rejection reason.
type OnRejected func(error) (interface{}, error)

// OnCompleted is a function called when the Promise is completed.
// This function has one argument,
// the fulfillment value when the Promise is fulfilled,
// or the rejection reason when the Promise is rejected.
type OnCompleted func(interface{}) (interface{}, error)

// OnfulfilledSideEffect is a function used as the argument of Promise.Tap
type OnfulfilledSideEffect func(interface{})

// TestFunc is a function used as the argument of Promise.Catch
type TestFunc func(error) bool

// Thenable is an interface that defines a Then method.
type Thenable interface {
	// Then method returns a Promise. It takes two arguments: callback functions
	// for the success and failure cases of the Promise.
	Then(onFulfilled OnFulfilled, onRejected ...OnRejected) Promise
}

// Promise is an interface of the JS Promise/A+ spec
// (https://promisesaplus.com/).
type Promise interface {
	Thenable

	// Catch handles errors emitted by this Promise.
	//
	// This is the asynchronous equivalent of a "catch" block.
	//
	// Returns a new Promise that will be completed with either the result of
	// this promise or the result of calling the onRejected callback.
	//
	// If this promise completes with a value, the returned promise completes
	// with the same value.
	//
	// If this promise completes with an error, then test is first called with
	// the error value.
	//
	// If test returns false, the error is not handled by this Catch, and the
	// returned promise completes with the same error and stack trace as this
	// promise.
	//
	// If test returns true, onRejected is called with the error and possibly
	// stack trace, and the returned promise is completed with the result of
	// this call in exactly the same way as for Then's onRejected.
	//
	// If test is omitted, it defaults to a function that always returns true.
	// The test function should not panic, but if it does, it is handled as if
	// the the onRejected function had panic.
	Catch(onRejected OnRejected, test ...TestFunc) Promise

	// Complete is the same way as Then(onCompleted, onCompleted)
	Complete(onCompleted OnCompleted) Promise

	// WhenComplete register a function to be called when the promise completes.
	//
	// The action function is called when this promise completes, whether it
	// does so with a value or with an error.
	//
	// If this promise completes with a value, the returned promise completes
	// with the same value.
	//
	// If this promise completes with an error, the returned promise completes
	// with the same error.
	//
	// The action function should not panic, but if it does, the returned
	// promise completes with a PanicError.
	WhenComplete(action func()) Promise

	// Done is the same semantics as Then except that it don't return a Promise.
	// If the callback function (onFulfilled or onRejected) returns error or
	// panics, the application will be crashing.
	// The result of the callback function will be ignored.
	Done(onFulfilled OnFulfilled, onRejected ...OnRejected)

	// Fail is the same way as Done(nil, onRejected)
	Fail(onRejected OnRejected)

	// Always is the same way as Done(onCompleted, onCompleted)
	Always(onCompleted OnCompleted)

	// State return the current state of the Promise
	State() State

	// Resolve method returns a Promise object that is resolved with the given
	// value. If the value is a Thenable (i.e. has a Then method), the returned
	// promise will "follow" that Thenable, adopting its eventual state;
	// otherwise the returned promise will be fulfilled with the value.
	Resolve(value interface{})

	// Reject method returns a Promise object that is rejected with the given
	// reason.
	Reject(reason error)

	// Fill the promise with this promise if the promise is in PENDING state.
	// otherwise nothing to do.
	Fill(promise Promise)

	// Timeout create a new promise that will reject with a TimeoutError or a
	// custom reason after a timeout if promise does not fulfill or reject
	// beforehand.
	Timeout(duration time.Duration, reason ...error) Promise

	// Delay create a new promise that will, after duration delay, fulfill with
	// the same value as this promise. If this promise rejects, delayed promise
	// will be rejected immediately.
	Delay(duration time.Duration) Promise

	// Tap executes a function as a side effect when promise fulfills.
	//
	// It returns a new promise:
	// 1. If promise fulfills, onFulfilledSideEffect is executed:
	//     * If onFulfilledSideEffect returns successfully, the promise
	//       returned by tap fulfills with promise's original fulfillment
	//       value.
	//     * If onFulfilledSideEffect panics, the promise returned by tap
	//       rejects with the panic message as the reason.
	// 2. If promise rejects, onFulfilledSideEffect is not executed, and the
	//    promise returned by tap rejects with promise's rejection reason.
	Tap(onfulfilledSideEffect OnfulfilledSideEffect) Promise

	// Get the value and reason synchronously, if this promise in PENDING state.
	// this method will block the current goroutine.
	Get() (interface{}, error)
}
<|endoftext|>


<commit_before>package vix

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"time"

	"github.com/c4milo/unzipit"
	govix "github.com/cloudescape/govix"
	"github.com/dustin/go-humanize"
)

// Virtual machine configuration
type VM struct {
	// Which VMware VIX service provider to use. ie: fusion, workstation, server, etc
	Provider string
	// Whether to verify SSL or not for remote connections in ESXi
	VerifySSL bool
	// Name of the virtual machine
	Name string
	// Description for the virtual machine, it is created as an annotation in
	// VMware.
	Description string
	// Image to use during the creation of this virtual machine
	Image Image
	// Number of virtual cpus
	CPUs uint
	// Memory size in megabytes.
	Memory string
	// Switches to where this machine is going to be attach to
	VSwitches []string
	// Whether to upgrade the VM virtual hardware
	UpgradeVHardware bool
	// The timeout to wait for VMware Tools to be initialized inside the VM
	ToolsInitTimeout time.Duration
	// Whether to launch the VM with graphical environment
	LaunchGUI bool
	// Whether to enable or disable shared folders for this VM
	SharedFolders bool
	// Network adapters
	VNetworkAdapters []*govix.NetworkAdapter
	// VM IP address as reported by VIX
	IPAddress string
}

// Creates VIX instance with VMware
func (v *VM) client() (*govix.Host, error) {
	var p govix.Provider

	switch strings.ToLower(v.Provider) {
	case "fusion", "workstation":
		p = govix.VMWARE_WORKSTATION
	case "serverv1":
		p = govix.VMWARE_SERVER
	case "serverv2":
		p = govix.VMWARE_VI_SERVER
	case "player":
		p = govix.VMWARE_PLAYER
	case "workstation_shared":
		p = govix.VMWARE_WORKSTATION_SHARED
	default:
		p = govix.VMWARE_WORKSTATION
	}

	var options govix.HostOption
	if v.VerifySSL {
		options = govix.VERIFY_SSL_CERT
	}

	host, err := govix.Connect(govix.ConnectConfig{
		Provider: p,
		Options:  options,
	})

	if err != nil {
		return nil, err
	}

	log.Printf("[INFO] VIX client configured for product: VMware %s. SSL: %t", v.Provider, v.VerifySSL)

	return host, nil
}

// Sets default values for VM attributes
func (v *VM) SetDefaults() {
	if v.CPUs <= 0 {
		v.CPUs = 1
	}

	if v.Memory == "" {
		v.Memory = "512mib"
	}

	if v.Description == "" {
		v.Description = "Machine was created using Terraform VIX provider"
	}

	if v.ToolsInitTimeout.Seconds() <= 0 {
		v.ToolsInitTimeout = time.Duration(30) * time.Second
	}
}

// Downloads, extracts and opens Gold virtual machine, then it creates a clone
// out of it.
func (v *VM) Create() (string, error) {
	log.Printf("[DEBUG] Creating VM resource...")

	usr, err := user.Current()
	if err != nil {
		return "", err
	}

	image := v.Image

	imgPath := filepath.Join(usr.HomeDir, ".terraform/vix/images", image.Checksum)
	if err = image.Download(imgPath); err != nil {
		return "", err
	}
	defer image.file.Close()

	goldPath := filepath.Join(usr.HomeDir, filepath.Join(".terraform/vix/gold", image.Checksum))
	_, err = os.Stat(goldPath)
	goldPathExist := err == nil || err != os.ErrNotExist

	// There is no need to get the error as the slice will be empty anyway
	finfo, _ := ioutil.ReadDir(goldPath)
	goldPathEmpty := len(finfo) == 0

	if !goldPathExist || goldPathEmpty {
		log.Println("[DEBUG] Gold virtual machine does not exist or is empty")
		log.Printf("[DEBUG] Unpacking Gold virtual machine into %s\n", goldPath)
		_, err = unzipit.Unpack(image.file, goldPath)
		if err != nil {
			return "", err
		}
	}

	pattern := filepath.Join(goldPath, "/**/*.vmx")

	log.Printf("[DEBUG] Finding Gold virtual machine vmx file in %s", pattern)
	files, _ := filepath.Glob(pattern)

	if len(files) == 0 {
		return "", fmt.Errorf("[ERROR] vmx file was not found: %s", pattern)
	}

	vmxFile := files[0]
	log.Printf("[DEBUG] Gold virtual machine vmx file found %v", vmxFile)

	// Gets VIX instance
	client, err := v.client()
	if err != nil {
		return "", err
	}
	defer client.Disconnect()

	log.Printf("[INFO] Opening Gold virtual machine from %s", vmxFile)

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return "", err
	}

	newvmx := filepath.Join(usr.HomeDir, ".terraform/vix/vms",
		image.Checksum, v.Name, v.Name+".vmx")

	if _, err = os.Stat(newvmx); err != os.ErrExist {
		log.Printf("[INFO] Cloning gold vm into %s...", newvmx)
		_, err := vm.Clone(govix.CLONETYPE_FULL, newvmx)
		// If there is an error and the error is other than "The snapshot already exists"
		// then return the error
		if err != nil && err.(*govix.VixError).Code != 13004 {
			return "", err
		}

		// Makes sure the first time the VM is created it has no virtual network adapters
		// log.Printf("[DEBUG] Removing all virtual network adapters from cloned VM...")
		// err = clonedVM.RemoveAllNetworkAdapters()
		// if err != nil {
		// 	return "", err
		// }
	} else {
		log.Printf("[INFO] VM Clone %s already exist, moving on.", newvmx)
	}

	if err = v.Update(newvmx); err != nil {
		return "", err
	}

	return newvmx, nil
}

// Opens and updates virtual machine resource
func (v *VM) Update(vmxFile string) error {
	// Sets default values if some attributes were not set or have
	// invalid values
	v.SetDefaults()

	// Gets VIX instance
	client, err := v.client()
	if err != nil {
		return err
	}
	defer client.Disconnect()

	if client.Provider == govix.VMWARE_VI_SERVER ||
		client.Provider == govix.VMWARE_SERVER {
		log.Printf("[INFO] Registering VM in host's inventory...")
		err = client.RegisterVm(vmxFile)
		if err != nil {
			return err
		}
	}

	log.Printf("[INFO] Opening virtual machine from %s", vmxFile)

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return err
	}

	running, err := vm.IsRunning()
	if err != nil {
		return err
	}

	if running {
		log.Printf("[INFO] Virtual machine seems to be running, we need to " +
			"power it off in order to make changes.")
		err = v.powerOff(vm)
		if err != nil {
			return err
		}
	}

	memoryInMb, err := humanize.ParseBytes(v.Memory)
	if err != nil {
		log.Printf("[WARN] Unable to set memory size, defaulting to 512mib: %s", err)
		memoryInMb = 512
	} else {
		memoryInMb = (memoryInMb / 1024) / 1024
	}

	log.Printf("[DEBUG] Setting memory size to %d megabytes", memoryInMb)
	vm.SetMemorySize(uint(memoryInMb))

	log.Printf("[DEBUG] Setting vcpus to %d", v.CPUs)
	vm.SetNumberVcpus(uint8(v.CPUs))

	log.Printf("[DEBUG] Setting name to %s", v.Name)
	vm.SetDisplayName(v.Name)

	log.Printf("[DEBUG] Setting description to %s", v.Description)
	vm.SetAnnotation(v.Description)

	if v.UpgradeVHardware &&
		client.Provider != govix.VMWARE_PLAYER {

		log.Println("[INFO] Upgrading virtual hardware...")
		err = vm.UpgradeVHardware()
		if err != nil {
			return err
		}
	}

	// log.Printf("[DEBUG] Loading all network adapters in memory...")
	// curAdapters, err := vm.NetworkAdapters()
	// if err != nil {
	// 	return err
	// }

	log.Printf("[DEBUG] Removing all network adapters from vmx file...")
	err = vm.RemoveAllNetworkAdapters()
	if err != nil {
		return err
	}

	log.Println("[DEBUG] Attaching virtual network adapters...")
	for _, adapter := range v.VNetworkAdapters {
		adapter.StartConnected = true
		if adapter.ConnType == govix.NETWORK_BRIDGED {
			adapter.LinkStatePropagation = true
		}

		log.Printf("[DEBUG] Adapter: %+v", adapter)
		err := vm.AddNetworkAdapter(adapter)
		if err != nil {
			return err
		}
	}

	log.Println("[INFO] Powering virtual machine on...")
	var options govix.VMPowerOption

	if v.LaunchGUI {
		log.Println("[INFO] Preparing to launch GUI...")
		options |= govix.VMPOWEROP_LAUNCH_GUI
	}

	options |= govix.VMPOWEROP_NORMAL

	err = vm.PowerOn(options)
	if err != nil {
		return err
	}

	log.Println("[INFO] Waiting for VMware Tools to initialize...")
	err = vm.WaitForToolsInGuest(v.ToolsInitTimeout)
	if err != nil {
		log.Println("[WARN] VMware Tools took too long to initialize or is not " +
			"installed.")

		if v.SharedFolders {
			log.Println("[WARN] Enabling shared folders is not possible.")
		}
		return nil
	}

	if v.SharedFolders {
		log.Println("[DEBUG] Enabling shared folders...")

		err = vm.EnableSharedFolders(v.SharedFolders)
		if err != nil {
			return err
		}
	}
	return nil
}

// Powers off a virtual machine attempting a graceful shutdown.
func (v *VM) powerOff(vm *govix.VM) error {
	tstate, err := vm.ToolsState()
	if err != nil {
		return err
	}

	var powerOpts govix.VMPowerOption
	log.Printf("Tools state %d", tstate)

	if (tstate & govix.TOOLSSTATE_RUNNING) != 0 {
		log.Printf("[INFO] VMware Tools is running, attempting a graceful shutdown...")
		// if VMware Tools is running, attempt a graceful shutdown.
		powerOpts |= govix.VMPOWEROP_FROM_GUEST
	} else {
		log.Printf("[INFO] VMware Tools is NOT running, shutting down the " +
			"machine abruptly...")
		powerOpts |= govix.VMPOWEROP_NORMAL
	}

	err = vm.PowerOff(powerOpts)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Virtual machine is off.")

	return nil
}

// Destroys a virtual machine resource
func (v *VM) Destroy(vmxFile string) error {
	log.Printf("[DEBUG] Destroying VM resource %s...", vmxFile)

	client, err := v.client()
	if err != nil {
		return err
	}
	defer client.Disconnect()

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return err
	}

	running, err := vm.IsRunning()
	if err != nil {
		return err
	}

	if running {
		if err = v.powerOff(vm); err != nil {
			return err
		}
	}

	if client.Provider == govix.VMWARE_VI_SERVER ||
		client.Provider == govix.VMWARE_SERVER {
		log.Printf("[INFO] Unregistering VM from host's inventory...")

		err := client.UnregisterVm(vmxFile)
		if err != nil {
			return err
		}
	}

	return vm.Delete(govix.VMDELETE_KEEP_FILES | govix.VMDELETE_FORCE)
}

// Refreshes state with VMware
func (v *VM) Refresh(vmxFile string) (bool, error) {
	log.Printf("[DEBUG] Syncing VM resource %s...", vmxFile)

	client, err := v.client()
	if err != nil {
		return false, err
	}
	defer client.Disconnect()

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return false, err
	}

	running, err := vm.IsRunning()
	if !running {
		return running, err
	}

	vcpus, err := vm.Vcpus()
	if err != nil {
		return running, err
	}

	memory, err := vm.MemorySize()
	if err != nil {
		return running, err
	}

	// We need to convert memory value to megabytes so humanize can interpret it
	// properly.
	memory = (memory * 1024) * 1024
	v.Memory = strings.ToLower(humanize.IBytes(uint64(memory)))
	v.CPUs = uint(vcpus)
	v.Name, err = vm.DisplayName()
	v.Description, err = vm.Annotation()
	v.VNetworkAdapters, err = vm.NetworkAdapters()
	v.IPAddress, err = vm.IPAddress()

	return running, err
}
<commit_msg>Minor fixes<commit_after>package vix

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"time"

	"github.com/c4milo/unzipit"
	govix "github.com/cloudescape/govix"
	"github.com/dustin/go-humanize"
)

// Virtual machine configuration
type VM struct {
	// Which VMware VIX service provider to use. ie: fusion, workstation, server, etc
	Provider string
	// Whether to verify SSL or not for remote connections in ESXi
	VerifySSL bool
	// Name of the virtual machine
	Name string
	// Description for the virtual machine, it is created as an annotation in
	// VMware.
	Description string
	// Image to use during the creation of this virtual machine
	Image Image
	// Number of virtual cpus
	CPUs uint
	// Memory size in megabytes.
	Memory string
	// Switches to where this machine is going to be attach to
	VSwitches []string
	// Whether to upgrade the VM virtual hardware
	UpgradeVHardware bool
	// The timeout to wait for VMware Tools to be initialized inside the VM
	ToolsInitTimeout time.Duration
	// Whether to launch the VM with graphical environment
	LaunchGUI bool
	// Whether to enable or disable shared folders for this VM
	SharedFolders bool
	// Network adapters
	VNetworkAdapters []*govix.NetworkAdapter
	// VM IP address as reported by VIX
	IPAddress string
}

// Creates VIX instance with VMware
func (v *VM) client() (*govix.Host, error) {
	var p govix.Provider

	switch strings.ToLower(v.Provider) {
	case "fusion", "workstation":
		p = govix.VMWARE_WORKSTATION
	case "serverv1":
		p = govix.VMWARE_SERVER
	case "serverv2":
		p = govix.VMWARE_VI_SERVER
	case "player":
		p = govix.VMWARE_PLAYER
	case "workstation_shared":
		p = govix.VMWARE_WORKSTATION_SHARED
	default:
		p = govix.VMWARE_WORKSTATION
	}

	var options govix.HostOption
	if v.VerifySSL {
		options = govix.VERIFY_SSL_CERT
	}

	host, err := govix.Connect(govix.ConnectConfig{
		Provider: p,
		Options:  options,
	})

	if err != nil {
		return nil, err
	}

	log.Printf("[INFO] VIX client configured for product: VMware %s. SSL: %t", v.Provider, v.VerifySSL)

	return host, nil
}

// Sets default values for VM attributes
func (v *VM) SetDefaults() {
	if v.CPUs <= 0 {
		v.CPUs = 2
	}

	if v.Memory == "" {
		v.Memory = "512mib"
	}

	if v.Description == "" {
		v.Description = "Machine was created using Terraform VIX provider"
	}

	if v.ToolsInitTimeout.Seconds() <= 0 {
		v.ToolsInitTimeout = time.Duration(30) * time.Second
	}
}

// Downloads, extracts and opens Gold virtual machine, then it creates a clone
// out of it.
func (v *VM) Create() (string, error) {
	log.Printf("[DEBUG] Creating VM resource...")

	usr, err := user.Current()
	if err != nil {
		return "", err
	}

	image := v.Image

	imgPath := filepath.Join(usr.HomeDir, ".terraform/vix/images", image.Checksum)
	if err = image.Download(imgPath); err != nil {
		return "", err
	}
	defer image.file.Close()

	goldPath := filepath.Join(usr.HomeDir, filepath.Join(".terraform/vix/gold", image.Checksum))
	_, err = os.Stat(goldPath)
	goldPathExist := err == nil || err != os.ErrNotExist

	// There is no need to get the error as the slice will be empty anyway
	finfo, _ := ioutil.ReadDir(goldPath)
	goldPathEmpty := len(finfo) == 0

	if !goldPathExist || goldPathEmpty {
		log.Println("[DEBUG] Gold virtual machine does not exist or is empty")
		log.Printf("[DEBUG] Unpacking Gold virtual machine into %s\n", goldPath)
		_, err = unzipit.Unpack(image.file, goldPath)
		if err != nil {
			return "", err
		}
	}

	pattern := filepath.Join(goldPath, "/**/*.vmx")

	log.Printf("[DEBUG] Finding Gold virtual machine vmx file in %s", pattern)
	files, _ := filepath.Glob(pattern)

	if len(files) == 0 {
		return "", fmt.Errorf("[ERROR] vmx file was not found: %s", pattern)
	}

	vmxFile := files[0]
	log.Printf("[DEBUG] Gold virtual machine vmx file found %v", vmxFile)

	// Gets VIX instance
	client, err := v.client()
	if err != nil {
		return "", err
	}
	defer client.Disconnect()

	log.Printf("[INFO] Opening Gold virtual machine from %s", vmxFile)

	vm, err := client.OpenVm(vmxFile, v.Image.Password)

	if err != nil {
		return "", err
	}

	newvmx := filepath.Join(usr.HomeDir, ".terraform", "vix", "vms",
		image.Checksum, v.Name, v.Name+".vmx")

	if _, err = os.Stat(newvmx); err != os.ErrExist {
		log.Printf("[INFO] Cloning gold vm into %s...", newvmx)
		_, err := vm.Clone(govix.CLONETYPE_FULL, newvmx)

		// If there is an error and the error is other than "The snapshot already exists"
		// then return the error
		if err != nil && err.(*govix.VixError).Code != 13004 {
			return "", err
		}

		// Makes sure the first time the VM is created it has no virtual network adapters
		// log.Printf("[DEBUG] Removing all virtual network adapters from cloned VM...")
		// err = clonedVM.RemoveAllNetworkAdapters()
		// if err != nil {
		// 	return "", err
		// }
	} else {
		log.Printf("[INFO] VM Clone %s already exist, moving on.", newvmx)
	}

	if err = v.Update(newvmx); err != nil {
		return "", err
	}

	return newvmx, nil
}

// Opens and updates virtual machine resource
func (v *VM) Update(vmxFile string) error {
	// Sets default values if some attributes were not set or have
	// invalid values
	v.SetDefaults()

	// Gets VIX instance
	client, err := v.client()
	if err != nil {
		return err
	}
	defer client.Disconnect()

	if client.Provider == govix.VMWARE_VI_SERVER ||
		client.Provider == govix.VMWARE_SERVER {
		log.Printf("[INFO] Registering VM in host's inventory...")
		err = client.RegisterVm(vmxFile)
		if err != nil {
			return err
		}
	}

	log.Printf("[INFO] Opening virtual machine from %s", vmxFile)

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return err
	}

	running, err := vm.IsRunning()
	if err != nil {
		return err
	}

	if running {
		log.Printf("[INFO] Virtual machine seems to be running, we need to " +
			"power it off in order to make changes.")
		err = v.powerOff(vm)
		if err != nil {
			return err
		}
	}

	memoryInMb, err := humanize.ParseBytes(v.Memory)
	if err != nil {
		log.Printf("[WARN] Unable to set memory size, defaulting to 512mib: %s", err)
		memoryInMb = 512
	} else {
		memoryInMb = (memoryInMb / 1024) / 1024
	}

	log.Printf("[DEBUG] Setting memory size to %d megabytes", memoryInMb)
	vm.SetMemorySize(uint(memoryInMb))

	log.Printf("[DEBUG] Setting vcpus to %d", v.CPUs)
	vm.SetNumberVcpus(v.CPUs)

	log.Printf("[DEBUG] Setting name to %s", v.Name)
	vm.SetDisplayName(v.Name)

	log.Printf("[DEBUG] Setting description to %s", v.Description)
	vm.SetAnnotation(v.Description)

	if v.UpgradeVHardware &&
		client.Provider != govix.VMWARE_PLAYER {

		log.Println("[INFO] Upgrading virtual hardware...")
		err = vm.UpgradeVHardware()
		if err != nil {
			return err
		}
	}

	// log.Printf("[DEBUG] Loading all network adapters in memory...")
	// curAdapters, err := vm.NetworkAdapters()
	// if err != nil {
	// 	return err
	// }

	log.Printf("[DEBUG] Removing all network adapters from vmx file...")
	err = vm.RemoveAllNetworkAdapters()
	if err != nil {
		return err
	}

	log.Println("[DEBUG] Attaching virtual network adapters...")
	for _, adapter := range v.VNetworkAdapters {
		adapter.StartConnected = true
		if adapter.ConnType == govix.NETWORK_BRIDGED {
			adapter.LinkStatePropagation = true
		}

		log.Printf("[DEBUG] Adapter: %+v", adapter)
		err := vm.AddNetworkAdapter(adapter)
		if err != nil {
			return err
		}
	}

	log.Println("[INFO] Powering virtual machine on...")
	var options govix.VMPowerOption

	if v.LaunchGUI {
		log.Println("[INFO] Preparing to launch GUI...")
		options |= govix.VMPOWEROP_LAUNCH_GUI
	}

	options |= govix.VMPOWEROP_NORMAL

	err = vm.PowerOn(options)
	if err != nil {
		return err
	}

	log.Println("[INFO] Waiting for VMware Tools to initialize...")
	err = vm.WaitForToolsInGuest(v.ToolsInitTimeout)
	if err != nil {
		log.Println("[WARN] VMware Tools took too long to initialize or is not " +
			"installed.")

		if v.SharedFolders {
			log.Println("[WARN] Enabling shared folders is not possible.")
		}
		return nil
	}

	if v.SharedFolders {
		log.Println("[DEBUG] Enabling shared folders...")

		err = vm.EnableSharedFolders(v.SharedFolders)
		if err != nil {
			return err
		}
	}
	return nil
}

// Powers off a virtual machine attempting a graceful shutdown.
func (v *VM) powerOff(vm *govix.VM) error {
	tstate, err := vm.ToolsState()
	if err != nil {
		return err
	}

	var powerOpts govix.VMPowerOption
	log.Printf("Tools state %d", tstate)

	if (tstate & govix.TOOLSSTATE_RUNNING) != 0 {
		log.Printf("[INFO] VMware Tools is running, attempting a graceful shutdown...")
		// if VMware Tools is running, attempt a graceful shutdown.
		powerOpts |= govix.VMPOWEROP_FROM_GUEST
	} else {
		log.Printf("[INFO] VMware Tools is NOT running, shutting down the " +
			"machine abruptly...")
		powerOpts |= govix.VMPOWEROP_NORMAL
	}

	err = vm.PowerOff(powerOpts)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Virtual machine is off.")

	return nil
}

// Destroys a virtual machine resource
func (v *VM) Destroy(vmxFile string) error {
	log.Printf("[DEBUG] Destroying VM resource %s...", vmxFile)

	client, err := v.client()
	if err != nil {
		return err
	}
	defer client.Disconnect()

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return err
	}

	running, err := vm.IsRunning()
	if err != nil {
		return err
	}

	if running {
		if err = v.powerOff(vm); err != nil {
			return err
		}
	}

	if client.Provider == govix.VMWARE_VI_SERVER ||
		client.Provider == govix.VMWARE_SERVER {
		log.Printf("[INFO] Unregistering VM from host's inventory...")

		err := client.UnregisterVm(vmxFile)
		if err != nil {
			return err
		}
	}

	return vm.Delete(govix.VMDELETE_KEEP_FILES | govix.VMDELETE_FORCE)
}

// Refreshes state with VMware
func (v *VM) Refresh(vmxFile string) (bool, error) {
	log.Printf("[DEBUG] Syncing VM resource %s...", vmxFile)

	client, err := v.client()
	if err != nil {
		return false, err
	}
	defer client.Disconnect()

	vm, err := client.OpenVm(vmxFile, v.Image.Password)
	if err != nil {
		return false, err
	}

	running, err := vm.IsRunning()
	if !running {
		return running, err
	}

	vcpus, err := vm.Vcpus()
	if err != nil {
		return running, err
	}

	memory, err := vm.MemorySize()
	if err != nil {
		return running, err
	}

	// We need to convert memory value to megabytes so humanize can interpret it
	// properly.
	memory = (memory * 1024) * 1024
	v.Memory = strings.ToLower(humanize.IBytes(uint64(memory)))
	v.CPUs = uint(vcpus)
	v.Name, err = vm.DisplayName()
	v.Description, err = vm.Annotation()
	v.VNetworkAdapters, err = vm.NetworkAdapters()
	v.IPAddress, err = vm.IPAddress()

	return running, err
}
<|endoftext|>


<commit_before>package core

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func testEqual(t1, t2 *Thunk) bool {
	return compare(t1.Eval(), t2.Eval()) == 0
}

func testLess(t1, t2 *Thunk) bool {
	return t1.Eval().(comparable).compare(t2.Eval().(comparable)) < 0
}

func TestLessFail(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fail()
		}
	}()

	compare(NewNumber(42).Eval(), NewError("you", "failed.").Eval())
}

func testCompare(t1, t2 *Thunk) NumberType {
	return PApp(Compare, t1, t2).Eval().(NumberType)
}

func TestCompareWithInvalidValues(t *testing.T) {
	for _, ts := range [][2]*Thunk{
		{True, False},
		{Nil, Nil},
		{NewNumber(0), False},
		{NewNumber(0), Nil},
		{True, Nil},
		{NewDictionary([]Value{Nil.Eval()}, []*Thunk{Nil}),
			NewDictionary([]Value{Nil.Eval()}, []*Thunk{Nil})},
		{NotNumberError(Nil), NotNumberError(Nil)},
	} {
		v := PApp(Compare, ts[0], ts[1]).Eval()

		t.Log(v)

		_, ok := v.(ErrorType)
		assert.True(t, ok)
	}
}

func TestOrdered(t *testing.T) {
	for _, th := range []*Thunk{
		NewNumber(42),
		NewString("foo"),
		EmptyList,
	} {
		_, ok := th.Eval().(ordered)
		assert.True(t, ok)
	}
}

func TestNotOrdered(t *testing.T) {
	for _, th := range []*Thunk{
		Nil,
		True,
		False,
		EmptyDictionary,
		ValueError("This is not ordered."),
		Merge,
	} {
		_, ok := th.Eval().(ordered)
		assert.False(t, ok)
	}
}
<commit_msg>Run ordered function for coverage<commit_after>package core

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func testEqual(t1, t2 *Thunk) bool {
	return compare(t1.Eval(), t2.Eval()) == 0
}

func testLess(t1, t2 *Thunk) bool {
	return t1.Eval().(comparable).compare(t2.Eval().(comparable)) < 0
}

func TestLessFail(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fail()
		}
	}()

	compare(NewNumber(42).Eval(), NewError("you", "failed.").Eval())
}

func testCompare(t1, t2 *Thunk) NumberType {
	return PApp(Compare, t1, t2).Eval().(NumberType)
}

func TestCompareWithInvalidValues(t *testing.T) {
	for _, ts := range [][2]*Thunk{
		{True, False},
		{Nil, Nil},
		{NewNumber(0), False},
		{NewNumber(0), Nil},
		{True, Nil},
		{NewDictionary([]Value{Nil.Eval()}, []*Thunk{Nil}),
			NewDictionary([]Value{Nil.Eval()}, []*Thunk{Nil})},
		{NotNumberError(Nil), NotNumberError(Nil)},
	} {
		v := PApp(Compare, ts[0], ts[1]).Eval()

		t.Log(v)

		_, ok := v.(ErrorType)
		assert.True(t, ok)
	}
}

func TestOrdered(t *testing.T) {
	for _, th := range []*Thunk{
		NewNumber(42),
		NewString("foo"),
		EmptyList,
	} {
		o, ok := th.Eval().(ordered)
		assert.True(t, ok)
		o.ordered()
	}
}

func TestNotOrdered(t *testing.T) {
	for _, th := range []*Thunk{
		Nil,
		True,
		False,
		EmptyDictionary,
		ValueError("This is not ordered."),
		Merge,
	} {
		_, ok := th.Eval().(ordered)
		assert.False(t, ok)
	}
}
<|endoftext|>


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

package orchestrator

import (
	"fmt"
	"runtime/trace"
	"sync"

	"github.com/ligato/cn-infra/logging"
	"golang.org/x/net/context"

	"github.com/gogo/protobuf/proto"
	kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api"
)

// KeyVal associates value with its key.
type KeyVal struct {
	Key string
	Val proto.Message
}

// KVPairs represents key-value pairs.
type KVPairs map[string]proto.Message

type Dispatcher interface {
	ListData() KVPairs
	PushData(context.Context, []KeyVal) ([]kvs.KeyWithError, error)
}

type dispatcher struct {
	log   logging.Logger
	kvs   kvs.KVScheduler
	mu    sync.Mutex
	store *memStore
}

// ListData retrieves actual data.
func (p *dispatcher) ListData() KVPairs {
	p.mu.Lock()
	defer p.mu.Unlock()

	return p.store.ListAll()
}

// PushData updates actual data.
func (p *dispatcher) PushData(ctx context.Context, kvPairs []KeyVal) (kvErrs []kvs.KeyWithError, err error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	trace.Logf(ctx, "kvPairs", "%d", len(kvPairs))

	pr := trace.StartRegion(ctx, "prepare kv data")

	dataSrc, ok := DataSrcFromContext(ctx)
	if !ok {
		dataSrc = "global"
	}

	p.log.Debugf("Pushing data with %d KV pairs (source: %s)", len(kvPairs), dataSrc)

	txn := p.kvs.StartNBTransaction()

	if typ, _ := kvs.IsResync(ctx); typ == kvs.FullResync {
		trace.Log(ctx, "resyncType", typ.String())
		p.store.Reset(dataSrc)
		for _, kv := range kvPairs {
			if kv.Val == nil {
				p.log.Debugf(" - PUT: %q (skipped nil value)", kv.Key)
				continue
			}
			p.log.Debugf(" - PUT: %q ", kv.Key)
			p.store.Update(dataSrc, kv.Key, kv.Val)
		}
		allPairs := p.store.ListAll()
		p.log.Debugf("will resync %d pairs", len(allPairs))
		for k, v := range allPairs {
			txn.SetValue(k, v)
		}
	} else {
		for _, kv := range kvPairs {
			if kv.Val == nil {
				p.log.Debugf(" - DELETE: %q", kv.Key)
				txn.SetValue(kv.Key, nil)
				p.store.Delete(dataSrc, kv.Key)
			} else {
				p.log.Debugf(" - UPDATE: %q ", kv.Key)
				txn.SetValue(kv.Key, kv.Val)
				p.store.Update(dataSrc, kv.Key, kv.Val)
			}
		}
	}

	pr.End()

	seqID, err := txn.Commit(ctx)
	if err != nil {
		if txErr, ok := err.(*kvs.TransactionError); ok && len(txErr.GetKVErrors()) > 0 {
			kvErrs = txErr.GetKVErrors()
			var errInfo = ""
			for i, kvErr := range kvErrs {
				errInfo += fmt.Sprintf(" - %3d. error (%s) %s - %v\n", i+1, kvErr.TxnOperation, kvErr.Key, kvErr.Error)
			}
			p.log.Errorf("Transaction #%d finished with %d errors", seqID, len(kvErrs))
			fmt.Println(errInfo)
		} else {
			p.log.Errorf("Transaction failed: %v", err)
		}
		return kvErrs, err
	}

	p.log.Infof("Transaction #%d successful!", seqID)

	return nil, nil
}

type dataSrcKeyT string

var dataSrcKey = dataSrcKeyT("dataSrc")

func DataSrcContext(ctx context.Context, dataSrc string) context.Context {
	return context.WithValue(ctx, dataSrcKey, dataSrc)
}

func DataSrcFromContext(ctx context.Context) (dataSrc string, ok bool) {
	dataSrc, ok = ctx.Value(dataSrcKey).(string)
	return
}
<commit_msg>Calculate transation duration<commit_after>//  Copyright (c) 2019 Cisco and/or its affiliates.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at:
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package orchestrator

import (
	"fmt"
	"runtime/trace"
	"sync"
	"time"

	"github.com/ligato/cn-infra/logging"
	"golang.org/x/net/context"

	"github.com/gogo/protobuf/proto"
	kvs "github.com/ligato/vpp-agent/plugins/kvscheduler/api"
)

// KeyVal associates value with its key.
type KeyVal struct {
	Key string
	Val proto.Message
}

// KVPairs represents key-value pairs.
type KVPairs map[string]proto.Message

type Dispatcher interface {
	ListData() KVPairs
	PushData(context.Context, []KeyVal) ([]kvs.KeyWithError, error)
}

type dispatcher struct {
	log   logging.Logger
	kvs   kvs.KVScheduler
	mu    sync.Mutex
	store *memStore
}

// ListData retrieves actual data.
func (p *dispatcher) ListData() KVPairs {
	p.mu.Lock()
	defer p.mu.Unlock()

	return p.store.ListAll()
}

// PushData updates actual data.
func (p *dispatcher) PushData(ctx context.Context, kvPairs []KeyVal) (kvErrs []kvs.KeyWithError, err error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	trace.Logf(ctx, "kvPairs", "%d", len(kvPairs))

	pr := trace.StartRegion(ctx, "prepare kv data")

	dataSrc, ok := DataSrcFromContext(ctx)
	if !ok {
		dataSrc = "global"
	}

	p.log.Debugf("Pushing data with %d KV pairs (source: %s)", len(kvPairs), dataSrc)

	txn := p.kvs.StartNBTransaction()

	if typ, _ := kvs.IsResync(ctx); typ == kvs.FullResync {
		trace.Log(ctx, "resyncType", typ.String())
		p.store.Reset(dataSrc)
		for _, kv := range kvPairs {
			if kv.Val == nil {
				p.log.Debugf(" - PUT: %q (skipped nil value)", kv.Key)
				continue
			}
			p.log.Debugf(" - PUT: %q ", kv.Key)
			p.store.Update(dataSrc, kv.Key, kv.Val)
		}
		allPairs := p.store.ListAll()
		p.log.Debugf("will resync %d pairs", len(allPairs))
		for k, v := range allPairs {
			txn.SetValue(k, v)
		}
	} else {
		for _, kv := range kvPairs {
			if kv.Val == nil {
				p.log.Debugf(" - DELETE: %q", kv.Key)
				txn.SetValue(kv.Key, nil)
				p.store.Delete(dataSrc, kv.Key)
			} else {
				p.log.Debugf(" - UPDATE: %q ", kv.Key)
				txn.SetValue(kv.Key, kv.Val)
				p.store.Update(dataSrc, kv.Key, kv.Val)
			}
		}
	}

	pr.End()

	t := time.Now()

	seqID, err := txn.Commit(ctx)
	if err != nil {
		if txErr, ok := err.(*kvs.TransactionError); ok && len(txErr.GetKVErrors()) > 0 {
			kvErrs = txErr.GetKVErrors()
			var errInfo = ""
			for i, kvErr := range kvErrs {
				errInfo += fmt.Sprintf(" - %3d. error (%s) %s - %v\n", i+1, kvErr.TxnOperation, kvErr.Key, kvErr.Error)
			}
			p.log.Errorf("Transaction #%d finished with %d errors", seqID, len(kvErrs))
			fmt.Println(errInfo)
		} else {
			p.log.Errorf("Transaction failed: %v", err)
		}
		return kvErrs, err
	}

	took := time.Since(t).Round(time.Microsecond * 100)
	p.log.Infof("Transaction #%d successful! (took %v)", seqID, took)

	return nil, nil
}

type dataSrcKeyT string

var dataSrcKey = dataSrcKeyT("dataSrc")

func DataSrcContext(ctx context.Context, dataSrc string) context.Context {
	return context.WithValue(ctx, dataSrcKey, dataSrc)
}

func DataSrcFromContext(ctx context.Context) (dataSrc string, ok bool) {
	dataSrc, ok = ctx.Value(dataSrcKey).(string)
	return
}
<|endoftext|>


<commit_before>package datadog

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strings"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/outputs"
)

type Datadog struct {
	Apikey  string
	Timeout internal.Duration

	apiUrl string
	client *http.Client
}

var sampleConfig = `
  # Datadog API key
  apikey = "my-secret-key" # required.

  # Connection timeout.
  # timeout = "5s"
`

type TimeSeries struct {
	Series []*Metric `json:"series"`
}

type Metric struct {
	Metric string   `json:"metric"`
	Points [1]Point `json:"metrics"`
	Host   string   `json:"host"`
	Tags   []string `json:"tags,omitemmy"`
}

type Point [2]float64

const datadog_api = "https://app.datadoghq.com/api/v1/series"

func NewDatadog(apiUrl string) *Datadog {
	return &Datadog{
		apiUrl: apiUrl,
	}
}

func (d *Datadog) Connect() error {
	if d.Apikey == "" {
		return fmt.Errorf("apikey is a required field for datadog output")
	}
	d.client = &http.Client{
		Timeout: d.Timeout.Duration,
	}
	return nil
}

func (d *Datadog) Write(metrics []telegraf.Metric) error {
	if len(metrics) == 0 {
		return nil
	}
	ts := TimeSeries{}
	tempSeries := []*Metric{}
	metricCounter := 0

	for _, m := range metrics {
		mname := strings.Replace(m.Name(), "_", ".", -1)
		if dogMs, err := buildMetrics(m); err == nil {
			for fieldName, dogM := range dogMs {
				// name of the datadog measurement
				var dname string
				if fieldName == "value" {
					// adding .value seems redundant here
					dname = mname
				} else {
					dname = mname + "." + strings.Replace(fieldName, "_", ".", -1)
				}
				metric := &Metric{
					Metric: dname,
					Tags:   buildTags(m.Tags()),
					Host:   m.Tags()["host"],
				}
				metric.Points[0] = dogM
				tempSeries = append(tempSeries, metric)
				metricCounter++
			}
		} else {
			log.Printf("unable to build Metric for %s, skipping\n", m.Name())
		}
	}

	ts.Series = make([]*Metric, metricCounter)
	copy(ts.Series, tempSeries[0:])
	tsBytes, err := json.Marshal(ts)
	if err != nil {
		return fmt.Errorf("unable to marshal TimeSeries, %s\n", err.Error())
	}
	req, err := http.NewRequest("POST", d.authenticatedUrl(), bytes.NewBuffer(tsBytes))
	if err != nil {
		return fmt.Errorf("unable to create http.Request, %s\n", err.Error())
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := d.client.Do(req)
	if err != nil {
		return fmt.Errorf("error POSTing metrics, %s\n", err.Error())
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 209 {
		return fmt.Errorf("received bad status code, %d\n", resp.StatusCode)
	}

	return nil
}

func (d *Datadog) SampleConfig() string {
	return sampleConfig
}

func (d *Datadog) Description() string {
	return "Configuration for DataDog API to send metrics to."
}

func (d *Datadog) authenticatedUrl() string {
	q := url.Values{
		"api_key": []string{d.Apikey},
	}
	return fmt.Sprintf("%s?%s", d.apiUrl, q.Encode())
}

func buildMetrics(m telegraf.Metric) (map[string]Point, error) {
	ms := make(map[string]Point)
	for k, v := range m.Fields() {
		var p Point
		if err := p.setValue(v); err != nil {
			return ms, fmt.Errorf("unable to extract value from Fields, %s", err.Error())
		}
		p[0] = float64(m.Time().Unix())
		ms[k] = p
	}
	return ms, nil
}

func buildTags(mTags map[string]string) []string {
	tags := make([]string, len(mTags))
	index := 0
	for k, v := range mTags {
		tags[index] = fmt.Sprintf("%s:%s", k, v)
		index += 1
	}
	sort.Strings(tags)
	return tags
}

func (p *Point) setValue(v interface{}) error {
	switch d := v.(type) {
	case int:
		p[1] = float64(int(d))
	case int32:
		p[1] = float64(int32(d))
	case int64:
		p[1] = float64(int64(d))
	case float32:
		p[1] = float64(d)
	case float64:
		p[1] = float64(d)
	default:
		return fmt.Errorf("undeterminable type")
	}
	return nil
}

func (d *Datadog) Close() error {
	return nil
}

func init() {
	outputs.Add("datadog", func() telegraf.Output {
		return NewDatadog(datadog_api)
	})
}
<commit_msg>Fix datadog json marshalling<commit_after>package datadog

import (
	"bytes"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strings"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/outputs"
)

type Datadog struct {
	Apikey  string
	Timeout internal.Duration

	apiUrl string
	client *http.Client
}

var sampleConfig = `
  # Datadog API key
  apikey = "my-secret-key" # required.

  # Connection timeout.
  # timeout = "5s"
`

type TimeSeries struct {
	Series []*Metric `json:"series"`
}

type Metric struct {
	Metric string   `json:"metric"`
	Points [1]Point `json:"points"`
	Host   string   `json:"host"`
	Tags   []string `json:"tags,omitempty"`
}

type Point [2]float64

const datadog_api = "https://app.datadoghq.com/api/v1/series"

func NewDatadog(apiUrl string) *Datadog {
	return &Datadog{
		apiUrl: apiUrl,
	}
}

func (d *Datadog) Connect() error {
	if d.Apikey == "" {
		return fmt.Errorf("apikey is a required field for datadog output")
	}
	d.client = &http.Client{
		Timeout: d.Timeout.Duration,
	}
	return nil
}

func (d *Datadog) Write(metrics []telegraf.Metric) error {
	if len(metrics) == 0 {
		return nil
	}
	ts := TimeSeries{}
	tempSeries := []*Metric{}
	metricCounter := 0

	for _, m := range metrics {
		mname := strings.Replace(m.Name(), "_", ".", -1)
		if dogMs, err := buildMetrics(m); err == nil {
			for fieldName, dogM := range dogMs {
				// name of the datadog measurement
				var dname string
				if fieldName == "value" {
					// adding .value seems redundant here
					dname = mname
				} else {
					dname = mname + "." + strings.Replace(fieldName, "_", ".", -1)
				}
				metric := &Metric{
					Metric: dname,
					Tags:   buildTags(m.Tags()),
					Host:   m.Tags()["host"],
				}
				metric.Points[0] = dogM
				tempSeries = append(tempSeries, metric)
				metricCounter++
			}
		} else {
			log.Printf("unable to build Metric for %s, skipping\n", m.Name())
		}
	}

	ts.Series = make([]*Metric, metricCounter)
	copy(ts.Series, tempSeries[0:])
	tsBytes, err := json.Marshal(ts)
	if err != nil {
		return fmt.Errorf("unable to marshal TimeSeries, %s\n", err.Error())
	}
	req, err := http.NewRequest("POST", d.authenticatedUrl(), bytes.NewBuffer(tsBytes))
	if err != nil {
		return fmt.Errorf("unable to create http.Request, %s\n", err.Error())
	}
	req.Header.Add("Content-Type", "application/json")

	resp, err := d.client.Do(req)
	if err != nil {
		return fmt.Errorf("error POSTing metrics, %s\n", err.Error())
	}
	defer resp.Body.Close()

	if resp.StatusCode < 200 || resp.StatusCode > 209 {
		return fmt.Errorf("received bad status code, %d\n", resp.StatusCode)
	}

	return nil
}

func (d *Datadog) SampleConfig() string {
	return sampleConfig
}

func (d *Datadog) Description() string {
	return "Configuration for DataDog API to send metrics to."
}

func (d *Datadog) authenticatedUrl() string {
	q := url.Values{
		"api_key": []string{d.Apikey},
	}
	return fmt.Sprintf("%s?%s", d.apiUrl, q.Encode())
}

func buildMetrics(m telegraf.Metric) (map[string]Point, error) {
	ms := make(map[string]Point)
	for k, v := range m.Fields() {
		var p Point
		if err := p.setValue(v); err != nil {
			return ms, fmt.Errorf("unable to extract value from Fields, %s", err.Error())
		}
		p[0] = float64(m.Time().Unix())
		ms[k] = p
	}
	return ms, nil
}

func buildTags(mTags map[string]string) []string {
	tags := make([]string, len(mTags))
	index := 0
	for k, v := range mTags {
		tags[index] = fmt.Sprintf("%s:%s", k, v)
		index += 1
	}
	sort.Strings(tags)
	return tags
}

func (p *Point) setValue(v interface{}) error {
	switch d := v.(type) {
	case int:
		p[1] = float64(int(d))
	case int32:
		p[1] = float64(int32(d))
	case int64:
		p[1] = float64(int64(d))
	case float32:
		p[1] = float64(d)
	case float64:
		p[1] = float64(d)
	default:
		return fmt.Errorf("undeterminable type")
	}
	return nil
}

func (d *Datadog) Close() error {
	return nil
}

func init() {
	outputs.Add("datadog", func() telegraf.Output {
		return NewDatadog(datadog_api)
	})
}
<|endoftext|>


<commit_before>// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package termui

import (
	"fmt"
)

// This is the implementation of multi-colored or stacked bar graph.  This is different from default barGraph which is implemented in bar.go
// Multi-Colored-BarChart creates multiple bars in a widget:
/*
   bc := termui.NewMBarChart()
   data := make([][]int, 2)
   data[0] := []int{3, 2, 5, 7, 9, 4}
   data[1] := []int{7, 8, 5, 3, 1, 6}
   bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
   bc.BorderLabel = "Bar Chart"
   bc.Data = data
   bc.Width = 26
   bc.Height = 10
   bc.DataLabels = bclabels
   bc.TextColor = termui.ColorGreen
   bc.BarColor = termui.ColorRed
   bc.NumColor = termui.ColorYellow
*/
type MBarChart struct {
	Block
	BarColor   [NumberofColors]Attribute
	TextColor  Attribute
	NumColor   [NumberofColors]Attribute
	Data       [NumberofColors][]int
	DataLabels []string
	BarWidth   int
	BarGap     int
	labels     [][]rune
	dataNum    [NumberofColors][][]rune
	numBar     int
	scale      float64
	max        int
	minDataLen int
	numStack   int
	ShowScale  bool
	maxScale   []rune
}

// NewBarChart returns a new *BarChart with current theme.
func NewMBarChart() *MBarChart {
	bc := &MBarChart{Block: *NewBlock()}
	bc.BarColor[0] = ThemeAttr("mbarchart.bar.bg")
	bc.NumColor[0] = ThemeAttr("mbarchart.num.fg")
	bc.TextColor = ThemeAttr("mbarchart.text.fg")
	bc.BarGap = 1
	bc.BarWidth = 3
	return bc
}

func (bc *MBarChart) layout() {
	bc.numBar = bc.innerArea.Dx() / (bc.BarGap + bc.BarWidth)
	bc.labels = make([][]rune, bc.numBar)
	DataLen := 0
	LabelLen := len(bc.DataLabels)
	bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length

	// We need to know how many stack/data array data[0] , data[1] are there
	for i := 0; i < len(bc.Data); i++ {
		if bc.Data[i] == nil {
			break
		}
		DataLen++
	}
	bc.numStack = DataLen

	//We need to know what is the minimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs

	for i := 0; i < DataLen; i++ {
		if bc.minDataLen > len(bc.Data[i]) {
			bc.minDataLen = len(bc.Data[i])
		}
	}

	if LabelLen > bc.minDataLen {
		LabelLen = bc.minDataLen
	}

	for i := 0; i < LabelLen && i < bc.numBar; i++ {
		bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
	}

	for i := 0; i < bc.numStack; i++ {
		bc.dataNum[i] = make([][]rune, len(bc.Data[i]))
		//For each stack of bar calculate the rune
		for j := 0; j < LabelLen && i < bc.numBar; j++ {
			n := bc.Data[i][j]
			s := fmt.Sprint(n)
			bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth)
		}
		//If color is not defined by default then populate a color that is different from the prevous bar
		if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault {
			if i == 0 {
				bc.BarColor[i] = ColorBlack
			} else {
				bc.BarColor[i] = bc.BarColor[i-1] + 1
				if bc.BarColor[i] > NumberofColors {
					bc.BarColor[i] = ColorBlack
				}
			}
			bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility
		}
	}

	//If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n]))

	if bc.max == 0 {
		bc.max = -1
	}
	for i := 0; i < bc.minDataLen && i < LabelLen; i++ {
		var dsum int
		for j := 0; j < bc.numStack; j++ {
			dsum += bc.Data[j][i]
		}
		if dsum > bc.max {
			bc.max = dsum
		}
	}

	//Finally Calculate max sale
	if bc.ShowScale {
		s := fmt.Sprintf("%d", bc.max)
		bc.maxScale = trimStr2Runes(s, len(s))
		bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-2)
	} else {
		bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-1)
	}

}

func (bc *MBarChart) SetMax(max int) {

	if max > 0 {
		bc.max = max
	}
}

// Buffer implements Bufferer interface.
func (bc *MBarChart) Buffer() Buffer {
	buf := bc.Block.Buffer()
	bc.layout()
	var oftX int

	for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ {
		ph := 0 //Previous Height to stack up
		oftX = i * (bc.BarWidth + bc.BarGap)
		for i1 := 0; i1 < bc.numStack; i1++ {
			h := int(float64(bc.Data[i1][i]) / bc.scale)
			// plot bars
			for j := 0; j < bc.BarWidth; j++ {
				for k := 0; k < h; k++ {
					c := Cell{
						Ch: ' ',
						Bg: bc.BarColor[i1],
					}
					if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
						c.Bg |= AttrReverse
					}
					x := bc.innerArea.Min.X + i*(bc.BarWidth+bc.BarGap) + j
					y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - k - ph
					buf.Set(x, y, c)

				}
			}
			ph += h
		}
		// plot text
		for j, k := 0, 0; j < len(bc.labels[i]); j++ {
			w := charWidth(bc.labels[i][j])
			c := Cell{
				Ch: bc.labels[i][j],
				Bg: bc.Bg,
				Fg: bc.TextColor,
			}
			y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 1
			x := bc.innerArea.Max.X + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
			buf.Set(x, y, c)
			k += w
		}
		// plot num
		ph = 0 //re-initialize previous height
		for i1 := 0; i1 < bc.numStack; i1++ {
			h := int(float64(bc.Data[i1][i]) / bc.scale)
			for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
				c := Cell{
					Ch: bc.dataNum[i1][i][j],
					Fg: bc.NumColor[i1],
					Bg: bc.BarColor[i1],
				}
				if bc.BarColor[i1] == ColorDefault { // the same as above
					c.Bg |= AttrReverse
				}
				if h == 0 {
					c.Bg = bc.Bg
				}
				x := bc.innerArea.Min.X + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
				y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - ph
				buf.Set(x, y, c)
			}
			ph += h
		}
	}

	if bc.ShowScale {
		//Currently bar graph only supprts data range from 0 to MAX
		//Plot 0
		c := Cell{
			Ch: '0',
			Bg: bc.Bg,
			Fg: bc.TextColor,
		}

		y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2
		x := bc.X
		buf.Set(x, y, c)

		//Plot the maximum sacle value
		for i := 0; i < len(bc.maxScale); i++ {
			c := Cell{
				Ch: bc.maxScale[i],
				Bg: bc.Bg,
				Fg: bc.TextColor,
			}

			y := bc.innerArea.Min.Y
			x := bc.X + i

			buf.Set(x, y, c)
		}

	}

	return buf
}
<commit_msg>spelling: previous<commit_after>// Copyright 2017 Zack Guo <zack.y.guo@gmail.com>. All rights reserved.
// Use of this source code is governed by a MIT license that can
// be found in the LICENSE file.

package termui

import (
	"fmt"
)

// This is the implementation of multi-colored or stacked bar graph.  This is different from default barGraph which is implemented in bar.go
// Multi-Colored-BarChart creates multiple bars in a widget:
/*
   bc := termui.NewMBarChart()
   data := make([][]int, 2)
   data[0] := []int{3, 2, 5, 7, 9, 4}
   data[1] := []int{7, 8, 5, 3, 1, 6}
   bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
   bc.BorderLabel = "Bar Chart"
   bc.Data = data
   bc.Width = 26
   bc.Height = 10
   bc.DataLabels = bclabels
   bc.TextColor = termui.ColorGreen
   bc.BarColor = termui.ColorRed
   bc.NumColor = termui.ColorYellow
*/
type MBarChart struct {
	Block
	BarColor   [NumberofColors]Attribute
	TextColor  Attribute
	NumColor   [NumberofColors]Attribute
	Data       [NumberofColors][]int
	DataLabels []string
	BarWidth   int
	BarGap     int
	labels     [][]rune
	dataNum    [NumberofColors][][]rune
	numBar     int
	scale      float64
	max        int
	minDataLen int
	numStack   int
	ShowScale  bool
	maxScale   []rune
}

// NewBarChart returns a new *BarChart with current theme.
func NewMBarChart() *MBarChart {
	bc := &MBarChart{Block: *NewBlock()}
	bc.BarColor[0] = ThemeAttr("mbarchart.bar.bg")
	bc.NumColor[0] = ThemeAttr("mbarchart.num.fg")
	bc.TextColor = ThemeAttr("mbarchart.text.fg")
	bc.BarGap = 1
	bc.BarWidth = 3
	return bc
}

func (bc *MBarChart) layout() {
	bc.numBar = bc.innerArea.Dx() / (bc.BarGap + bc.BarWidth)
	bc.labels = make([][]rune, bc.numBar)
	DataLen := 0
	LabelLen := len(bc.DataLabels)
	bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length

	// We need to know how many stack/data array data[0] , data[1] are there
	for i := 0; i < len(bc.Data); i++ {
		if bc.Data[i] == nil {
			break
		}
		DataLen++
	}
	bc.numStack = DataLen

	//We need to know what is the minimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs

	for i := 0; i < DataLen; i++ {
		if bc.minDataLen > len(bc.Data[i]) {
			bc.minDataLen = len(bc.Data[i])
		}
	}

	if LabelLen > bc.minDataLen {
		LabelLen = bc.minDataLen
	}

	for i := 0; i < LabelLen && i < bc.numBar; i++ {
		bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
	}

	for i := 0; i < bc.numStack; i++ {
		bc.dataNum[i] = make([][]rune, len(bc.Data[i]))
		//For each stack of bar calculate the rune
		for j := 0; j < LabelLen && i < bc.numBar; j++ {
			n := bc.Data[i][j]
			s := fmt.Sprint(n)
			bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth)
		}
		//If color is not defined by default then populate a color that is different from the previous bar
		if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault {
			if i == 0 {
				bc.BarColor[i] = ColorBlack
			} else {
				bc.BarColor[i] = bc.BarColor[i-1] + 1
				if bc.BarColor[i] > NumberofColors {
					bc.BarColor[i] = ColorBlack
				}
			}
			bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility
		}
	}

	//If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n]))

	if bc.max == 0 {
		bc.max = -1
	}
	for i := 0; i < bc.minDataLen && i < LabelLen; i++ {
		var dsum int
		for j := 0; j < bc.numStack; j++ {
			dsum += bc.Data[j][i]
		}
		if dsum > bc.max {
			bc.max = dsum
		}
	}

	//Finally Calculate max sale
	if bc.ShowScale {
		s := fmt.Sprintf("%d", bc.max)
		bc.maxScale = trimStr2Runes(s, len(s))
		bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-2)
	} else {
		bc.scale = float64(bc.max) / float64(bc.innerArea.Dy()-1)
	}

}

func (bc *MBarChart) SetMax(max int) {

	if max > 0 {
		bc.max = max
	}
}

// Buffer implements Bufferer interface.
func (bc *MBarChart) Buffer() Buffer {
	buf := bc.Block.Buffer()
	bc.layout()
	var oftX int

	for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ {
		ph := 0 //Previous Height to stack up
		oftX = i * (bc.BarWidth + bc.BarGap)
		for i1 := 0; i1 < bc.numStack; i1++ {
			h := int(float64(bc.Data[i1][i]) / bc.scale)
			// plot bars
			for j := 0; j < bc.BarWidth; j++ {
				for k := 0; k < h; k++ {
					c := Cell{
						Ch: ' ',
						Bg: bc.BarColor[i1],
					}
					if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
						c.Bg |= AttrReverse
					}
					x := bc.innerArea.Min.X + i*(bc.BarWidth+bc.BarGap) + j
					y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - k - ph
					buf.Set(x, y, c)

				}
			}
			ph += h
		}
		// plot text
		for j, k := 0, 0; j < len(bc.labels[i]); j++ {
			w := charWidth(bc.labels[i][j])
			c := Cell{
				Ch: bc.labels[i][j],
				Bg: bc.Bg,
				Fg: bc.TextColor,
			}
			y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 1
			x := bc.innerArea.Max.X + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
			buf.Set(x, y, c)
			k += w
		}
		// plot num
		ph = 0 //re-initialize previous height
		for i1 := 0; i1 < bc.numStack; i1++ {
			h := int(float64(bc.Data[i1][i]) / bc.scale)
			for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
				c := Cell{
					Ch: bc.dataNum[i1][i][j],
					Fg: bc.NumColor[i1],
					Bg: bc.BarColor[i1],
				}
				if bc.BarColor[i1] == ColorDefault { // the same as above
					c.Bg |= AttrReverse
				}
				if h == 0 {
					c.Bg = bc.Bg
				}
				x := bc.innerArea.Min.X + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
				y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2 - ph
				buf.Set(x, y, c)
			}
			ph += h
		}
	}

	if bc.ShowScale {
		//Currently bar graph only supprts data range from 0 to MAX
		//Plot 0
		c := Cell{
			Ch: '0',
			Bg: bc.Bg,
			Fg: bc.TextColor,
		}

		y := bc.innerArea.Min.Y + bc.innerArea.Dy() - 2
		x := bc.X
		buf.Set(x, y, c)

		//Plot the maximum sacle value
		for i := 0; i < len(bc.maxScale); i++ {
			c := Cell{
				Ch: bc.maxScale[i],
				Bg: bc.Bg,
				Fg: bc.TextColor,
			}

			y := bc.innerArea.Min.Y
			x := bc.X + i

			buf.Set(x, y, c)
		}

	}

	return buf
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "os"
  "os/exec"
  "syscall"
  "io/ioutil"
  "path/filepath"
  "strings"
  "sort"
  "encoding/json"
  "github.com/Masterminds/semver"
)

import . "github.com/tj/go-debug"

var debug = Debug("nodist:shim")

const pathSep = string(os.PathSeparator)

func main() {
  // Prerequisites

  if "" == os.Getenv("NODIST_PREFIX") {
    fmt.Println("Please set the path to the nodist directory in the NODIST_PREFIX environment variable.")
    os.Exit(40)
  }

  // Determine version spec

  var spec string = ""
  if v := os.Getenv("NODE_VERSION"); v != "" {
    spec = v
    debug("NODE_VERSION found:'%s'", spec)
  } else
  if v = os.Getenv("NODIST_VERSION"); v != "" {
    spec = v
    debug("NODIST_VERSION found:'%s'", spec)
  } else
  if v, err := getTargetEngine(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = v
    debug("Target engine found:'%s'", spec)
  } else
  if v, localFile, err := getLocalVersion(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = string(v)
    debug("Local file found:'%s' @ %s", spec, localFile)
  } else
  if v, err := ioutil.ReadFile(os.Getenv("NODIST_PREFIX")+"\\.node-version"); err == nil {
    spec = string(v)
    debug("Global file found: '%s'", spec)
  }

  spec = strings.Trim(spec, "v \r\n")

  if spec == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Please set a version.")
    os.Exit(41)
  }

  var constraint *semver.Constraints

  if spec != "latest" {
    var err error
    constraint, err = semver.NewConstraint(spec)

    if err != nil {
      fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Malformatted version spec ", spec, " . Please set a new version.")
      os.Exit(43)
    }
  }

  // Find an installed version matching the spec...

  installed, err := getInstalledVersions()

  if err != nil {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't list installed versions.")
    os.Exit(44)
  }

  version := ""

  if spec == "latest" {
    version = installed[0].String()
  }else{
    for _, v := range installed {
      debug("checking %s against %s", v.String(), spec)
      if constraint.Check(v) {
	version = v.String()
	break
      }
    }
  }

  if version == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't find an installed version that matches version spec ", spec)
    os.Exit(45)
  }

  debug("found matching version: %s", version)

  // Determine architecture

  x64 := false

  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }

  // Set up binary path

  var path string
  var nodebin string

  path = os.Getenv("NODIST_PREFIX")+"/v"

  if x64 {
    path += "-x64"
  }

  path = path+"/"+version
  nodebin = path+"/node.exe"

  // Run node!

  cmd := exec.Command(nodebin, os.Args[1:]...)
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  cmd.Stdin = os.Stdin
  err = cmd.Run()

  if err != nil {
    exitError, isExitError := err.(*(exec.ExitError))
    if isExitError {
      // You know it. Black Magic...
      os.Exit(exitError.Sys().(syscall.WaitStatus).ExitStatus())
    } else {
      fmt.Println("Sorry, there's a problem with nodist.")
      fmt.Println("Error: ", err)
      os.Exit(42)
    }
  }
}

func getLocalVersion() (version string, file string, returnedError error) {
  var dir string
  var err error
  if len(os.Args) < 2 {
    dir, err = os.Getwd()
    if err != nil {
      returnedError = err
      return
    }
  }else{
    targetFile := os.Args[1]
    dir = filepath.Dir(targetFile)

    if !filepath.IsAbs(dir) {
      cwd, err := os.Getwd()
      if err != nil {
        returnedError = err
        return
      }
      dir = filepath.Join(cwd, dir)
    }
  }

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file = dir+"\\.node-version"
    v, err := ioutil.ReadFile(file);

    if err == nil {
      version = string(v)
      return
    }

    if !os.IsNotExist(err) {
      returnedError = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  version = ""
  return
}

func getInstalledVersions() (versions []*semver.Version, error error) {
  // Determine architecture
  x64 := false
  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }
  // construct path to version dir
  path := os.Getenv("NODIST_PREFIX")+"/v"
  if x64 {
    path += "-x64"
  }

  dirs, err := ioutil.ReadDir(path)
  if err != nil {
    error = err
    return
  }

  versions = make([]*semver.Version, len(dirs))
  for i, dir := range dirs {
    v, err := semver.NewVersion(dir.Name())
    if err == nil {
      versions[i] = v
    }
  }

  sort.Sort(sort.Reverse(semver.Collection(versions)))

  return
}

func getTargetEngine() (spec string, error error) {
  if len(os.Args) < 2 {
    return
  }

  targetFile := os.Args[1]

  dir := filepath.Dir(targetFile)
  if !filepath.IsAbs(dir) {
    cwd, err := os.Getwd()
    if err != nil {
      error = err
      return
    }
    dir = filepath.Join(cwd, dir)
  }

  debug("getTargetEngine: targetDir: %s", dir)

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  spec = ""

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file := dir+"\\package.json"
    rawPackageJSON, err := ioutil.ReadFile(file);
    debug("getTargetEngine: ReadFile %s", file)
    if err == nil {
      // no error handling for parsing, cause we don't want to use a different package.json if we've already found one
      spec, error = getVerSpecFromPackageJSON(rawPackageJSON)
      return
    }

    if !os.IsNotExist(err) {
      error = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  return
}

func getVerSpecFromPackageJSON(rawPackageJSON []byte) (spec string, err error) {
  type PackageJSON struct {
    Engines struct {
      Node string
    }
  }
  var packageJSON PackageJSON
  err = json.Unmarshal(rawPackageJSON, &packageJSON)

  if err == nil {
    spec = packageJSON.Engines.Node
    debug("getVerSpecFromPackageJSON: %+v", packageJSON)
    return
  }

  debug("getVerSpecFromPackageJSON: error: %s", err.Error())

  // incorrect JSON -- bad luck
  return
}
<commit_msg>[shim] Fix #127: Use a fork of semver to be compatible with npm's semver<commit_after>package main

import (
  "fmt"
  "os"
  "os/exec"
  "syscall"
  "io/ioutil"
  "path/filepath"
  "strings"
  "sort"
  "encoding/json"
  "github.com/marcelklehr/semver"
)

import . "github.com/tj/go-debug"

var debug = Debug("nodist:shim")

const pathSep = string(os.PathSeparator)

func main() {
  // Prerequisites

  if "" == os.Getenv("NODIST_PREFIX") {
    fmt.Println("Please set the path to the nodist directory in the NODIST_PREFIX environment variable.")
    os.Exit(40)
  }

  // Determine version spec

  var spec string = ""
  if v := os.Getenv("NODE_VERSION"); v != "" {
    spec = v
    debug("NODE_VERSION found:'%s'", spec)
  } else
  if v = os.Getenv("NODIST_VERSION"); v != "" {
    spec = v
    debug("NODIST_VERSION found:'%s'", spec)
  } else
  if v, err := getTargetEngine(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = v
    debug("Target engine found:'%s'", spec)
  } else
  if v, localFile, err := getLocalVersion(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = string(v)
    debug("Local file found:'%s' @ %s", spec, localFile)
  } else
  if v, err := ioutil.ReadFile(os.Getenv("NODIST_PREFIX")+"\\.node-version"); err == nil {
    spec = string(v)
    debug("Global file found: '%s'", spec)
  }

  spec = strings.Trim(spec, "v \r\n")

  if spec == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Please set a version.")
    os.Exit(41)
  }

  var constraint *semver.Constraints

  if spec != "latest" {
    var err error
    constraint, err = semver.NewConstraint(spec)

    if err != nil {
      fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Malformatted version spec ", spec, " . Please set a new version.")
      os.Exit(43)
    }
  }

  // Find an installed version matching the spec...

  installed, err := getInstalledVersions()

  if err != nil {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't list installed versions.")
    os.Exit(44)
  }

  version := ""

  if spec == "latest" {
    version = installed[0].String()
  }else{
    for _, v := range installed {
      debug("checking %s against %s", v.String(), spec)
      if constraint.Check(v) {
	version = v.String()
	break
      }
    }
  }

  if version == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't find an installed version that matches version spec ", spec)
    os.Exit(45)
  }

  debug("found matching version: %s", version)

  // Determine architecture

  x64 := false

  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }

  // Set up binary path

  var path string
  var nodebin string

  path = os.Getenv("NODIST_PREFIX")+"/v"

  if x64 {
    path += "-x64"
  }

  path = path+"/"+version
  nodebin = path+"/node.exe"

  // Run node!

  cmd := exec.Command(nodebin, os.Args[1:]...)
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  cmd.Stdin = os.Stdin
  err = cmd.Run()

  if err != nil {
    exitError, isExitError := err.(*(exec.ExitError))
    if isExitError {
      // You know it. Black Magic...
      os.Exit(exitError.Sys().(syscall.WaitStatus).ExitStatus())
    } else {
      fmt.Println("Sorry, there's a problem with nodist.")
      fmt.Println("Error: ", err)
      os.Exit(42)
    }
  }
}

func getLocalVersion() (version string, file string, returnedError error) {
  var dir string
  var err error
  if len(os.Args) < 2 {
    dir, err = os.Getwd()
    if err != nil {
      returnedError = err
      return
    }
  }else{
    targetFile := os.Args[1]
    dir = filepath.Dir(targetFile)

    if !filepath.IsAbs(dir) {
      cwd, err := os.Getwd()
      if err != nil {
        returnedError = err
        return
      }
      dir = filepath.Join(cwd, dir)
    }
  }

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file = dir+"\\.node-version"
    v, err := ioutil.ReadFile(file);

    if err == nil {
      version = string(v)
      return
    }

    if !os.IsNotExist(err) {
      returnedError = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  version = ""
  return
}

func getInstalledVersions() (versions []*semver.Version, error error) {
  // Determine architecture
  x64 := false
  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }
  // construct path to version dir
  path := os.Getenv("NODIST_PREFIX")+"/v"
  if x64 {
    path += "-x64"
  }

  dirs, err := ioutil.ReadDir(path)
  if err != nil {
    error = err
    return
  }

  versions = make([]*semver.Version, len(dirs))
  for i, dir := range dirs {
    v, err := semver.NewVersion(dir.Name())
    if err == nil {
      versions[i] = v
    }
  }

  sort.Sort(sort.Reverse(semver.Collection(versions)))

  return
}

func getTargetEngine() (spec string, error error) {
  if len(os.Args) < 2 {
    return
  }

  targetFile := os.Args[1]

  dir := filepath.Dir(targetFile)
  if !filepath.IsAbs(dir) {
    cwd, err := os.Getwd()
    if err != nil {
      error = err
      return
    }
    dir = filepath.Join(cwd, dir)
  }

  debug("getTargetEngine: targetDir: %s", dir)

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  spec = ""

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file := dir+"\\package.json"
    rawPackageJSON, err := ioutil.ReadFile(file);
    debug("getTargetEngine: ReadFile %s", file)
    if err == nil {
      // no error handling for parsing, cause we don't want to use a different package.json if we've already found one
      spec, error = getVerSpecFromPackageJSON(rawPackageJSON)
      return
    }

    if !os.IsNotExist(err) {
      error = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  return
}

func getVerSpecFromPackageJSON(rawPackageJSON []byte) (spec string, err error) {
  type PackageJSON struct {
    Engines struct {
      Node string
    }
  }
  var packageJSON PackageJSON
  err = json.Unmarshal(rawPackageJSON, &packageJSON)

  if err == nil {
    spec = packageJSON.Engines.Node
    debug("getVerSpecFromPackageJSON: %+v", packageJSON)
    return
  }

  debug("getVerSpecFromPackageJSON: error: %s", err.Error())

  // incorrect JSON -- bad luck
  return
}
<|endoftext|>


<commit_before>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
import "C"
import "errors"

type MediaList struct {
	list *C.libvlc_media_list_t
}

// NewMediaList creates an empty media list.
func NewMediaList() (*MediaList, error) {
	if instance == nil {
		return nil, errors.New("Module must be initialized first")
	}

	var list *C.libvlc_media_list_t
	if list = C.libvlc_media_list_new(instance); list == nil {
		return nil, getError()
	}

	return &MediaList{list: list}, nil
}

// Release destroys the media list instance.
func (ml *MediaList) Release() error {
	if ml.list == nil {
		return nil
	}

	C.libvlc_media_list_release(ml.list)
	ml.list = nil

	return getError()
}

// AddMedia adds a Media instance to the media list.
func (ml *MediaList) AddMedia(m *Media) error {
	if ml.list == nil {
		return errors.New("Media list must be initialized first")
	}
	if m.media == nil {
		return errors.New("Media must be initialized first")
	}

	C.libvlc_media_list_add_media(ml.list, m.media)
	return getError()
}

// AddMediaFromPath loads a media file from path and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromPath(path string) error {
	media, err := NewMediaFromPath(path)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// AddMediaFromURL loads a media file from url and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromURL(url string) error {
	media, err := NewMediaFromURL(url)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}
<commit_msg>Add Lock and Unlock methods on media list<commit_after>package vlc

// #cgo LDFLAGS: -lvlc
// #include <vlc/vlc.h>
import "C"
import "errors"

type MediaList struct {
	list *C.libvlc_media_list_t
}

// NewMediaList creates an empty media list.
func NewMediaList() (*MediaList, error) {
	if instance == nil {
		return nil, errors.New("Module must be initialized first")
	}

	var list *C.libvlc_media_list_t
	if list = C.libvlc_media_list_new(instance); list == nil {
		return nil, getError()
	}

	return &MediaList{list: list}, nil
}

// Release destroys the media list instance.
func (ml *MediaList) Release() error {
	if ml.list == nil {
		return nil
	}

	C.libvlc_media_list_release(ml.list)
	ml.list = nil

	return getError()
}

// AddMedia adds a Media instance to the media list.
func (ml *MediaList) AddMedia(m *Media) error {
	if ml.list == nil {
		return errors.New("Media list must be initialized first")
	}
	if m.media == nil {
		return errors.New("Media must be initialized first")
	}

	C.libvlc_media_list_add_media(ml.list, m.media)
	return getError()
}

// AddMediaFromPath loads a media file from path and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromPath(path string) error {
	media, err := NewMediaFromPath(path)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// AddMediaFromURL loads a media file from url and adds it
// to the the media list.
func (ml *MediaList) AddMediaFromURL(url string) error {
	media, err := NewMediaFromURL(url)
	if err != nil {
		return err
	}

	return ml.AddMedia(media)
}

// Lock makes the caller the current owner of the media list.
func (ml *MediaList) Lock() error {
	if ml.list == nil {
		return errors.New("Media list must be initialized first")
	}

	C.libvlc_media_list_lock(ml.list)
	return getError()
}

// Unlock releases ownership of the media list.
func (ml *MediaList) Unlock() error {
	if ml.list == nil {
		return errors.New("Media list must be initialized first")
	}

	C.libvlc_media_list_unlock(ml.list)
	return getError()
}
<|endoftext|>