<commit_before>package util

import (
	"log"
	"net/http"
	//"net/http/httputil"
	"github.com/gorilla/websocket"
	"io"
	"net"
	"net/url"
	"strings"
	"sync"
	"time"
)

var DEBUG = false

func dlogln(stuff ...interface{}) {
	if DEBUG {
		log.Println(stuff...)
	}
}

// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger

	// Configure Websocket
	WsCFG WsConfig
}

type WsConfig struct {
	Enabled             bool          `yaml:"enabled"`
	ReadBufferSize      int           `yaml:"read_buffer_size"`
	WriteBufferSize     int           `yaml:"write_buffer_size"`
	ReadDeadlineSeconds time.Duration `yaml:"read_deadline_seconds"`
}

type wsbridge struct {
	proxy2endpoint *websocket.Conn
	client2proxy   *websocket.Conn
	rp             *ReverseProxy
}

func (b *wsbridge) EndpointLoopRead() {
	defer func() {
		//ticker.Stop()
		b.proxy2endpoint.Close()
		b.client2proxy.Close()
	}()
	b.proxy2endpoint.SetReadLimit(int64(b.rp.WsCFG.ReadBufferSize))
	b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
	b.proxy2endpoint.SetPongHandler(func(string) error {
		b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		//TODO: ping the endpoint
		return nil
	})
	for {
		b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		b.proxy2endpoint.SetWriteDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		mtype, rdr, err := b.proxy2endpoint.NextReader()
		if err != nil {
			return
		}
		wc, err := b.client2proxy.NextWriter(mtype)
		if err != nil {
			return
		}
		io.Copy(wc, rdr)
		wc.Close()
		//TODO: react on close
	}
}

func (b *wsbridge) ClientLoopRead() {
	//ticker := time.NewTicker(time.Second * 50)
	defer func() {
		//ticker.Stop()
		b.proxy2endpoint.Close()
		b.client2proxy.Close()
	}()
	b.client2proxy.SetReadLimit(int64(b.rp.WsCFG.ReadBufferSize))
	b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
	b.client2proxy.SetPongHandler(func(string) error {
		b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		//TODO: ping the endpoint
		return nil
	})
	for {
		b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		b.client2proxy.SetWriteDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		mtype, rdr, err := b.client2proxy.NextReader()
		if err != nil {
			return
		}
		wc, err := b.proxy2endpoint.NextWriter(mtype)
		if err != nil {
			return
		}
		io.Copy(wc, rdr)
		wc.Close()
		//TODO: react on close
	}
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL, wsconfig WsConfig) *ReverseProxy {
	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
	}
	return &ReverseProxy{Director: director, WsCFG: wsconfig}
}

func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	transport := p.Transport
	if transport == nil {
		transport = http.DefaultTransport
	}

	outreq := new(http.Request)
	*outreq = *req // includes shallow copies of maps, but okay

	p.Director(outreq)
	outreq.Proto = "HTTP/1.1"
	outreq.ProtoMajor = 1
	outreq.ProtoMinor = 1
	outreq.Close = false

	// support for Websockets
	useWebsockets := false
	if p.WsCFG.Enabled {
		if v0 := req.Header.Get("Connection"); v0 == "Upgrade" || v0 == "upgrade" {
			if v1 := req.Header.Get("Upgrade"); v1 == "websocket" || v1 == "Websocket" {
				if req.Method != "GET" {
					// cut the cord earlier to avoid useless cpu use
					http.Error(rw, "method not allowed", http.StatusMethodNotAllowed)
					return
				}
				useWebsockets = true
			}
		}
	}

	// Remove hop-by-hop headers to the backend.  Especially
	// important is "Connection" because we want a persistent
	// connection, regardless of what the client sent to us.  This
	// is modifying the same underlying map from req (shallow
	// copied above) so we only copy it if necessary.
	copiedHeaders := false
	for _, h := range hopHeaders {
		if outreq.Header.Get(h) != "" {
			if !copiedHeaders {
				outreq.Header = make(http.Header)
				copyHeader(outreq.Header, req.Header)
				copiedHeaders = true
			}
			outreq.Header.Del(h)
		}
	}

	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
		// If we aren't the first proxy retain prior
		// X-Forwarded-For information as a comma+space
		// separated list and fold multiple headers into one.
		if prior, ok := outreq.Header["X-Forwarded-For"]; ok {
			clientIP = strings.Join(prior, ", ") + ", " + clientIP
		}
		outreq.Header.Set("X-Forwarded-For", clientIP)
	}
	// pass the origin al protocol
	aa := ""
	if req.TLS != nil { // TODO: fix url scheme
		aa = "s"
	}
	outreq.Header.Set("X-Forwarded-Proto", req.URL.Scheme+aa)

	if useWebsockets {
		// connect to the proxied server and asks for websockets!
		c, err := net.Dial("tcp", outreq.URL.Host)
		if err != nil {
			dlogln("net dial tcp error", err)
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
			return
		}
		url2 := *outreq.URL
		url2.Scheme = "ws"
		proxy2endserver, _, err := websocket.NewClient(c, &url2, outreq.Header, p.WsCFG.ReadBufferSize, p.WsCFG.WriteBufferSize)
		if err != nil {
			dlogln("websocket newclient", err, url2)
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
			return
		}

		upgrader := websocket.Upgrader{
			ReadBufferSize:  p.WsCFG.ReadBufferSize,
			WriteBufferSize: p.WsCFG.WriteBufferSize,
		}
		req.Header.Set("Connection", "Upgrade")
		req.Header.Set("Upgrade", "websocket")
		client2proxy, err := upgrader.Upgrade(rw, req, nil)
		if err != nil {
			dlogln("upgrader error", err)
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
		}
		//
		wsb := &wsbridge{
			proxy2endpoint: proxy2endserver,
			client2proxy:   client2proxy,
			rp:             p,
		}
		go wsb.ClientLoopRead()
		wsb.EndpointLoopRead()
		//
		return
	}

	res, err := transport.RoundTrip(outreq)
	if err != nil {
		p.logf("http: proxy error: %v", err)
		rw.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()

	for _, h := range hopHeaders {
		res.Header.Del(h)
	}

	copyHeader(rw.Header(), res.Header)

	rw.WriteHeader(res.StatusCode)
	p.copyResponse(rw, res.Body)
}

func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
	if p.FlushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:     wf,
				latency: p.FlushInterval,
				done:    make(chan bool),
			}
			go mlw.flushLoop()
			defer mlw.stop()
			dst = mlw
		}
	}

	io.Copy(dst, src)
}

