<commit_before>// +build darwin linux

package collectors

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

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/slog"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_hbase_region, init: hbrInit})
}

var (
	hbaseEnable bool
	hbaseLock   sync.Mutex
)

func hbaseEnabled() (b bool) {
	hbaseLock.Lock()
	b = hbaseEnable
	hbaseLock.Unlock()
	return
}

const hbrURL = "http://localhost:60030/jmx?qry=hadoop:service=RegionServer,name=RegionServerStatistics"

func hbrInit() {
	update := func() {
		resp, err := http.Get(hbrURL)
		hbaseLock.Lock()
		defer hbaseLock.Unlock()
		if err != nil {
			hbaseEnable = false
			return
		}
		resp.Body.Close()
		hbaseEnable = resp.StatusCode == 200
	}
	update()
	go func() {
		for _ = range time.Tick(time.Minute * 5) {
			update()
		}
	}()
}

func c_hbase_region() opentsdb.MultiDataPoint {
	if !hbaseEnabled() {
		return nil
	}
	var md opentsdb.MultiDataPoint
	res, err := http.Get(hbrURL)
	if err != nil {
		slog.Errorln(err)
		return nil
	}
	defer res.Body.Close()
	var r struct {
		Beans []map[string]interface{} `json:"beans"`
	}
	j := json.NewDecoder(res.Body)
	if err := j.Decode(&r); err != nil {
		slog.Errorln(err)
		return nil
	}
	if len(r.Beans) > 0 && len(r.Beans[0]) > 0 {
		for k, v := range r.Beans[0] {
			if _, ok := v.(float64); ok {
				Add(&md, "hbase.region."+k, v, nil, metadata.Unknown, metadata.None, "")
			}
		}
	}
	return md
}
<commit_msg>cmd/scollector: Merge pull request #35 from StackExchange/hbase_replication<commit_after>// +build darwin linux

package collectors

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

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/slog"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_hbase_region, init: hbrInit})
	collectors = append(collectors, &IntervalCollector{F: c_hbase_replication, init: hbrepInit})
}

type hEnabled struct {
	Enable bool
	sync.Mutex
}

var (
	hbrEnable   hEnabled
	hbrepEnable hEnabled
)

func (e hEnabled) Enabled() (b bool) {
	e.Lock()
	b = e.Enable
	e.Unlock()
	return
}

const hbrURL = "http://localhost:60030/jmx?qry=hadoop:service=RegionServer,name=RegionServerStatistics"
const hbrepURL = "http://localhost:60030/jmx?qry=hadoop:service=Replication,name=*"

func hTestUrl(url string, e *hEnabled) func() {
	update := func() {
		resp, err := http.Get(url)
		e.Lock()
		defer e.Unlock()
		if err != nil {
			e.Enable = false
			return
		}
		resp.Body.Close()
		e.Enable = resp.StatusCode == 200
	}
	return update
}

func hbrInit() {
	update := hTestUrl(hbrURL, &hbrEnable)
	update()
	go func() {
		for _ = range time.Tick(time.Minute * 5) {
			update()
		}
	}()
}

type jmx struct {
	Beans []map[string]interface{} `json:"beans"`
}

func getBeans(url string, jmx *jmx) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err := json.NewDecoder(res.Body).Decode(&jmx); err != nil {
		return err
	}
	return nil
}

func c_hbase_region() opentsdb.MultiDataPoint {
	if !hbrEnable.Enabled() {
		return nil
	}
	var jmx jmx
	if err := getBeans(hbrURL, &jmx); err != nil {
		slog.Errorln(err)
		return nil
	}
	var md opentsdb.MultiDataPoint
	if len(jmx.Beans) > 0 && len(jmx.Beans[0]) > 0 {
		for k, v := range jmx.Beans[0] {
			if _, ok := v.(float64); ok {
				Add(&md, "hbase.region."+k, v, nil, metadata.Unknown, metadata.None, "")
			}
		}
	}
	return md
}

func hbrepInit() {
	update := hTestUrl(hbrepURL, &hbrepEnable)
	update()
	go func() {
		for _ = range time.Tick(time.Minute * 5) {
			update()
		}
	}()
}

func c_hbase_replication() opentsdb.MultiDataPoint {
	if !hbrepEnable.Enabled() {
		return nil
	}
	var jmx jmx
	if err := getBeans(hbrepURL, &jmx); err != nil {
		slog.Errorln(err)
		return nil
	}
	var md opentsdb.MultiDataPoint
	for _, section := range jmx.Beans {
		var tags opentsdb.TagSet
		for k, v := range section {
			if s, ok := v.(string); ok && k == "name" {
				if strings.HasPrefix(s, "hadoop:service=Replication,name=ReplicationSource for") {
					sa := strings.Split(s, " ")
					if len(sa) == 3 {
						tags = opentsdb.TagSet{"instance": sa[2]}
						break
					}
				}
			}
		}
		for k, v := range section {
			if _, ok := v.(float64); ok {
				Add(&md, "hbase.region."+k, v, tags, metadata.Unknown, metadata.None, "")
			}
		}
	}
	return md
}
<|endoftext|>


<commit_before>package cliedit

import (
	"fmt"
	"os"

	"github.com/elves/elvish/cli"
	"github.com/elves/elvish/diag"
	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/eval/vals"
	"github.com/elves/elvish/eval/vars"
)

func initConfigAPI(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	initMaxHeight(appSpec, ns)
	initBeforeReadline(appSpec, ev, ns)
	initAfterReadline(appSpec, ev, ns)
}

func initMaxHeight(appSpec *cli.AppSpec, ns eval.Ns) {
	maxHeight := newIntVar(-1)
	appSpec.MaxHeight = func() int { return maxHeight.GetRaw().(int) }
	ns.Add("max-height", maxHeight)
}

func initBeforeReadline(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	hook := newListVar(vals.EmptyList)
	ns["before-readline"] = hook
	appSpec.BeforeReadline = func() {
		i := -1
		hook := hook.GetRaw().(vals.List)
		for it := hook.Iterator(); it.HasElem(); it.Next() {
			i++
			name := fmt.Sprintf("$before-readline[%d]", i)
			fn, ok := it.Elem().(eval.Callable)
			if !ok {
				// TODO(xiaq): This is not testable as it depends on stderr.
				// Make it testable.
				diag.Complainf("%s not function", name)
				continue
			}
			// TODO(xiaq): This should use stdPorts, but stdPorts is currently
			// unexported from eval.
			ports := []*eval.Port{
				{File: os.Stdin}, {File: os.Stdout}, {File: os.Stderr}}
			fm := eval.NewTopFrame(ev, eval.NewInternalSource(name), ports)
			fm.Call(fn, eval.NoArgs, eval.NoOpts)
		}
	}
}

func initAfterReadline(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	hook := newListVar(vals.EmptyList)
	ns["after-readline"] = hook
	appSpec.AfterReadline = func(code string) {
		i := -1
		hook := hook.GetRaw().(vals.List)
		for it := hook.Iterator(); it.HasElem(); it.Next() {
			i++
			name := fmt.Sprintf("$after-readline[%d]", i)
			fn, ok := it.Elem().(eval.Callable)
			if !ok {
				// TODO(xiaq): This is not testable as it depends on stderr.
				// Make it testable.
				diag.Complainf("%s not function", name)
				continue
			}
			// TODO(xiaq): This should use stdPorts, but stdPorts is currently
			// unexported from eval.
			ports := []*eval.Port{
				{File: os.Stdin}, {File: os.Stdout}, {File: os.Stderr}}
			fm := eval.NewTopFrame(ev, eval.NewInternalSource(name), ports)
			fm.Call(fn, []interface{}{code}, eval.NoOpts)
		}
	}
}

func newIntVar(i int) vars.PtrVar            { return vars.FromPtr(&i) }
func newBoolVar(b bool) vars.PtrVar          { return vars.FromPtr(&b) }
func newListVar(l vals.List) vars.PtrVar     { return vars.FromPtr(&l) }
func newBindingVar(b bindingMap) vars.PtrVar { return vars.FromPtr(&b) }
<commit_msg>cliedit: Factor out the common parts for $edit:{before,after}-readline.<commit_after>package cliedit

import (
	"fmt"
	"os"

	"github.com/elves/elvish/cli"
	"github.com/elves/elvish/diag"
	"github.com/elves/elvish/eval"
	"github.com/elves/elvish/eval/vals"
	"github.com/elves/elvish/eval/vars"
)

func initConfigAPI(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	initMaxHeight(appSpec, ns)
	initBeforeReadline(appSpec, ev, ns)
	initAfterReadline(appSpec, ev, ns)
}

func initMaxHeight(appSpec *cli.AppSpec, ns eval.Ns) {
	maxHeight := newIntVar(-1)
	appSpec.MaxHeight = func() int { return maxHeight.GetRaw().(int) }
	ns.Add("max-height", maxHeight)
}

func initBeforeReadline(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	hook := newListVar(vals.EmptyList)
	ns["before-readline"] = hook
	appSpec.BeforeReadline = func() {
		callHooks(ev, "$<edit>:before-readline", hook.Get().(vals.List))
	}
}

func initAfterReadline(appSpec *cli.AppSpec, ev *eval.Evaler, ns eval.Ns) {
	hook := newListVar(vals.EmptyList)
	ns["after-readline"] = hook
	appSpec.AfterReadline = func(code string) {
		callHooks(ev, "$<edit>:after-readline", hook.Get().(vals.List), code)
	}
}

func callHooks(ev *eval.Evaler, name string, hook vals.List, args ...interface{}) {
	i := -1
	for it := hook.Iterator(); it.HasElem(); it.Next() {
		i++
		name := fmt.Sprintf("%s[%d]", name, i)
		fn, ok := it.Elem().(eval.Callable)
		if !ok {
			// TODO(xiaq): This is not testable as it depends on stderr.
			// Make it testable.
			diag.Complainf("%s not function", name)
			continue
		}
		// TODO(xiaq): This should use stdPorts, but stdPorts is currently
		// unexported from eval.
		ports := []*eval.Port{
			{File: os.Stdin}, {File: os.Stdout}, {File: os.Stderr}}
		fm := eval.NewTopFrame(ev, eval.NewInternalSource(name), ports)
		fm.Call(fn, args, eval.NoOpts)
	}
}

func newIntVar(i int) vars.PtrVar            { return vars.FromPtr(&i) }
func newBoolVar(b bool) vars.PtrVar          { return vars.FromPtr(&b) }
func newListVar(l vals.List) vars.PtrVar     { return vars.FromPtr(&l) }
func newBindingVar(b bindingMap) vars.PtrVar { return vars.FromPtr(&b) }
<|endoftext|>


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

package render

import (
	"bytes"
	"fmt"
	htmlTemplate "html/template"
	"io"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// TODO: render HTML using golang/x/net/html or template.

var (
	doubleQuote = []byte{'"'}
	lessThan    = []byte{'<'}
	greaterThan = []byte{'>'}
	newLine     = []byte{'\n'}
)

// HTML renders nodes as the markup for the target env.
func HTML(ctx Context, nodes ...types.Node) (htmlTemplate.HTML, error) {
	var buf bytes.Buffer
	if err := WriteHTML(&buf, ctx.Env, ctx.Format, nodes...); err != nil {
		return "", err
	}
	return htmlTemplate.HTML(buf.String()), nil
}

// WriteHTML does the same as HTML but outputs rendered markup to w.
func WriteHTML(w io.Writer, env string, fmt string, nodes ...types.Node) error {
	hw := htmlWriter{w: w, env: env, format: fmt}
	return hw.write(nodes...)
}

// ReplaceDoubleCurlyBracketsWithEntity replaces Double Curly Brackets with their charater entity.
func ReplaceDoubleCurlyBracketsWithEntity(s string) string {
	return strings.Replace(s, "{{", "{{", -1)
}

type htmlWriter struct {
	w      io.Writer // output writer
	env    string    // target environment
	format string    // target template
	err    error     // error during any writeXxx methods
}

func (hw *htmlWriter) matchEnv(v []string) bool {
	if len(v) == 0 || hw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, hw.env)
	return i < len(v) && v[i] == hw.env
}

func (hw *htmlWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !hw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			hw.text(n)
		case *types.ImageNode:
			hw.image(n)
		case *types.URLNode:
			hw.url(n)
		case *types.ButtonNode:
			hw.button(n)
		case *types.CodeNode:
			hw.code(n)
			hw.writeBytes(newLine)
		case *types.ListNode:
			hw.list(n)
			hw.writeBytes(newLine)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			hw.list(n.Content)
			hw.writeBytes(newLine)
		case *types.ItemsListNode:
			hw.itemsList(n)
			hw.writeBytes(newLine)
		case *types.GridNode:
			hw.grid(n)
			hw.writeBytes(newLine)
		case *types.InfoboxNode:
			hw.infobox(n)
			hw.writeBytes(newLine)
		case *types.SurveyNode:
			hw.survey(n)
			hw.writeBytes(newLine)
		case *types.HeaderNode:
			hw.header(n)
			hw.writeBytes(newLine)
		case *types.YouTubeNode:
			hw.youtube(n)
			hw.writeBytes(newLine)
		case *types.IframeNode:
			hw.iframe(n)
			hw.writeBytes(newLine)
		}
		if hw.err != nil {
			return hw.err
		}
	}
	return nil
}