func (p *ReverseProxy) logf(format string, args ...interface{}) {
	if p.ErrorLog != nil {
		p.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

type writeFlusher interface {
	io.Writer
	http.Flusher
}

type maxLatencyWriter struct {
	dst     writeFlusher
	latency time.Duration

	lk   sync.Mutex // protects Write + Flush
	done chan bool
}

func (m *maxLatencyWriter) Write(p []byte) (int, error) {
	m.lk.Lock()
	defer m.lk.Unlock()
	return m.dst.Write(p)
}

func (m *maxLatencyWriter) flushLoop() {
	t := time.NewTicker(m.latency)
	defer t.Stop()
	for {
		select {
		case <-m.done:
			if onExitFlushLoop != nil {
				onExitFlushLoop()
			}
			return
		case <-t.C:
			m.lk.Lock()
			m.dst.Flush()
			m.lk.Unlock()
		}
	}
}

func (m *maxLatencyWriter) stop() { m.done <- true }

func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

// onExitFlushLoop is a callback set by tests to detect the state of the
// flushLoop() goroutine.
var onExitFlushLoop func()
<commit_msg>ws url<commit_after>package util

import (
	"log"
	"net/http"
	//"net/http/httputil"
	"github.com/gorilla/websocket"
	"io"
	"net"
	"net/url"
	"strings"
	"sync"
	"time"
)

var DEBUG = false

func dlogln(stuff ...interface{}) {
	if DEBUG {
		log.Println(stuff...)
	}
}

// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
type ReverseProxy struct {
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger

	// Configure Websocket
	WsCFG WsConfig
}

type WsConfig struct {
	Enabled             bool          `yaml:"enabled"`
	ReadBufferSize      int           `yaml:"read_buffer_size"`
	WriteBufferSize     int           `yaml:"write_buffer_size"`
	ReadDeadlineSeconds time.Duration `yaml:"read_deadline_seconds"`
}

type wsbridge struct {
	proxy2endpoint *websocket.Conn
	client2proxy   *websocket.Conn
	rp             *ReverseProxy
}

func (b *wsbridge) EndpointLoopRead() {
	defer func() {
		//ticker.Stop()
		b.proxy2endpoint.Close()
		b.client2proxy.Close()
	}()
	b.proxy2endpoint.SetReadLimit(int64(b.rp.WsCFG.ReadBufferSize))
	b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
	b.proxy2endpoint.SetPongHandler(func(string) error {
		b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		//TODO: ping the endpoint
		return nil
	})
	for {
		b.proxy2endpoint.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		b.proxy2endpoint.SetWriteDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		mtype, rdr, err := b.proxy2endpoint.NextReader()
		if err != nil {
			return
		}
		wc, err := b.client2proxy.NextWriter(mtype)
		if err != nil {
			return
		}
		io.Copy(wc, rdr)
		wc.Close()
		//TODO: react on close
	}
}

func (b *wsbridge) ClientLoopRead() {
	//ticker := time.NewTicker(time.Second * 50)
	defer func() {
		//ticker.Stop()
		b.proxy2endpoint.Close()
		b.client2proxy.Close()
	}()
	b.client2proxy.SetReadLimit(int64(b.rp.WsCFG.ReadBufferSize))
	b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
	b.client2proxy.SetPongHandler(func(string) error {
		b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		//TODO: ping the endpoint
		return nil
	})
	for {
		b.client2proxy.SetReadDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		b.client2proxy.SetWriteDeadline(time.Now().Add(b.rp.WsCFG.ReadDeadlineSeconds))
		mtype, rdr, err := b.client2proxy.NextReader()
		if err != nil {
			return
		}
		wc, err := b.proxy2endpoint.NextWriter(mtype)
		if err != nil {
			return
		}
		io.Copy(wc, rdr)
		wc.Close()
		//TODO: react on close
	}
}

func copyHeader(dst, src http.Header) {
	for k, vv := range src {
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
var hopHeaders = []string{
	"Connection",
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te", // canonicalized version of "TE"
	"Trailers",
	"Transfer-Encoding",
	"Upgrade",
}

// NewSingleHostReverseProxy returns a new ReverseProxy that rewrites
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
func NewSingleHostReverseProxy(target *url.URL, wsconfig WsConfig) *ReverseProxy {
	targetQuery := target.RawQuery
	director := func(req *http.Request) {
		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if targetQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = targetQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
		}
	}
	return &ReverseProxy{Director: director, WsCFG: wsconfig}
}

func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	transport := p.Transport
	if transport == nil {
		transport = http.DefaultTransport
	}

	outreq := new(http.Request)
	*outreq = *req // includes shallow copies of maps, but okay

	p.Director(outreq)
	outreq.Proto = "HTTP/1.1"
	outreq.ProtoMajor = 1
	outreq.ProtoMinor = 1
	outreq.Close = false

	// support for Websockets
	useWebsockets := false
	if p.WsCFG.Enabled {
		if v0 := req.Header.Get("Connection"); v0 == "Upgrade" || v0 == "upgrade" {
			if v1 := req.Header.Get("Upgrade"); v1 == "websocket" || v1 == "Websocket" {
				if req.Method != "GET" {
					// cut the cord earlier to avoid useless cpu use
					http.Error(rw, "method not allowed", http.StatusMethodNotAllowed)
					return
				}
				useWebsockets = true
			}
		}
	}

	// Remove hop-by-hop headers to the backend.  Especially
	// important is "Connection" because we want a persistent
	// connection, regardless of what the client sent to us.  This
	// is modifying the same underlying map from req (shallow
	// copied above) so we only copy it if necessary.
	copiedHeaders := false
	for _, h := range hopHeaders {
		if outreq.Header.Get(h) != "" {
			if !copiedHeaders {
				outreq.Header = make(http.Header)
				copyHeader(outreq.Header, req.Header)
				copiedHeaders = true
			}
			outreq.Header.Del(h)
		}
	}

	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
		// If we aren't the first proxy retain prior
		// X-Forwarded-For information as a comma+space
		// separated list and fold multiple headers into one.
		if prior, ok := outreq.Header["X-Forwarded-For"]; ok {
			clientIP = strings.Join(prior, ", ") + ", " + clientIP
		}
		outreq.Header.Set("X-Forwarded-For", clientIP)
	}
	// pass the origin al protocol
	aa := ""
	if req.TLS != nil { // TODO: fix url scheme
		aa = "s"
	}
	outreq.Header.Set("X-Forwarded-Proto", req.URL.Scheme+aa)

	if useWebsockets {
		// connect to the proxied server and asks for websockets!
		c, err := net.Dial("tcp", outreq.URL.Host)
		if err != nil {
			dlogln("net dial tcp error", err)
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
			return
		}
		url2 := *outreq.URL
		url2.Scheme = "ws"
		proxy2endserver, _, err := websocket.NewClient(c, &url2, outreq.Header, p.WsCFG.ReadBufferSize, p.WsCFG.WriteBufferSize)
		if err != nil {
			dlogln("websocket newclient", err, url2.String())
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
			return
		}

		upgrader := websocket.Upgrader{
			ReadBufferSize:  p.WsCFG.ReadBufferSize,
			WriteBufferSize: p.WsCFG.WriteBufferSize,
		}
		req.Header.Set("Connection", "Upgrade")
		req.Header.Set("Upgrade", "websocket")
		client2proxy, err := upgrader.Upgrade(rw, req, nil)
		if err != nil {
			dlogln("upgrader error", err)
			http.Error(rw, "Internal Server Error - "+err.Error(), http.StatusInternalServerError)
		}
		//
		wsb := &wsbridge{
			proxy2endpoint: proxy2endserver,
			client2proxy:   client2proxy,
			rp:             p,
		}
		go wsb.ClientLoopRead()
		wsb.EndpointLoopRead()
		//
		return
	}

	res, err := transport.RoundTrip(outreq)
	if err != nil {
		p.logf("http: proxy error: %v", err)
		rw.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()

	for _, h := range hopHeaders {
		res.Header.Del(h)
	}

	copyHeader(rw.Header(), res.Header)

	rw.WriteHeader(res.StatusCode)
	p.copyResponse(rw, res.Body)
}

func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
	if p.FlushInterval != 0 {
		if wf, ok := dst.(writeFlusher); ok {
			mlw := &maxLatencyWriter{
				dst:     wf,
				latency: p.FlushInterval,
				done:    make(chan bool),
			}
			go mlw.flushLoop()
			defer mlw.stop()
			dst = mlw
		}
	}

	io.Copy(dst, src)
}

func (p *ReverseProxy) logf(format string, args ...interface{}) {
	if p.ErrorLog != nil {
		p.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

type writeFlusher interface {
	io.Writer
	http.Flusher
}

type maxLatencyWriter struct {
	dst     writeFlusher
	latency time.Duration

	lk   sync.Mutex // protects Write + Flush
	done chan bool
}

func (m *maxLatencyWriter) Write(p []byte) (int, error) {
	m.lk.Lock()
	defer m.lk.Unlock()
	return m.dst.Write(p)
}

func (m *maxLatencyWriter) flushLoop() {
	t := time.NewTicker(m.latency)
	defer t.Stop()
	for {
		select {
		case <-m.done:
			if onExitFlushLoop != nil {
				onExitFlushLoop()
			}
			return
		case <-t.C:
			m.lk.Lock()
			m.dst.Flush()
			m.lk.Unlock()
		}
	}
}

func (m *maxLatencyWriter) stop() { m.done <- true }

func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

// onExitFlushLoop is a callback set by tests to detect the state of the
// flushLoop() goroutine.
var onExitFlushLoop func()
<|endoftext|>


<commit_before>package shh

import(
  "encoding/json"
  "fmt"
  "net"
  "net/http"
  "time"

  "github.com/heroku/slog"
)

type FolsomMemory struct {
  Total uint64 `json:"total"`
  Processes uint64 `json:"processes"`
  ProcessesUsed uint64 `json:"processes_used"`
  System uint64 `json:"system"`
  Atom uint64 `json:"atom"`
  AtomUsed uint64 `json:"atom_used"`
  Binary uint64 `json:"binary"`
  Code uint64 `json:"code"`
  Ets uint64 `json:"ets"`
}

type FolsomStatistics struct {
  ContextSwitches uint64 `json:"context_switches"`
  GarbageCollection FolsomGarbageCollection `json:"garbage_collection"`
  Io FolsomIo `json:"io"`
  Reductions FolsomReductions `json:"reductions"`
  RunQueue uint64 `json:"run_queue"`
  Runtime FolsomRuntime `json:"runtime"`
  WallClock FolsomWallClock `json:"wall_clock"`
}

type FolsomGarbageCollection struct {
  NumOfGcs uint64 `json:"number_of_gcs"`
  WordsReclaimed uint64 `json:"words_reclaimed"`
}

type FolsomIo struct {
  Input uint64 `json:"input"`
  Output uint64 `json:"output"`
}

type FolsomReductions struct {
  Total uint64 `json:"total_reductions"`
  SinceLast uint64 `json:"reductions_since_last_call"`
}

type FolsomRuntime struct {
  Total uint64 `json:"total_run_time"`
  SinceLast uint64 `json:"time_since_last_call"`
}

type FolsomWallClock struct {
  Total uint64 `json:"total_wall_clock_time"`
  SinceLast uint64 `json:"wall_clock_time_since_last_call"`
}

type FolsomMetrics struct {
  Metrics []string `json:""`
}

type FolsomValue struct {
  Name string
  Value uint64 `json:"value"`
}

type FolsomPoller struct {
  measurements chan<- Measurement
  baseUrl string
  client *http.Client
}

func NewFolsomPoller(measurements chan<- Measurement, config Config) FolsomPoller {
  var url string

  if config.FolsomBaseUrl != nil {
    url = config.FolsomBaseUrl.String()
  }

  client := &http.Client{
    Transport: &http.Transport{
      ResponseHeaderTimeout: config.NetworkTimeout,
      Dial: func(network, address string) (net.Conn, error) {
        return net.DialTimeout(network, address, config.NetworkTimeout)
      },
    },
  }

  return FolsomPoller{
    measurements: measurements,
		baseUrl:      url,
		client:       client,
  }
}

func (poller FolsomPoller) Poll(tick time.Time) {
	if poller.baseUrl == "" {
		return
	}

	ctx := slog.Context{"poller": poller.Name(), "fn": "Poll", "tick": tick}

  poller.doMemoryPoll(ctx, tick)
  poller.doStatisticsPoll(ctx, tick)
  poller.doMetricsPoll(ctx, tick)
}

func (poller FolsomPoller) doMemoryPoll(ctx slog.Context, tick time.Time) () {
	memory := FolsomMemory{}

	if err := poller.decodeReq("/_memory", &memory); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "total"}, memory.Total, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "procs", "total"}, memory.Processes, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "procs", "used"}, memory.ProcessesUsed, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "system"}, memory.System, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "atom", "total"}, memory.Atom, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "atom", "used"}, memory.AtomUsed, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "binary"}, memory.Binary, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "code"}, memory.Code, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "ets"}, memory.Ets, Bytes}
}

func (poller FolsomPoller) doStatisticsPoll(ctx slog.Context, tick time.Time) () {
	stats := FolsomStatistics{}
	if err := poller.decodeReq("/_statistics", &stats); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "context-switches"}, stats.ContextSwitches, ContextSwitches}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "gc", "num"}, stats.GarbageCollection.NumOfGcs, Empty}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "gc", "reclaimed"}, stats.GarbageCollection.WordsReclaimed, Words}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "io", "input"}, stats.Io.Input, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "io", "output"}, stats.Io.Output, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "reductions"}, stats.Reductions.SinceLast, Reductions}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "run-queue"}, stats.RunQueue, Processes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "runtime"}, stats.Runtime.SinceLast, MilliSeconds}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "wall-clock"}, stats.WallClock.SinceLast, MilliSeconds}
}

func (poller FolsomPoller) doMetricsPoll(ctx slog.Context, tick time.Time) () {
	keys := []string{}
	if err := poller.decodeReq("/_metrics", &keys); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

  for i := range keys {
    value := FolsomValue{}
    if err := poller.decodeReq("/_metrics/" + keys[i], &value); err != nil {
      LogError(ctx, err, "while performing request for " + keys[i] + "this tick")
      return
    }

    poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{keys[i]}, value.Value, Empty}
  }
}

func (poller FolsomPoller) decodeReq(path string, v interface{}) (error) {
	req, err := http.NewRequest("GET", poller.baseUrl + path, nil)
	if err != nil {
		return err
	}

	resp, rerr := poller.client.Do(req)
	if rerr != nil {
		return rerr
	} else if resp.StatusCode >= 300 {
		resp.Body.Close()
		return fmt.Errorf("Response returned a %d", resp.StatusCode)
	}

	defer resp.Body.Close()

	decoder := json.NewDecoder(resp.Body)
	if derr := decoder.Decode(v); derr != nil {
		return derr
	}

	return nil
}

func (poller FolsomPoller) Name() string {
	return "erlang"
}

func (poller FolsomPoller) Exit() {}
<commit_msg>greater detection of actual dynamic metric<commit_after>package shh

import(
  "encoding/json"
  "fmt"
  "net"
  "net/http"
  "time"
  "strings"

  "github.com/heroku/slog"
)

type FolsomMemory struct {
  Total uint64 `json:"total"`
  Processes uint64 `json:"processes"`
  ProcessesUsed uint64 `json:"processes_used"`
  System uint64 `json:"system"`
  Atom uint64 `json:"atom"`
  AtomUsed uint64 `json:"atom_used"`
  Binary uint64 `json:"binary"`
  Code uint64 `json:"code"`
  Ets uint64 `json:"ets"`
}

type FolsomStatistics struct {
  ContextSwitches uint64 `json:"context_switches"`
  GarbageCollection FolsomGarbageCollection `json:"garbage_collection"`
  Io FolsomIo `json:"io"`
  Reductions FolsomReductions `json:"reductions"`
  RunQueue uint64 `json:"run_queue"`
  Runtime FolsomRuntime `json:"runtime"`
  WallClock FolsomWallClock `json:"wall_clock"`
}

type FolsomGarbageCollection struct {
  NumOfGcs uint64 `json:"number_of_gcs"`
  WordsReclaimed uint64 `json:"words_reclaimed"`
}