func (hw *htmlWriter) writeBytes(b []byte) {
	if hw.err != nil {
		return
	}
	_, hw.err = hw.w.Write(b)
}

func (hw *htmlWriter) writeString(s string) {
	hw.writeBytes([]byte(s))
}

func (hw *htmlWriter) writeFmt(f string, a ...interface{}) {
	hw.writeString(fmt.Sprintf(f, a...))
}

func (hw *htmlWriter) writeEscape(s string) {
	s = htmlTemplate.HTMLEscapeString(s)
	hw.writeString(ReplaceDoubleCurlyBracketsWithEntity(s))
}

func (hw *htmlWriter) text(n *types.TextNode) {
	if n.Bold {
		hw.writeString("")
	}
	if n.Italic {
		hw.writeString("")
	}
	if n.Code {
		hw.writeString("")
	}
	s := htmlTemplate.HTMLEscapeString(n.Value)
	s = ReplaceDoubleCurlyBracketsWithEntity(s)
	hw.writeString(strings.Replace(s, "\n", "
", -1))
	if n.Code {
		hw.writeString("")
	}
	if n.Italic {
		hw.writeString("")
	}
	if n.Bold {
		hw.writeString("")
	}
}

func (hw *htmlWriter) image(n *types.ImageNode) {
	hw.writeString(" 0 {
		hw.writeFmt(` style="width: %.2fpx"`, n.Width)
	}
	hw.writeString(` src="`)
	hw.writeString(n.Src)
	hw.writeBytes(doubleQuote)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) url(n *types.URLNode) {
	hw.writeString("<a")
	if n.URL != "" {
		hw.writeString(` href="`)
		hw.writeString(n.URL)
		hw.writeBytes(doubleQuote)
	}
	if n.Name != "" {
		hw.writeString(` name="`)
		hw.writeEscape(n.Name)
		hw.writeBytes(doubleQuote)
	}
	if n.Target != "" {
		hw.writeString(` target="`)
		hw.writeEscape(n.Target)
		hw.writeBytes(doubleQuote)
	}
	hw.writeBytes(greaterThan)
	hw.write(n.Content.Nodes...)
	hw.writeString("")
}

func (hw *htmlWriter) button(n *types.ButtonNode) {
	hw.writeString("<paper-button")
	if n.Colored {
		hw.writeString(` class="colored"`)
	}
	if n.Raised {
		hw.writeString(" raised")
	}
	hw.writeBytes(greaterThan)
	if n.Download {
		hw.writeString(`<iron-icon icon="file-download"></iron-icon>`)
	}
	hw.write(n.Content.Nodes...)
	hw.writeString("</paper-button>")
}

func (hw *htmlWriter) code(n *types.CodeNode) {
	hw.writeString("
")
	if !n.Term {
		hw.writeString("<code")
		if n.Lang != "" {
			hw.writeFmt(" language=%q class=%q", n.Lang, n.Lang)
		}
		hw.writeBytes(greaterThan)
	}
	if hw.format == "devsite" {
		hw.writeString("{% verbatim %}")
	}
	hw.writeEscape(n.Value)
	if hw.format == "devsite" {
		hw.writeString("{% endverbatim %}")
	}
	if !n.Term {
		hw.writeString("")
	}
	hw.writeString("
")
}

func (hw *htmlWriter) list(n *types.ListNode) {
	wrap := n.Block() == true
	if wrap {
		if onlyImages(n.Nodes...) {
			hw.writeString(`<p class="image-container">`)
		} else {
			hw.writeString("
")
		}
	}
	hw.write(n.Nodes...)
	if wrap {
		hw.writeString("
")
	}
}

// Returns true if the list of Nodes contains only images or white spaces.
func onlyImages(nodes ...types.Node) bool {
	for _, n := range nodes {
		switch n := n.(type) {
		case *types.TextNode:
			if len(strings.TrimSpace(n.Value)) == 0 {
				continue
			}
			return false
		case *types.ImageNode:
			continue
		default:
			return false
		}
	}
	return true
}

func (hw *htmlWriter) itemsList(n *types.ItemsListNode) {
	tag := "ul"
	if n.Type() == types.NodeItemsList && (n.Start > 0 || n.ListType != "") {
		tag = "ol"
	}
	hw.writeBytes(lessThan)
	hw.writeString(tag)
	switch n.Type() {
	case types.NodeItemsCheck:
		hw.writeString(` class="checklist"`)
	case types.NodeItemsFAQ:
		hw.writeString(` class="faq"`)
	default:
		if n.ListType != "" {
			hw.writeString(` type="`)
			hw.writeString(n.ListType)
			hw.writeBytes(doubleQuote)
		}
		if n.Start > 0 {
			hw.writeFmt(` start="%d"`, n.Start)
		}
	}
	hw.writeBytes(greaterThan)
	hw.writeBytes(newLine)

	for _, i := range n.Items {
		hw.writeString("
")
		hw.write(i.Nodes...)
		hw.writeString("
\n")
	}

	hw.writeString("</")
	hw.writeString(tag)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) grid(n *types.GridNode) {
	hw.writeString("
\n")
	for _, r := range n.Rows {
		hw.writeString("
")
		for _, c := range r {
			hw.writeFmt(`<td colspan="%d" rowspan="%d">`, c.Colspan, c.Rowspan)
			hw.write(c.Content.Nodes...)
			hw.writeString("	")
		}
		hw.writeString("
\n")
	}
	hw.writeString("
")
}

func (hw *htmlWriter) infobox(n *types.InfoboxNode) {
	hw.writeString(`<aside class="`)
	hw.writeEscape(string(n.Kind))
	hw.writeString(`">`)
	hw.write(n.Content.Nodes...)
	hw.writeString("")
}

func (hw *htmlWriter) survey(n *types.SurveyNode) {
	hw.writeString(`<google-codelab-survey survey-id="`)
	hw.writeString(n.ID)
	hw.writeBytes(doubleQuote)
	hw.writeString(">\n")
	for _, g := range n.Groups {
		hw.writeString("
")
		hw.writeEscape(g.Name)
		hw.writeString("
\n<paper-radio-group>\n")
		for _, o := range g.Options {
			hw.writeString("<paper-radio-button>")
			hw.writeEscape(o)
			hw.writeString("</paper-radio-button>\n")
		}
		hw.writeString("</paper-radio-group>\n")
	}
	hw.writeString("</google-codelab-survey>")
}

func (hw *htmlWriter) header(n *types.HeaderNode) {
	tag := "h" + strconv.Itoa(n.Level)
	hw.writeBytes(lessThan)
	hw.writeString(tag)
	switch n.Type() {
	case types.NodeHeaderCheck:
		hw.writeString(` class="checklist"`)
	case types.NodeHeaderFAQ:
		hw.writeString(` class="faq"`)

	}
	hw.writeString(` is-upgraded`)
	hw.writeBytes(greaterThan)
	hw.write(n.Content.Nodes...)
	hw.writeString("</")
	hw.writeString(tag)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) youtube(n *types.YouTubeNode) {
	hw.writeFmt(`<iframe class="youtube-video" `+
		`src="https://www.youtube.com/embed/%s?rel=0" allow="accelerometer; `+
		`autoplay; encrypted-media; gyroscope; picture-in-picture" `+
		`allowfullscreen></iframe>`, n.VideoID)
}

func (hw *htmlWriter) iframe(n *types.IframeNode) {
	hw.writeFmt(`<iframe class="embedded-iframe" src="%s"></iframe>`,
		n.URL)
}
<commit_msg>Skip HTML escaping inside inline  blocks.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package render

import (
	"bytes"
	"fmt"
	htmlTemplate "html/template"
	"io"
	"sort"
	"strconv"
	"strings"

	"github.com/googlecodelabs/tools/claat/types"
)

// TODO: render HTML using golang/x/net/html or template.

var (
	doubleQuote = []byte{'"'}
	lessThan    = []byte{'<'}
	greaterThan = []byte{'>'}
	newLine     = []byte{'\n'}
)

// HTML renders nodes as the markup for the target env.
func HTML(ctx Context, nodes ...types.Node) (htmlTemplate.HTML, error) {
	var buf bytes.Buffer
	if err := WriteHTML(&buf, ctx.Env, ctx.Format, nodes...); err != nil {
		return "", err
	}
	return htmlTemplate.HTML(buf.String()), nil
}

// WriteHTML does the same as HTML but outputs rendered markup to w.
func WriteHTML(w io.Writer, env string, fmt string, nodes ...types.Node) error {
	hw := htmlWriter{w: w, env: env, format: fmt}
	return hw.write(nodes...)
}

// ReplaceDoubleCurlyBracketsWithEntity replaces Double Curly Brackets with their charater entity.
func ReplaceDoubleCurlyBracketsWithEntity(s string) string {
	return strings.Replace(s, "{{", "{{", -1)
}

type htmlWriter struct {
	w      io.Writer // output writer
	env    string    // target environment
	format string    // target template
	err    error     // error during any writeXxx methods
}

func (hw *htmlWriter) matchEnv(v []string) bool {
	if len(v) == 0 || hw.env == "" {
		return true
	}
	i := sort.SearchStrings(v, hw.env)
	return i < len(v) && v[i] == hw.env
}

func (hw *htmlWriter) write(nodes ...types.Node) error {
	for _, n := range nodes {
		if !hw.matchEnv(n.Env()) {
			continue
		}
		switch n := n.(type) {
		case *types.TextNode:
			hw.text(n)
		case *types.ImageNode:
			hw.image(n)
		case *types.URLNode:
			hw.url(n)
		case *types.ButtonNode:
			hw.button(n)
		case *types.CodeNode:
			hw.code(n)
			hw.writeBytes(newLine)
		case *types.ListNode:
			hw.list(n)
			hw.writeBytes(newLine)
		case *types.ImportNode:
			if len(n.Content.Nodes) == 0 {
				break
			}
			hw.list(n.Content)
			hw.writeBytes(newLine)
		case *types.ItemsListNode:
			hw.itemsList(n)
			hw.writeBytes(newLine)
		case *types.GridNode:
			hw.grid(n)
			hw.writeBytes(newLine)
		case *types.InfoboxNode:
			hw.infobox(n)
			hw.writeBytes(newLine)
		case *types.SurveyNode:
			hw.survey(n)
			hw.writeBytes(newLine)
		case *types.HeaderNode:
			hw.header(n)
			hw.writeBytes(newLine)
		case *types.YouTubeNode:
			hw.youtube(n)
			hw.writeBytes(newLine)
		case *types.IframeNode:
			hw.iframe(n)
			hw.writeBytes(newLine)
		}
		if hw.err != nil {
			return hw.err
		}
	}
	return nil
}

func (hw *htmlWriter) writeBytes(b []byte) {
	if hw.err != nil {
		return
	}
	_, hw.err = hw.w.Write(b)
}

func (hw *htmlWriter) writeString(s string) {
	hw.writeBytes([]byte(s))
}

func (hw *htmlWriter) writeFmt(f string, a ...interface{}) {
	hw.writeString(fmt.Sprintf(f, a...))
}

func (hw *htmlWriter) writeEscape(s string) {
	s = htmlTemplate.HTMLEscapeString(s)
	hw.writeString(ReplaceDoubleCurlyBracketsWithEntity(s))
}

func (hw *htmlWriter) text(n *types.TextNode) {
	s := n.Value
	shouldEsc := true
	if n.Bold {
		hw.writeString("")
	}
	if n.Italic {
		hw.writeString("")
	}
	if n.Code {
		hw.writeString("")
		shouldEsc = false
	}
	if shouldEsc {
		s = htmlTemplate.HTMLEscapeString(n.Value)
	}
	s = ReplaceDoubleCurlyBracketsWithEntity(s)
	hw.writeString(strings.Replace(s, "\n", "
", -1))
	if n.Code {
		hw.writeString("")
	}
	if n.Italic {
		hw.writeString("")
	}
	if n.Bold {
		hw.writeString("")
	}
}

func (hw *htmlWriter) image(n *types.ImageNode) {
	hw.writeString(" 0 {
		hw.writeFmt(` style="width: %.2fpx"`, n.Width)
	}
	hw.writeString(` src="`)
	hw.writeString(n.Src)
	hw.writeBytes(doubleQuote)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) url(n *types.URLNode) {
	hw.writeString("<a")
	if n.URL != "" {
		hw.writeString(` href="`)
		hw.writeString(n.URL)
		hw.writeBytes(doubleQuote)
	}
	if n.Name != "" {
		hw.writeString(` name="`)
		hw.writeEscape(n.Name)
		hw.writeBytes(doubleQuote)
	}
	if n.Target != "" {
		hw.writeString(` target="`)
		hw.writeEscape(n.Target)
		hw.writeBytes(doubleQuote)
	}
	hw.writeBytes(greaterThan)
	hw.write(n.Content.Nodes...)
	hw.writeString("")
}

func (hw *htmlWriter) button(n *types.ButtonNode) {
	hw.writeString("<paper-button")
	if n.Colored {
		hw.writeString(` class="colored"`)
	}
	if n.Raised {
		hw.writeString(" raised")
	}
	hw.writeBytes(greaterThan)
	if n.Download {
		hw.writeString(`<iron-icon icon="file-download"></iron-icon>`)
	}
	hw.write(n.Content.Nodes...)
	hw.writeString("</paper-button>")
}

func (hw *htmlWriter) code(n *types.CodeNode) {
	hw.writeString("
")
	if !n.Term {
		hw.writeString("<code")
		if n.Lang != "" {
			hw.writeFmt(" language=%q class=%q", n.Lang, n.Lang)
		}
		hw.writeBytes(greaterThan)
	}
	if hw.format == "devsite" {
		hw.writeString("{% verbatim %}")
	}
	hw.writeEscape(n.Value)
	if hw.format == "devsite" {
		hw.writeString("{% endverbatim %}")
	}
	if !n.Term {
		hw.writeString("")
	}
	hw.writeString("
")
}

func (hw *htmlWriter) list(n *types.ListNode) {
	wrap := n.Block() == true
	if wrap {
		if onlyImages(n.Nodes...) {
			hw.writeString(`<p class="image-container">`)
		} else {
			hw.writeString("
")
		}
	}
	hw.write(n.Nodes...)
	if wrap {
		hw.writeString("
")
	}
}

// Returns true if the list of Nodes contains only images or white spaces.
func onlyImages(nodes ...types.Node) bool {
	for _, n := range nodes {
		switch n := n.(type) {
		case *types.TextNode:
			if len(strings.TrimSpace(n.Value)) == 0 {
				continue
			}
			return false
		case *types.ImageNode:
			continue
		default:
			return false
		}
	}
	return true
}

func (hw *htmlWriter) itemsList(n *types.ItemsListNode) {
	tag := "ul"
	if n.Type() == types.NodeItemsList && (n.Start > 0 || n.ListType != "") {
		tag = "ol"
	}
	hw.writeBytes(lessThan)
	hw.writeString(tag)
	switch n.Type() {
	case types.NodeItemsCheck:
		hw.writeString(` class="checklist"`)
	case types.NodeItemsFAQ:
		hw.writeString(` class="faq"`)
	default:
		if n.ListType != "" {
			hw.writeString(` type="`)
			hw.writeString(n.ListType)
			hw.writeBytes(doubleQuote)
		}
		if n.Start > 0 {
			hw.writeFmt(` start="%d"`, n.Start)
		}
	}
	hw.writeBytes(greaterThan)
	hw.writeBytes(newLine)

	for _, i := range n.Items {
		hw.writeString("
")
		hw.write(i.Nodes...)
		hw.writeString("
\n")
	}

	hw.writeString("</")
	hw.writeString(tag)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) grid(n *types.GridNode) {
	hw.writeString("
\n")
	for _, r := range n.Rows {
		hw.writeString("
")
		for _, c := range r {
			hw.writeFmt(`<td colspan="%d" rowspan="%d">`, c.Colspan, c.Rowspan)
			hw.write(c.Content.Nodes...)
			hw.writeString("	")
		}
		hw.writeString("
\n")
	}
	hw.writeString("
")
}

func (hw *htmlWriter) infobox(n *types.InfoboxNode) {
	hw.writeString(`<aside class="`)
	hw.writeEscape(string(n.Kind))
	hw.writeString(`">`)
	hw.write(n.Content.Nodes...)
	hw.writeString("")
}

func (hw *htmlWriter) survey(n *types.SurveyNode) {
	hw.writeString(`<google-codelab-survey survey-id="`)
	hw.writeString(n.ID)
	hw.writeBytes(doubleQuote)
	hw.writeString(">\n")
	for _, g := range n.Groups {
		hw.writeString("
")
		hw.writeEscape(g.Name)
		hw.writeString("
\n<paper-radio-group>\n")
		for _, o := range g.Options {
			hw.writeString("<paper-radio-button>")
			hw.writeEscape(o)
			hw.writeString("</paper-radio-button>\n")
		}
		hw.writeString("</paper-radio-group>\n")
	}
	hw.writeString("</google-codelab-survey>")
}

func (hw *htmlWriter) header(n *types.HeaderNode) {
	tag := "h" + strconv.Itoa(n.Level)
	hw.writeBytes(lessThan)
	hw.writeString(tag)
	switch n.Type() {
	case types.NodeHeaderCheck:
		hw.writeString(` class="checklist"`)
	case types.NodeHeaderFAQ:
		hw.writeString(` class="faq"`)

	}
	hw.writeString(` is-upgraded`)
	hw.writeBytes(greaterThan)
	hw.write(n.Content.Nodes...)
	hw.writeString("</")
	hw.writeString(tag)
	hw.writeBytes(greaterThan)
}

func (hw *htmlWriter) youtube(n *types.YouTubeNode) {
	hw.writeFmt(`<iframe class="youtube-video" `+
		`src="https://www.youtube.com/embed/%s?rel=0" allow="accelerometer; `+
		`autoplay; encrypted-media; gyroscope; picture-in-picture" `+
		`allowfullscreen></iframe>`, n.VideoID)
}

func (hw *htmlWriter) iframe(n *types.IframeNode) {
	hw.writeFmt(`<iframe class="embedded-iframe" src="%s"></iframe>`,
		n.URL)
}
<|endoftext|>


<commit_before>package veneur

import (
	"context"
	"math/rand"
	"net"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/proto"
	"github.com/stripe/veneur/ssf"
)

const traceKey = "trace"

type Trace struct {
	// the ID for the root span
	// which is also the ID for the trace itself
	TraceId int64

	// For the root span, this will be equal
	// to the TraceId
	SpanId int64

	// For the root span, this will be <= 0
	ParentId int64

	// The Resource should be the same for all spans in the same trace
	Resource string

	Start time.Time
}

func (t *Trace) Record(name string, tags []*ssf.SSFTag) {
	recordTrace(t.Start, name, tags, t.SpanId, t.TraceId, t.ParentId, t.Resource)
}

// Attach attaches the current trace to the context
// and returns a copy of the context with that trace
// stored under the key "trace".
func (t *Trace) Attach(c context.Context) context.Context {
	return context.WithValue(c, traceKey, t)
}

// SpanFromContext is used to create a child span
// when the parent trace is in the context
func SpanFromContext(c context.Context) *Trace {
	parent, ok := c.Value(traceKey).(*Trace)
	if !ok {
		// do something here
	}

	spanId := proto.Int64(rand.Int63())
	span := &Trace{
		TraceId:  parent.TraceId,
		SpanId:   *spanId,
		ParentId: parent.SpanId,
		Resource: parent.Resource,
		Start:    time.Now(),
	}

	return span
}

// StartTrace is called by to create the root-level span
// for a trace
func StartTrace(resource string) *Trace {
	traceId := proto.Int64(rand.Int63())

	t := &Trace{
		TraceId:  *traceId,
		SpanId:   *traceId,
		ParentId: 0,
		Resource: resource,
	}

	t.Start = time.Now()
	return t
}

func sendSample(sample *ssf.SSFSample) error {
	server_addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8128")
	if err != nil {
		return err
	}

	conn, err := net.DialUDP("udp", nil, server_addr)
	if err != nil {
		return err
	}

	defer conn.Close()

	data, err := proto.Marshal(sample)
	if err != nil {
		return err
	}

	_, err = conn.Write(data)
	if err != nil {
		return err
	}

	return nil
}

// recordTrace sends a trace to DataDog.
// If the spanId is negative, it will be regenerated.
// If this is the root trace, parentId should be zero.
// resource will be ignored for non-root spans.
func recordTrace(startTime time.Time, name string, tags []*ssf.SSFTag, spanId, traceId, parentId int64, resource string) {
	if spanId < 0 {
		spanId = *proto.Int64(rand.Int63())
	}
	duration := time.Now().Sub(startTime).Nanoseconds()

	sample := &ssf.SSFSample{
		Metric:    ssf.SSFSample_TRACE,
		Timestamp: startTime.UnixNano(),
		Status:    ssf.SSFSample_OK,
		Name:      *proto.String(name),
		Trace: &ssf.SSFTrace{
			TraceId:  traceId,
			Id:       spanId,
			ParentId: parentId,
		},
		Value:      duration,
		SampleRate: *proto.Float32(.10),
		Tags:       []*ssf.SSFTag{},
		Resource:   resource,
		Service:    "veneur",
	}

	err := sendSample(sample)
	if err != nil {
		log.WithError(err).Error("Error submitting sample")
	}
	log.WithFields(logrus.Fields{
		"parent":   parentId,
		"spanId":   spanId,
		"name":     name,
		"resource": resource,
		"traceId":  traceId,
	}).Debug("Recorded trace")
}
<commit_msg>Seed rand with current time<commit_after>package veneur

import (
	"context"
	"math/rand"
	"net"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/golang/protobuf/proto"
	"github.com/stripe/veneur/ssf"
)

func init() {
	rand.Seed(time.Now().Unix())
}

const traceKey = "trace"

type Trace struct {
	// the ID for the root span
	// which is also the ID for the trace itself
	TraceId int64

	// For the root span, this will be equal
	// to the TraceId
	SpanId int64

	// For the root span, this will be <= 0
	ParentId int64

	// The Resource should be the same for all spans in the same trace
	Resource string

	Start time.Time
}

func (t *Trace) Record(name string, tags []*ssf.SSFTag) {
	recordTrace(t.Start, name, tags, t.SpanId, t.TraceId, t.ParentId, t.Resource)
}

// Attach attaches the current trace to the context
// and returns a copy of the context with that trace
// stored under the key "trace".
func (t *Trace) Attach(c context.Context) context.Context {
	return context.WithValue(c, traceKey, t)
}

// SpanFromContext is used to create a child span
// when the parent trace is in the context
func SpanFromContext(c context.Context) *Trace {
	parent, ok := c.Value(traceKey).(*Trace)
	if !ok {
		// do something here
	}

	spanId := proto.Int64(rand.Int63())
	span := &Trace{
		TraceId:  parent.TraceId,
		SpanId:   *spanId,
		ParentId: parent.SpanId,
		Resource: parent.Resource,
		Start:    time.Now(),
	}

	return span
}

// StartTrace is called by to create the root-level span
// for a trace
func StartTrace(resource string) *Trace {
	traceId := proto.Int64(rand.Int63())

	t := &Trace{
		TraceId:  *traceId,
		SpanId:   *traceId,
		ParentId: 0,
		Resource: resource,
	}

	t.Start = time.Now()
	return t
}

func sendSample(sample *ssf.SSFSample) error {
	server_addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8128")
	if err != nil {
		return err
	}

	conn, err := net.DialUDP("udp", nil, server_addr)
	if err != nil {
		return err
	}

	defer conn.Close()

	data, err := proto.Marshal(sample)
	if err != nil {
		return err
	}

	_, err = conn.Write(data)
	if err != nil {
		return err
	}

	return nil
}

// recordTrace sends a trace to DataDog.
// If the spanId is negative, it will be regenerated.
// If this is the root trace, parentId should be zero.
// resource will be ignored for non-root spans.
func recordTrace(startTime time.Time, name string, tags []*ssf.SSFTag, spanId, traceId, parentId int64, resource string) {
	if spanId < 0 {
		spanId = *proto.Int64(rand.Int63())
	}
	duration := time.Now().Sub(startTime).Nanoseconds()

	sample := &ssf.SSFSample{
		Metric:    ssf.SSFSample_TRACE,
		Timestamp: startTime.UnixNano(),
		Status:    ssf.SSFSample_OK,
		Name:      *proto.String(name),
		Trace: &ssf.SSFTrace{
			TraceId:  traceId,
			Id:       spanId,
			ParentId: parentId,
		},
		Value:      duration,
		SampleRate: *proto.Float32(.10),
		Tags:       []*ssf.SSFTag{},
		Resource:   resource,
		Service:    "veneur",
	}

	err := sendSample(sample)
	if err != nil {
		log.WithError(err).Error("Error submitting sample")
	}
	log.WithFields(logrus.Fields{
		"parent":   parentId,
		"spanId":   spanId,
		"name":     name,
		"resource": resource,
		"traceId":  traceId,
	}).Debug("Recorded trace")
}
<|endoftext|>


<commit_before>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"errors"
	"net/http"
	"time"
)

var client Client

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	id     []byte
	labels map[string][]byte
}

// ID returns the backend-specific global identifier of the span.
func (s *Span) ID() []byte {
	return s.id
}

// SetLabel allows you to set a label on the current span. Labels are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) SetLabel(key string, val []byte) {
	s.labels[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string) (*Span, FinishFunc) {
	child := &Span{
		id:     client.NewSpan(s.id, nil),
		labels: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.id, name, child.labels, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	hc, ok := client.(HTTPCarrier)
	if ok {
		return req, errors.New("not supported")
	}
	err := hc.ToHTTPReq(req, s.id)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func (s *Span) Causal(name string) (*Span, FinishFunc) {
	panic("not yet")
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(HTTPCarrier)
	if ok {
		return nil, errors.New("not supported")
	}
	id, err := hc.FromHTTPReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{id: id}, nil
}

// HTTPCarrier represents a mechanism that can attach the tracing
// information into an HTTP request or extract it from one.
type HTTPCarrier interface {
	FromHTTPReq(req *http.Request) (id []byte, err error)
	ToHTTPReq(req *http.Request, id []byte) error
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPCarrier if it can propagate the tracing
// information via an HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte, causal []byte) (id []byte)
	Finish(id []byte, name string, labels map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string) (*Span, FinishFunc) {
	span := &Span{
		id:     client.NewSpan(nil, nil),
		labels: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.id, name, span.labels, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

// FinishFunc finalizes the span from the current context.
// Each span context created by ChildSpan should be finished when their work is finished.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}
<commit_msg>s/SetLabel/Annotate<commit_after>// Package trace defines common-use Dapper-style tracing APIs for the Go programming language.
//
// Package trace provides a backend-agnostic APIs and various tracing providers
// can be used with the package by importing various implementations of the Client interface.
package trace

import (
	"context"
	"errors"
	"net/http"
	"time"
)

var client Client

// TODO(jbd): A big TODO, we probably don't want to set a global client.
func Configure(c Client) {
	client = c
}

// Span represents a work.
type Span struct {
	id     []byte
	labels map[string][]byte
}

// ID returns the backend-specific global identifier of the span.
func (s *Span) ID() []byte {
	return s.id
}

// Annotate allows you to attach data to a span. Key-value pairs are
// arbitary information you want to collect in the lifetime of a span.
func (s *Span) Annotate(key string, val []byte) {
	s.labels[key] = val
}

// Child creates a child span from s with the given name.
// Created child span needs to be finished by calling
// the finishing function.
func (s *Span) Child(name string) (*Span, FinishFunc) {
	child := &Span{
		id:     client.NewSpan(s.id, nil),
		labels: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(child.id, name, child.labels, start, time.Now())
	}
	return child, fn
}

// ToHTTPReq injects the span information in the given request
// and returns the modified request.
//
// If the current client is not supporting HTTP propagation,
// an error is returned.
func (s *Span) ToHTTPReq(req *http.Request) (*http.Request, error) {
	hc, ok := client.(HTTPCarrier)
	if ok {
		return req, errors.New("not supported")
	}
	err := hc.ToHTTPReq(req, s.id)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func (s *Span) Causal(name string) (*Span, FinishFunc) {
	panic("not yet")
}

// FromHTTPReq creates a *Span from an incoming request.
//
// An error will be returned if the current tracing client is
// not supporting propagation via HTTP.
func FromHTTPReq(req *http.Request) (*Span, error) {
	hc, ok := client.(HTTPCarrier)
	if ok {
		return nil, errors.New("not supported")
	}
	id, err := hc.FromHTTPReq(req)
	if err != nil {
		return nil, err
	}
	return &Span{id: id}, nil
}

// HTTPCarrier represents a mechanism that can attach the tracing
// information into an HTTP request or extract it from one.
type HTTPCarrier interface {
	FromHTTPReq(req *http.Request) (id []byte, err error)
	ToHTTPReq(req *http.Request, id []byte) error
}

// Client represents a client communicates with a tracing backend.
// Tracing backends are supposed to implement the interface in order to
// provide Go support.
//
// A Client is an HTTPCarrier if it can propagate the tracing
// information via an HTTP request.
//
// If you are not a tracing provider, you will never have to interact with
// this interface directly.
type Client interface {
	NewSpan(parent []byte, causal []byte) (id []byte)
	Finish(id []byte, name string, labels map[string][]byte, start, end time.Time) error
}

// NewSpan creates a new root-level span.
//
// The span must be finished when the job it represents it is finished.
func NewSpan(name string) (*Span, FinishFunc) {
	span := &Span{
		id:     client.NewSpan(nil, nil),
		labels: make(map[string][]byte),
	}
	start := time.Now()
	fn := func() error {
		return client.Finish(span.id, name, span.labels, start, time.Now())
	}
	return span, fn
}

// NewContext returns a context with the span in.
func NewContext(ctx context.Context, span *Span) context.Context {
	return context.WithValue(ctx, spanKey, span)
}

// FromContext returns a span from the given context.
func FromContext(ctx context.Context) *Span {
	return ctx.Value(spanKey).(*Span)
}

// FinishFunc finalizes the span from the current context.
// Each span context created by ChildSpan should be finished when their work is finished.
type FinishFunc func() error

type contextKey struct{}

var spanKey = contextKey{}
<|endoftext|>


<commit_before>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

var debug bool

func EnableDebug() {
	debug = true
}

// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error, args ...interface{}) Error {
	t := newTrace(runtime.Caller(1))
	t.error = err
	if len(args) != 0 {
		t.Message = fmt.Sprintf(fmt.Sprintf("%v", args[0]), args[1:]...)
	}
	return t
}

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	t := newTrace(runtime.Caller(1))
	t.error = fmt.Errorf(format, args...)
	return t
}

// Fatalf. If debug is false Fatalf calls Errorf. If debug is
// true Fatalf calls panic
func Fatalf(format string, args ...interface{}) error {
	if debug {
		panic(fmt.Sprintf(format, args))
	} else {
		return Errorf(format, args)
	}
}

func newTrace(pc uintptr, filePath string, line int, ok bool) *TraceErr {
	if !ok {
		return &TraceErr{
			File: "unknown_file",
			Path: "unknown_path",
			Func: "unknown_func",
			Line: 0,
		}
	}
	return &TraceErr{
		File: filepath.Base(filePath),
		Path: filePath,
		Func: runtime.FuncForPC(pc).Name(),
		Line: line,
	}
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	error
	Message string
	File    string
	Path    string
	Func    string
	Line    int
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v %v", e.File, e.Line, e.Message, e.error)
}

func (e *TraceErr) OrigError() error {
	return e.error
}

// Error is an interface that helps to adapt usage of trace in the code
// When applications define new error types, they can implement the interface
// So error handlers can use OrigError() to retrieve error from the wrapper
type Error interface {
	error
	OrigError() error
}
<commit_msg>add support for better integration with errors<commit_after>package trace

import (
	"fmt"
	"path/filepath"
	"runtime"
)

var debug bool

func EnableDebug() {
	debug = true
}

// Wrap takes the original error and wraps it into the Trace struct
// memorizing the context of the error.
func Wrap(err error, args ...interface{}) Error {
	t := newTrace(runtime.Caller(1))
	if s, ok := err.(TraceSetter); ok {
		s.SetTrace(t.Trace)
		return s
	}
	t.error = err
	if len(args) != 0 {
		t.Message = fmt.Sprintf(fmt.Sprintf("%v", args[0]), args[1:]...)
	}
	return t
}

// Errorf is similar to fmt.Errorf except that it captures
// more information about the origin of error, such as
// callee, line number and function that simplifies debugging
func Errorf(format string, args ...interface{}) error {
	t := newTrace(runtime.Caller(1))
	t.error = fmt.Errorf(format, args...)
	return t
}

// Fatalf. If debug is false Fatalf calls Errorf. If debug is
// true Fatalf calls panic
func Fatalf(format string, args ...interface{}) error {
	if debug {
		panic(fmt.Sprintf(format, args))
	} else {
		return Errorf(format, args)
	}
}

func newTrace(pc uintptr, filePath string, line int, ok bool) *TraceErr {
	if !ok {
		return &TraceErr{
			nil,
			Trace{
				File: "unknown_file",
				Path: "unknown_path",
				Func: "unknown_func",
				Line: 0,
			},
			"",
		}
	}
	return &TraceErr{
		nil,
		Trace{
			File: filepath.Base(filePath),
			Path: filePath,
			Func: runtime.FuncForPC(pc).Name(),
			Line: line,
		},
		"",
	}
}

type Trace struct {
	File string
	Path string
	Func string
	Line int
}

// TraceErr contains error message and some additional
// information about the error origin
type TraceErr struct {
	error
	Trace
	Message string
}

func (e *TraceErr) Error() string {
	return fmt.Sprintf("[%v:%v] %v %v", e.File, e.Line, e.Message, e.error)
}

func (e *TraceErr) OrigError() error {
	return e.error
}

// Error is an interface that helps to adapt usage of trace in the code
// When applications define new error types, they can implement the interface
// So error handlers can use OrigError() to retrieve error from the wrapper
type Error interface {
	error
	OrigError() error
}

type TraceSetter interface {
	Error
	SetTrace(Trace)
}
<|endoftext|>


<commit_before>package emoteservice

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
	"github.com/gempir/gempbot/internal/log"
	"github.com/gempir/gempbot/internal/store"
	"github.com/gempir/gempbot/internal/utils"
)

const DefaultSevenTvApiBaseUrl = "https://api.7tv.app/v2"
const DefaultSevenTvGqlBaseUrl = "https://api.7tv.app/v2/gql"

type SevenTvClient struct {
	store      store.Store
	apiBaseUrl string
	gqlBaseUrl string
}

func NewSevenTvClient(store store.Store) *SevenTvClient {
	return &SevenTvClient{
		store:      store,
		apiBaseUrl: DefaultSevenTvApiBaseUrl,
		gqlBaseUrl: DefaultSevenTvGqlBaseUrl,
	}
}

func (c *SevenTvClient) GetEmote(emoteID string) (Emote, error) {
	var emoteData sevenTvEmote

	err := requests.URL(c.apiBaseUrl + "/emotes/" + emoteID).
		ToJSON(&emoteData).
		Fetch(context.Background())

	if utils.BitField.HasBits(int64(emoteData.Visibility), int64(EmoteVisibilityPrivate)) ||
		utils.BitField.HasBits(int64(emoteData.Visibility), int64(EmoteVisibilityUnlisted)) {

		return Emote{}, fmt.Errorf("emote %s has incorrect visibility", emoteData.Name)
	}

	return Emote{Code: emoteData.Name, ID: emoteData.ID}, err
}

func (c *SevenTvClient) RemoveEmote(channelUserID, emoteID string) error {
	user, err := c.GetUser(channelUserID)
	if err != nil {
		return err
	}

	var empty struct{}
	err = c.QuerySevenTvGQL(
		`mutation RemoveChannelEmote($ch: String!, $em: String!, $re: String!) {removeChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`,
		map[string]interface{}{
			"ch": user.ID,
			"re": "blocked emote",
			"em": emoteID,
		}, &empty,
	)

	return err
}

func (c *SevenTvClient) AddEmote(channelUserID string, emoteID string) error {
	user, err := c.GetUser(channelUserID)
	if err != nil {
		return err
	}

	var empty struct{}
	err = c.QuerySevenTvGQL(
		`mutation AddChannelEmote($ch: String!, $em: String!, $re: String!) {addChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`,
		map[string]interface{}{
			"ch": user.ID,
			"re": "bot.gempir.com redemption",
			"em": emoteID,
		}, &empty,
	)

	return err
}

func (c *SevenTvClient) GetUser(channelID string) (User, error) {
	var userData SevenTvUserResponse
	err := c.QuerySevenTvGQL(`
	query GetUser($id: String!) {
		user(id: $id) {
		  ...FullUser
		}
	  }

	fragment FullUser on User {
		id
		emotes {
			id
			name
			status
			visibility
			width
			height
		}
		emote_slots
	}
	`, map[string]interface{}{"id": channelID}, &userData)
	if err != nil {
		return User{}, err
	}

	var emotes []Emote
	for _, emote := range userData.Data.User.Emotes {
		emotes = append(emotes, Emote{ID: emote.ID, Code: emote.Name})
	}

	return User{ID: userData.Data.User.ID, Emotes: emotes, EmoteSlots: userData.Data.User.EmoteSlots}, nil
}

func (c *SevenTvClient) QuerySevenTvGQL(query string, variables map[string]interface{}, response interface{}) error {
	gqlQuery := gqlQuery{Query: query, Variables: variables}

	err := requests.
		URL(c.gqlBaseUrl).
		BodyJSON(gqlQuery).
		Bearer(c.store.GetSevenTvToken(context.Background())).
		ToJSON(&response).
		Fetch(context.Background())
	if err != nil {
		log.Infof("7tv query '%s' with '%v' resp: '%v'", query, variables, response)
		return err
	}

	log.Infof("7tv query '%s' with '%v' resp: '%v'", query, variables, response)

	return nil
}

const SEVEN_TV_ADD_EMOTE_QUERY = `mutation AddChannelEmote($ch: String!, $em: String!, $re: String!) {addChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`
<commit_msg>setup some value functions for seventv emote sets<commit_after>package emoteservice

import (
	"context"
	"fmt"

	"github.com/carlmjohnson/requests"
	"github.com/gempir/gempbot/internal/log"
	"github.com/gempir/gempbot/internal/store"
	"github.com/gempir/gempbot/internal/utils"
)

const DefaultSevenTvApiBaseUrl = "https://api.7tv.app/v2"
const DefaultSevenTvV3ApiBaseUrl = "https://7tv.io/v3"
const DefaultSevenTvGqlBaseUrl = "https://api.7tv.app/v2/gql"

type SevenTvClient struct {
	store      store.Store
	apiBaseUrl string
	gqlBaseUrl string
}

func NewSevenTvClient(store store.Store) *SevenTvClient {
	return &SevenTvClient{
		store:      store,
		apiBaseUrl: DefaultSevenTvApiBaseUrl,
		gqlBaseUrl: DefaultSevenTvGqlBaseUrl,
	}
}

type UserV3 struct {
	ID                string `json:"id"`
	Username          string `json:"username"`
	ProfilePictureURL string `json:"profile_picture_url"`
	DisplayName       string `json:"display_name"`
	Style             struct {
		Color int         `json:"color"`
		Paint interface{} `json:"paint"`
	} `json:"style"`
	Biography string `json:"biography"`
	Editors   []struct {
		ID          string `json:"id"`
		Permissions int    `json:"permissions"`
		Visible     bool   `json:"visible"`
		AddedAt     int64  `json:"added_at"`
	} `json:"editors"`
	Roles       []string `json:"roles"`
	Connections []struct {
		ID            string `json:"id"`
		Platform      string `json:"platform"`
		Username      string `json:"username"`
		DisplayName   string `json:"display_name"`
		LinkedAt      int64  `json:"linked_at"`
		EmoteCapacity int    `json:"emote_capacity"`
	} `json:"connections"`
}

func (c *SevenTvClient) GetUserV3(userID string) (UserV3, error) {
	// first figure out the bttvUserId for the channel, might cache this later on
	var userResp UserV3
	err := requests.
		URL(DefaultSevenTvV3ApiBaseUrl).
		Pathf("/users/%s", userID).
		ToJSON(&userResp).
		Fetch(context.Background())
	if err != nil {
		return UserV3{}, err
	}

	return userResp, nil
}

func (c *SevenTvClient) GetTwitchConnection(userID string) (string, error) {
	user, err := c.GetUserV3(userID)
	if err != nil {
		return "", err
	}

	for _, connection := range user.Connections {
		if connection.Platform == "TWITCH" {
			return connection.Username, nil
		}
	}

	return "", fmt.Errorf("no twitch connection found for user %s", userID)
}

func (c *SevenTvClient) GetEmote(emoteID string) (Emote, error) {
	var emoteData sevenTvEmote

	err := requests.URL(c.apiBaseUrl + "/emotes/" + emoteID).
		ToJSON(&emoteData).
		Fetch(context.Background())

	if utils.BitField.HasBits(int64(emoteData.Visibility), int64(EmoteVisibilityPrivate)) ||
		utils.BitField.HasBits(int64(emoteData.Visibility), int64(EmoteVisibilityUnlisted)) {

		return Emote{}, fmt.Errorf("emote %s has incorrect visibility", emoteData.Name)
	}

	return Emote{Code: emoteData.Name, ID: emoteData.ID}, err
}

func (c *SevenTvClient) RemoveEmote(channelUserID, emoteID string) error {
	user, err := c.GetUser(channelUserID)
	if err != nil {
		return err
	}

	var empty struct{}
	err = c.QuerySevenTvGQL(
		`mutation RemoveChannelEmote($ch: String!, $em: String!, $re: String!) {removeChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`,
		map[string]interface{}{
			"ch": user.ID,
			"re": "blocked emote",
			"em": emoteID,
		}, &empty,
	)

	return err
}

func (c *SevenTvClient) AddEmote(channelUserID string, emoteID string) error {
	user, err := c.GetUser(channelUserID)
	if err != nil {
		return err
	}

	var empty struct{}
	err = c.QuerySevenTvGQL(
		`mutation AddChannelEmote($ch: String!, $em: String!, $re: String!) {addChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`,
		map[string]interface{}{
			"ch": user.ID,
			"re": "bot.gempir.com redemption",
			"em": emoteID,
		}, &empty,
	)

	return err
}

func (c *SevenTvClient) GetUser(channelID string) (User, error) {
	var userData SevenTvUserResponse
	err := c.QuerySevenTvGQL(`
	query GetUser($id: String!) {
		user(id: $id) {
		  ...FullUser
		}
	  }

	fragment FullUser on User {
		id
		emotes {
			id
			name
			status
			visibility
			width
			height
		}
		emote_slots
	}
	`, map[string]interface{}{"id": channelID}, &userData)
	if err != nil {
		return User{}, err
	}

	var emotes []Emote
	for _, emote := range userData.Data.User.Emotes {
		emotes = append(emotes, Emote{ID: emote.ID, Code: emote.Name})
	}

	return User{ID: userData.Data.User.ID, Emotes: emotes, EmoteSlots: userData.Data.User.EmoteSlots}, nil
}

func (c *SevenTvClient) QuerySevenTvGQL(query string, variables map[string]interface{}, response interface{}) error {
	gqlQuery := gqlQuery{Query: query, Variables: variables}

	err := requests.
		URL(c.gqlBaseUrl).
		BodyJSON(gqlQuery).
		Bearer(c.store.GetSevenTvToken(context.Background())).
		ToJSON(&response).
		Fetch(context.Background())
	if err != nil {
		log.Infof("7tv query '%s' with '%v' resp: '%v'", query, variables, response)
		return err
	}

	log.Infof("7tv query '%s' with '%v' resp: '%v'", query, variables, response)

	return nil
}

const SEVEN_TV_ADD_EMOTE_QUERY = `mutation AddChannelEmote($ch: String!, $em: String!, $re: String!) {addChannelEmote(channel_id: $ch, emote_id: $em, reason: $re) {emote_ids}}`
<|endoftext|>


<commit_before>package driver

import (
	"encoding/json"
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/client/driver/executor"
	dstructs "github.com/hashicorp/nomad/client/driver/structs"
	"github.com/hashicorp/nomad/client/fingerprint"
	cstructs "github.com/hashicorp/nomad/client/structs"
	"github.com/hashicorp/nomad/helper/discover"
	"github.com/hashicorp/nomad/helper/fields"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

var (
	reQemuVersion = regexp.MustCompile(`version (\d[\.\d+]+)`)
)

const (
	// The key populated in Node Attributes to indicate presence of the Qemu
	// driver
	qemuDriverAttr = "driver.qemu"
)

// QemuDriver is a driver for running images via Qemu
// We attempt to chose sane defaults for now, with more configuration available
// planned in the future
type QemuDriver struct {
	DriverContext
	fingerprint.StaticFingerprinter
}

type QemuDriverConfig struct {
	ImagePath   string           `mapstructure:"image_path"`
	Accelerator string           `mapstructure:"accelerator"`
	PortMap     []map[string]int `mapstructure:"port_map"` // A map of host port labels and to guest ports.
	Args    []string `mapstructure:"args"` // extra arguments to qemu executable
}

// qemuHandle is returned from Start/Open as a handle to the PID
type qemuHandle struct {
	pluginClient   *plugin.Client
	userPid        int
	executor       executor.Executor
	allocDir       *allocdir.AllocDir
	killTimeout    time.Duration
	maxKillTimeout time.Duration
	logger         *log.Logger
	version        string
	waitCh         chan *dstructs.WaitResult
	doneCh         chan struct{}
}

// NewQemuDriver is used to create a new exec driver
func NewQemuDriver(ctx *DriverContext) Driver {
	return &QemuDriver{DriverContext: *ctx}
}

// Validate is used to validate the driver configuration
func (d *QemuDriver) Validate(config map[string]interface{}) error {
	fd := &fields.FieldData{
		Raw: config,
		Schema: map[string]*fields.FieldSchema{
			"image_path": &fields.FieldSchema{
				Type:     fields.TypeString,
				Required: true,
			},
			"accelerator": &fields.FieldSchema{
				Type: fields.TypeString,
			},
			"port_map": &fields.FieldSchema{
				Type: fields.TypeArray,
			},
			"args": &fields.FieldSchema{
				Type: fields.TypeArray,
			},
		},
	}

	if err := fd.Validate(); err != nil {
		return err
	}

	return nil
}

func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// Get the current status so that we can log any debug messages only if the
	// state changes
	_, currentlyEnabled := node.Attributes[qemuDriverAttr]

	bin := "qemu-system-x86_64"
	if runtime.GOOS == "windows" {
		// On windows, the "qemu-system-x86_64" command does not respond to the
		// version flag.
		bin = "qemu-img"
	}
	outBytes, err := exec.Command(bin, "--version").Output()
	if err != nil {
		delete(node.Attributes, qemuDriverAttr)
		return false, nil
	}
	out := strings.TrimSpace(string(outBytes))

	matches := reQemuVersion.FindStringSubmatch(out)
	if len(matches) != 2 {
		delete(node.Attributes, qemuDriverAttr)
		return false, fmt.Errorf("Unable to parse Qemu version string: %#v", matches)
	}

	if !currentlyEnabled {
		d.logger.Printf("[DEBUG] driver.qemu: enabling driver")
	}
	node.Attributes[qemuDriverAttr] = "1"
	node.Attributes["driver.qemu.version"] = matches[1]
	return true, nil
}

// Run an existing Qemu image. Start() will pull down an existing, valid Qemu
// image and save it to the Drivers Allocation Dir
func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var driverConfig QemuDriverConfig
	if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
		return nil, err
	}

	if len(driverConfig.PortMap) > 1 {
		return nil, fmt.Errorf("Only one port_map block is allowed in the qemu driver config")
	}

	// Get the image source
	vmPath := driverConfig.ImagePath
	if vmPath == "" {
		return nil, fmt.Errorf("image_path must be set")
	}
	vmID := filepath.Base(vmPath)

	// Get the tasks local directory.
	taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
	if !ok {
		return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
	}

	// Parse configuration arguments
	// Create the base arguments
	accelerator := "tcg"
	if driverConfig.Accelerator != "" {
		accelerator = driverConfig.Accelerator
	}
	// TODO: Check a lower bounds, e.g. the default 128 of Qemu
	mem := fmt.Sprintf("%dM", task.Resources.MemoryMB)

	absPath, err := GetAbsolutePath("qemu-system-x86_64")
	if err != nil {
		return nil, err
	}

	args := []string{
		absPath,
		"-machine", "type=pc,accel=" + accelerator,
		"-name", vmID,
		"-m", mem,
		"-drive", "file=" + vmPath,
		"-nographic",
	}

	// Add pass through arguments to qemu executable. A user can specify
	// these arguments in driver task configuration. These arguments are
	// passed directly to the qemu driver as command line options.
	// For example, args = [ "-nodefconfig", "-nodefaults" ]
	// This will allow a VM with embedded configuration to boot successfully.
	args = append(args, driverConfig.Args...)

	// Check the Resources required Networks to add port mappings. If no resources
	// are required, we assume the VM is a purely compute job and does not require
	// the outside world to be able to reach it. VMs ran without port mappings can
	// still reach out to the world, but without port mappings it is effectively
	// firewalled
	protocols := []string{"udp", "tcp"}
	if len(task.Resources.Networks) > 0 && len(driverConfig.PortMap) == 1 {
		// Loop through the port map and construct the hostfwd string, to map
		// reserved ports to the ports listenting in the VM
		// Ex: hostfwd=tcp::22000-:22,hostfwd=tcp::80-:8080
		var forwarding []string
		taskPorts := task.Resources.Networks[0].MapLabelToValues(nil)
		for label, guest := range driverConfig.PortMap[0] {
			host, ok := taskPorts[label]
			if !ok {
				return nil, fmt.Errorf("Unknown port label %q", label)
			}

			for _, p := range protocols {
				forwarding = append(forwarding, fmt.Sprintf("hostfwd=%s::%d-:%d", p, host, guest))
			}
		}

		if len(forwarding) != 0 {
			args = append(args,
				"-netdev",
				fmt.Sprintf("user,id=user.0,%s", strings.Join(forwarding, ",")),
				"-device", "virtio-net,netdev=user.0",
			)
		}
	}

	// If using KVM, add optimization args
	if accelerator == "kvm" {
		args = append(args,
			"-enable-kvm",
			"-cpu", "host",
			// Do we have cores information available to the Driver?
			// "-smp", fmt.Sprintf("%d", cores),
		)
	}

	d.logger.Printf("[DEBUG] Starting QemuVM command: %q", strings.Join(args, " "))
	bin, err := discover.NomadExecutable()
	if err != nil {
		return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
	}

	pluginLogFile := filepath.Join(taskDir, fmt.Sprintf("%s-executor.out", task.Name))
	pluginConfig := &plugin.ClientConfig{
		Cmd: exec.Command(bin, "executor", pluginLogFile),
	}

	exec, pluginClient, err := createExecutor(pluginConfig, d.config.LogOutput, d.config)
	if err != nil {
		return nil, err
	}
	executorCtx := &executor.ExecutorContext{
		TaskEnv:  d.taskEnv,
		Driver:   "qemu",
		AllocDir: ctx.AllocDir,
		AllocID:  ctx.AllocID,
		Task:     task,
	}
	ps, err := exec.LaunchCmd(&executor.ExecCommand{
		Cmd:  args[0],
		Args: args[1:],
		User: task.User,
	}, executorCtx)
	if err != nil {
		pluginClient.Kill()
		return nil, err
	}
	d.logger.Printf("[INFO] Started new QemuVM: %s", vmID)

	// Create and Return Handle
	maxKill := d.DriverContext.config.MaxKillTimeout
	h := &qemuHandle{
		pluginClient:   pluginClient,
		executor:       exec,
		userPid:        ps.Pid,
		allocDir:       ctx.AllocDir,
		killTimeout:    GetKillTimeout(task.KillTimeout, maxKill),
		maxKillTimeout: maxKill,
		version:        d.config.Version,
		logger:         d.logger,
		doneCh:         make(chan struct{}),
		waitCh:         make(chan *dstructs.WaitResult, 1),
	}

	if err := h.executor.SyncServices(consulContext(d.config, "")); err != nil {
		h.logger.Printf("[ERR] driver.qemu: error registering services for task: %q: %v", task.Name, err)
	}
	go h.run()
	return h, nil
}

type qemuId struct {
	Version        string
	KillTimeout    time.Duration
	MaxKillTimeout time.Duration
	UserPid        int
	PluginConfig   *PluginReattachConfig
	AllocDir       *allocdir.AllocDir
}

func (d *QemuDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
	id := &qemuId{}
	if err := json.Unmarshal([]byte(handleID), id); err != nil {
		return nil, fmt.Errorf("Failed to parse handle '%s': %v", handleID, err)
	}

	pluginConfig := &plugin.ClientConfig{
		Reattach: id.PluginConfig.PluginConfig(),
	}

	exec, pluginClient, err := createExecutor(pluginConfig, d.config.LogOutput, d.config)
	if err != nil {
		d.logger.Println("[ERR] driver.qemu: error connecting to plugin so destroying plugin pid and user pid")
		if e := destroyPlugin(id.PluginConfig.Pid, id.UserPid); e != nil {
			d.logger.Printf("[ERR] driver.qemu: error destroying plugin and userpid: %v", e)
		}
		return nil, fmt.Errorf("error connecting to plugin: %v", err)
	}

	ver, _ := exec.Version()
	d.logger.Printf("[DEBUG] driver.qemu: version of executor: %v", ver.Version)
	// Return a driver handle
	h := &qemuHandle{
		pluginClient:   pluginClient,
		executor:       exec,
		userPid:        id.UserPid,
		allocDir:       id.AllocDir,
		logger:         d.logger,
		killTimeout:    id.KillTimeout,
		maxKillTimeout: id.MaxKillTimeout,
		version:        id.Version,
		doneCh:         make(chan struct{}),
		waitCh:         make(chan *dstructs.WaitResult, 1),
	}
	if err := h.executor.SyncServices(consulContext(d.config, "")); err != nil {
		h.logger.Printf("[ERR] driver.qemu: error registering services: %v", err)
	}
	go h.run()
	return h, nil
}

func (h *qemuHandle) ID() string {
	id := qemuId{
		Version:        h.version,
		KillTimeout:    h.killTimeout,
		MaxKillTimeout: h.maxKillTimeout,
		PluginConfig:   NewPluginReattachConfig(h.pluginClient.ReattachConfig()),
		UserPid:        h.userPid,
		AllocDir:       h.allocDir,
	}

	data, err := json.Marshal(id)
	if err != nil {
		h.logger.Printf("[ERR] driver.qemu: failed to marshal ID to JSON: %s", err)
	}
	return string(data)
}

func (h *qemuHandle) WaitCh() chan *dstructs.WaitResult {
	return h.waitCh
}

func (h *qemuHandle) Update(task *structs.Task) error {
	// Store the updated kill timeout.
	h.killTimeout = GetKillTimeout(task.KillTimeout, h.maxKillTimeout)
	h.executor.UpdateTask(task)

	// Update is not possible
	return nil
}

// TODO: allow a 'shutdown_command' that can be executed over a ssh connection
// to the VM
func (h *qemuHandle) Kill() error {
	if err := h.executor.ShutDown(); err != nil {
		if h.pluginClient.Exited() {
			return nil
		}
		return fmt.Errorf("executor Shutdown failed: %v", err)
	}

	select {
	case <-h.doneCh:
		return nil
	case <-time.After(h.killTimeout):
		if h.pluginClient.Exited() {
			return nil
		}
		if err := h.executor.Exit(); err != nil {
			return fmt.Errorf("executor Exit failed: %v", err)
		}

		return nil
	}
}

func (h *qemuHandle) Stats() (*cstructs.TaskResourceUsage, error) {
	return h.executor.Stats()
}

func (h *qemuHandle) run() {
	ps, err := h.executor.Wait()
	if ps.ExitCode == 0 && err != nil {
		if e := killProcess(h.userPid); e != nil {
			h.logger.Printf("[ERR] driver.qemu: error killing user process: %v", e)
		}
		if e := h.allocDir.UnmountAll(); e != nil {
			h.logger.Printf("[ERR] driver.qemu: unmounting dev,proc and alloc dirs failed: %v", e)
		}
	}
	close(h.doneCh)
	h.waitCh <- &dstructs.WaitResult{ExitCode: ps.ExitCode, Signal: ps.Signal, Err: err}
	close(h.waitCh)
	// Remove services
	if err := h.executor.DeregisterServices(); err != nil {
		h.logger.Printf("[ERR] driver.qemu: failed to deregister services: %v", err)
	}

	h.executor.Exit()
	h.pluginClient.Kill()
}
<commit_msg>go fmt performed code when copied from another directory got messed up again ? Ok, ran go fmt again<commit_after>package driver

import (
	"encoding/json"
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/hashicorp/go-plugin"
	"github.com/hashicorp/nomad/client/allocdir"
	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/client/driver/executor"
	dstructs "github.com/hashicorp/nomad/client/driver/structs"
	"github.com/hashicorp/nomad/client/fingerprint"
	cstructs "github.com/hashicorp/nomad/client/structs"
	"github.com/hashicorp/nomad/helper/discover"
	"github.com/hashicorp/nomad/helper/fields"
	"github.com/hashicorp/nomad/nomad/structs"
	"github.com/mitchellh/mapstructure"
)

var (
	reQemuVersion = regexp.MustCompile(`version (\d[\.\d+]+)`)
)

const (
	// The key populated in Node Attributes to indicate presence of the Qemu
	// driver
	qemuDriverAttr = "driver.qemu"
)

// QemuDriver is a driver for running images via Qemu
// We attempt to chose sane defaults for now, with more configuration available
// planned in the future
type QemuDriver struct {
	DriverContext
	fingerprint.StaticFingerprinter
}

type QemuDriverConfig struct {
	ImagePath   string           `mapstructure:"image_path"`
	Accelerator string           `mapstructure:"accelerator"`
	PortMap     []map[string]int `mapstructure:"port_map"` // A map of host port labels and to guest ports.
	Args        []string         `mapstructure:"args"`     // extra arguments to qemu executable
}

// qemuHandle is returned from Start/Open as a handle to the PID
type qemuHandle struct {
	pluginClient   *plugin.Client
	userPid        int
	executor       executor.Executor
	allocDir       *allocdir.AllocDir
	killTimeout    time.Duration
	maxKillTimeout time.Duration
	logger         *log.Logger
	version        string
	waitCh         chan *dstructs.WaitResult
	doneCh         chan struct{}
}

// NewQemuDriver is used to create a new exec driver
func NewQemuDriver(ctx *DriverContext) Driver {
	return &QemuDriver{DriverContext: *ctx}
}

// Validate is used to validate the driver configuration
func (d *QemuDriver) Validate(config map[string]interface{}) error {
	fd := &fields.FieldData{
		Raw: config,
		Schema: map[string]*fields.FieldSchema{
			"image_path": &fields.FieldSchema{
				Type:     fields.TypeString,
				Required: true,
			},
			"accelerator": &fields.FieldSchema{
				Type: fields.TypeString,
			},
			"port_map": &fields.FieldSchema{
				Type: fields.TypeArray,
			},
			"args": &fields.FieldSchema{
				Type: fields.TypeArray,
			},
		},
	}

	if err := fd.Validate(); err != nil {
		return err
	}

	return nil
}

func (d *QemuDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	// Get the current status so that we can log any debug messages only if the
	// state changes
	_, currentlyEnabled := node.Attributes[qemuDriverAttr]

	bin := "qemu-system-x86_64"
	if runtime.GOOS == "windows" {
		// On windows, the "qemu-system-x86_64" command does not respond to the
		// version flag.
		bin = "qemu-img"
	}
	outBytes, err := exec.Command(bin, "--version").Output()
	if err != nil {
		delete(node.Attributes, qemuDriverAttr)
		return false, nil
	}
	out := strings.TrimSpace(string(outBytes))

	matches := reQemuVersion.FindStringSubmatch(out)
	if len(matches) != 2 {
		delete(node.Attributes, qemuDriverAttr)
		return false, fmt.Errorf("Unable to parse Qemu version string: %#v", matches)
	}

	if !currentlyEnabled {
		d.logger.Printf("[DEBUG] driver.qemu: enabling driver")
	}
	node.Attributes[qemuDriverAttr] = "1"
	node.Attributes["driver.qemu.version"] = matches[1]
	return true, nil
}

// Run an existing Qemu image. Start() will pull down an existing, valid Qemu
// image and save it to the Drivers Allocation Dir
func (d *QemuDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle, error) {
	var driverConfig QemuDriverConfig
	if err := mapstructure.WeakDecode(task.Config, &driverConfig); err != nil {
		return nil, err
	}

	if len(driverConfig.PortMap) > 1 {
		return nil, fmt.Errorf("Only one port_map block is allowed in the qemu driver config")
	}

	// Get the image source
	vmPath := driverConfig.ImagePath
	if vmPath == "" {
		return nil, fmt.Errorf("image_path must be set")
	}
	vmID := filepath.Base(vmPath)

	// Get the tasks local directory.
	taskDir, ok := ctx.AllocDir.TaskDirs[d.DriverContext.taskName]
	if !ok {
		return nil, fmt.Errorf("Could not find task directory for task: %v", d.DriverContext.taskName)
	}

	// Parse configuration arguments
	// Create the base arguments
	accelerator := "tcg"
	if driverConfig.Accelerator != "" {
		accelerator = driverConfig.Accelerator
	}
	// TODO: Check a lower bounds, e.g. the default 128 of Qemu
	mem := fmt.Sprintf("%dM", task.Resources.MemoryMB)

	absPath, err := GetAbsolutePath("qemu-system-x86_64")
	if err != nil {
		return nil, err
	}

	args := []string{
		absPath,
		"-machine", "type=pc,accel=" + accelerator,
		"-name", vmID,
		"-m", mem,
		"-drive", "file=" + vmPath,
		"-nographic",
	}

	// Add pass through arguments to qemu executable. A user can specify
	// these arguments in driver task configuration. These arguments are
	// passed directly to the qemu driver as command line options.
	// For example, args = [ "-nodefconfig", "-nodefaults" ]
	// This will allow a VM with embedded configuration to boot successfully.
	args = append(args, driverConfig.Args...)

	// Check the Resources required Networks to add port mappings. If no resources
	// are required, we assume the VM is a purely compute job and does not require
	// the outside world to be able to reach it. VMs ran without port mappings can
	// still reach out to the world, but without port mappings it is effectively
	// firewalled
	protocols := []string{"udp", "tcp"}
	if len(task.Resources.Networks) > 0 && len(driverConfig.PortMap) == 1 {
		// Loop through the port map and construct the hostfwd string, to map
		// reserved ports to the ports listenting in the VM
		// Ex: hostfwd=tcp::22000-:22,hostfwd=tcp::80-:8080
		var forwarding []string
		taskPorts := task.Resources.Networks[0].MapLabelToValues(nil)
		for label, guest := range driverConfig.PortMap[0] {
			host, ok := taskPorts[label]
			if !ok {
				return nil, fmt.Errorf("Unknown port label %q", label)
			}

			for _, p := range protocols {
				forwarding = append(forwarding, fmt.Sprintf("hostfwd=%s::%d-:%d", p, host, guest))
			}
		}

		if len(forwarding) != 0 {
			args = append(args,
				"-netdev",
				fmt.Sprintf("user,id=user.0,%s", strings.Join(forwarding, ",")),
				"-device", "virtio-net,netdev=user.0",
			)
		}
	}

	// If using KVM, add optimization args
	if accelerator == "kvm" {
		args = append(args,
			"-enable-kvm",
			"-cpu", "host",
			// Do we have cores information available to the Driver?
			// "-smp", fmt.Sprintf("%d", cores),
		)
	}

	d.logger.Printf("[DEBUG] Starting QemuVM command: %q", strings.Join(args, " "))
	bin, err := discover.NomadExecutable()
	if err != nil {
		return nil, fmt.Errorf("unable to find the nomad binary: %v", err)
	}

	pluginLogFile := filepath.Join(taskDir, fmt.Sprintf("%s-executor.out", task.Name))
	pluginConfig := &plugin.ClientConfig{
		Cmd: exec.Command(bin, "executor", pluginLogFile),
	}

	exec, pluginClient, err := createExecutor(pluginConfig, d.config.LogOutput, d.config)
	if err != nil {
		return nil, err
	}
	executorCtx := &executor.ExecutorContext{
		TaskEnv:  d.taskEnv,
		Driver:   "qemu",
		AllocDir: ctx.AllocDir,
		AllocID:  ctx.AllocID,
		Task:     task,
	}
	ps, err := exec.LaunchCmd(&executor.ExecCommand{
		Cmd:  args[0],
		Args: args[1:],
		User: task.User,
	}, executorCtx)
	if err != nil {
		pluginClient.Kill()
		return nil, err
	}
	d.logger.Printf("[INFO] Started new QemuVM: %s", vmID)

	// Create and Return Handle
	maxKill := d.DriverContext.config.MaxKillTimeout
	h := &qemuHandle{
		pluginClient:   pluginClient,
		executor:       exec,
		userPid:        ps.Pid,
		allocDir:       ctx.AllocDir,
		killTimeout:    GetKillTimeout(task.KillTimeout, maxKill),
		maxKillTimeout: maxKill,
		version:        d.config.Version,
		logger:         d.logger,
		doneCh:         make(chan struct{}),
		waitCh:         make(chan *dstructs.WaitResult, 1),
	}

	if err := h.executor.SyncServices(consulContext(d.config, "")); err != nil {
		h.logger.Printf("[ERR] driver.qemu: error registering services for task: %q: %v", task.Name, err)
	}
	go h.run()
	return h, nil
}

type qemuId struct {
	Version        string
	KillTimeout    time.Duration
	MaxKillTimeout time.Duration
	UserPid        int
	PluginConfig   *PluginReattachConfig
	AllocDir       *allocdir.AllocDir
}

func (d *QemuDriver) Open(ctx *ExecContext, handleID string) (DriverHandle, error) {
	id := &qemuId{}
	if err := json.Unmarshal([]byte(handleID), id); err != nil {
		return nil, fmt.Errorf("Failed to parse handle '%s': %v", handleID, err)
	}

	pluginConfig := &plugin.ClientConfig{
		Reattach: id.PluginConfig.PluginConfig(),
	}

	exec, pluginClient, err := createExecutor(pluginConfig, d.config.LogOutput, d.config)
	if err != nil {
		d.logger.Println("[ERR] driver.qemu: error connecting to plugin so destroying plugin pid and user pid")
		if e := destroyPlugin(id.PluginConfig.Pid, id.UserPid); e != nil {
			d.logger.Printf("[ERR] driver.qemu: error destroying plugin and userpid: %v", e)
		}
		return nil, fmt.Errorf("error connecting to plugin: %v", err)
	}

	ver, _ := exec.Version()
	d.logger.Printf("[DEBUG] driver.qemu: version of executor: %v", ver.Version)
	// Return a driver handle
	h := &qemuHandle{
		pluginClient:   pluginClient,
		executor:       exec,
		userPid:        id.UserPid,
		allocDir:       id.AllocDir,
		logger:         d.logger,
		killTimeout:    id.KillTimeout,
		maxKillTimeout: id.MaxKillTimeout,
		version:        id.Version,
		doneCh:         make(chan struct{}),
		waitCh:         make(chan *dstructs.WaitResult, 1),
	}
	if err := h.executor.SyncServices(consulContext(d.config, "")); err != nil {
		h.logger.Printf("[ERR] driver.qemu: error registering services: %v", err)
	}
	go h.run()
	return h, nil
}

func (h *qemuHandle) ID() string {
	id := qemuId{
		Version:        h.version,
		KillTimeout:    h.killTimeout,
		MaxKillTimeout: h.maxKillTimeout,
		PluginConfig:   NewPluginReattachConfig(h.pluginClient.ReattachConfig()),
		UserPid:        h.userPid,
		AllocDir:       h.allocDir,
	}

	data, err := json.Marshal(id)
	if err != nil {
		h.logger.Printf("[ERR] driver.qemu: failed to marshal ID to JSON: %s", err)
	}
	return string(data)
}

func (h *qemuHandle) WaitCh() chan *dstructs.WaitResult {
	return h.waitCh
}

func (h *qemuHandle) Update(task *structs.Task) error {
	// Store the updated kill timeout.
	h.killTimeout = GetKillTimeout(task.KillTimeout, h.maxKillTimeout)
	h.executor.UpdateTask(task)

	// Update is not possible
	return nil
}

// TODO: allow a 'shutdown_command' that can be executed over a ssh connection
// to the VM
func (h *qemuHandle) Kill() error {
	if err := h.executor.ShutDown(); err != nil {
		if h.pluginClient.Exited() {
			return nil
		}
		return fmt.Errorf("executor Shutdown failed: %v", err)
	}

	select {
	case <-h.doneCh:
		return nil
	case <-time.After(h.killTimeout):
		if h.pluginClient.Exited() {
			return nil
		}
		if err := h.executor.Exit(); err != nil {
			return fmt.Errorf("executor Exit failed: %v", err)
		}

		return nil
	}
}

func (h *qemuHandle) Stats() (*cstructs.TaskResourceUsage, error) {
	return h.executor.Stats()
}

func (h *qemuHandle) run() {
	ps, err := h.executor.Wait()
	if ps.ExitCode == 0 && err != nil {
		if e := killProcess(h.userPid); e != nil {
			h.logger.Printf("[ERR] driver.qemu: error killing user process: %v", e)
		}
		if e := h.allocDir.UnmountAll(); e != nil {
			h.logger.Printf("[ERR] driver.qemu: unmounting dev,proc and alloc dirs failed: %v", e)
		}
	}
	close(h.doneCh)
	h.waitCh <- &dstructs.WaitResult{ExitCode: ps.ExitCode, Signal: ps.Signal, Err: err}
	close(h.waitCh)
	// Remove services
	if err := h.executor.DeregisterServices(); err != nil {
		h.logger.Printf("[ERR] driver.qemu: failed to deregister services: %v", err)
	}

	h.executor.Exit()
	h.pluginClient.Kill()
}
<|endoftext|>


<commit_before>package rpcclient

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-rpc/types"
	"github.com/tendermint/go-wire"
)

// JSON rpc takes params as a slice
type ClientJSONRPC struct {
	remote string
}

func NewClientJSONRPC(remote string) *ClientJSONRPC {
	return &ClientJSONRPC{remote}
}

func (c *ClientJSONRPC) Call(method string, params []interface{}, result interface{}) (interface{}, error) {
	return CallHTTP_JSONRPC(c.remote, method, params, result)
}

// URI takes params as a map
type ClientURI struct {
	remote string
}

func NewClientURI(remote string) *ClientURI {
	if !strings.HasSuffix(remote, "/") {
		remote = remote + "/"
	}
	return &ClientURI{remote}
}

func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	return CallHTTP_URI(c.remote, method, params, result)
}

func CallHTTP_JSONRPC(remote string, method string, params []interface{}, result interface{}) (interface{}, error) {
	// Make request and get responseBytes
	request := rpctypes.RPCRequest{
		JSONRPC: "2.0",
		Method:  method,
		Params:  params,
		ID:      "",
	}
	requestBytes := wire.JSONBytes(request)
	requestBuf := bytes.NewBuffer(requestBytes)
	log.Info(Fmt("RPC request to %v: %v", remote, string(requestBytes)))
	httpResponse, err := http.Post(remote, "text/json", requestBuf)
	if err != nil {
		return nil, err
	}
	defer httpResponse.Body.Close()
	responseBytes, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, err
	}
	log.Info(Fmt("RPC response: %v", string(responseBytes)))
	return unmarshalResponseBytes(responseBytes, result)
}

func CallHTTP_URI(remote string, method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	values, err := argsToURLValues(params)
	if err != nil {
		return nil, err
	}
	log.Info(Fmt("URI request to %v: %v", remote, values))
	resp, err := http.PostForm(remote+method, values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	responseBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return unmarshalResponseBytes(responseBytes, result)
}

//------------------------------------------------

func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
	// read response
	// if rpc/core/types is imported, the result will unmarshal
	// into the correct type
	var err error
	response := &rpctypes.RPCResponse{}
	err = json.Unmarshal(responseBytes, response)
	if err != nil {
		return nil, err
	}
	errorStr := response.Error
	if errorStr != "" {
		return nil, errors.New(errorStr)
	}
	// unmarshal the RawMessage into the result
	result = wire.ReadJSONPtr(result, *response.Result, &err)
	return result, err
}

func argsToURLValues(args map[string]interface{}) (url.Values, error) {
	values := make(url.Values)
	if len(args) == 0 {
		return values, nil
	}
	err := argsToJson(args)
	if err != nil {
		return nil, err
	}
	for key, val := range args {
		values.Set(key, val.(string))
	}
	return values, nil
}

func argsToJson(args map[string]interface{}) error {
	var n int
	var err error
	for k, v := range args {
		buf := new(bytes.Buffer)
		wire.WriteJSON(v, buf, &n, &err)
		if err != nil {
			return err
		}
		args[k] = buf.String()
	}
	return nil
}
<commit_msg>print method in client log<commit_after>package rpcclient

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-rpc/types"
	"github.com/tendermint/go-wire"
)

// JSON rpc takes params as a slice
type ClientJSONRPC struct {
	remote string
}

func NewClientJSONRPC(remote string) *ClientJSONRPC {
	return &ClientJSONRPC{remote}
}

func (c *ClientJSONRPC) Call(method string, params []interface{}, result interface{}) (interface{}, error) {
	return CallHTTP_JSONRPC(c.remote, method, params, result)
}

// URI takes params as a map
type ClientURI struct {
	remote string
}

func NewClientURI(remote string) *ClientURI {
	if !strings.HasSuffix(remote, "/") {
		remote = remote + "/"
	}
	return &ClientURI{remote}
}

func (c *ClientURI) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	return CallHTTP_URI(c.remote, method, params, result)
}

func CallHTTP_JSONRPC(remote string, method string, params []interface{}, result interface{}) (interface{}, error) {
	// Make request and get responseBytes
	request := rpctypes.RPCRequest{
		JSONRPC: "2.0",
		Method:  method,
		Params:  params,
		ID:      "",
	}
	requestBytes := wire.JSONBytes(request)
	requestBuf := bytes.NewBuffer(requestBytes)
	log.Info(Fmt("RPC request to %v (%v): %v", remote, method, string(requestBytes)))
	httpResponse, err := http.Post(remote, "text/json", requestBuf)
	if err != nil {
		return nil, err
	}
	defer httpResponse.Body.Close()
	responseBytes, err := ioutil.ReadAll(httpResponse.Body)
	if err != nil {
		return nil, err
	}
	log.Info(Fmt("RPC response: %v", string(responseBytes)))
	return unmarshalResponseBytes(responseBytes, result)
}

func CallHTTP_URI(remote string, method string, params map[string]interface{}, result interface{}) (interface{}, error) {
	values, err := argsToURLValues(params)
	if err != nil {
		return nil, err
	}
	log.Info(Fmt("URI request to %v (%v): %v", remote, method, values))
	resp, err := http.PostForm(remote+method, values)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	responseBytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return unmarshalResponseBytes(responseBytes, result)
}

//------------------------------------------------

func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface{}, error) {
	// read response
	// if rpc/core/types is imported, the result will unmarshal
	// into the correct type
	var err error
	response := &rpctypes.RPCResponse{}
	err = json.Unmarshal(responseBytes, response)
	if err != nil {
		return nil, err
	}
	errorStr := response.Error
	if errorStr != "" {
		return nil, errors.New(errorStr)
	}
	// unmarshal the RawMessage into the result
	result = wire.ReadJSONPtr(result, *response.Result, &err)
	return result, err
}

func argsToURLValues(args map[string]interface{}) (url.Values, error) {
	values := make(url.Values)
	if len(args) == 0 {
		return values, nil
	}
	err := argsToJson(args)
	if err != nil {
		return nil, err
	}
	for key, val := range args {
		values.Set(key, val.(string))
	}
	return values, nil
}

func argsToJson(args map[string]interface{}) error {
	var n int
	var err error
	for k, v := range args {
		buf := new(bytes.Buffer)
		wire.WriteJSON(v, buf, &n, &err)
		if err != nil {
			return err
		}
		args[k] = buf.String()
	}
	return nil
}
<|endoftext|>


<commit_before>package suggest_test

import (
	"bytes"
	"encoding/json"
	"go/build"
	"go/importer"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/mdempsky/gocode/internal/suggest"
)

func TestRegress(t *testing.T) {
	testDirs, err := filepath.Glob("testdata/test.*")
	if err != nil {
		t.Fatal(err)
	}

	for _, testDir := range testDirs {
		// Skip test test.0011 for Go < 1.11 because a method was added to reflect.Value.
		if !contains(build.Default.ReleaseTags, "go1.11") && strings.HasSuffix(testDir, "test.0011") {
			continue
		}
		testDir := testDir // capture
		name := strings.TrimPrefix(testDir, "testdata/")
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			testRegress(t, testDir)
		})
	}
}

func testRegress(t *testing.T, testDir string) {
	testDir, err := filepath.Abs(testDir)
	if err != nil {
		t.Errorf("Abs failed: %v", err)
		return
	}

	filename := filepath.Join(testDir, "test.go.in")
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Errorf("ReadFile failed: %v", err)
		return
	}

	cursor := bytes.IndexByte(data, '@')
	if cursor < 0 {
		t.Errorf("Missing @")
		return
	}
	data = append(data[:cursor], data[cursor+1:]...)

	cfg := suggest.Config{
		Importer: importer.Default(),
	}
	if testing.Verbose() {
		cfg.Logf = t.Logf
	}
	if cfgJSON, err := os.Open(filepath.Join(testDir, "config.json")); err == nil {
		if err := json.NewDecoder(cfgJSON).Decode(&cfg); err != nil {
			t.Errorf("Decode failed: %v", err)
			return
		}
	} else if !os.IsNotExist(err) {
		t.Errorf("Open failed: %v", err)
		return
	}
	candidates, prefixLen := cfg.Suggest(filename, data, cursor)

	var out bytes.Buffer
	suggest.NiceFormat(&out, candidates, prefixLen)

	want, _ := ioutil.ReadFile(filepath.Join(testDir, "out.expected"))
	if got := out.Bytes(); !bytes.Equal(got, want) {
		t.Errorf("%s:\nGot:\n%s\nWant:\n%s\n", testDir, got, want)
		return
	}
}

func contains(haystack []string, needle string) bool {
	for _, x := range haystack {
		if needle == x {
			return true
		}
	}
	return false
}<commit_msg>fix test for Go 1.11<commit_after>package suggest_test

import (
	"bytes"
	"encoding/json"
	"go/importer"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/mdempsky/gocode/internal/suggest"
)

func TestRegress(t *testing.T) {
	testDirs, err := filepath.Glob("testdata/test.*")
	if err != nil {
		t.Fatal(err)
	}

	for _, testDir := range testDirs {
		// Skip test.0011 for Go <= 1.11 because a method was added to reflect.Value.
		// TODO(rstambler): Change this when Go 1.12 comes out.
		if !strings.HasPrefix(runtime.Version(), "devel") && strings.HasSuffix(testDir, "test.0011") {
				continue
		}
		testDir := testDir // capture
		name := strings.TrimPrefix(testDir, "testdata/")
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			testRegress(t, testDir)
		})
	}
}

func testRegress(t *testing.T, testDir string) {
	testDir, err := filepath.Abs(testDir)
	if err != nil {
		t.Errorf("Abs failed: %v", err)
		return
	}

	filename := filepath.Join(testDir, "test.go.in")
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Errorf("ReadFile failed: %v", err)
		return
	}

	cursor := bytes.IndexByte(data, '@')
	if cursor < 0 {
		t.Errorf("Missing @")
		return
	}
	data = append(data[:cursor], data[cursor+1:]...)

	cfg := suggest.Config{
		Importer: importer.Default(),
	}
	if testing.Verbose() {
		cfg.Logf = t.Logf
	}
	if cfgJSON, err := os.Open(filepath.Join(testDir, "config.json")); err == nil {
		if err := json.NewDecoder(cfgJSON).Decode(&cfg); err != nil {
			t.Errorf("Decode failed: %v", err)
			return
		}
	} else if !os.IsNotExist(err) {
		t.Errorf("Open failed: %v", err)
		return
	}
	candidates, prefixLen := cfg.Suggest(filename, data, cursor)

	var out bytes.Buffer
	suggest.NiceFormat(&out, candidates, prefixLen)

	want, _ := ioutil.ReadFile(filepath.Join(testDir, "out.expected"))
	if got := out.Bytes(); !bytes.Equal(got, want) {
		t.Errorf("%s:\nGot:\n%s\nWant:\n%s\n", testDir, got, want)
		return
	}
}

func contains(haystack []string, needle string) bool {
	for _, x := range haystack {
		if needle == x {
			return true
		}
	}
	return false
}<|endoftext|>


<commit_before>// +build linux aix
// +build !js

package logrus

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TCGETS

func isTerminal(fd int) bool {
	_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
	return err == nil
}
<commit_msg>Add build tag to enable a successful build for zos<commit_after>// +build linux aix zos
// +build !js

package logrus

import "golang.org/x/sys/unix"

const ioctlReadTermios = unix.TCGETS

func isTerminal(fd int) bool {
	_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
	return err == nil
}
<|endoftext|>


<commit_before>package cli

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

	"github.com/alecthomas/kingpin"
	"github.com/prometheus/alertmanager/cli/format"
	"github.com/prometheus/alertmanager/pkg/parse"
	"github.com/prometheus/alertmanager/types"
)

var (
	queryCmd     = silenceCmd.Command("query", "Query Alertmanager silences.").Default()
	queryExpired = queryCmd.Flag("expired", "Show expired silences as well as active").Bool()
	silenceQuery = queryCmd.Arg("matcher-groups", "Query filter").Strings()
	queryWithin  = queryCmd.Flag("within", "Show silences that will expire within a duration").Duration()
)

func init() {
	queryCmd.Action(query)
	longHelpText["silence query"] = `Query Alertmanager silences.

Amtool has a simplified prometheus query syntax, but contains robust support for
bash variable expansions. The non-option section of arguments constructs a list
of "Matcher Groups" that will be used to filter your query. The following
examples will attempt to show this behaviour in action:

amtool silence query alertname=foo node=bar

	This query will match all silences with the alertname=foo and node=bar label
	value pairs set.

amtool silence query foo node=bar

	If alertname is ommited and the first argument does not contain a '=' or a
	'=~' then it will be assumed to be the value of the alertname pair.

amtool silence query 'alertname=~foo.*'

	As well as direct equality, regex matching is also supported. The '=~' syntax
	(similar to prometheus) is used to represent a regex match. Regex matching
	can be used in combination with a direct match.

In addition to filtering by silence labels, one can also query for silences
that are due to expire soon with the "--within" parameter. In the event that
you want to preemptively act upon expiring silences by either fixing them or
extending them. For example:

amtool silence query --within 8h

gives all the silences due to expire within the next 8 hours. This syntax can
also be combined with the label based filtering above for more flexibility.`
}

func fetchSilences(filter string) ([]types.Silence, error) {
	silenceResponse := alertmanagerSilenceResponse{}

	u := GetAlertmanagerURL("/api/v1/silences")
	u.RawQuery = "filter=" + url.QueryEscape(filter)

	res, err := http.Get(u.String())
	if err != nil {
		return []types.Silence{}, err
	}

	defer res.Body.Close()

	err = json.NewDecoder(res.Body).Decode(&silenceResponse)
	if err != nil {
		return []types.Silence{}, err
	}

	if silenceResponse.Status != "success" {
		return []types.Silence{}, fmt.Errorf("[%s] %s", silenceResponse.ErrorType, silenceResponse.Error)
	}

	return silenceResponse.Data, nil
}

func query(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
	var filterString = ""
	if len(*silenceQuery) == 1 {
		// If we only have one argument then it's possible that the user wants me to assume alertname=<arg>
		// Attempt to use the parser to pare the argument
		// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets prepend `alertname=` to the front
		_, err := parse.Matcher((*silenceQuery)[0])
		if err != nil {
			filterString = fmt.Sprintf("{alertname=%s}", (*silenceQuery)[0])
		} else {
			filterString = fmt.Sprintf("{%s}", strings.Join(*silenceQuery, ","))
		}
	} else if len(*silenceQuery) > 1 {
		filterString = fmt.Sprintf("{%s}", strings.Join(*silenceQuery, ","))
	}

	fetchedSilences, err := fetchSilences(filterString)
	if err != nil {
		return err
	}

	displaySilences := []types.Silence{}
	for _, silence := range fetchedSilences {
		// If we are only returning current silences and this one has already expired skip it
		if !*queryExpired && silence.EndsAt.Before(time.Now()) {
			continue
		}

		if int64(*queryWithin) > 0 && silence.EndsAt.After(time.Now().UTC().Add(*queryWithin)) {
			continue
		}

		displaySilences = append(displaySilences, silence)
	}

	if *silenceQuiet {
		for _, silence := range displaySilences {
			fmt.Println(silence.ID)
		}
	} else {
		formatter, found := format.Formatters[*output]
		if !found {
			return errors.New("unknown output formatter")
		}
		formatter.FormatSilences(displaySilences)
	}
	return nil
}
<commit_msg>Make --expired list only expired silences (#1176) (#1190)<commit_after>package cli

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

	"github.com/alecthomas/kingpin"
	"github.com/prometheus/alertmanager/cli/format"
	"github.com/prometheus/alertmanager/pkg/parse"
	"github.com/prometheus/alertmanager/types"
)

var (
	queryCmd     = silenceCmd.Command("query", "Query Alertmanager silences.").Default()
	queryExpired = queryCmd.Flag("expired", "Show expired silences instead of active").Bool()
	silenceQuery = queryCmd.Arg("matcher-groups", "Query filter").Strings()
	queryWithin  = queryCmd.Flag("within", "Show silences that will expire or have expired within a duration").Duration()
)

func init() {
	queryCmd.Action(query)
	longHelpText["silence query"] = `Query Alertmanager silences.

Amtool has a simplified prometheus query syntax, but contains robust support for
bash variable expansions. The non-option section of arguments constructs a list
of "Matcher Groups" that will be used to filter your query. The following
examples will attempt to show this behaviour in action:

amtool silence query alertname=foo node=bar

	This query will match all silences with the alertname=foo and node=bar label
	value pairs set.

amtool silence query foo node=bar

	If alertname is ommited and the first argument does not contain a '=' or a
	'=~' then it will be assumed to be the value of the alertname pair.

amtool silence query 'alertname=~foo.*'

	As well as direct equality, regex matching is also supported. The '=~' syntax
	(similar to prometheus) is used to represent a regex match. Regex matching
	can be used in combination with a direct match.

In addition to filtering by silence labels, one can also query for silences
that are due to expire soon with the "--within" parameter. In the event that
you want to preemptively act upon expiring silences by either fixing them or
extending them. For example:

amtool silence query --within 8h

gives all the silences due to expire within the next 8 hours. This syntax can
also be combined with the label based filtering above for more flexibility.`
}

func fetchSilences(filter string) ([]types.Silence, error) {
	silenceResponse := alertmanagerSilenceResponse{}

	u := GetAlertmanagerURL("/api/v1/silences")
	u.RawQuery = "filter=" + url.QueryEscape(filter)

	res, err := http.Get(u.String())
	if err != nil {
		return []types.Silence{}, err
	}

	defer res.Body.Close()

	err = json.NewDecoder(res.Body).Decode(&silenceResponse)
	if err != nil {
		return []types.Silence{}, err
	}

	if silenceResponse.Status != "success" {
		return []types.Silence{}, fmt.Errorf("[%s] %s", silenceResponse.ErrorType, silenceResponse.Error)
	}

	return silenceResponse.Data, nil
}

func query(element *kingpin.ParseElement, ctx *kingpin.ParseContext) error {
	var filterString = ""
	if len(*silenceQuery) == 1 {
		// If we only have one argument then it's possible that the user wants me to assume alertname=<arg>
		// Attempt to use the parser to pare the argument
		// If the parser fails then we likely don't have a (=|=~|!=|!~) so lets prepend `alertname=` to the front
		_, err := parse.Matcher((*silenceQuery)[0])
		if err != nil {
			filterString = fmt.Sprintf("{alertname=%s}", (*silenceQuery)[0])
		} else {
			filterString = fmt.Sprintf("{%s}", strings.Join(*silenceQuery, ","))
		}
	} else if len(*silenceQuery) > 1 {
		filterString = fmt.Sprintf("{%s}", strings.Join(*silenceQuery, ","))
	}

	fetchedSilences, err := fetchSilences(filterString)
	if err != nil {
		return err
	}

	displaySilences := []types.Silence{}
	for _, silence := range fetchedSilences {
		// skip expired silences if --expired is not set
		if !*queryExpired && silence.EndsAt.Before(time.Now()) {
			continue
		}
		// skip active silences if --expired is set
		if *queryExpired && silence.EndsAt.After(time.Now()) {
			continue
		}
		// skip active silences expiring after "--within"
		if !*queryExpired && int64(*queryWithin) > 0 && silence.EndsAt.After(time.Now().UTC().Add(*queryWithin)) {
			continue
		}
		// skip silences that expired before "--within"
		if *queryExpired && int64(*queryWithin) > 0 && silence.EndsAt.Before(time.Now().UTC().Add(-*queryWithin)) {
			continue
		}

		displaySilences = append(displaySilences, silence)
	}

	if *silenceQuiet {
		for _, silence := range displaySilences {
			fmt.Println(silence.ID)
		}
	} else {
		formatter, found := format.Formatters[*output]
		if !found {
			return errors.New("unknown output formatter")
		}
		formatter.FormatSilences(displaySilences)
	}
	return nil
}
<|endoftext|>