type FolsomIo struct {
  Input uint64 `json:"input"`
  Output uint64 `json:"output"`
}

type FolsomReductions struct {
  Total uint64 `json:"total_reductions"`
  SinceLast uint64 `json:"reductions_since_last_call"`
}

type FolsomRuntime struct {
  Total uint64 `json:"total_run_time"`
  SinceLast uint64 `json:"time_since_last_call"`
}

type FolsomWallClock struct {
  Total uint64 `json:"total_wall_clock_time"`
  SinceLast uint64 `json:"wall_clock_time_since_last_call"`
}

type FolsomMetrics struct {
  Metrics []string `json:""`
}

type FolsomValue struct {
  Name string
  Type string `json:"type"`
  Value json.Number `json:"value"`
}

type FolsomPoller struct {
  measurements chan<- Measurement
  baseUrl string
  client *http.Client
}

func NewFolsomPoller(measurements chan<- Measurement, config Config) FolsomPoller {
  var url string

  if config.FolsomBaseUrl != nil {
    url = config.FolsomBaseUrl.String()
  }

  client := &http.Client{
    Transport: &http.Transport{
      ResponseHeaderTimeout: config.NetworkTimeout,
      Dial: func(network, address string) (net.Conn, error) {
        return net.DialTimeout(network, address, config.NetworkTimeout)
      },
    },
  }

  return FolsomPoller{
    measurements: measurements,
		baseUrl:      url,
		client:       client,
  }
}

func (poller FolsomPoller) Poll(tick time.Time) {
	if poller.baseUrl == "" {
		return
	}

	ctx := slog.Context{"poller": poller.Name(), "fn": "Poll", "tick": tick}

  poller.doMemoryPoll(ctx, tick)
  poller.doStatisticsPoll(ctx, tick)
  poller.doMetricsPoll(ctx, tick)
}

func (poller FolsomPoller) doMemoryPoll(ctx slog.Context, tick time.Time) () {
	memory := FolsomMemory{}

	if err := poller.decodeReq("/_memory", &memory); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "total"}, memory.Total, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "procs", "total"}, memory.Processes, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "procs", "used"}, memory.ProcessesUsed, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "system"}, memory.System, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "atom", "total"}, memory.Atom, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "atom", "used"}, memory.AtomUsed, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "binary"}, memory.Binary, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "code"}, memory.Code, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"mem", "ets"}, memory.Ets, Bytes}
}

func (poller FolsomPoller) doStatisticsPoll(ctx slog.Context, tick time.Time) () {
	stats := FolsomStatistics{}
	if err := poller.decodeReq("/_statistics", &stats); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

	poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{"stats", "context-switches"}, stats.ContextSwitches, ContextSwitches}
	poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{"stats", "gc", "num"}, stats.GarbageCollection.NumOfGcs, Empty}
	poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{"stats", "gc", "reclaimed"}, stats.GarbageCollection.WordsReclaimed, Words}
	poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{"stats", "io", "input"}, stats.Io.Input, Bytes}
	poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{"stats", "io", "output"}, stats.Io.Output, Bytes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "reductions"}, stats.Reductions.SinceLast, Reductions}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "run-queue"}, stats.RunQueue, Processes}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "runtime"}, stats.Runtime.SinceLast, MilliSeconds}
	poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{"stats", "wall-clock"}, stats.WallClock.SinceLast, MilliSeconds}
}

func (poller FolsomPoller) doMetricsPoll(ctx slog.Context, tick time.Time) () {
	keys := []string{}
	if err := poller.decodeReq("/_metrics", &keys); err != nil {
		LogError(ctx, err, "while performing request for this tick")
		return
	}

  for i := range keys {
    value := FolsomValue{}
    if err := poller.decodeReq("/_metrics/" + keys[i], &value); err != nil {
      LogError(ctx, err, "while performing request for " + keys[i] + "this tick")
      return
    }

    switch value.Type {
    case "counter":
      val, err := value.Value.Int64();
      if err != nil {
        LogError(ctx, err, "error parsing int counter for " + keys[i] + " this tick")
      }
      poller.measurements <- CounterMeasurement{tick, poller.Name(), []string{keys[i]}, uint64(val), Empty}
    case "gauge":
      if (strings.Contains(value.Value.String(), ".")) {
        val, err := value.Value.Float64()
        if err != nil {
          LogError(ctx, err, "error parsing float gauge for " + keys[i] + " this tick")
        }
        poller.measurements <- FloatGaugeMeasurement{tick, poller.Name(), []string{keys[i]}, val, Empty}
      } else {
        val, err := value.Value.Int64()
        if err != nil {
          LogError(ctx, err, "error parsing int counter for " + keys[i] + " this tick")
        }
        poller.measurements <- GaugeMeasurement{tick, poller.Name(), []string{keys[i]}, uint64(val), Empty}
      }
    }
  }
}

func (poller FolsomPoller) decodeReq(path string, v interface{}) (error) {
	req, err := http.NewRequest("GET", poller.baseUrl + path, nil)
	if err != nil {
		return err
	}

	resp, rerr := poller.client.Do(req)
	if rerr != nil {
		return rerr
	} else if resp.StatusCode >= 300 {
		resp.Body.Close()
		return fmt.Errorf("Response returned a %d", resp.StatusCode)
	}

	defer resp.Body.Close()

	decoder := json.NewDecoder(resp.Body)
	if derr := decoder.Decode(v); derr != nil {
		return derr
	}

	return nil
}

func (poller FolsomPoller) Name() string {
	return "folsom"
}

func (poller FolsomPoller) Exit() {}
<|endoftext|>


<commit_before>// vcfanno is a command-line application and an api for annotating intervals (bed or vcf).
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"

	"time"

	"github.com/BurntSushi/toml"
	"github.com/brentp/bix"
	"github.com/brentp/irelate"
	"github.com/brentp/irelate/interfaces"
	. "github.com/brentp/vcfanno/api"
	. "github.com/brentp/vcfanno/shared"
	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

const VERSION = "0.0.8"

func main() {
	fmt.Fprintf(os.Stderr, `
=============================================
vcfanno version %s [built with %s]

see: https://github.com/brentp/vcfanno
=============================================
`, VERSION, runtime.Version())

	ends := flag.Bool("ends", false, "annotate the start and end as well as the interval itself.")
	notstrict := flag.Bool("permissive-overlap", false, "annotate with an overlapping variant even it doesn't"+
		" share the same ref and alt alleles. Default is to require exact match between variants.")
	js := flag.String("js", "", "optional path to a file containing custom javascript functions to be used as ops")
	base := flag.String("base-path", "", "optional base-path to prepend to annotation files in the config")
	procs := flag.Int("p", 2, "number of processes to use. default is 2")
	flag.Parse()
	inFiles := flag.Args()
	if len(inFiles) != 2 {
		fmt.Printf(`Usage:
%s config.toml intput.vcf > annotated.vcf

To run a server:

%s server

`, os.Args[0], os.Args[0])
		flag.PrintDefaults()
		return
	}
	queryFile := inFiles[1]
	if !(xopen.Exists(queryFile)) {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find query file: %s\n", queryFile)
		os.Exit(2)
	}
	if !(xopen.Exists(queryFile + ".tbi")) {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find index for query file: %s\n", queryFile)
		os.Exit(2)
	}
	runtime.GOMAXPROCS(*procs)

	var config Config
	if _, err := toml.DecodeFile(inFiles[0], &config); err != nil {
		panic(err)
	}
	config.Base = *base
	for _, a := range config.Annotation {
		err := CheckAnno(&a)
		if err != nil {
			log.Fatal("CheckAnno err:", err)
		}
	}
	sources, e := config.Sources()
	if e != nil {
		log.Fatal(e)
	}

	log.Printf("found %d sources from %d files\n", len(sources), len(config.Annotation))
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	jsString := ReadJs(*js)
	strict := !*notstrict
	var a = NewAnnotator(sources, jsString, *ends, strict)

	var out io.Writer = os.Stdout
	defer os.Stdout.Close()

	var err error
	var bx interfaces.RelatableIterator
	b, err := bix.New(queryFile, 1)

	a.UpdateHeader(b)

	if err != nil {
		log.Fatal(err)
	}
	bx, err = b.Query(nil)
	if err != nil {
		log.Fatal(err)
	}

	files, err := a.SetupStreams()
	if err != nil {
		log.Fatal(err)
	}
	aends := INTERVAL
	if *ends {
		aends = BOTH
	}

	fn := func(v interfaces.Relatable) {
		a.AnnotateEnds(v, aends)
	}

	queryables := make([]interfaces.Queryable, len(files))
	for i, f := range files {
		q, err := bix.New(f, 1)
		if err != nil {
			log.Fatal(err)
		}
		queryables[i] = q
	}
	stream := irelate.PIRelate(6000, 70000, bx, *ends, fn, queryables...)

	// make a reader from the string header.
	hdr := strings.NewReader(b.Header)
	v, err := vcfgo.NewReader(hdr, true)
	out, err = vcfgo.NewWriter(out, v.Header)

	if err != nil {
		log.Fatal(err)
	}

	start := time.Now()
	n := 0

	if os.Getenv("IRELATE_PROFILE") == "TRUE" {
		log.Println("profiling to: irelate.pprof")
		f, err := os.Create("irelate.pprof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	for interval := range stream {
		fmt.Fprintf(out, "%s\n", interval)
		n++
	}
	printTime(start, n)
}

func printTime(start time.Time, n int) {
	dur := time.Since(start)
	duri, duru := dur.Seconds(), "second"
	if duri > float64(600) {
		duri, duru = dur.Minutes(), "minute"
	}
	log.Printf("annotated %d variants in %.2f %ss (%.1f / %s)", n, duri, duru, float64(n)/duri, duru)
}
<commit_msg>skip more<commit_after>// vcfanno is a command-line application and an api for annotating intervals (bed or vcf).
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"strings"

	"time"

	"github.com/BurntSushi/toml"
	"github.com/brentp/bix"
	"github.com/brentp/irelate"
	"github.com/brentp/irelate/interfaces"
	. "github.com/brentp/vcfanno/api"
	. "github.com/brentp/vcfanno/shared"
	"github.com/brentp/vcfgo"
	"github.com/brentp/xopen"
)

const VERSION = "0.0.8"

func main() {
	fmt.Fprintf(os.Stderr, `
=============================================
vcfanno version %s [built with %s]

see: https://github.com/brentp/vcfanno
=============================================
`, VERSION, runtime.Version())

	ends := flag.Bool("ends", false, "annotate the start and end as well as the interval itself.")
	notstrict := flag.Bool("permissive-overlap", false, "annotate with an overlapping variant even it doesn't"+
		" share the same ref and alt alleles. Default is to require exact match between variants.")
	js := flag.String("js", "", "optional path to a file containing custom javascript functions to be used as ops")
	base := flag.String("base-path", "", "optional base-path to prepend to annotation files in the config")
	procs := flag.Int("p", 2, "number of processes to use. default is 2")
	flag.Parse()
	inFiles := flag.Args()
	if len(inFiles) != 2 {
		fmt.Printf(`Usage:
%s config.toml intput.vcf > annotated.vcf

To run a server:

%s server

`, os.Args[0], os.Args[0])
		flag.PrintDefaults()
		return
	}
	queryFile := inFiles[1]
	if !(xopen.Exists(queryFile)) {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find query file: %s\n", queryFile)
		os.Exit(2)
	}
	if !(xopen.Exists(queryFile + ".tbi")) {
		fmt.Fprintf(os.Stderr, "\nERROR: can't find index for query file: %s\n", queryFile)
		os.Exit(2)
	}
	runtime.GOMAXPROCS(*procs)

	var config Config
	if _, err := toml.DecodeFile(inFiles[0], &config); err != nil {
		panic(err)
	}
	config.Base = *base
	for _, a := range config.Annotation {
		err := CheckAnno(&a)
		if err != nil {
			log.Fatal("CheckAnno err:", err)
		}
	}
	sources, e := config.Sources()
	if e != nil {
		log.Fatal(e)
	}

	log.Printf("found %d sources from %d files\n", len(sources), len(config.Annotation))
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	jsString := ReadJs(*js)
	strict := !*notstrict
	var a = NewAnnotator(sources, jsString, *ends, strict)

	var out io.Writer = os.Stdout
	defer os.Stdout.Close()

	var err error
	var bx interfaces.RelatableIterator
	b, err := bix.New(queryFile, 1)

	a.UpdateHeader(b)

	if err != nil {
		log.Fatal(err)
	}
	bx, err = b.Query(nil)
	if err != nil {
		log.Fatal(err)
	}

	files, err := a.SetupStreams()
	if err != nil {
		log.Fatal(err)
	}
	aends := INTERVAL
	if *ends {
		aends = BOTH
	}

	fn := func(v interfaces.Relatable) {
		a.AnnotateEnds(v, aends)
	}

	queryables := make([]interfaces.Queryable, len(files))
	for i, f := range files {
		q, err := bix.New(f, 1)
		if err != nil {
			log.Fatal(err)
		}
		queryables[i] = q
	}
	stream := irelate.PIRelate(4000, 20000, bx, *ends, fn, queryables...)

	// make a reader from the string header.
	hdr := strings.NewReader(b.Header)
	v, err := vcfgo.NewReader(hdr, true)
	out, err = vcfgo.NewWriter(out, v.Header)

	if err != nil {
		log.Fatal(err)
	}

	start := time.Now()
	n := 0

	if os.Getenv("IRELATE_PROFILE") == "TRUE" {
		log.Println("profiling to: irelate.pprof")
		f, err := os.Create("irelate.pprof")
		if err != nil {
			panic(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	for interval := range stream {
		fmt.Fprintf(out, "%s\n", interval)
		n++
	}
	printTime(start, n)
}

func printTime(start time.Time, n int) {
	dur := time.Since(start)
	duri, duru := dur.Seconds(), "second"
	if duri > float64(600) {
		duri, duru = dur.Minutes(), "minute"
	}
	log.Printf("annotated %d variants in %.2f %ss (%.1f / %s)", n, duri, duru, float64(n)/duri, duru)
}
<|endoftext|>


<commit_before>// Package gosnowflake is a Go Snowflake Driver for Go's database/sql
//
// Copyright (c) 2017 Snowflake Computing Inc. All right reserved.
//
package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver
const SnowflakeGoDriverVersion = "0.3.0"
<commit_msg>Bumped up version to 0.4.0<commit_after>// Package gosnowflake is a Go Snowflake Driver for Go's database/sql
//
// Copyright (c) 2017 Snowflake Computing Inc. All right reserved.
//
package gosnowflake

// SnowflakeGoDriverVersion is the version of Go Snowflake Driver
const SnowflakeGoDriverVersion = "0.4.0"
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 1
	appMinor uint = 0
	appPatch uint = 4

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = ""
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild=foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild = "dev"

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<commit_msg>Bump for v1.0.5<commit_after>// Copyright (c) 2013-2014 The btcsuite developers
// Copyright (c) 2015 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"fmt"
	"strings"
)

// semanticAlphabet
const semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"

// These constants define the application version and follow the semantic
// versioning 2.0.0 spec (http://semver.org/).
const (
	appMajor uint = 1
	appMinor uint = 0
	appPatch uint = 5

	// appPreRelease MUST only contain characters from semanticAlphabet
	// per the semantic versioning spec.
	appPreRelease = ""
)

// appBuild is defined as a variable so it can be overridden during the build
// process with '-ldflags "-X main.appBuild=foo' if needed.  It MUST only
// contain characters from semanticAlphabet per the semantic versioning spec.
var appBuild = "dev"

// version returns the application version as a properly formed string per the
// semantic versioning 2.0.0 spec (http://semver.org/).
func version() string {
	// Start with the major, minor, and path versions.
	version := fmt.Sprintf("%d.%d.%d", appMajor, appMinor, appPatch)

	// Append pre-release version if there is one.  The hyphen called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the pre-release string.  The pre-release version
	// is not appended if it contains invalid characters.
	preRelease := normalizeVerString(appPreRelease)
	if preRelease != "" {
		version = fmt.Sprintf("%s-%s", version, preRelease)
	}

	// Append build metadata if there is any.  The plus called for
	// by the semantic versioning spec is automatically appended and should
	// not be contained in the build metadata string.  The build metadata
	// string is not appended if it contains invalid characters.
	build := normalizeVerString(appBuild)
	if build != "" {
		version = fmt.Sprintf("%s+%s", version, build)
	}

	return version
}

// normalizeVerString returns the passed string stripped of all characters which
// are not valid according to the semantic versioning guidelines for pre-release
// version and build metadata strings.  In particular they MUST only contain
// characters in semanticAlphabet.
func normalizeVerString(str string) string {
	result := bytes.Buffer{}
	for _, r := range str {
		if strings.ContainsRune(semanticAlphabet, r) {
			_, err := result.WriteRune(r)
			// Writing to a bytes.Buffer panics on OOM, and all
			// errors are unexpected.
			if err != nil {
				panic(err)
			}
		}
	}
	return result.String()
}
<|endoftext|>


<commit_before>package main

// version
const ver = "0.1"
<commit_msg>bump version for 0.2 release<commit_after>package main

// version
const ver = "0.2"
<|endoftext|>


<commit_before>package main

var VERSION string = "v0.4.0.3"
<commit_msg>Version test<commit_after>package main
var VERSION string = "v0.4.0.5"
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"runtime"
)

const (
	AppName         = "whatunga"
	AppVersionMajor = 0
	AppVersionMinor = 1
)

// revision part of the program version.
// This will be set automatically at build time like so:
//
//     go build -ldflags "-X main.AppVersionRev `date -u +%s`"
var AppVersionRev string

func Version() string {
	if len(AppVersionRev) == 0 {
		AppVersionRev = "0"
	}

	return fmt.Sprintf("%s %d.%d.%s (Go runtime %s).\nCopyright (c) 2010-2013, Jim Teeuwen.",
		AppName, AppVersionMajor, AppVersionMinor, AppVersionRev, runtime.Version())
}

const (
	WildFly = "WildFly"
	EAP     = "EAP"
)

type ProductVersion struct {
	Product string
	Version string
}

func (v ProductVersion) String() string {
	return v.Product + ":" + v.Version
}

var SupportedVersions = []ProductVersion{
	{WildFly, "8.0"},
	{WildFly, "8.1"},
	{EAP, "6.3"},
}

// the xmlns version of the config files
var ModelVersions = map[string]ProductVersion{
	"2.0": {WildFly, "8.0"},
	"2.1": {WildFly, "8.1"},
	"1.6": {EAP, "6.3"},
}
<commit_msg>Bump to 0.2<commit_after>package main

import (
	"fmt"
	"runtime"
)

const (
	AppName         = "whatunga"
	AppVersionMajor = 0
	AppVersionMinor = 2
)

// revision part of the program version.
// This will be set automatically at build time like so:
//
//     go build -ldflags "-X main.AppVersionRev `date -u +%s`"
var AppVersionRev string

func Version() string {
	if len(AppVersionRev) == 0 {
		AppVersionRev = "0"
	}

	return fmt.Sprintf("%s %d.%d.%s (Go runtime %s).\nCopyright (c) 2010-2013, Jim Teeuwen.",
		AppName, AppVersionMajor, AppVersionMinor, AppVersionRev, runtime.Version())
}

const (
	WildFly = "WildFly"
	EAP     = "EAP"
)

type ProductVersion struct {
	Product string
	Version string
}

func (v ProductVersion) String() string {
	return v.Product + ":" + v.Version
}

var SupportedVersions = []ProductVersion{
	{WildFly, "8.0"},
	{WildFly, "8.1"},
	{EAP, "6.3"},
}

// the xmlns version of the config files
var ModelVersions = map[string]ProductVersion{
	"2.0": {WildFly, "8.0"},
	"2.1": {WildFly, "8.1"},
	"1.6": {EAP, "6.3"},
}
<|endoftext|>


<commit_before>package main

const Version = "1.0.0"
<commit_msg>1.0.1<commit_after>package main

const Version = "1.0.1"
<|endoftext|>


<commit_before>package main

const Version = "0.1.4"
<commit_msg>feat(version): bump<commit_after>package main

const Version = "0.1.5"
<|endoftext|>


<commit_before>package test161

import (
	"fmt"
)

type ProgramVersion struct {
	Major    uint `yaml:"major"`
	Minor    uint `yaml:"minor"`
	Revision uint `yaml:"revision"`
}

var Version = ProgramVersion{
	Major:    1,
	Minor:    2,
	Revision: 3,
}

func (v ProgramVersion) String() string {
	return fmt.Sprintf("%v.%v.%v", v.Major, v.Minor, v.Revision)
}

// Returns 1 if this > other, 0 if this == other, and -1 if this < other
func (this ProgramVersion) CompareTo(other ProgramVersion) int {

	if this.Major > other.Major {
		return 1
	} else if this.Major < other.Major {
		return -1
	} else if this.Minor > other.Minor {
		return 1
	} else if this.Minor < other.Minor {
		return -1
	} else if this.Revision > other.Revision {
		return 1
	} else if this.Revision < other.Revision {
		return -1
	} else {
		return 0
	}

}
<commit_msg>Update version to 1.2.4<commit_after>package test161

import (
	"fmt"
)

type ProgramVersion struct {
	Major    uint `yaml:"major"`
	Minor    uint `yaml:"minor"`
	Revision uint `yaml:"revision"`
}

var Version = ProgramVersion{
	Major:    1,
	Minor:    2,
	Revision: 4,
}

func (v ProgramVersion) String() string {
	return fmt.Sprintf("%v.%v.%v", v.Major, v.Minor, v.Revision)
}

// Returns 1 if this > other, 0 if this == other, and -1 if this < other
func (this ProgramVersion) CompareTo(other ProgramVersion) int {

	if this.Major > other.Major {
		return 1
	} else if this.Major < other.Major {
		return -1
	} else if this.Minor > other.Minor {
		return 1
	} else if this.Minor < other.Minor {
		return -1
	} else if this.Revision > other.Revision {
		return 1
	} else if this.Revision < other.Revision {
		return -1
	} else {
		return 0
	}

}
<|endoftext|>


<commit_before>package nut

import (
	"fmt"
	"regexp"
	"strconv"
)

// Current format for nut version.
var VersionRegexp = regexp.MustCompile(`^(\d+).(\d+).(\d+)$`)

// Describes nut version. See http://gonuts.io/XXX for explanation of version specification.
type Version struct {
	Major int
	Minor int
	Patch int
}

// Parse and set version.
func NewVersion(version string) (v *Version, err error) {
	v = new(Version)
	err = v.setVersion(version)
	return
}

// Return version as string in current format.
func (v Version) String() string {
	res := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if !VersionRegexp.MatchString(res) { // sanity check
		panic(fmt.Sprintf("%s not matches %s", res, VersionRegexp))
	}
	return res
}

// Returns true if left < right, false otherwise.
func (left *Version) Less(right *Version) bool {
	if left.Major < right.Major {
		return true
	} else if left.Major > right.Major {
		return false
	}

	if left.Minor < right.Minor {
		return true
	} else if left.Minor > right.Minor {
		return false
	}

	if left.Patch < right.Patch {
		return true
	} else if left.Patch > right.Patch {
		return false
	}

	// left == right => "left < right" is false
	return false
}

// Marshal to JSON.
func (v *Version) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf(`"%s"`, v)), nil
}

// Unmarshal from JSON.
func (v *Version) UnmarshalJSON(b []byte) error {
	return v.setVersion(string(b[1 : len(b)-1]))
}

func (v *Version) setVersion(version string) (err error) {
	parsed := VersionRegexp.FindAllStringSubmatch(version, -1)
	if (parsed == nil) || (len(parsed[0]) != 4) {
		err = fmt.Errorf("Bad format for version %q: parsed as %#v", version, parsed)
		return
	}

	v.Major, _ = strconv.Atoi(parsed[0][1])
	v.Minor, _ = strconv.Atoi(parsed[0][2])
	v.Patch, _ = strconv.Atoi(parsed[0][3])
	return
}
<commit_msg>Link to versioning documentation.<commit_after>package nut

import (
	"fmt"
	"regexp"
	"strconv"
)

// Current format for nut version.
var VersionRegexp = regexp.MustCompile(`^(\d+).(\d+).(\d+)$`)

// Describes nut version. See http://gonuts.io/-/doc/versioning for explanation of version specification.
type Version struct {
	Major int
	Minor int
	Patch int
}

// Parse and set version.
func NewVersion(version string) (v *Version, err error) {
	v = new(Version)
	err = v.setVersion(version)
	return
}

// Return version as string in current format.
func (v Version) String() string {
	res := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
	if !VersionRegexp.MatchString(res) { // sanity check
		panic(fmt.Sprintf("%s not matches %s", res, VersionRegexp))
	}
	return res
}

// Returns true if left < right, false otherwise.
func (left *Version) Less(right *Version) bool {
	if left.Major < right.Major {
		return true
	} else if left.Major > right.Major {
		return false
	}

	if left.Minor < right.Minor {
		return true
	} else if left.Minor > right.Minor {
		return false
	}

	if left.Patch < right.Patch {
		return true
	} else if left.Patch > right.Patch {
		return false
	}

	// left == right => "left < right" is false
	return false
}

// Marshal to JSON.
func (v *Version) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf(`"%s"`, v)), nil
}

// Unmarshal from JSON.
func (v *Version) UnmarshalJSON(b []byte) error {
	return v.setVersion(string(b[1 : len(b)-1]))
}

func (v *Version) setVersion(version string) (err error) {
	parsed := VersionRegexp.FindAllStringSubmatch(version, -1)
	if (parsed == nil) || (len(parsed[0]) != 4) {
		err = fmt.Errorf("Bad format for version %q: parsed as %#v", version, parsed)
		return
	}

	v.Major, _ = strconv.Atoi(parsed[0][1])
	v.Minor, _ = strconv.Atoi(parsed[0][2])
	v.Patch, _ = strconv.Atoi(parsed[0][3])
	return
}
<|endoftext|>


<commit_before>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 29}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<commit_msg>Release 1.1.30<commit_after>package dns

import "fmt"

// Version is current version of this library.
var Version = v{1, 1, 30}

// v holds the version of this library.
type v struct {
	Major, Minor, Patch int
}

func (v v) String() string {
	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
}
<|endoftext|>


<commit_before>package main

/*
Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
*/
const VersionMajor = 4
const VersionMinor = 14
const VersionPatch = 2
<commit_msg>Version bump<commit_after>package main

/*
Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible manner, and
PATCH version when you make backwards-compatible bug fixes.
*/
const VersionMajor = 4
const VersionMinor = 14
const VersionPatch = 3
<|endoftext|>


<commit_before>// Copyright © 2016 Pennock Tech, LLC.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package main

import (
	"fmt"
)

// TODO: figure out if we want to bother with a makefile and git-derived version tagging, as used elsewhere

const fingerProgram = "fingerd"

var fingerVersion string = "0.1.1"

func version() {
	fmt.Printf("%s: Version %s\n", fingerProgram, fingerVersion)
}
<commit_msg>Behavior change (blocking NUL, '\') so bump version<commit_after>// Copyright © 2016 Pennock Tech, LLC.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package main

import (
	"fmt"
)

// TODO: figure out if we want to bother with a makefile and git-derived version tagging, as used elsewhere

const fingerProgram = "fingerd"

var fingerVersion string = "0.1.2"

func version() {
	fmt.Printf("%s: Version %s\n", fingerProgram, fingerVersion)
}
<|endoftext|>


<commit_before>package flect

//Version holds Flect version number
const Version = "v0.1.2"
<commit_msg>version bump: v0.1.3<commit_after>package flect

//Version holds Flect version number
const Version = "v0.1.3"
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/getgauge/common"
	"os"
	"path"
	"runtime"
	"sort"
	"strings"
)

const (
	gaugeRepositoryUrl = "http://raw.github.com/getgauge/gauge-repository/master"
)

type installDescription struct {
	Name        string
	Description string
	Versions    []versionInstallDescription
}

type versionInstallDescription struct {
	Version             string
	GaugeVersionSupport versionSupport
	Install             platformSpecifics
	DownloadUrls        downloadUrls
}

type downloadUrls struct {
	X86 platformSpecifics
	X64 platformSpecifics
}

type platformSpecifics struct {
	Windows string
	Linux   string
	Darwin  string
}

type versionSupport struct {
	Minimum string
	Maximum string
}

func installPlugin(pluginName, version string) {
	installDescription, err := getInstallDescription(pluginName)
	if err != nil {
		fmt.Printf("[Error] Failed to find install description for Plugin: '%s' %s. : %s \n", pluginName, version, err)
		return
	}
	if err := installPluginWithDescription(installDescription, version); err != nil {
		fmt.Printf("[Error] Failed installing Plugin '%s' %s : %s \n", pluginName, version, err)
		return
	}
	fmt.Printf("Successfully installed plugin: %s %s\n", pluginName, version)
}

func installPluginWithDescription(installDescription *installDescription, version string) error {
	var versionInstallDescription *versionInstallDescription
	var err error
	if version != "" {
		versionInstallDescription, err = installDescription.getVersion(version)
		if err != nil {
			return err
		}
		if compatibilityError := checkCompatiblity(currentGaugeVersion, &versionInstallDescription.GaugeVersionSupport); compatibilityError != nil {
			return errors.New(fmt.Sprintf("Plugin Version %s is not supported for gauge %s : %s", installDescription.Name, versionInstallDescription.Version, versionInstallDescription.Version, currentGaugeVersion.String(), compatibilityError.Error()))
		}
	} else {
		versionInstallDescription, err = installDescription.getLatestCompatibleVersionTo(currentGaugeVersion)
		if err != nil {
			return errors.New(fmt.Sprintf("Could not find compatible version for plugin %s. : %s", installDescription.Name, err))
		}
	}
	return installPluginVersion(installDescription, versionInstallDescription)
}

func installPluginVersion(installDesc *installDescription, versionInstallDescription *versionInstallDescription) error {
	fmt.Printf("Installing Plugin => %s %s\n", installDesc.Name, versionInstallDescription.Version)
	pluginZip, err := downloadPluginZip(versionInstallDescription.DownloadUrls)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to download plugin zip: %s.", err))
	}
	unzippedPluginDir, err := common.UnzipArchive(pluginZip)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to Unzip plugin-zip file %s.", err))
	}
	if err := runInstallCommands(versionInstallDescription.Install, unzippedPluginDir); err != nil {
		return errors.New(fmt.Sprintf("Failed to Run install command. %s.", err))
	}
	return copyPluginFilesToGauge(installDesc, versionInstallDescription, unzippedPluginDir)
}

func runInstallCommands(installCommands platformSpecifics, workingDir string) error {
	command := ""
	switch runtime.GOOS {
	case "windows":
		command = installCommands.Windows
		break
	case "darwin":
		command = installCommands.Darwin
		break
	default:
		command = installCommands.Linux
		break
	}

	if command == "" {
		return nil
	}

	cmd := common.GetExecutableCommand(command)
	cmd.Dir = workingDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		return err
	}

	return cmd.Wait()
}

func copyPluginFilesToGauge(installDesc *installDescription, versionInstallDesc *versionInstallDescription, pluginContents string) error {
	pluginsDir, err := common.GetPrimaryPluginsInstallDir()
	if err != nil {
		return err
	}
	versionedPluginDir := path.Join(pluginsDir, installDesc.Name, versionInstallDesc.Version)
	if common.DirExists(versionedPluginDir) {
		return errors.New(fmt.Sprintf("Plugin %s %s already installed at %s", installDesc.Name, versionInstallDesc.Version, versionedPluginDir))
	}
	return common.MirrorDir(pluginContents, versionedPluginDir)

}

func downloadPluginZip(downloadUrls downloadUrls) (string, error) {
	var platformLinks *platformSpecifics
	if strings.Contains(runtime.GOARCH, "64") {
		platformLinks = &downloadUrls.X64
	} else {
		platformLinks = &downloadUrls.X86
	}

	var downloadLink string
	switch runtime.GOOS {
	case "windows":
		downloadLink = platformLinks.Windows
		break
	case "darwin":
		downloadLink = platformLinks.Darwin
		break
	default:
		downloadLink = platformLinks.Linux
		break
	}
	if downloadLink == "" {
		return "", errors.New("Plugin download URL not available for current platform.")
	}
	downloadedFile, err := common.DownloadToTempDir(downloadLink)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Failed to download File %s: %s", downloadLink, err.Error()))
	}
	return downloadedFile, err
}

func getInstallDescription(plugin string) (*installDescription, error) {
	installJson, err := getPluginInstallJson(plugin)
	if err != nil {
		return nil, err
	}
	InstallJsonContents, readErr := common.ReadFileContents(installJson)
	if readErr != nil {
		return nil, readErr
	}
	installDescription := &installDescription{}
	if err = json.Unmarshal([]byte(InstallJsonContents), installDescription); err != nil {
		return nil, err
	}
	return installDescription, nil
}

func getPluginInstallJson(plugin string) (string, error) {
	versionInstallDescriptionJsonFile := plugin + "-install.json"
	versionInstallDescriptionJsonUrl := constructPluginInstallJsonUrl(plugin)

	downloadedFile, downloadErr := common.DownloadToTempDir(versionInstallDescriptionJsonUrl)
	if downloadErr != nil {
		return "", errors.New(fmt.Sprintf("Could not find %s file. Check install name and version. %s", versionInstallDescriptionJsonFile, downloadErr.Error()))
	}
	return downloadedFile, nil
}

func constructPluginInstallJsonUrl(plugin string) string {
	installJsonFile := plugin + "-install.json"
	return fmt.Sprintf("%s/%s", gaugeRepositoryUrl, installJsonFile)
}

func (installDesc *installDescription) getVersion(version string) (*versionInstallDescription, error) {
	for _, versionInstallDescription := range installDesc.Versions {
		if versionInstallDescription.Version == version {
			return &versionInstallDescription, nil
		}
	}
	return nil, errors.New("Could not find install description for Version " + version)
}

func (installDesc *installDescription) getLatestCompatibleVersionTo(version *version) (*versionInstallDescription, error) {
	installDesc.sortVersionInstallDescriptions()
	for _, versionInstallDesc := range installDesc.Versions {
		if err := checkCompatiblity(version, &versionInstallDesc.GaugeVersionSupport); err == nil {
			return &versionInstallDesc, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("Compatible version to %s not found", version))

}

func (installDescription *installDescription) sortVersionInstallDescriptions() {
	sort.Sort(ByDecreasingVersion(installDescription.Versions))
}

func checkCompatiblity(version *version, versionSupport *versionSupport) error {
	minSupportVersion, err := parseVersion(versionSupport.Minimum)
	if err != nil {
		return errors.New(fmt.Sprintf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err))
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := parseVersion(versionSupport.Maximum)
		if err != nil {
			return errors.New(fmt.Sprintf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err))
		}
		if version.isBetween(minSupportVersion, maxSupportVersion) {
			return nil
		} else {
			return errors.New(fmt.Sprintf("Version %s is not between %s and %s", version, minSupportVersion, maxSupportVersion))
		}
	}

	if minSupportVersion.isLesserThanEqualTo(version) {
		return nil
	}
	return errors.New(fmt.Sprintf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, version))
}

type ByDecreasingVersion []versionInstallDescription

func (a ByDecreasingVersion) Len() int      { return len(a) }
func (a ByDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByDecreasingVersion) Less(i, j int) bool {
	version1, _ := parseVersion(a[i].Version)
	version2, _ := parseVersion(a[j].Version)
	return version1.isGreaterThan(version2)
}
<commit_msg>Checking if plugin is installed before downloading the plugin zip<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/getgauge/common"
	"os"
	"path"
	"runtime"
	"sort"
	"strings"
)

const (
	gaugeRepositoryUrl = "http://raw.github.com/getgauge/gauge-repository/master"
)

type installDescription struct {
	Name        string
	Description string
	Versions    []versionInstallDescription
}

type versionInstallDescription struct {
	Version             string
	GaugeVersionSupport versionSupport
	Install             platformSpecifics
	DownloadUrls        downloadUrls
}

type downloadUrls struct {
	X86 platformSpecifics
	X64 platformSpecifics
}

type platformSpecifics struct {
	Windows string
	Linux   string
	Darwin  string
}

type versionSupport struct {
	Minimum string
	Maximum string
}

func installPlugin(pluginName, version string) {
	installDescription, err := getInstallDescription(pluginName)
	if err != nil {
		fmt.Printf("[Error] Failed to find install description for Plugin: '%s' %s. : %s \n", pluginName, version, err)
		return
	}
	if err := installPluginWithDescription(installDescription, version); err != nil {
		fmt.Printf("[Error] Failed installing Plugin '%s' %s : %s \n", pluginName, version, err)
		return
	}
	fmt.Printf("Successfully installed plugin: %s %s\n", pluginName, version)
}

func installPluginWithDescription(installDescription *installDescription, version string) error {
	var versionInstallDescription *versionInstallDescription
	var err error
	if version != "" {
		versionInstallDescription, err = installDescription.getVersion(version)
		if err != nil {
			return err
		}
		if compatibilityError := checkCompatiblity(currentGaugeVersion, &versionInstallDescription.GaugeVersionSupport); compatibilityError != nil {
			return errors.New(fmt.Sprintf("Plugin Version %s is not supported for gauge %s : %s", installDescription.Name, versionInstallDescription.Version, versionInstallDescription.Version, currentGaugeVersion.String(), compatibilityError.Error()))
		}
	} else {
		versionInstallDescription, err = installDescription.getLatestCompatibleVersionTo(currentGaugeVersion)
		if err != nil {
			return errors.New(fmt.Sprintf("Could not find compatible version for plugin %s. : %s", installDescription.Name, err))
		}
	}
	return installPluginVersion(installDescription, versionInstallDescription)
}

func installPluginVersion(installDesc *installDescription, versionInstallDescription *versionInstallDescription) error {
	if common.IsPluginInstalled(installDesc.Name, versionInstallDescription.Version) {
		return errors.New(fmt.Sprintf("Plugin %s %s is already installed.", installDesc.Name, versionInstallDescription.Version))
	}

	fmt.Printf("Installing Plugin => %s %s\n", installDesc.Name, versionInstallDescription.Version)
	pluginZip, err := downloadPluginZip(versionInstallDescription.DownloadUrls)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to download plugin zip: %s.", err))
	}
	unzippedPluginDir, err := common.UnzipArchive(pluginZip)
	if err != nil {
		return errors.New(fmt.Sprintf("Failed to Unzip plugin-zip file %s.", err))
	}
	if err := runInstallCommands(versionInstallDescription.Install, unzippedPluginDir); err != nil {
		return errors.New(fmt.Sprintf("Failed to Run install command. %s.", err))
	}
	return copyPluginFilesToGauge(installDesc, versionInstallDescription, unzippedPluginDir)
}

func runInstallCommands(installCommands platformSpecifics, workingDir string) error {
	command := ""
	switch runtime.GOOS {
	case "windows":
		command = installCommands.Windows
		break
	case "darwin":
		command = installCommands.Darwin
		break
	default:
		command = installCommands.Linux
		break
	}

	if command == "" {
		return nil
	}

	cmd := common.GetExecutableCommand(command)
	cmd.Dir = workingDir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		return err
	}

	return cmd.Wait()
}

func copyPluginFilesToGauge(installDesc *installDescription, versionInstallDesc *versionInstallDescription, pluginContents string) error {
	pluginsDir, err := common.GetPrimaryPluginsInstallDir()
	if err != nil {
		return err
	}
	versionedPluginDir := path.Join(pluginsDir, installDesc.Name, versionInstallDesc.Version)
	if common.DirExists(versionedPluginDir) {
		return errors.New(fmt.Sprintf("Plugin %s %s already installed at %s", installDesc.Name, versionInstallDesc.Version, versionedPluginDir))
	}
	return common.MirrorDir(pluginContents, versionedPluginDir)

}

func downloadPluginZip(downloadUrls downloadUrls) (string, error) {
	var platformLinks *platformSpecifics
	if strings.Contains(runtime.GOARCH, "64") {
		platformLinks = &downloadUrls.X64
	} else {
		platformLinks = &downloadUrls.X86
	}

	var downloadLink string
	switch runtime.GOOS {
	case "windows":
		downloadLink = platformLinks.Windows
		break
	case "darwin":
		downloadLink = platformLinks.Darwin
		break
	default:
		downloadLink = platformLinks.Linux
		break
	}
	if downloadLink == "" {
		return "", errors.New("Plugin download URL not available for current platform.")
	}
	downloadedFile, err := common.DownloadToTempDir(downloadLink)
	if err != nil {
		return "", errors.New(fmt.Sprintf("Failed to download File %s: %s", downloadLink, err.Error()))
	}
	return downloadedFile, err
}

func getInstallDescription(plugin string) (*installDescription, error) {
	installJson, err := getPluginInstallJson(plugin)
	if err != nil {
		return nil, err
	}
	InstallJsonContents, readErr := common.ReadFileContents(installJson)
	if readErr != nil {
		return nil, readErr
	}
	installDescription := &installDescription{}
	if err = json.Unmarshal([]byte(InstallJsonContents), installDescription); err != nil {
		return nil, err
	}
	return installDescription, nil
}

func getPluginInstallJson(plugin string) (string, error) {
	versionInstallDescriptionJsonFile := plugin + "-install.json"
	versionInstallDescriptionJsonUrl := constructPluginInstallJsonUrl(plugin)

	downloadedFile, downloadErr := common.DownloadToTempDir(versionInstallDescriptionJsonUrl)
	if downloadErr != nil {
		return "", errors.New(fmt.Sprintf("Could not find %s file. Check install name and version. %s", versionInstallDescriptionJsonFile, downloadErr.Error()))
	}
	return downloadedFile, nil
}

func constructPluginInstallJsonUrl(plugin string) string {
	installJsonFile := plugin + "-install.json"
	return fmt.Sprintf("%s/%s", gaugeRepositoryUrl, installJsonFile)
}

func (installDesc *installDescription) getVersion(version string) (*versionInstallDescription, error) {
	for _, versionInstallDescription := range installDesc.Versions {
		if versionInstallDescription.Version == version {
			return &versionInstallDescription, nil
		}
	}
	return nil, errors.New("Could not find install description for Version " + version)
}

func (installDesc *installDescription) getLatestCompatibleVersionTo(version *version) (*versionInstallDescription, error) {
	installDesc.sortVersionInstallDescriptions()
	for _, versionInstallDesc := range installDesc.Versions {
		if err := checkCompatiblity(version, &versionInstallDesc.GaugeVersionSupport); err == nil {
			return &versionInstallDesc, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("Compatible version to %s not found", version))

}

func (installDescription *installDescription) sortVersionInstallDescriptions() {
	sort.Sort(ByDecreasingVersion(installDescription.Versions))
}

func checkCompatiblity(version *version, versionSupport *versionSupport) error {
	minSupportVersion, err := parseVersion(versionSupport.Minimum)
	if err != nil {
		return errors.New(fmt.Sprintf("Invalid minimum support version %s. : %s. ", versionSupport.Minimum, err))
	}
	if versionSupport.Maximum != "" {
		maxSupportVersion, err := parseVersion(versionSupport.Maximum)
		if err != nil {
			return errors.New(fmt.Sprintf("Invalid maximum support version %s. : %s. ", versionSupport.Maximum, err))
		}
		if version.isBetween(minSupportVersion, maxSupportVersion) {
			return nil
		} else {
			return errors.New(fmt.Sprintf("Version %s is not between %s and %s", version, minSupportVersion, maxSupportVersion))
		}
	}

	if minSupportVersion.isLesserThanEqualTo(version) {
		return nil
	}
	return errors.New(fmt.Sprintf("Incompatible version. Minimum support version %s is higher than current version %s", minSupportVersion, version))
}

type ByDecreasingVersion []versionInstallDescription

func (a ByDecreasingVersion) Len() int      { return len(a) }
func (a ByDecreasingVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByDecreasingVersion) Less(i, j int) bool {
	version1, _ := parseVersion(a[i].Version)
	version2, _ := parseVersion(a[j].Version)
	return version1.isGreaterThan(version2)
}
<|endoftext|>


<commit_before>package pgstorage

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"strings"

	"github.com/jacksontj/dataman/datamantype"
	"github.com/jacksontj/dataman/record"
	"github.com/jacksontj/dataman/stream"
	"github.com/jacksontj/dataman/stream/local"
)

func DoQuery(ctx context.Context, db *sql.DB, query string, colAddrs []ColAddr, args ...interface{}) ([]record.Record, error) {
	rows, err := db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("Error running query: Err=%v query=%s ", err, query)
	}

	results := make([]record.Record, 0)

	// Get the list of column names
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}
	columns := make([]interface{}, len(cols))
	columnPointers := make([]interface{}, len(cols))
	for i := range columns {
		columnPointers[i] = &columns[i]
	}

	// If there aren't any rows, we return a nil result
	for rows.Next() {
		// Scan the result into the column pointers...
		if err := rows.Scan(columnPointers...); err != nil {
			rows.Close()
			return nil, err
		}

		// Create our map, and retrieve the value for each column from the pointers slice,
		// storing it in the map with the name of the column as the key.
		data := make(record.Record)
		skipN := 0
		for i, colName := range cols {
			val := columnPointers[i].(*interface{})
			if colAddrs != nil {
				if colAddrs[i].skipN > 0 {
					if *val != true {
						skipN = colAddrs[i].skipN
					} else {
						skipN = 0
					}
				} else {
					if skipN <= 0 {
						data.Set(colAddrs[i].key, *val)
					} else {
						skipN--
					}
				}
			} else {
				data[colName] = *val
			}
		}
		results = append(results, data)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return results, nil
}

func DoStreamQuery(ctx context.Context, db *sql.DB, query string, colAddrs []ColAddr, args ...interface{}) (stream.ClientStream, error) {
	rows, err := db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("Error running query: Err=%v query=%s ", err, query)
	}

	resultsChan := make(chan stream.Result, 100)
	errorChan := make(chan error, 1)

	serverStream := local.NewServerStream(ctx, resultsChan, errorChan)
	clientStream := local.NewClientStream(ctx, resultsChan, errorChan)

	// TODO: without goroutine?
	go func() {
		defer serverStream.Close()
		// Get the list of column names
		cols, err := rows.Columns()
		if err != nil {
			serverStream.SendError(err)
			return
		}
		columns := make([]interface{}, len(cols))
		columnPointers := make([]interface{}, len(cols))
		for i := range columns {
			columnPointers[i] = &columns[i]
		}

		// If there aren't any rows, we return a nil result
		for rows.Next() {
			// Scan the result into the column pointers...
			if err := rows.Scan(columnPointers...); err != nil {
				rows.Close()
				serverStream.SendError(err)
				return
			}

			// Create our map, and retrieve the value for each column from the pointers slice,
			// storing it in the map with the name of the column as the key.
			data := make(record.Record)
			skipN := 0
			for i, colName := range cols {
				val := columnPointers[i].(*interface{})
				if colAddrs != nil {
					if colAddrs[i].skipN > 0 {
						// if we didn't find the key in the selector, then we skipN
						// this accounts for nil and false return types
						if *val != true {
							skipN = colAddrs[i].skipN
						} else {
							skipN = 0
						}
					} else {
						if skipN <= 0 {
							data.Set(colAddrs[i].key, *val)
						} else {
							skipN--
						}
					}
				} else {
					data[colName] = *val
				}
			}
			serverStream.SendResult(data)
		}

		if err := rows.Err(); err != nil {
			serverStream.SendError(err)
			return
		}
	}()

	return clientStream, nil
}

// Normalize field names. This takes a string such as "(data ->> 'created'::text)"
// and converts it to "data.created"
func normalizeFieldName(in string) string {
	if in[0] != '(' || in[len(in)-1] != ')' {
		return in
	}
	in = in[1 : len(in)-1]

	var output string

	for _, part := range strings.Split(in, " ") {
		if sepIdx := strings.Index(part, "'::"); sepIdx > -1 {
			part = part[1:sepIdx]
		}
		if part == "->>" {
			output += "."
		} else {
			output += part
		}
	}

	return output
}

// TODO: remove?
func serializeValue(v interface{}) (string, error) {
	switch vTyped := v.(type) {
	case time.Time:
		return fmt.Sprintf("'%v'", vTyped.Format(datamantype.DateTimeFormatStr)), nil
	default:
		return fmt.Sprintf("'%v'", v), nil
	}
}

// Take a path to an object and convert it to postgres json addressing
func collectionFieldToSelector(path []string) string {
	switch len(path) {
	case 1:
		return path[0]
	case 2:
		return path[0] + "->>'" + path[1] + "'"
	default:
		fieldChain := path[1:]
		return path[0] + "->'" + strings.Join(fieldChain[:len(fieldChain)-1], "'->'") + "'->>'" + path[len(path)-1] + "'"
	}
}

// TODO: remove? or consolidate?
// When we want to do existence checks ( top->'level'->'key' ? 'subkey' we can't use the
// ->> selector since it will return "text" (seemingly the actual value) whereas -> returns
// a map-like object with which we can do selection and ? checks on.
func collectionFieldParentToSelector(path []string) string {
	switch len(path) {
	case 1:
		return path[0]
	case 2:
		return path[0] + "->'" + path[1] + "'"
	default:
		fieldChain := path[1:]
		return path[0] + "->'" + strings.Join(fieldChain[:len(fieldChain)-1], "'->'") + "'->'" + path[len(path)-1] + "'"
	}
}

// ColAddr is a list of addresses of columns
type ColAddr struct {
	key []string
	// Number of columns this is a "selector" for. This is used for jsonb columns
	// so we can differentiate between nil meaning the value in the json is null
	// and the field not existing in the JSON
	// is this a `?` selector telling us whether or not to skip the next one
	skipN int
}

// selectFields returns a SELECT string and the corresponding ColAddr
func selectFields(fields []string) (string, []ColAddr) {
	// TODO: remove?
	// If no projection, then just return all
	if fields == nil {
		return "*", nil
	}

	fieldSelectors := make([]string, 0, len(fields))
	cAddrs := make([]ColAddr, 0, len(fields))
	for _, field := range fields {
		fieldParts := strings.Split(field, ".")
		if len(fieldParts) > 1 {
			cAddrs = append(cAddrs, ColAddr{skipN: 1})
			fieldSelectors = append(fieldSelectors, collectionFieldParentToSelector(fieldParts[:len(fieldParts)-1])+" ? '"+fieldParts[len(fieldParts)-1]+"'")
		}
		cAddrs = append(cAddrs, ColAddr{
			key: fieldParts,
		})
		fieldSelectors = append(fieldSelectors, collectionFieldToSelector(fieldParts))

	}

	return strings.Join(fieldSelectors, ","), cAddrs
}
<commit_msg>Properly serializeValue for maps<commit_after>package pgstorage

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"time"

	"strings"

	"github.com/jacksontj/dataman/datamantype"
	"github.com/jacksontj/dataman/record"
	"github.com/jacksontj/dataman/stream"
	"github.com/jacksontj/dataman/stream/local"
)

func DoQuery(ctx context.Context, db *sql.DB, query string, colAddrs []ColAddr, args ...interface{}) ([]record.Record, error) {
	rows, err := db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("Error running query: Err=%v query=%s ", err, query)
	}

	results := make([]record.Record, 0)

	// Get the list of column names
	cols, err := rows.Columns()
	if err != nil {
		return nil, err
	}
	columns := make([]interface{}, len(cols))
	columnPointers := make([]interface{}, len(cols))
	for i := range columns {
		columnPointers[i] = &columns[i]
	}

	// If there aren't any rows, we return a nil result
	for rows.Next() {
		// Scan the result into the column pointers...
		if err := rows.Scan(columnPointers...); err != nil {
			rows.Close()
			return nil, err
		}

		// Create our map, and retrieve the value for each column from the pointers slice,
		// storing it in the map with the name of the column as the key.
		data := make(record.Record)
		skipN := 0
		for i, colName := range cols {
			val := columnPointers[i].(*interface{})
			if colAddrs != nil {
				if colAddrs[i].skipN > 0 {
					if *val != true {
						skipN = colAddrs[i].skipN
					} else {
						skipN = 0
					}
				} else {
					if skipN <= 0 {
						data.Set(colAddrs[i].key, *val)
					} else {
						skipN--
					}
				}
			} else {
				data[colName] = *val
			}
		}
		results = append(results, data)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}

	return results, nil
}

func DoStreamQuery(ctx context.Context, db *sql.DB, query string, colAddrs []ColAddr, args ...interface{}) (stream.ClientStream, error) {
	rows, err := db.QueryContext(ctx, query, args...)
	if err != nil {
		return nil, fmt.Errorf("Error running query: Err=%v query=%s ", err, query)
	}

	resultsChan := make(chan stream.Result, 100)
	errorChan := make(chan error, 1)

	serverStream := local.NewServerStream(ctx, resultsChan, errorChan)
	clientStream := local.NewClientStream(ctx, resultsChan, errorChan)

	// TODO: without goroutine?
	go func() {
		defer serverStream.Close()
		// Get the list of column names
		cols, err := rows.Columns()
		if err != nil {
			serverStream.SendError(err)
			return
		}
		columns := make([]interface{}, len(cols))
		columnPointers := make([]interface{}, len(cols))
		for i := range columns {
			columnPointers[i] = &columns[i]
		}

		// If there aren't any rows, we return a nil result
		for rows.Next() {
			// Scan the result into the column pointers...
			if err := rows.Scan(columnPointers...); err != nil {
				rows.Close()
				serverStream.SendError(err)
				return
			}

			// Create our map, and retrieve the value for each column from the pointers slice,
			// storing it in the map with the name of the column as the key.
			data := make(record.Record)
			skipN := 0
			for i, colName := range cols {
				val := columnPointers[i].(*interface{})
				if colAddrs != nil {
					if colAddrs[i].skipN > 0 {
						// if we didn't find the key in the selector, then we skipN
						// this accounts for nil and false return types
						if *val != true {
							skipN = colAddrs[i].skipN
						} else {
							skipN = 0
						}
					} else {
						if skipN <= 0 {
							data.Set(colAddrs[i].key, *val)
						} else {
							skipN--
						}
					}
				} else {
					data[colName] = *val
				}
			}
			serverStream.SendResult(data)
		}

		if err := rows.Err(); err != nil {
			serverStream.SendError(err)
			return
		}
	}()

	return clientStream, nil
}

// Normalize field names. This takes a string such as "(data ->> 'created'::text)"
// and converts it to "data.created"
func normalizeFieldName(in string) string {
	if in[0] != '(' || in[len(in)-1] != ')' {
		return in
	}
	in = in[1 : len(in)-1]

	var output string

	for _, part := range strings.Split(in, " ") {
		if sepIdx := strings.Index(part, "'::"); sepIdx > -1 {
			part = part[1:sepIdx]
		}
		if part == "->>" {
			output += "."
		} else {
			output += part
		}
	}

	return output
}

// TODO: remove?
func serializeValue(v interface{}) (string, error) {
	switch vTyped := v.(type) {
	case time.Time:
		return fmt.Sprintf("'%v'", vTyped.Format(datamantype.DateTimeFormatStr)), nil
	case map[string]interface{}:
		b, err := json.Marshal(v)
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("'%s'", string(b)), nil
	default:
		return fmt.Sprintf("'%v'", v), nil
	}
}

// Take a path to an object and convert it to postgres json addressing
func collectionFieldToSelector(path []string) string {
	switch len(path) {
	case 1:
		return path[0]
	case 2:
		return path[0] + "->>'" + path[1] + "'"
	default:
		fieldChain := path[1:]
		return path[0] + "->'" + strings.Join(fieldChain[:len(fieldChain)-1], "'->'") + "'->>'" + path[len(path)-1] + "'"
	}
}

// TODO: remove? or consolidate?
// When we want to do existence checks ( top->'level'->'key' ? 'subkey' we can't use the
// ->> selector since it will return "text" (seemingly the actual value) whereas -> returns
// a map-like object with which we can do selection and ? checks on.
func collectionFieldParentToSelector(path []string) string {
	switch len(path) {
	case 1:
		return path[0]
	case 2:
		return path[0] + "->'" + path[1] + "'"
	default:
		fieldChain := path[1:]
		return path[0] + "->'" + strings.Join(fieldChain[:len(fieldChain)-1], "'->'") + "'->'" + path[len(path)-1] + "'"
	}
}

// ColAddr is a list of addresses of columns
type ColAddr struct {
	key []string
	// Number of columns this is a "selector" for. This is used for jsonb columns
	// so we can differentiate between nil meaning the value in the json is null
	// and the field not existing in the JSON
	// is this a `?` selector telling us whether or not to skip the next one
	skipN int
}

// selectFields returns a SELECT string and the corresponding ColAddr
func selectFields(fields []string) (string, []ColAddr) {
	// TODO: remove?
	// If no projection, then just return all
	if fields == nil {
		return "*", nil
	}

	fieldSelectors := make([]string, 0, len(fields))
	cAddrs := make([]ColAddr, 0, len(fields))
	for _, field := range fields {
		fieldParts := strings.Split(field, ".")
		if len(fieldParts) > 1 {
			cAddrs = append(cAddrs, ColAddr{skipN: 1})
			fieldSelectors = append(fieldSelectors, collectionFieldParentToSelector(fieldParts[:len(fieldParts)-1])+" ? '"+fieldParts[len(fieldParts)-1]+"'")
		}
		cAddrs = append(cAddrs, ColAddr{
			key: fieldParts,
		})
		fieldSelectors = append(fieldSelectors, collectionFieldToSelector(fieldParts))

	}

	return strings.Join(fieldSelectors, ","), cAddrs
}
<|endoftext|>


<commit_before>// These tests for the ghstatus package start an internal web server that
// returns fake responses. To talk to the real service, set the environment
// variable REALHTTP.
package ghstatus

import (
	"fmt"
	"net/http"
	"os"

	"github.com/stretchr/testify/assert"
	"net/http/httptest"
	"testing"
)

var testResponses = map[string]string{
	"GET /api/status.json":       `{"status":"good","last_updated":"2013-07-31T12:09:46Z"}`,
	"GET /api/last-message.json": `{"status":"good","body":"Everything operating normally.","created_on":"2013-07-29T22:23:19Z"}`,
	"GET /api/messages.json": `[
		{
			"body": "Everything operating normally.",
			"created_on": "2013-07-29T22:23:19Z",
			"status": "good"
		},
		{
			"body": "We are continuing to work on the increased exception rate on the GitHub API.",
			"created_on": "2013-07-29T21:09:54Z",
			"status": "minor"
		},
		{
			"body": "We've mitigated the DDoS attack and the site should responding normally.",
			"created_on": "2013-07-29T16:10:54Z",
			"status": "minor"
		},
		{
			"body": "We're currently experiencing a large DDoS attack.",
			"created_on": "2013-07-29T15:05:38Z",
			"status": "major"
		},
		{
			"body": "We're investigating a small increase in exceptions affecting the GitHub API.",
			"created_on": "2013-07-29T13:29:24Z",
			"status": "minor"
		}]`,
}

func serveTestResponses(w http.ResponseWriter, r *http.Request) {
	if body := testResponses[r.Method+" "+r.URL.Path]; body != "" {
		fmt.Fprint(w, body)
	} else {
		http.Error(w, "", http.StatusNotFound)
	}
}

func init() {
	if os.Getenv("REALHTTP") == "" {
		ts := httptest.NewServer(http.HandlerFunc(serveTestResponses))
		SetServiceURL(ts.URL)
	}
}

func checkStatus(s string) bool {
	switch s {
	case Good, Minor, Major:
		return true
	}
	return false
}

func TestGetStatus(t *testing.T) {
	status, err := GetStatus()
	if assert.NoError(t, err) {
		assert.True(t, checkStatus(status.Status))
		assert.False(t, status.LastUpdated.IsZero())
	}
}

func TestGetMessages(t *testing.T) {
	messages, err := GetMessages()
	if assert.NoError(t, err) {
		assert.NotEmpty(t, messages)
		for _, m := range messages {
			assert.True(t, checkStatus(m.Status))
			assert.NotEmpty(t, m.Body)
			assert.False(t, m.CreatedOn.IsZero())
		}
	}
}

func TestGetLastMessage(t *testing.T) {
	m, err := GetLastMessage()
	if assert.NoError(t, err) {
		assert.True(t, checkStatus(m.Status))
		assert.NotEmpty(t, m.Body)
		assert.False(t, m.CreatedOn.IsZero())
	}
}
<commit_msg>Read test data from disk<commit_after>// These tests for the ghstatus package start an internal web server that
// returns fake responses. To talk to the real service, set the environment
// variable REALHTTP.
package ghstatus

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/stretchr/testify/assert"
	"net/http/httptest"
	"testing"
)

func init() {
	if os.Getenv("REALHTTP") == "" {
		ts := httptest.NewServer(http.HandlerFunc(serveTestResponses))
		SetServiceURL(ts.URL)
	}
}

func serveTestResponses(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "method must be GET", http.StatusMethodNotAllowed)
		return
	}
	content, err := ioutil.ReadFile("testdata" + r.URL.Path)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	fmt.Fprint(w, string(content))
}

func checkStatus(s string) bool {
	switch s {
	case Good, Minor, Major:
		return true
	}
	return false
}

func TestGetStatus(t *testing.T) {
	status, err := GetStatus()
	if assert.NoError(t, err) {
		assert.True(t, checkStatus(status.Status))
		assert.False(t, status.LastUpdated.IsZero())
	}
}

func TestGetMessages(t *testing.T) {
	messages, err := GetMessages()
	if assert.NoError(t, err) {
		assert.NotEmpty(t, messages)
		for _, m := range messages {
			assert.True(t, checkStatus(m.Status))
			assert.NotEmpty(t, m.Body)
			assert.False(t, m.CreatedOn.IsZero())
		}
	}
}

func TestGetLastMessage(t *testing.T) {
	m, err := GetLastMessage()
	if assert.NoError(t, err) {
		assert.True(t, checkStatus(m.Status))
		assert.NotEmpty(t, m.Body)
		assert.False(t, m.CreatedOn.IsZero())
	}
}
<|endoftext|>


<commit_before>package ciutil

import (
	"fmt"
	"net"
	"net/http"
	"sync"

	"github.com/miekg/dns"
)

var (
	muTravisIPAddrs sync.RWMutex
	travisIPAddrs   = map[string]bool{}

	// https://www.appveyor.com/docs/build-environment/#ip-addresses
	appveyorIPAddrs = map[string]bool{
		"74.205.54.20":    true,
		"104.197.110.30":  true,
		"104.197.145.181": true,
		"146.148.85.29":   true,
		"67.225.139.254":  true,
		"67.225.138.82":   true,
		"67.225.139.144":  true,
		"138.91.141.243":  true,
	}
)

// IsFromCI returns true if given request is from tructed CI provider.
func IsFromCI(r *http.Request) bool {
	return IsFromTravisCI(r) || IsFromAppveyor(r)
}

// IsFromTravisCI returns true if given request is from Travis CI.
// https://docs.travis-ci.com/user/ip-addresses/
func IsFromTravisCI(r *http.Request) bool {
	muTravisIPAddrs.RLock()
	defer muTravisIPAddrs.RUnlock()
	return travisIPAddrs[ipFromReq(r)]
}

// https://docs.travis-ci.com/user/ip-addresses/
func UpdateTravisCIIPAddrs(cli *http.Client) error {
	ips, err := ipAddrs("nat.travisci.net", cli)
	if err != nil {
		return err
	}
	muTravisIPAddrs.Lock()
	defer muTravisIPAddrs.Unlock()
	travisIPAddrs = map[string]bool{}
	for _, ip := range ips {
		travisIPAddrs[ip.String()] = true
	}
	return nil
}

// IsFromAppveyor returns true if given request is from Appveyor.
// https://www.appveyor.com/docs/build-environment/#ip-addresses
func IsFromAppveyor(r *http.Request) bool {
	return appveyorIPAddrs[ipFromReq(r)]
}

func ipFromReq(r *http.Request) string {
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	return ip
}

func ipAddrs(target string, cli *http.Client) ([]net.IP, error) {
	server := "8.8.8.8"
	c := dns.Client{Net: "tcp"}
	if cli != nil {
		c.HTTPClient = cli
	}
	m := dns.Msg{}
	m.SetQuestion(target+".", dns.TypeA)
	r, _, err := c.Exchange(&m, server+":53")
	if err != nil {
		return nil, err
	}
	if len(r.Answer) == 0 {
		return nil, fmt.Errorf("No results for %s", target)
	}
	addrs := make([]net.IP, 0, len(r.Answer))
	for _, ans := range r.Answer {
		if aRecord, ok := ans.(*dns.A); ok {
			addrs = append(addrs, aRecord.A)
		}
	}
	return addrs, nil
}
<commit_msg>doghouse: use dnsjson.com instead of github.com/miekg/dns<commit_after>package ciutil

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"sync"
)

var (
	muTravisIPAddrs sync.RWMutex
	travisIPAddrs   = map[string]bool{}

	// https://www.appveyor.com/docs/build-environment/#ip-addresses
	appveyorIPAddrs = map[string]bool{
		"74.205.54.20":    true,
		"104.197.110.30":  true,
		"104.197.145.181": true,
		"146.148.85.29":   true,
		"67.225.139.254":  true,
		"67.225.138.82":   true,
		"67.225.139.144":  true,
		"138.91.141.243":  true,
	}
)

// IsFromCI returns true if given request is from tructed CI provider.
func IsFromCI(r *http.Request) bool {
	return IsFromTravisCI(r) || IsFromAppveyor(r)
}

// IsFromTravisCI returns true if given request is from Travis CI.
// https://docs.travis-ci.com/user/ip-addresses/
func IsFromTravisCI(r *http.Request) bool {
	muTravisIPAddrs.RLock()
	defer muTravisIPAddrs.RUnlock()
	return travisIPAddrs[ipFromReq(r)]
}

// https://docs.travis-ci.com/user/ip-addresses/
func UpdateTravisCIIPAddrs(cli *http.Client) error {
	ips, err := ipAddrs("nat.travisci.net", cli)
	if err != nil {
		return err
	}
	muTravisIPAddrs.Lock()
	defer muTravisIPAddrs.Unlock()
	travisIPAddrs = map[string]bool{}
	for _, ip := range ips {
		travisIPAddrs[ip] = true
	}
	return nil
}

// IsFromAppveyor returns true if given request is from Appveyor.
// https://www.appveyor.com/docs/build-environment/#ip-addresses
func IsFromAppveyor(r *http.Request) bool {
	return appveyorIPAddrs[ipFromReq(r)]
}

func ipFromReq(r *http.Request) string {
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	return ip
}

// Cannot use "github.com/miekg/dns" in Google App Engine.
// Use dnsjson.com instead as workaround.
func ipAddrs(target string, cli *http.Client) ([]string, error) {
	url := fmt.Sprintf("https://dnsjson.com/%s/A.json", target)
	c := http.DefaultClient
	if cli != nil {
		c = cli
	}
	r, err := c.Get(url)
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()

	var res struct {
		Results struct {
			Records []string `json:"records"`
		} `json:"results"`
	}

	if err := json.NewDecoder(r.Body).Decode(&res); err != nil {
		return nil, err
	}

	if len(res.Results.Records) == 0 {
		return nil, fmt.Errorf("failed to get IP addresses of %s", target)
	}

	return res.Results.Records, nil
}
<|endoftext|>