<commit_before>package proxy

import (
	"crypto/tls"
	"net"
	"net/http"
	"regexp"
	"strings"

	"github.com/fsouza/go-dockerclient"
	. "github.com/weaveworks/weave/common"
)

const (
	defaultCaFile   = "ca.pem"
	defaultKeyFile  = "key.pem"
	defaultCertFile = "cert.pem"
)

var (
	containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
	containerStartRegexp  = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
	execCreateRegexp      = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/exec$")
)

type Config struct {
	ListenAddr    string
	NoDefaultIPAM bool
	TLSConfig     TLSConfig
	Version       string
	WithDNS       bool
	WithoutDNS    bool
}

type Proxy struct {
	Config
	client         *docker.Client
	dockerBridgeIP string
}

func NewProxy(c Config) (*Proxy, error) {
	p := &Proxy{Config: c}

	if !p.WithoutDNS {
		dockerBridgeIP, err := callWeave("docker-bridge-ip")
		if err != nil {
			return nil, err
		}
		p.dockerBridgeIP = string(dockerBridgeIP)
	}

	if err := p.TLSConfig.loadCerts(); err != nil {
		Error.Fatalf("Could not configure tls for proxy: %s", err)
	}

	client, err := docker.NewClient("unix:///var/run/docker.sock")
	if err != nil {
		return nil, err
	}
	p.client = client
	return p, nil
}

func (proxy *Proxy) Dial() (net.Conn, error) {
	return net.Dial("unix", "/var/run/docker.sock")
}

func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	Info.Printf("%s %s", r.Method, r.URL)
	path := r.URL.Path
	var i interceptor
	switch {
	case containerCreateRegexp.MatchString(path):
		i = &createContainerInterceptor{proxy}
	case containerStartRegexp.MatchString(path):
		i = &startContainerInterceptor{proxy}
	case execCreateRegexp.MatchString(path):
		i = &createExecInterceptor{proxy}
	default:
		i = &nullInterceptor{}
	}
	proxy.Intercept(i, w, r)
}

func (proxy *Proxy) ListenAndServe() error {
	listener, err := net.Listen("tcp", proxy.ListenAddr)
	if err != nil {
		return err
	}

	if proxy.TLSConfig.enabled() {
		listener = tls.NewListener(listener, proxy.TLSConfig.Config)
	}

	Info.Println("proxy listening on", proxy.ListenAddr)

	return (&http.Server{Handler: proxy}).Serve(listener)
}

func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) {
	for _, e := range config.Env {
		if strings.HasPrefix(e, "WEAVE_CIDR=") {
			if e[11:] == "none" {
				return nil, false
			}
			return strings.Fields(e[11:]), true
		}
	}
	return nil, !proxy.NoDefaultIPAM
}
<commit_msg>refactor(ish): get the more fundamental setup out of the way first<commit_after>package proxy

import (
	"crypto/tls"
	"net"
	"net/http"
	"regexp"
	"strings"

	"github.com/fsouza/go-dockerclient"
	. "github.com/weaveworks/weave/common"
)

const (
	defaultCaFile   = "ca.pem"
	defaultKeyFile  = "key.pem"
	defaultCertFile = "cert.pem"
)

var (
	containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
	containerStartRegexp  = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
	execCreateRegexp      = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/exec$")
)

type Config struct {
	ListenAddr    string
	NoDefaultIPAM bool
	TLSConfig     TLSConfig
	Version       string
	WithDNS       bool
	WithoutDNS    bool
}

type Proxy struct {
	Config
	client         *docker.Client
	dockerBridgeIP string
}

func NewProxy(c Config) (*Proxy, error) {
	p := &Proxy{Config: c}

	if err := p.TLSConfig.loadCerts(); err != nil {
		Error.Fatalf("Could not configure tls for proxy: %s", err)
	}

	client, err := docker.NewClient("unix:///var/run/docker.sock")
	if err != nil {
		return nil, err
	}
	p.client = client

	if !p.WithoutDNS {
		dockerBridgeIP, err := callWeave("docker-bridge-ip")
		if err != nil {
			return nil, err
		}
		p.dockerBridgeIP = string(dockerBridgeIP)
	}

	return p, nil
}

func (proxy *Proxy) Dial() (net.Conn, error) {
	return net.Dial("unix", "/var/run/docker.sock")
}

func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	Info.Printf("%s %s", r.Method, r.URL)
	path := r.URL.Path
	var i interceptor
	switch {
	case containerCreateRegexp.MatchString(path):
		i = &createContainerInterceptor{proxy}
	case containerStartRegexp.MatchString(path):
		i = &startContainerInterceptor{proxy}
	case execCreateRegexp.MatchString(path):
		i = &createExecInterceptor{proxy}
	default:
		i = &nullInterceptor{}
	}
	proxy.Intercept(i, w, r)
}

func (proxy *Proxy) ListenAndServe() error {
	listener, err := net.Listen("tcp", proxy.ListenAddr)
	if err != nil {
		return err
	}

	if proxy.TLSConfig.enabled() {
		listener = tls.NewListener(listener, proxy.TLSConfig.Config)
	}

	Info.Println("proxy listening on", proxy.ListenAddr)

	return (&http.Server{Handler: proxy}).Serve(listener)
}

func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) {
	for _, e := range config.Env {
		if strings.HasPrefix(e, "WEAVE_CIDR=") {
			if e[11:] == "none" {
				return nil, false
			}
			return strings.Fields(e[11:]), true
		}
	}
	return nil, !proxy.NoDefaultIPAM
}
<|endoftext|>


<commit_before>// Copyright 2018 Adam Tauber
//
// 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 proxy

import (
	"context"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/gocolly/colly/v2"
)

type roundRobinSwitcher struct {
	proxyURLs []*url.URL
	index     uint32
}

func (r *roundRobinSwitcher) GetProxy(pr *http.Request) (*url.URL, error) {
	index := atomic.AddUint32(&r.index, 1) - 1
	u := r.proxyURL[index%uint32(len(r.proxyURLs))]

	ctx := context.WithValue(pr.Context(), colly.ProxyURLKey, u.String())
	*pr = *pr.WithContext(ctx)
	return u, nil
}

// RoundRobinProxySwitcher creates a proxy switcher function which rotates
// ProxyURLs on every request.
// The proxy type is determined by the URL scheme. "http", "https"
// and "socks5" are supported. If the scheme is empty,
// "http" is assumed.
func RoundRobinProxySwitcher(ProxyURLs ...string) (colly.ProxyFunc, error) {
	if len(ProxyURLs) < 1 {
		return nil, colly.ErrEmptyProxyURL
	}
	urls := make([]*url.URL, len(ProxyURLs))
	for i, u := range ProxyURLs {
		parsedU, err := url.Parse(u)
		if err != nil {
			return nil, err
		}
		urls[i] = parsedU
	}
	var mutex sync.Mutex
	return (&roundRobinSwitcher{urls, 0}).GetProxy, nil
}
<commit_msg>Update proxy.go<commit_after>// Copyright 2018 Adam Tauber
//
// 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 proxy

import (
	"context"
	"net/http"
	"net/url"
	"sync/atomic"

	"github.com/gocolly/colly/v2"
)

type roundRobinSwitcher struct {
	proxyURLs []*url.URL
	index     uint32
}

func (r *roundRobinSwitcher) GetProxy(pr *http.Request) (*url.URL, error) {
	index := atomic.AddUint32(&r.index, 1) - 1
	u := r.proxyURL[index%uint32(len(r.proxyURLs))]

	ctx := context.WithValue(pr.Context(), colly.ProxyURLKey, u.String())
	*pr = *pr.WithContext(ctx)
	return u, nil
}

// RoundRobinProxySwitcher creates a proxy switcher function which rotates
// ProxyURLs on every request.
// The proxy type is determined by the URL scheme. "http", "https"
// and "socks5" are supported. If the scheme is empty,
// "http" is assumed.
func RoundRobinProxySwitcher(ProxyURLs ...string) (colly.ProxyFunc, error) {
	if len(ProxyURLs) < 1 {
		return nil, colly.ErrEmptyProxyURL
	}
	urls := make([]*url.URL, len(ProxyURLs))
	for i, u := range ProxyURLs {
		parsedU, err := url.Parse(u)
		if err != nil {
			return nil, err
		}
		urls[i] = parsedU
	}
	return (&roundRobinSwitcher{urls, 0}).GetProxy, nil
}
<|endoftext|>


<commit_before>package proxy

import (
	disc "github.com/jeffjen/go-discovery"
	"github.com/jeffjen/go-libkv/libkv"
	"github.com/jeffjen/go-proxy/proxy"

	log "github.com/Sirupsen/logrus"
	etcd "github.com/coreos/etcd/client"
	ctx "golang.org/x/net/context"

	"encoding/json"
)

var (
	ProxyConfigKey string

	ConfigReset ctx.CancelFunc

	retry = &proxy.Backoff{}
)

func parse(spec string) (*Info, error) {
	var i = new(Info)
	if err := json.Unmarshal([]byte(spec), i); err != nil {
		return nil, err
	}
	if i.Name == "" {
		return nil, ErrMissingName
	}
	return i, nil
}

func get(value string) (targets []*Info) {
	targets = make([]*Info, 0)
	if err := json.Unmarshal([]byte(value), &targets); err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bad proxy spec")
		targets = nil
	}
	return
}

func doReload(pxycfg []*Info) {
	it, mod := Store.IterateW()
	for elem := range it {
		mod <- &libkv.Value{R: true}
		elem.X.(*Info).Cancel()
	}
	for _, spec := range Targets {
		meta, err := parse(spec)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Warning("reload")
			continue
		}
		if err = Listen(meta); err != nil {
			if err != ErrProxyExist {
				log.WithFields(log.Fields{"err": err}).Debug("reload")
			}
		}
	}
	for _, meta := range pxycfg {
		if err := Listen(meta); err != nil {
			if err != ErrProxyExist {
				log.WithFields(log.Fields{"err": err}).Debug("reload")
			}
		}
	}
}

func reloadWorker() chan<- []*Info {
	order := make(chan []*Info)
	go func() {
		for o := range order {
			doReload(o)
		}
	}()
	return order
}

func doWatch(c ctx.Context, watcher etcd.Watcher) <-chan []*Info {
	v := make(chan []*Info)
	go func() {
		evt, err := watcher.Next(c)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Debug("config")
			retry.Delay()
			v <- nil
		} else {
			retry.Reset()
			if evt.Node.Dir {
				log.WithFields(log.Fields{"key": evt.Node.Key}).Warning("not a valid node")
				v <- nil
			} else {
				// FIXME: check that is is not a del or expire
				v <- get(evt.Node.Value)
			}
		}
	}()
	return v
}

func followBootStrap() {
	cfg := etcd.Config{Endpoints: disc.Endpoints()}
	kAPI, err := proxy.NewKeysAPI(cfg)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bootstrap")
		return
	}
	resp, err := kAPI.Get(RootContext, ProxyConfigKey, nil)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bootstrap")
		doReload(make([]*Info, 0))
	} else if resp.Node.Dir {
		log.WithFields(log.Fields{"key": resp.Node.Key}).Warning("not a valid node")
		doReload(make([]*Info, 0))
	} else {
		doReload(get(resp.Node.Value))
	}
}

func Follow() {
	followBootStrap() // bootstrap proxy config

	var c ctx.Context

	c, ConfigReset = ctx.WithCancel(RootContext)
	go func() {
		cfg := etcd.Config{Endpoints: disc.Endpoints()}
		watcher, err := proxy.NewWatcher(cfg, ProxyConfigKey, 0)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Warning("config")
			return
		}
		order := reloadWorker()
		defer close(order)
		for yay := true; yay; {
			v := doWatch(c, watcher)
			select {
			case <-c.Done():
				yay = false
			case proxyTargets, ok := <-v:
				if ok && proxyTargets != nil {
					order <- proxyTargets
				}
				yay = ok
			}
		}
	}()
}
<commit_msg>NIT: log cfg key and value<commit_after>package proxy

import (
	disc "github.com/jeffjen/go-discovery"
	"github.com/jeffjen/go-libkv/libkv"
	"github.com/jeffjen/go-proxy/proxy"

	log "github.com/Sirupsen/logrus"
	etcd "github.com/coreos/etcd/client"
	ctx "golang.org/x/net/context"

	"encoding/json"
)

var (
	ProxyConfigKey string

	ConfigReset ctx.CancelFunc

	retry = &proxy.Backoff{}
)

func parse(spec string) (*Info, error) {
	var i = new(Info)
	if err := json.Unmarshal([]byte(spec), i); err != nil {
		return nil, err
	}
	if i.Name == "" {
		return nil, ErrMissingName
	}
	return i, nil
}

func get(value string) (targets []*Info) {
	targets = make([]*Info, 0)
	if err := json.Unmarshal([]byte(value), &targets); err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bad proxy spec")
		targets = nil
	}
	return
}

func doReload(pxycfg []*Info) {
	it, mod := Store.IterateW()
	for elem := range it {
		mod <- &libkv.Value{R: true}
		elem.X.(*Info).Cancel()
	}
	for _, spec := range Targets {
		meta, err := parse(spec)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Warning("reload")
			continue
		}
		if err = Listen(meta); err != nil {
			if err != ErrProxyExist {
				log.WithFields(log.Fields{"err": err}).Debug("reload")
			}
		}
	}
	for _, meta := range pxycfg {
		if err := Listen(meta); err != nil {
			if err != ErrProxyExist {
				log.WithFields(log.Fields{"err": err}).Debug("reload")
			}
		}
	}
}

func reloadWorker() chan<- []*Info {
	order := make(chan []*Info)
	go func() {
		for o := range order {
			doReload(o)
		}
	}()
	return order
}

func doWatch(c ctx.Context, watcher etcd.Watcher) <-chan []*Info {
	v := make(chan []*Info)
	go func() {
		evt, err := watcher.Next(c)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Debug("config")
			retry.Delay()
			v <- nil
		} else {
			retry.Reset()
			if evt.Node.Dir {
				log.WithFields(log.Fields{"key": evt.Node.Key}).Warning("not a valid node")
				v <- nil
			} else {
				// FIXME: check that is is not a del or expire
				v <- get(evt.Node.Value)
			}
		}
	}()
	return v
}

func followBootStrap() {
	cfg := etcd.Config{Endpoints: disc.Endpoints()}
	kAPI, err := proxy.NewKeysAPI(cfg)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bootstrap")
		return
	}
	resp, err := kAPI.Get(RootContext, ProxyConfigKey, nil)
	if err != nil {
		log.WithFields(log.Fields{"err": err}).Warning("bootstrap")
		doReload(make([]*Info, 0))
	} else if resp.Node.Dir {
		log.WithFields(log.Fields{"key": resp.Node.Key}).Warning("not a valid node")
		doReload(make([]*Info, 0))
	} else {
		log.WithFields(log.Fields{"key": resp.Node.Key, "val": resp.Node.Value}).Debug("cfgkey")
		doReload(get(resp.Node.Value))
	}
}

func Follow() {
	followBootStrap() // bootstrap proxy config

	var c ctx.Context

	c, ConfigReset = ctx.WithCancel(RootContext)
	go func() {
		cfg := etcd.Config{Endpoints: disc.Endpoints()}
		watcher, err := proxy.NewWatcher(cfg, ProxyConfigKey, 0)
		if err != nil {
			log.WithFields(log.Fields{"err": err}).Warning("config")
			return
		}
		order := reloadWorker()
		defer close(order)
		for yay := true; yay; {
			v := doWatch(c, watcher)
			select {
			case <-c.Done():
				yay = false
			case proxyTargets, ok := <-v:
				if ok && proxyTargets != nil {
					order <- proxyTargets
				}
				yay = ok
			}
		}
	}()
}
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
)

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type systemMessage struct {
	level  systemMessageLevel
	line   int
	source string
	items  []item
}

type sectionLevel struct {
	char     rune // The adornment character used to describe the section
	overline bool // The section contains an overline
	length   int  // The length of the adornment lines
}

type sectionLevels []sectionLevel

func (s *sectionLevels) String() string {
	var out string
	for lvl, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			lvl+1, sec.char, sec.overline, sec.length)
	}
	return out
}

func (s *sectionLevels) Add(adornChar rune, overline bool, length int) int {
	lvl := s.Find(adornChar)
	if lvl > 0 {
		return lvl
	}
	*s = append(*s, sectionLevel{char: adornChar, overline: overline, length: length})
	return len(*s)
}

// Returns -1 if not found
func (s *sectionLevels) Find(adornChar rune) int {
	for lvl, sec := range *s {
		if sec.char == adornChar {
			return lvl + 1
		}
	}
	return -1
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{Name: name, sectionLevels: new(sectionLevels)}
}

type Tree struct {
	Name          string
	Nodes         *NodeList // The root node list
	Errors        []error
	text          string
	branch        *NodeList // The current branch to add nodes to
	lex           *lexer
	peekCount     int
	token         [3]item        // three-token look-ahead for parser.
	sectionLevel  int            // The current section level of parsing
	sectionLevels *sectionLevels // Encountered section levels
	id            int            // The unique id of the node in the tree
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.Nodes = nil
	t.branch = nil
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.Nodes = newList()
	t.branch = newList()

	for t.peek().Type != itemEOF {
		var n Node
		switch token := t.next(); token.Type {
		case itemTitle: // Section includes overline/underline
			n = t.section(token)
		case itemBlankLine:
			n = newBlankLine(token, &t.id)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		}

		if len([]Node(*t.Nodes)) == 0 {
			t.Nodes.append(n)
		} else {
			t.branch.append(n)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() {
	t.peekCount++
}

// peekBack returns the last item sent from the lexer.
func (t *Tree) peekBack() item {
	return *t.lex.lastItem
}

// peek returns but does not consume the next token.
func (t *Tree) peek() item {
	if t.peekCount > 0 {
		return t.token[t.peekCount-1]

	}
	t.peekCount = 1
	t.token[0] = t.lex.nextItem()
	return t.token[0]
}

func (t *Tree) next() item {
	if t.peekCount > 0 {
		t.peekCount--
	} else {
		t.token[0] = t.lex.nextItem()
	}
	return t.token[t.peekCount]
}

func (t *Tree) section(i item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn item
	var overline bool

	if t.peekBack().Type == itemSectionAdornment {
		overline = true
		overAdorn = t.peekBack()
	}

	title = i
	underAdorn = t.next() // Grab the section underline

	// Check adornment for proper syntax
	if title.Length != underAdorn.Length {
		t.errorf("Section under line  not equal to title length!")
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	// Check section levels to make sure the order of sections seen has not been violated
	if level := t.sectionLevels.Find(rune(underAdorn.Text.(string)[0])); level > 0 {
		if t.sectionLevel == t.sectionLevels.Level() {
			t.sectionLevel++
		} else {
			// The current section level of the parser does not match the previously
			// found section level. This means the user has used incorrect section
			// syntax.
			t.errorf("Incorrect section adornment \"%q\" for section level %d",
				underAdorn.Text.(string)[0], t.sectionLevel)
		}
	} else {
		t.sectionLevel++
	}

	t.sectionLevels.Add(rune(underAdorn.Text.(string)[0]), overline, len(underAdorn.Text.(string)))
	ret := newSection(title, &t.id, t.sectionLevel, overAdorn, underAdorn)
	t.branch = &ret.NodeList

	log.Debugln("End")
	return ret
}
<commit_msg>parse.go: Add newline to t.errorf format<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"fmt"
	"github.com/demizer/go-elog"
)

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type systemMessage struct {
	level  systemMessageLevel
	line   int
	source string
	items  []item
}

type sectionLevel struct {
	char     rune // The adornment character used to describe the section
	overline bool // The section contains an overline
	length   int  // The length of the adornment lines
}

type sectionLevels []sectionLevel

func (s *sectionLevels) String() string {
	var out string
	for lvl, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			lvl+1, sec.char, sec.overline, sec.length)
	}
	return out
}

func (s *sectionLevels) Add(adornChar rune, overline bool, length int) int {
	lvl := s.Find(adornChar)
	if lvl > 0 {
		return lvl
	}
	*s = append(*s, sectionLevel{char: adornChar, overline: overline, length: length})
	return len(*s)
}

// Returns -1 if not found
func (s *sectionLevels) Find(adornChar rune) int {
	for lvl, sec := range *s {
		if sec.char == adornChar {
			return lvl + 1
		}
	}
	return -1
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{Name: name, sectionLevels: new(sectionLevels)}
}

type Tree struct {
	Name          string
	Nodes         *NodeList // The root node list
	Errors        []error
	text          string
	branch        *NodeList // The current branch to add nodes to
	lex           *lexer
	peekCount     int
	token         [3]item        // three-token look-ahead for parser.
	sectionLevel  int            // The current section level of parsing
	sectionLevels *sectionLevels // Encountered section levels
	id            int            // The unique id of the node in the tree
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.Nodes = nil
	t.branch = nil
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.Nodes = newList()
	t.branch = newList()

	for t.peek().Type != itemEOF {
		var n Node
		switch token := t.next(); token.Type {
		case itemTitle: // Section includes overline/underline
			n = t.section(token)
		case itemBlankLine:
			n = newBlankLine(token, &t.id)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		}

		if len([]Node(*t.Nodes)) == 0 {
			t.Nodes.append(n)
		} else {
			t.branch.append(n)
		}
	}

	log.Debugln("End")
}

func (t *Tree) backup() {
	t.peekCount++
}

// peekBack returns the last item sent from the lexer.
func (t *Tree) peekBack() item {
	return *t.lex.lastItem
}

// peek returns but does not consume the next token.
func (t *Tree) peek() item {
	if t.peekCount > 0 {
		return t.token[t.peekCount-1]

	}
	t.peekCount = 1
	t.token[0] = t.lex.nextItem()
	return t.token[0]
}

func (t *Tree) next() item {
	if t.peekCount > 0 {
		t.peekCount--
	} else {
		t.token[0] = t.lex.nextItem()
	}
	return t.token[t.peekCount]
}

func (t *Tree) section(i item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn item
	var overline bool

	if t.peekBack().Type == itemSectionAdornment {
		overline = true
		overAdorn = t.peekBack()
	}

	title = i
	underAdorn = t.next() // Grab the section underline

	// Check adornment for proper syntax
	if title.Length != underAdorn.Length {
		t.errorf("Section under line  not equal to title length!")
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	// Check section levels to make sure the order of sections seen has not been violated
	if level := t.sectionLevels.Find(rune(underAdorn.Text.(string)[0])); level > 0 {
		if t.sectionLevel == t.sectionLevels.Level() {
			t.sectionLevel++
		} else {
			// The current section level of the parser does not match the previously
			// found section level. This means the user has used incorrect section
			// syntax.
			t.errorf("Incorrect section adornment \"%q\" for section level %d",
				underAdorn.Text.(string)[0], t.sectionLevel)
		}
	} else {
		t.sectionLevel++
	}

	t.sectionLevels.Add(rune(underAdorn.Text.(string)[0]), overline, len(underAdorn.Text.(string)))
	ret := newSection(title, &t.id, t.sectionLevel, overAdorn, underAdorn)
	t.branch = &ret.NodeList

	log.Debugln("End")
	return ret
}
<|endoftext|>


<commit_before>package veneur

import (
	"testing"

	"fmt"
	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/samplers"
	"github.com/stripe/veneur/ssf"
)

func freshSSFMetric() *ssf.SSFSample {
	return &ssf.SSFSample{
		Metric:     0,
		Name:       "test.ssf_metric",
		Value:      5,
		Message:    "test_msg",
		Status:     0,
		SampleRate: 1,
		Tags: map[string]string{
			"tag1": "value1",
			"tag2": "value2",
		},
	}
}

func TestParserSSF(t *testing.T) {
	standardMetric := freshSSFMetric()
	m, _ := samplers.ParseMetricSSF(standardMetric)
	fmt.Printf("%v\n", m)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
}

func TestParserSSFGauge(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.Metric = ssf.SSFSample_GAUGE
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "gauge", m.Type, "Type")
}

func TestParserSSFSet(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.Metric = ssf.SSFSample_SET
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, standardMetric.Message, m.Value, "Value")
	assert.Equal(t, "set", m.Type, "Type")
}

func TestParserSSFWithTags(t *testing.T) {
	standardMetric := freshSSFMetric()
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, 2, len(m.Tags), "# of Tags")
}

func TestParserSSFWithSampleRate(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.SampleRate = 0.1
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
}

func TestParserSSFWithSampleRateAndTags(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.SampleRate = 0.1
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
	assert.Len(t, m.Tags, 2, "Tags")
}

func TestParser(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
}

func TestParserGauge(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|g"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "gauge", m.Type, "Type")
}

func TestParserHistogram(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|h"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "histogram", m.Type, "Type")
}

func TestParserTimer(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|ms"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "timer", m.Type, "Type")
}

func TestParserSet(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:foo|s"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, "foo", m.Value, "Value")
	assert.Equal(t, "set", m.Type, "Type")
}

func TestParserWithTags(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|#foo:bar,baz:gorch"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, 2, len(m.Tags), "# of Tags")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")
}

func TestParserWithSampleRate(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|@0.1"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")

	_, valueError = samplers.ParseMetric([]byte("a.b.c:1|g|@0.1"))
	assert.NoError(t, valueError, "Got errors when parsing")
}

func TestParserWithSampleRateAndTags(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|@0.1|#foo:bar,baz:gorch"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
	assert.Len(t, m.Tags, 2, "Tags")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")
}

func TestInvalidPackets(t *testing.T) {
	table := map[string]string{
		"foo":                                "1 colon",
		"foo:1":                              "1 pipe",
		"foo:1||":                            "metric type",
		"foo:|c|":                            "metric value",
		"this_is_a_bad_metric:nan|g|#shell":  "metric value",
		"this_is_a_bad_metric:NaN|g|#shell":  "metric value",
		"this_is_a_bad_metric:-inf|g|#shell": "metric value",
		"this_is_a_bad_metric:+inf|g|#shell": "metric value",
		"foo:1|foo|":                         "Invalid type",
		"foo:1|c||":                          "pipes",
		"foo:1|c|foo":                        "unknown section",
		"foo:1|c|@-0.1":                      ">0",
		"foo:1|c|@1.1":                       "<=1",
		"foo:1|c|@0.5|@0.2":                  "multiple sample rates",
		"foo:1|c|#foo|#bar":                  "multiple tag sections",
	}

	for packet, errContent := range table {
		_, err := samplers.ParseMetric([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestLocalOnlyEscape(t *testing.T) {
	m, err := samplers.ParseMetric([]byte("a.b.c:1|h|#veneurlocalonly,tag2:quacks"))
	assert.NoError(t, err, "should have no error parsing")
	assert.Equal(t, samplers.LocalOnly, m.Scope, "should have gotten local only metric")
	assert.NotContains(t, m.Tags, "veneurlocalonly", "veneurlocalonly should not actually be a tag")
	assert.Contains(t, m.Tags, "tag2:quacks", "tag2 should be preserved in the list of tags after removing magic tags")
}

func TestGlobalOnlyEscape(t *testing.T) {
	m, err := samplers.ParseMetric([]byte("a.b.c:1|h|#veneurglobalonly,tag2:quacks"))
	assert.NoError(t, err, "should have no error parsing")
	assert.Equal(t, samplers.GlobalOnly, m.Scope, "should have gotten local only metric")
	assert.NotContains(t, m.Tags, "veneurglobalonly", "veneurlocalonly should not actually be a tag")
	assert.Contains(t, m.Tags, "tag2:quacks", "tag2 should be preserved in the list of tags after removing magic tags")
}

func TestEvents(t *testing.T) {
	evt, err := samplers.ParseEvent([]byte("_e{3,3}:foo|bar|k:foos|s:test|t:success|p:low|#foo:bar,baz:qux|d:1136239445|h:example.com"))
	assert.NoError(t, err, "should have parsed correctly")
	assert.EqualValues(t, &samplers.UDPEvent{
		Title:       "foo",
		Text:        "bar",
		Timestamp:   1136239445,
		Aggregation: "foos",
		Source:      "test",
		AlertLevel:  "success",
		Priority:    "low",
		Tags:        []string{"foo:bar", "baz:qux"},
		Hostname:    "example.com",
	}, evt, "should have parsed event")

	table := map[string]string{
		"_e{4,3}:foo|bar":               "title length",
		"_e{3,4}:foo|bar":               "text length",
		"_e{3,3}:foo|bar|d:abc":         "date",
		"_e{3,3}:foo|bar|p:baz":         "priority",
		"_e{3,3}:foo|bar|t:baz":         "alert",
		"_e{3,3}:foo|bar|t:info|t:info": "multiple alert",
		"_e{3,3}:foo|bar||":             "pipe",
		"_e{3,0}:foo||":                 "text length",
		"_e{3,3}:foo":                   "text",
		"_e{3,3}":                       "colon",
	}
	for packet, errContent := range table {
		_, err := samplers.ParseEvent([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestServiceChecks(t *testing.T) {
	evt, err := samplers.ParseServiceCheck([]byte("_sc|foo.bar|0|d:1136239445|h:example.com"))
	assert.NoError(t, err, "should have parsed correctly")
	assert.EqualValues(t, &samplers.UDPServiceCheck{
		Name:      "foo.bar",
		Status:    0,
		Timestamp: 1136239445,
		Hostname:  "example.com",
	}, evt, "should have parsed event")

	table := map[string]string{
		"foo.bar|0":           "_sc",
		"_sc|foo.bar":         "status",
		"_sc|foo.bar|5":       "status",
		"_sc|foo.bar|0||":     "pipe",
		"_sc|foo.bar|0|d:abc": "date",
	}
	for packet, errContent := range table {
		_, err := samplers.ParseServiceCheck([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestEventMessageUnescape(t *testing.T) {
	packet := []byte("_e{3,15}:foo|foo\\nbar\\nbaz\\n")
	evt, err := samplers.ParseEvent(packet)
	assert.NoError(t, err, "Should have parsed correctly")
	assert.Equal(t, "foo\nbar\nbaz\n", evt.Text, "Should contain newline")
}

func TestServiceCheckMessageUnescape(t *testing.T) {
	packet := []byte("_sc|foo|0|m:foo\\nbar\\nbaz\\n")
	svcheck, err := samplers.ParseServiceCheck(packet)
	assert.NoError(t, err, "Should have parsed correctly")
	assert.Equal(t, "foo\nbar\nbaz\n", svcheck.Message, "Should contain newline")
}
<commit_msg>Remove debug prints<commit_after>package veneur

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stripe/veneur/samplers"
	"github.com/stripe/veneur/ssf"
)

func freshSSFMetric() *ssf.SSFSample {
	return &ssf.SSFSample{
		Metric:     0,
		Name:       "test.ssf_metric",
		Value:      5,
		Message:    "test_msg",
		Status:     0,
		SampleRate: 1,
		Tags: map[string]string{
			"tag1": "value1",
			"tag2": "value2",
		},
	}
}

func TestParserSSF(t *testing.T) {
	standardMetric := freshSSFMetric()
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
}

func TestParserSSFGauge(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.Metric = ssf.SSFSample_GAUGE
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "gauge", m.Type, "Type")
}

func TestParserSSFSet(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.Metric = ssf.SSFSample_SET
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, standardMetric.Message, m.Value, "Value")
	assert.Equal(t, "set", m.Type, "Type")
}

func TestParserSSFWithTags(t *testing.T) {
	standardMetric := freshSSFMetric()
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, 2, len(m.Tags), "# of Tags")
}

func TestParserSSFWithSampleRate(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.SampleRate = 0.1
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
}

func TestParserSSFWithSampleRateAndTags(t *testing.T) {
	standardMetric := freshSSFMetric()
	standardMetric.SampleRate = 0.1
	m, _ := samplers.ParseMetricSSF(standardMetric)
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, standardMetric.Name, m.Name, "Name")
	assert.Equal(t, float64(standardMetric.Value), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
	assert.Len(t, m.Tags, 2, "Tags")
}

func TestParser(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
}

func TestParserGauge(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|g"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "gauge", m.Type, "Type")
}

func TestParserHistogram(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|h"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "histogram", m.Type, "Type")
}

func TestParserTimer(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|ms"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "timer", m.Type, "Type")
}

func TestParserSet(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:foo|s"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, "foo", m.Value, "Value")
	assert.Equal(t, "set", m.Type, "Type")
}

func TestParserWithTags(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|#foo:bar,baz:gorch"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, 2, len(m.Tags), "# of Tags")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")
}

func TestParserWithSampleRate(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|@0.1"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")

	_, valueError = samplers.ParseMetric([]byte("a.b.c:1|g|@0.1"))
	assert.NoError(t, valueError, "Got errors when parsing")
}

func TestParserWithSampleRateAndTags(t *testing.T) {
	m, _ := samplers.ParseMetric([]byte("a.b.c:1|c|@0.1|#foo:bar,baz:gorch"))
	assert.NotNil(t, m, "Got nil metric!")
	assert.Equal(t, "a.b.c", m.Name, "Name")
	assert.Equal(t, float64(1), m.Value, "Value")
	assert.Equal(t, "counter", m.Type, "Type")
	assert.Equal(t, float32(0.1), m.SampleRate, "Sample Rate")
	assert.Len(t, m.Tags, 2, "Tags")

	_, valueError := samplers.ParseMetric([]byte("a.b.c:fart|c"))
	assert.NotNil(t, valueError, "No errors when parsing")
	assert.Contains(t, valueError.Error(), "Invalid number", "Invalid number error missing")
}

func TestInvalidPackets(t *testing.T) {
	table := map[string]string{
		"foo":                                "1 colon",
		"foo:1":                              "1 pipe",
		"foo:1||":                            "metric type",
		"foo:|c|":                            "metric value",
		"this_is_a_bad_metric:nan|g|#shell":  "metric value",
		"this_is_a_bad_metric:NaN|g|#shell":  "metric value",
		"this_is_a_bad_metric:-inf|g|#shell": "metric value",
		"this_is_a_bad_metric:+inf|g|#shell": "metric value",
		"foo:1|foo|":                         "Invalid type",
		"foo:1|c||":                          "pipes",
		"foo:1|c|foo":                        "unknown section",
		"foo:1|c|@-0.1":                      ">0",
		"foo:1|c|@1.1":                       "<=1",
		"foo:1|c|@0.5|@0.2":                  "multiple sample rates",
		"foo:1|c|#foo|#bar":                  "multiple tag sections",
	}

	for packet, errContent := range table {
		_, err := samplers.ParseMetric([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestLocalOnlyEscape(t *testing.T) {
	m, err := samplers.ParseMetric([]byte("a.b.c:1|h|#veneurlocalonly,tag2:quacks"))
	assert.NoError(t, err, "should have no error parsing")
	assert.Equal(t, samplers.LocalOnly, m.Scope, "should have gotten local only metric")
	assert.NotContains(t, m.Tags, "veneurlocalonly", "veneurlocalonly should not actually be a tag")
	assert.Contains(t, m.Tags, "tag2:quacks", "tag2 should be preserved in the list of tags after removing magic tags")
}

func TestGlobalOnlyEscape(t *testing.T) {
	m, err := samplers.ParseMetric([]byte("a.b.c:1|h|#veneurglobalonly,tag2:quacks"))
	assert.NoError(t, err, "should have no error parsing")
	assert.Equal(t, samplers.GlobalOnly, m.Scope, "should have gotten local only metric")
	assert.NotContains(t, m.Tags, "veneurglobalonly", "veneurlocalonly should not actually be a tag")
	assert.Contains(t, m.Tags, "tag2:quacks", "tag2 should be preserved in the list of tags after removing magic tags")
}

func TestEvents(t *testing.T) {
	evt, err := samplers.ParseEvent([]byte("_e{3,3}:foo|bar|k:foos|s:test|t:success|p:low|#foo:bar,baz:qux|d:1136239445|h:example.com"))
	assert.NoError(t, err, "should have parsed correctly")
	assert.EqualValues(t, &samplers.UDPEvent{
		Title:       "foo",
		Text:        "bar",
		Timestamp:   1136239445,
		Aggregation: "foos",
		Source:      "test",
		AlertLevel:  "success",
		Priority:    "low",
		Tags:        []string{"foo:bar", "baz:qux"},
		Hostname:    "example.com",
	}, evt, "should have parsed event")

	table := map[string]string{
		"_e{4,3}:foo|bar":               "title length",
		"_e{3,4}:foo|bar":               "text length",
		"_e{3,3}:foo|bar|d:abc":         "date",
		"_e{3,3}:foo|bar|p:baz":         "priority",
		"_e{3,3}:foo|bar|t:baz":         "alert",
		"_e{3,3}:foo|bar|t:info|t:info": "multiple alert",
		"_e{3,3}:foo|bar||":             "pipe",
		"_e{3,0}:foo||":                 "text length",
		"_e{3,3}:foo":                   "text",
		"_e{3,3}":                       "colon",
	}
	for packet, errContent := range table {
		_, err := samplers.ParseEvent([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestServiceChecks(t *testing.T) {
	evt, err := samplers.ParseServiceCheck([]byte("_sc|foo.bar|0|d:1136239445|h:example.com"))
	assert.NoError(t, err, "should have parsed correctly")
	assert.EqualValues(t, &samplers.UDPServiceCheck{
		Name:      "foo.bar",
		Status:    0,
		Timestamp: 1136239445,
		Hostname:  "example.com",
	}, evt, "should have parsed event")

	table := map[string]string{
		"foo.bar|0":           "_sc",
		"_sc|foo.bar":         "status",
		"_sc|foo.bar|5":       "status",
		"_sc|foo.bar|0||":     "pipe",
		"_sc|foo.bar|0|d:abc": "date",
	}
	for packet, errContent := range table {
		_, err := samplers.ParseServiceCheck([]byte(packet))
		assert.NotNil(t, err, "Should have gotten error parsing %q", packet)
		assert.Contains(t, err.Error(), errContent, "Error should have contained text")
	}
}

func TestEventMessageUnescape(t *testing.T) {
	packet := []byte("_e{3,15}:foo|foo\\nbar\\nbaz\\n")
	evt, err := samplers.ParseEvent(packet)
	assert.NoError(t, err, "Should have parsed correctly")
	assert.Equal(t, "foo\nbar\nbaz\n", evt.Text, "Should contain newline")
}

func TestServiceCheckMessageUnescape(t *testing.T) {
	packet := []byte("_sc|foo|0|m:foo\\nbar\\nbaz\\n")
	svcheck, err := samplers.ParseServiceCheck(packet)
	assert.NoError(t, err, "Should have parsed correctly")
	assert.Equal(t, "foo\nbar\nbaz\n", svcheck.Message, "Should contain newline")
}
<|endoftext|>


<commit_before>// +build tools

package tools

import (
	// See README.md before touching this file
	_ "github.com/cheekybits/genny"
	_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
	_ "github.com/goreleaser/goreleaser"
	_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
	_ "github.com/shurcooL/vfsgen/cmd/vfsgendev"
	_ "github.com/vektra/mockery/cmd/mockery"
)
<commit_msg>chore(tools): remove build constraint<commit_after>package tools

import (
	// See README.md before touching this file
	_ "github.com/cheekybits/genny"
	_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
	_ "github.com/goreleaser/goreleaser"
	_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
	_ "github.com/shurcooL/vfsgen/cmd/vfsgendev"
	_ "github.com/vektra/mockery/cmd/mockery"
)
<|endoftext|>


<commit_before>package travel

import (
	"fmt"
	"os"

	"github.com/akerl/speculate/creds"
	"github.com/akerl/speculate/executors"
	"github.com/akerl/timber/log"

	"github.com/akerl/voyager/cartogram"
	"github.com/akerl/voyager/profiles"
	"github.com/akerl/voyager/prompt"
)

var logger = log.NewLogger("voyager")

type hop struct {
	Profile string
	Account string
	Region  string
	Role    string
	Mfa     bool
	Policy  string
}

// Itinerary describes a travel request
type Itinerary struct {
	Args        []string
	RoleName    []string
	ProfileName []string
	SessionName string
	Policy      string
	Lifetime    int64
	MfaCode     string
	MfaSerial   string
	MfaPrompt   executors.MfaPrompt
	Prompt      prompt.Func
	Store       profiles.Store
	pack        *cartogram.Pack
}

// Travel loads creds from a full set of parameters
func (i *Itinerary) Travel() (creds.Creds, error) {
	return i.getCreds()
}

func (i *Itinerary) getStore() profiles.Store {
	if i.Store == nil {
		logger.InfoMsg("Using default profile store")
		i.Store = profiles.NewDefaultStore()
	}
	return i.Store
}

func (i *Itinerary) getPrompt() prompt.Func {
	if i.Prompt == nil {
		logger.InfoMsg("Using default prompt")
		i.Prompt = prompt.WithDefault
	}
	return i.Prompt
}

func (i *Itinerary) getPack() (cartogram.Pack, error) {
	if i.pack != nil {
		return *i.pack, nil
	}
	i.pack = &cartogram.Pack{}
	err := i.pack.Load()
	return *i.pack, err
}

func (i *Itinerary) getAccount() (cartogram.Account, error) {
	pack, err := i.getPack()
	if err != nil {
		return cartogram.Account{}, err
	}
	return pack.FindWithPrompt(i.Args, i.getPrompt())
}

func (i *Itinerary) getCreds() (creds.Creds, error) {
	var c creds.Creds
	var err error

	path, err := i.getPath()
	if err != nil {
		return c, err
	}

	err = clearEnvironment()
	if err != nil {
		return c, err
	}

	profileHop, stack := path[0], path[1:]
	logger.InfoMsg(fmt.Sprintf("Setting origin hop: %+v", profileHop))
	store := i.getStore()
	err = profiles.SetProfile(profileHop.Profile, store)
	if err != nil {
		return c, err
	}
	logger.InfoMsg(fmt.Sprintf("Setting AWS_DEFAULT_REGION to %s", profileHop.Region))
	err = os.Setenv("AWS_DEFAULT_REGION", profileHop.Region)
	if err != nil {
		return c, err
	}

	stack[len(stack)-1].Policy = i.Policy
	for _, thisHop := range stack {
		c, err = i.executeHop(thisHop, c)
		if err != nil {
			break
		}
	}
	return c, err
}

func clearEnvironment() error {
	for varName := range creds.Translations["envvar"] {
		logger.InfoMsg(fmt.Sprintf("Unsetting env var: %s", varName))
		err := os.Unsetenv(varName)
		if err != nil {
			return err
		}
	}
	return nil
}

//revive:disable-next-line:cyclomatic
func (i *Itinerary) executeHop(thisHop hop, c creds.Creds) (creds.Creds, error) {
	var newCreds creds.Creds
	logger.InfoMsg(fmt.Sprintf("Executing hop: %+v", thisHop))
	a := executors.Assumption{}
	if err := a.SetAccountID(thisHop.Account); err != nil {
		return newCreds, err
	}
	if err := a.SetRoleName(thisHop.Role); err != nil {
		return newCreds, err
	}
	if err := a.SetSessionName(i.SessionName); err != nil {
		return newCreds, err
	}
	if err := a.SetLifetime(i.Lifetime); err != nil {
		return newCreds, err
	}
	if err := a.SetPolicy(thisHop.Policy); err != nil {
		return newCreds, err
	}
	if thisHop.Mfa {
		if err := a.SetMfa(true); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaSerial(i.MfaSerial); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaCode(i.MfaCode); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaPrompt(i.MfaPrompt); err != nil {
			return newCreds, err
		}
	}
	newCreds, err := a.ExecuteWithCreds(c)
	newCreds.Region = thisHop.Region
	return newCreds, err
}

func (i *Itinerary) getPath() ([]hop, error) { //revive:disable-line:cyclomatic
	var paths [][]hop
	mapProfiles := make(map[string]bool)
	mapRoles := make(map[string]bool)

	account, err := i.getAccount()
	if err != nil {
		return []hop{}, err
	}

	for _, r := range account.Roles {
		p, err := i.tracePath(account, r)
		if err != nil {
			return []hop{}, err
		}
		for _, item := range p {
			paths = append(paths, item)
			mapRoles[item[len(item)-1].Role] = true
		}
	}

	allRoles := keys(mapRoles)
	role, err := i.getPrompt().Filtered(i.RoleName, allRoles, "Desired target role:")
	if err != nil {
		return []hop{}, err
	}
	hopsWithMatchingRoles := [][]hop{}
	for _, item := range paths {
		if item[len(item)-1].Role == role {
			hopsWithMatchingRoles = append(hopsWithMatchingRoles, item)
			mapProfiles[item[0].Profile] = true
		}
	}

	allProfiles := keys(mapProfiles)
	profile, err := i.getPrompt().Filtered(i.ProfileName, allProfiles, "Desired target profile:")
	if err != nil {
		return []hop{}, err
	}
	hopsWithMatchingProfiles := [][]hop{}
	for _, item := range hopsWithMatchingRoles {
		if item[0].Profile == profile {
			hopsWithMatchingProfiles = append(hopsWithMatchingProfiles, item)
		}
	}

	if len(hopsWithMatchingProfiles) > 1 {
		logger.InfoMsg("Multiple valid paths detected. Selecting the first option")
	}
	return hopsWithMatchingProfiles[0], nil
}

func (i *Itinerary) tracePath(acc cartogram.Account, role cartogram.Role) ([][]hop, error) {
	var srcHops [][]hop

	for _, item := range role.Sources {
		pathMatch := cartogram.AccountRegex.FindStringSubmatch(item.Path)
		if len(pathMatch) == 3 {
			err := i.testSourcePath(pathMatch[1], pathMatch[2], &srcHops)
			if err != nil {
				return [][]hop{}, err
			}
		} else {
			srcHops = append(srcHops, []hop{{
				Profile: item.Path,
				Region:  acc.Region,
			}})
		}
	}

	myHop := hop{
		Role:    role.Name,
		Account: acc.Account,
		Region:  acc.Region,
		Mfa:     role.Mfa,
	}

	for i := range srcHops {
		srcHops[i] = append(srcHops[i], myHop)
	}
	return srcHops, nil
}

func (i *Itinerary) testSourcePath(srcAccID, srcRoleName string, srcHops *[][]hop) error {
	ok, srcAcc := i.pack.Lookup(srcAccID)
	if !ok {
		logger.DebugMsg(fmt.Sprintf("Found dead end due to missing account: %s", srcAccID))
		return nil
	}
	ok, srcRole := srcAcc.Roles.Lookup(srcRoleName)
	if !ok {
		logger.DebugMsg(fmt.Sprintf(
			"Found dead end due to missing role: %s/%s", srcAccID, srcRoleName,
		))
		return nil
	}
	newPaths, err := i.tracePath(srcAcc, srcRole)
	if err != nil {
		return err
	}
	for _, np := range newPaths {
		*srcHops = append(*srcHops, np)
	}
	return nil
}

func keys(input map[string]bool) []string {
	list := []string{}
	for k := range input {
		list = append(list, k)
	}
	return list
}
<commit_msg>Fix/cleaner region setting (#12)<commit_after>package travel

import (
	"fmt"
	"os"

	"github.com/akerl/speculate/creds"
	"github.com/akerl/speculate/executors"
	"github.com/akerl/timber/log"

	"github.com/akerl/voyager/cartogram"
	"github.com/akerl/voyager/profiles"
	"github.com/akerl/voyager/prompt"
)

var logger = log.NewLogger("voyager")

type hop struct {
	Profile string
	Account string
	Region  string
	Role    string
	Mfa     bool
	Policy  string
}

// Itinerary describes a travel request
type Itinerary struct {
	Args        []string
	RoleName    []string
	ProfileName []string
	SessionName string
	Policy      string
	Lifetime    int64
	MfaCode     string
	MfaSerial   string
	MfaPrompt   executors.MfaPrompt
	Prompt      prompt.Func
	Store       profiles.Store
	pack        *cartogram.Pack
}

// Travel loads creds from a full set of parameters
func (i *Itinerary) Travel() (creds.Creds, error) {
	return i.getCreds()
}

func (i *Itinerary) getStore() profiles.Store {
	if i.Store == nil {
		logger.InfoMsg("Using default profile store")
		i.Store = profiles.NewDefaultStore()
	}
	return i.Store
}

func (i *Itinerary) getPrompt() prompt.Func {
	if i.Prompt == nil {
		logger.InfoMsg("Using default prompt")
		i.Prompt = prompt.WithDefault
	}
	return i.Prompt
}

func (i *Itinerary) getPack() (cartogram.Pack, error) {
	if i.pack != nil {
		return *i.pack, nil
	}
	i.pack = &cartogram.Pack{}
	err := i.pack.Load()
	return *i.pack, err
}

func (i *Itinerary) getAccount() (cartogram.Account, error) {
	pack, err := i.getPack()
	if err != nil {
		return cartogram.Account{}, err
	}
	return pack.FindWithPrompt(i.Args, i.getPrompt())
}

func (i *Itinerary) getCreds() (creds.Creds, error) {
	var c creds.Creds
	var err error

	path, err := i.getPath()
	if err != nil {
		return c, err
	}

	err = clearEnvironment()
	if err != nil {
		return c, err
	}

	profileHop, stack := path[0], path[1:]
	logger.InfoMsg(fmt.Sprintf("Setting origin hop: %+v", profileHop))
	store := i.getStore()
	err = profiles.SetProfile(profileHop.Profile, store)
	if err != nil {
		return c, err
	}

	stack[len(stack)-1].Policy = i.Policy
	for _, thisHop := range stack {
		c, err = i.executeHop(thisHop, c)
		if err != nil {
			break
		}
	}
	return c, err
}

func clearEnvironment() error {
	for varName := range creds.Translations["envvar"] {
		logger.InfoMsg(fmt.Sprintf("Unsetting env var: %s", varName))
		err := os.Unsetenv(varName)
		if err != nil {
			return err
		}
	}
	return nil
}

//revive:disable-next-line:cyclomatic
func (i *Itinerary) executeHop(thisHop hop, c creds.Creds) (creds.Creds, error) {
	var newCreds creds.Creds
	logger.InfoMsg(fmt.Sprintf("Executing hop: %+v", thisHop))
	a := executors.Assumption{}

	logger.InfoMsg(fmt.Sprintf("Setting AWS_DEFAULT_REGION to %s", thisHop.Region))
	err := os.Setenv("AWS_DEFAULT_REGION", thisHop.Region)
	if err != nil {
		return newCreds, err
	}

	if err := a.SetAccountID(thisHop.Account); err != nil {
		return newCreds, err
	}
	if err := a.SetRoleName(thisHop.Role); err != nil {
		return newCreds, err
	}
	if err := a.SetSessionName(i.SessionName); err != nil {
		return newCreds, err
	}
	if err := a.SetLifetime(i.Lifetime); err != nil {
		return newCreds, err
	}
	if err := a.SetPolicy(thisHop.Policy); err != nil {
		return newCreds, err
	}
	if thisHop.Mfa {
		if err := a.SetMfa(true); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaSerial(i.MfaSerial); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaCode(i.MfaCode); err != nil {
			return newCreds, err
		}
		if err := a.SetMfaPrompt(i.MfaPrompt); err != nil {
			return newCreds, err
		}
	}
	newCreds, err = a.ExecuteWithCreds(c)
	newCreds.Region = thisHop.Region
	return newCreds, err
}

func (i *Itinerary) getPath() ([]hop, error) { //revive:disable-line:cyclomatic
	var paths [][]hop
	mapProfiles := make(map[string]bool)
	mapRoles := make(map[string]bool)

	account, err := i.getAccount()
	if err != nil {
		return []hop{}, err
	}

	for _, r := range account.Roles {
		p, err := i.tracePath(account, r)
		if err != nil {
			return []hop{}, err
		}
		for _, item := range p {
			paths = append(paths, item)
			mapRoles[item[len(item)-1].Role] = true
		}
	}

	allRoles := keys(mapRoles)
	role, err := i.getPrompt().Filtered(i.RoleName, allRoles, "Desired target role:")
	if err != nil {
		return []hop{}, err
	}
	hopsWithMatchingRoles := [][]hop{}
	for _, item := range paths {
		if item[len(item)-1].Role == role {
			hopsWithMatchingRoles = append(hopsWithMatchingRoles, item)
			mapProfiles[item[0].Profile] = true
		}
	}

	allProfiles := keys(mapProfiles)
	profile, err := i.getPrompt().Filtered(i.ProfileName, allProfiles, "Desired target profile:")
	if err != nil {
		return []hop{}, err
	}
	hopsWithMatchingProfiles := [][]hop{}
	for _, item := range hopsWithMatchingRoles {
		if item[0].Profile == profile {
			hopsWithMatchingProfiles = append(hopsWithMatchingProfiles, item)
		}
	}

	if len(hopsWithMatchingProfiles) > 1 {
		logger.InfoMsg("Multiple valid paths detected. Selecting the first option")
	}
	return hopsWithMatchingProfiles[0], nil
}

func (i *Itinerary) tracePath(acc cartogram.Account, role cartogram.Role) ([][]hop, error) {
	var srcHops [][]hop

	for _, item := range role.Sources {
		pathMatch := cartogram.AccountRegex.FindStringSubmatch(item.Path)
		if len(pathMatch) == 3 {
			err := i.testSourcePath(pathMatch[1], pathMatch[2], &srcHops)
			if err != nil {
				return [][]hop{}, err
			}
		} else {
			srcHops = append(srcHops, []hop{{
				Profile: item.Path,
			}})
		}
	}

	myHop := hop{
		Role:    role.Name,
		Account: acc.Account,
		Region:  acc.Region,
		Mfa:     role.Mfa,
	}

	for i := range srcHops {
		srcHops[i] = append(srcHops[i], myHop)
	}
	return srcHops, nil
}

func (i *Itinerary) testSourcePath(srcAccID, srcRoleName string, srcHops *[][]hop) error {
	ok, srcAcc := i.pack.Lookup(srcAccID)
	if !ok {
		logger.DebugMsg(fmt.Sprintf("Found dead end due to missing account: %s", srcAccID))
		return nil
	}
	ok, srcRole := srcAcc.Roles.Lookup(srcRoleName)
	if !ok {
		logger.DebugMsg(fmt.Sprintf(
			"Found dead end due to missing role: %s/%s", srcAccID, srcRoleName,
		))
		return nil
	}
	newPaths, err := i.tracePath(srcAcc, srcRole)
	if err != nil {
		return err
	}
	for _, np := range newPaths {
		*srcHops = append(*srcHops, np)
	}
	return nil
}

func keys(input map[string]bool) []string {
	list := []string{}
	for k := range input {
		list = append(list, k)
	}
	return list
}
<|endoftext|>


<commit_before>package otto

import (
	"fmt"
	"regexp"
	"strings"
)

type _regExpObject struct {
	RegularExpression *regexp.Regexp
	Global bool
	IgnoreCase bool
	Multiline bool
	Source string
	LastIndex Value
}

func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object {
	self := runtime.newObject()
	self.class = "RegExp"

	global := false
	ignoreCase := false
	multiline := false
	re2flags := ""

	for _, rune := range flags {
		switch rune {
		case 'g':
			if global {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			global = true
		case 'm':
			if multiline {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			multiline = true
		case 'i':
			if ignoreCase {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			ignoreCase = true
			re2flags += "i"
		}
	}

	re2pattern := transformRegExp(pattern)
	if len(re2flags) > 0 {
		re2pattern = fmt.Sprintf("(?%s:%s)", re2flags, re2pattern)
	}

	regularExpression, err := regexp.Compile(re2pattern)
	if err != nil {
		panic(newSyntaxError("Invalid regular expression: %s", err.Error()[22:]))
	}

	self._RegExp = &_regExpObject{
		RegularExpression: regularExpression,
		Global: global,
		IgnoreCase: ignoreCase,
		Multiline: multiline,
		Source: pattern,
		LastIndex: toValue(0),
	}
	self.stash = newRegExpStash(self._RegExp, self.stash)
	return self
}

func execRegExp(this *_object, target string) (match bool, result []int) {
	lastIndex := toInteger(this.get("lastIndex"))
	index := lastIndex
	global := toBoolean(this.get("global"))
	if !global {
		index = 0
	}
	if 0 > index || index > int64(len(target)) {
	} else {
		result = this._RegExp.RegularExpression.FindStringSubmatchIndex(target[index:])
	}
	if result == nil {
		this.set("lastIndex", toValue(0), true)
		return // !match
	}
	match = true
	endIndex := int(lastIndex) + result[1]
	if global {
		this.set("lastIndex", toValue(endIndex), true)
	}
	return // match
}

func execResultToArray(runtime *_runtime, target string, result []int) *_object {
	captureCount := len(result) / 2
	valueArray := make([]Value, captureCount)
	for index := 0; index < captureCount; index++ {
		offset := 2 * index
		if result[offset] != -1 {
			valueArray[index] = toValue(target[result[offset]:result[offset+1]])
		} else {
			valueArray[index] = UndefinedValue()
		}
	}
	return runtime.newArray(valueArray)
}

// 0031,0032,0033,0034,0035,0036,0037,0038,0039 // 1 - 9
// 0043,0045,0046,0047,0048,0049,004A,004B,004C,004D,004E,004F
// 0050,0052,0054,0055,0056,0058,0059,005A
// 0063,0065,0067,0068,0069,006A,006B,006C,006D,006F
// 0070,0071,0075,0078,0079
// 0080,0081,0082,0083,0084,0085,0086,0087,0088,0089,008A,008B,008C,008D,008E,008F
// 0090,0091,0092,0093,0094,0095,0096,0097,0098,0099,009A,009B,009C,009D,009E,009F
// 00A0,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A8,00A9,00AA,00AB,00AC,00AD,00AE,00AF
// 00B0,00B1,00B2,00B3,00B4,00B5,00B6,00B7,00B8,00B9,00BA,00BB,00BC,00BD,00BE,00BF
// 00C0,00C1,00C2,00C3,00C4,00C5,00C6,00C7,00C8,00C9,00CA,00CB,00CC,00CD,00CE,00CF
// ...
// c = 63* c[A-Z]
// p = 70
// u = 75* u[:xdigit:]{4}
// x = 78* x[:xdigit:]{2}
//\x{0031}-\x{0039}

var transformRegExp_matchSlashU = regexp.MustCompile(`\\u([[:xdigit:]]{1,4})`)
var transformRegExp_unescape = regexp.MustCompile(strings.NewReplacer("\n", "", "\t", "", " ", "").Replace(`

	(?:
		\\(
		[
			\x{0043}\x{0045}-\x{004F}
			\x{0050}\x{0052}\x{0054}-\x{0056}\x{0058}-\x{005A}
			\x{0065}\x{0067}-\x{006D}\x{006F}
			\x{0070}\x{0071}\x{0079}
			\x{0080}-\x{FFFF}
		]
		)()
	) |
	(?:
		\\(c)([^A-Z])
	) |
	(?:
		\\(u)([^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][:xdigit:][:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(x)([^[:xdigit:]])
	) |
	(?:
		\\(x)([:xdigit:][^[:xdigit:]])
	)

`))
var transformRegExp_unescapeDollar = regexp.MustCompile(strings.NewReplacer("\n", "", "\t", "", " ", "").Replace(`

	(?:
		\\([cux])$
	)

`))
// TODO Go "regexp" bug? Can't do: (?:)|(?:$)

func transformRegExp(ecmaRegExp string) (goRegExp string) {
	tmp := []byte(ecmaRegExp)
	tmp = transformRegExp_unescape.ReplaceAll(tmp, []byte(`$1$2`))
	tmp = transformRegExp_unescapeDollar.ReplaceAll(tmp, []byte(`$1`))
	tmp = transformRegExp_matchSlashU.ReplaceAll(tmp, []byte(`\x{$1}`))
	return string(tmp)
}

func isValidRegExp(ecmaRegExp string) bool {
	shibboleth := 0 // The shibboleth in this case is (?
					// Since we're looking for (?! / (?=
	inSet := false // In a bracketed set, e.g. [0-9]
	escape := false
	for _, chr := range ecmaRegExp {
		if escape {
			escape = false
			shibboleth = 0
			continue
		}
		if chr == '\\' {
			escape = true
			continue
		}
		if inSet {
			if chr == ']' {
				inSet = false
				shibboleth = 0
			}
			continue
		}
		switch chr {
		case '[':
			inSet = true
			continue
		case '(':
			shibboleth = 1
			continue
		case '?':
			if shibboleth == 1 {
				shibboleth = 2
			}
			continue
		case '=', '!':
			if shibboleth == 2 {
				return false
			}
		}
		shibboleth = 0
	}

	return true
}

// _regExpStash

type _regExpStash struct {
	_regExpObject *_regExpObject
	_stash
}

func newRegExpStash(_regExpObject *_regExpObject, stash _stash) *_regExpStash {
	self := &_regExpStash{
		_regExpObject,
		stash,
	}
	return self
}

func (self *_regExpStash) test(name string) bool {
	switch name {
	case "global", "ignoreCase", "multiline", "lastIndex", "source":
		return true
	}
	return self._stash.test(name)
}

func (self *_regExpStash) get(name string) Value {
	switch name {
	case "global":
		return toValue(self._regExpObject.Global)
	case "ignoreCase":
		return toValue(self._regExpObject.IgnoreCase)
	case "multiline":
		return toValue(self._regExpObject.Multiline)
	case "lastIndex":
		return self._regExpObject.LastIndex
	case "source":
		return toValue(self._regExpObject.Source)
	}
	return self._stash.get(name)
}

func (self *_regExpStash) put(name string, value Value) {
	switch name {
	case "global", "ignoreCase", "multiline", "source":
		// TODO Is this good enough? Check DefineOwnProperty
		panic(newTypeError())
	case "lastIndex":
		self._regExpObject.LastIndex = value
		return
	}
	self._stash.put(name, value)
}

func (self *_regExpStash) property(name string) *_property {
	switch name {
	case "global":
		return &_property{value: toValue(self._regExpObject.Global), mode: 0} // -Write -Enumerate -Configure
	case "ignoreCase":
		return &_property{value: toValue(self._regExpObject.IgnoreCase), mode: 0} // -Write -Enumerate -Configure
	case "multiline":
		return &_property{value: toValue(self._regExpObject.Multiline), mode: 0} // -Write -Enumerate -Configure
	case "lastIndex":
		return &_property{value: (self._regExpObject.LastIndex), mode: 0100} // +Write -Enumerate -Configure
	case "source":
		return &_property{value: toValue(self._regExpObject.Source), mode: 0} // -Write -Enumerate -Configure
	}
	return self._stash.property(name)
}

func (self *_regExpStash) enumerate(each func(string)) {
	// Skip global, ignoreCase, multiline, source, & lastIndex
	self._stash.enumerate(each)
}
<commit_msg>Expand \c replacement range to include a-z ([A-Za-z])<commit_after>package otto

import (
	"fmt"
	"regexp"
	"strings"
)

type _regExpObject struct {
	RegularExpression *regexp.Regexp
	Global bool
	IgnoreCase bool
	Multiline bool
	Source string
	LastIndex Value
}

func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object {
	self := runtime.newObject()
	self.class = "RegExp"

	global := false
	ignoreCase := false
	multiline := false
	re2flags := ""

	for _, rune := range flags {
		switch rune {
		case 'g':
			if global {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			global = true
		case 'm':
			if multiline {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			multiline = true
		case 'i':
			if ignoreCase {
				panic(newError("SyntaxError: newRegExpObject: %s %s", pattern, flags))
			}
			ignoreCase = true
			re2flags += "i"
		}
	}

	re2pattern := transformRegExp(pattern)
	if len(re2flags) > 0 {
		re2pattern = fmt.Sprintf("(?%s:%s)", re2flags, re2pattern)
	}

	regularExpression, err := regexp.Compile(re2pattern)
	if err != nil {
		panic(newSyntaxError("Invalid regular expression: %s", err.Error()[22:]))
	}

	self._RegExp = &_regExpObject{
		RegularExpression: regularExpression,
		Global: global,
		IgnoreCase: ignoreCase,
		Multiline: multiline,
		Source: pattern,
		LastIndex: toValue(0),
	}
	self.stash = newRegExpStash(self._RegExp, self.stash)
	return self
}

func execRegExp(this *_object, target string) (match bool, result []int) {
	lastIndex := toInteger(this.get("lastIndex"))
	index := lastIndex
	global := toBoolean(this.get("global"))
	if !global {
		index = 0
	}
	if 0 > index || index > int64(len(target)) {
	} else {
		result = this._RegExp.RegularExpression.FindStringSubmatchIndex(target[index:])
	}
	if result == nil {
		this.set("lastIndex", toValue(0), true)
		return // !match
	}
	match = true
	endIndex := int(lastIndex) + result[1]
	if global {
		this.set("lastIndex", toValue(endIndex), true)
	}
	return // match
}

func execResultToArray(runtime *_runtime, target string, result []int) *_object {
	captureCount := len(result) / 2
	valueArray := make([]Value, captureCount)
	for index := 0; index < captureCount; index++ {
		offset := 2 * index
		if result[offset] != -1 {
			valueArray[index] = toValue(target[result[offset]:result[offset+1]])
		} else {
			valueArray[index] = UndefinedValue()
		}
	}
	return runtime.newArray(valueArray)
}

// 0031,0032,0033,0034,0035,0036,0037,0038,0039 // 1 - 9
// 0043,0045,0046,0047,0048,0049,004A,004B,004C,004D,004E,004F
// 0050,0052,0054,0055,0056,0058,0059,005A
// 0063,0065,0067,0068,0069,006A,006B,006C,006D,006F
// 0070,0071,0075,0078,0079
// 0080,0081,0082,0083,0084,0085,0086,0087,0088,0089,008A,008B,008C,008D,008E,008F
// 0090,0091,0092,0093,0094,0095,0096,0097,0098,0099,009A,009B,009C,009D,009E,009F
// 00A0,00A1,00A2,00A3,00A4,00A5,00A6,00A7,00A8,00A9,00AA,00AB,00AC,00AD,00AE,00AF
// 00B0,00B1,00B2,00B3,00B4,00B5,00B6,00B7,00B8,00B9,00BA,00BB,00BC,00BD,00BE,00BF
// 00C0,00C1,00C2,00C3,00C4,00C5,00C6,00C7,00C8,00C9,00CA,00CB,00CC,00CD,00CE,00CF
// ...
// c = 63* c[A-Z]
// p = 70
// u = 75* u[:xdigit:]{4}
// x = 78* x[:xdigit:]{2}
//\x{0031}-\x{0039}

var transformRegExp_matchSlashU = regexp.MustCompile(`\\u([[:xdigit:]]{1,4})`)
// ? Changing \\(c)([^A-Za-z]) to \\(c)([^A-Z]) causes ch15/15.10/15.10.2/15.10.2.10/S15.10.2.10_A2.1_T3.js to panic
var transformRegExp_unescape = regexp.MustCompile(strings.NewReplacer("\n", "", "\t", "", " ", "").Replace(`

	(?:
		\\(
		[
			\x{0043}\x{0045}-\x{004F}
			\x{0050}\x{0052}\x{0054}-\x{0056}\x{0058}-\x{005A}
			\x{0065}\x{0067}-\x{006D}\x{006F}
			\x{0070}\x{0071}\x{0079}
			\x{0080}-\x{FFFF}
		]
		)()
	) |
	(?:
		\\(c)([^A-Za-z])
	) |
	(?:
		\\(u)([^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(u)([:xdigit:][:xdigit:][:xdigit:][^[:xdigit:]])
	) |
	(?:
		\\(x)([^[:xdigit:]])
	) |
	(?:
		\\(x)([:xdigit:][^[:xdigit:]])
	)

`))
var transformRegExp_unescapeDollar = regexp.MustCompile(strings.NewReplacer("\n", "", "\t", "", " ", "").Replace(`

	(?:
		\\([cux])$
	)

`))
// TODO Go "regexp" bug? Can't do: (?:)|(?:$)

func transformRegExp(ecmaRegExp string) (goRegExp string) {
	// https://bugzilla.mozilla.org/show_bug.cgi/show_bug.cgi?id=334158
	tmp := []byte(ecmaRegExp)
	tmp = transformRegExp_unescape.ReplaceAll(tmp, []byte(`$1$2`))
	tmp = transformRegExp_unescapeDollar.ReplaceAll(tmp, []byte(`$1`))
	tmp = transformRegExp_matchSlashU.ReplaceAll(tmp, []byte(`\x{$1}`))
	return string(tmp)
}

func isValidRegExp(ecmaRegExp string) bool {
	shibboleth := 0 // The shibboleth in this case is (?
					// Since we're looking for (?! / (?=
	inSet := false // In a bracketed set, e.g. [0-9]
	escape := false
	for _, chr := range ecmaRegExp {
		if escape {
			escape = false
			shibboleth = 0
			continue
		}
		if chr == '\\' {
			escape = true
			continue
		}
		if inSet {
			if chr == ']' {
				inSet = false
				shibboleth = 0
			}
			continue
		}
		switch chr {
		case '[':
			inSet = true
			continue
		case '(':
			shibboleth = 1
			continue
		case '?':
			if shibboleth == 1 {
				shibboleth = 2
			}
			continue
		case '=', '!':
			if shibboleth == 2 {
				return false
			}
		}
		shibboleth = 0
	}

	return true
}

// _regExpStash

type _regExpStash struct {
	_regExpObject *_regExpObject
	_stash
}

func newRegExpStash(_regExpObject *_regExpObject, stash _stash) *_regExpStash {
	self := &_regExpStash{
		_regExpObject,
		stash,
	}
	return self
}

func (self *_regExpStash) test(name string) bool {
	switch name {
	case "global", "ignoreCase", "multiline", "lastIndex", "source":
		return true
	}
	return self._stash.test(name)
}

func (self *_regExpStash) get(name string) Value {
	switch name {
	case "global":
		return toValue(self._regExpObject.Global)
	case "ignoreCase":
		return toValue(self._regExpObject.IgnoreCase)
	case "multiline":
		return toValue(self._regExpObject.Multiline)
	case "lastIndex":
		return self._regExpObject.LastIndex
	case "source":
		return toValue(self._regExpObject.Source)
	}
	return self._stash.get(name)
}

func (self *_regExpStash) put(name string, value Value) {
	switch name {
	case "global", "ignoreCase", "multiline", "source":
		// TODO Is this good enough? Check DefineOwnProperty
		panic(newTypeError())
	case "lastIndex":
		self._regExpObject.LastIndex = value
		return
	}
	self._stash.put(name, value)
}

func (self *_regExpStash) property(name string) *_property {
	switch name {
	case "global":
		return &_property{value: toValue(self._regExpObject.Global), mode: 0} // -Write -Enumerate -Configure
	case "ignoreCase":
		return &_property{value: toValue(self._regExpObject.IgnoreCase), mode: 0} // -Write -Enumerate -Configure
	case "multiline":
		return &_property{value: toValue(self._regExpObject.Multiline), mode: 0} // -Write -Enumerate -Configure
	case "lastIndex":
		return &_property{value: (self._regExpObject.LastIndex), mode: 0100} // +Write -Enumerate -Configure
	case "source":
		return &_property{value: toValue(self._regExpObject.Source), mode: 0} // -Write -Enumerate -Configure
	}
	return self._stash.property(name)
}

func (self *_regExpStash) enumerate(each func(string)) {
	// Skip global, ignoreCase, multiline, source, & lastIndex
	self._stash.enumerate(each)
}
<|endoftext|>


<commit_before>package toml

import (
	"fmt"
	"reflect"

	"github.com/pelletier/go-toml/v2/internal/ast"
)

func Unmarshal(data []byte, v interface{}) error {
	p := parser{}
	err := p.parse(data)
	if err != nil {
		return err
	}
	return fromAst(p.tree, v)
}

func fromAst(tree ast.Root, v interface{}) error {
	r := reflect.ValueOf(v)
	if r.Kind() != reflect.Ptr {
		return fmt.Errorf("need to target a pointer, not %s", r.Kind())
	}
	if r.IsNil() {
		return fmt.Errorf("target pointer must be non-nil")
	}

	var err error
	var root target = valueTarget(r.Elem())
	current := root
	for _, node := range tree {
		current, err = unmarshalTopLevelNode(root, current, &node)
		if err != nil {
			return err
		}
	}

	return nil
}

// The target return value is the target for the next top-level node. Mostly
// unchanged, except by table and array table.
func unmarshalTopLevelNode(root target, x target, node *ast.Node) (target, error) {
	switch node.Kind {
	case ast.KeyValue:
		return x, unmarshalKeyValue(x, node)
	case ast.Table:
		return scopeWithKey(root, node.Key())
	case ast.ArrayTable:
		return scopeWithArrayTable(root, node.Key())
	default:
		panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
	}
}

// scopeWithKey performs target scoping when unmarshaling an ast.KeyValue node.
//
// The goal is to hop from target to target recursively using the names in key.
// Parts of the key should be used to resolve field names for structs, and as
// keys when targeting maps.
//
// When encountering slices, it should always use its last element, and error
// if the slice does not have any.
func scopeWithKey(x target, key []ast.Node) (target, error) {
	var err error
	for _, n := range key {
		x, err = scopeTableTarget(false, x, string(n.Data))
		if err != nil {
			return nil, err
		}
	}
	return x, nil
}

// scopeWithArrayTable performs target scoping when unmarshaling an
// ast.ArrayTable node.
//
// It is the same as scopeWithKey, but when scoping the last part of the key
// it creates a new element in the array instead of using the last one.
func scopeWithArrayTable(x target, key []ast.Node) (target, error) {
	var err error
	if len(key) > 1 {
		for _, n := range key[:len(key)-1] {
			x, err = scopeTableTarget(false, x, string(n.Data))
			if err != nil {
				return nil, err
			}
		}
	}
	x, err = scopeTableTarget(true, x, string(key[len(key)-1].Data))
	if err != nil {
		return x, err
	}

	v := x.get()

	if v.Kind() == reflect.Interface {
		x, err = scopeInterface(true, x)
		if err != nil {
			return x, err
		}
		v = x.get()
	}

	if v.Kind() == reflect.Slice {
		return scopeSlice(true, x)
	}

	return x, err
}

func unmarshalKeyValue(x target, node *ast.Node) error {
	assertNode(ast.KeyValue, node)

	x, err := scopeWithKey(x, node.Key())
	if err != nil {
		return err
	}

	return unmarshalValue(x, node.Value())
}

func unmarshalValue(x target, node *ast.Node) error {
	switch node.Kind {
	case ast.String:
		return unmarshalString(x, node)
	case ast.Bool:
		return unmarshalBool(x, node)
	case ast.Integer:
		return unmarshalInteger(x, node)
	case ast.Float:
		return unmarshalFloat(x, node)
	case ast.Array:
		return unmarshalArray(x, node)
	case ast.InlineTable:
		return unmarshalInlineTable(x, node)
	default:
		panic(fmt.Errorf("unhandled unmarshalValue kind %s", node.Kind))
	}
}

func unmarshalString(x target, node *ast.Node) error {
	assertNode(ast.String, node)
	return setString(x, string(node.Data))
}

func unmarshalBool(x target, node *ast.Node) error {
	assertNode(ast.Bool, node)
	v := node.Data[0] == 't'
	return setBool(x, v)
}

func unmarshalInteger(x target, node *ast.Node) error {
	assertNode(ast.Integer, node)
	v, err := node.DecodeInteger()
	if err != nil {
		return err
	}
	return setInt64(x, v)
}

func unmarshalFloat(x target, node *ast.Node) error {
	assertNode(ast.Float, node)
	v, err := node.DecodeFloat()
	if err != nil {
		return err
	}
	return setFloat64(x, v)
}

func unmarshalInlineTable(x target, node *ast.Node) error {
	assertNode(ast.InlineTable, node)

	for _, kv := range node.Children {
		err := unmarshalKeyValue(x, &kv)
		if err != nil {
			return err
		}
	}
	return nil
}

func unmarshalArray(x target, node *ast.Node) error {
	assertNode(ast.Array, node)

	err := ensureSlice(x)
	if err != nil {
		return err
	}

	for _, n := range node.Children {
		v, err := pushNew(x)
		if err != nil {
			return err
		}
		err = unmarshalValue(v, &n)
		if err != nil {
			return err
		}
	}
	return nil
}

func assertNode(expected ast.Kind, node *ast.Node) {
	if node.Kind != expected {
		panic(fmt.Errorf("expected node of kind %s, not %s", expected, node.Kind))
	}
}
<commit_msg>Fix multiple sub-table in array table<commit_after>package toml

import (
	"fmt"
	"reflect"

	"github.com/pelletier/go-toml/v2/internal/ast"
)

func Unmarshal(data []byte, v interface{}) error {
	p := parser{}
	err := p.parse(data)
	if err != nil {
		return err
	}
	return fromAst(p.tree, v)
}

func fromAst(tree ast.Root, v interface{}) error {
	r := reflect.ValueOf(v)
	if r.Kind() != reflect.Ptr {
		return fmt.Errorf("need to target a pointer, not %s", r.Kind())
	}
	if r.IsNil() {
		return fmt.Errorf("target pointer must be non-nil")
	}

	var err error
	var root target = valueTarget(r.Elem())
	current := root
	for _, node := range tree {
		current, err = unmarshalTopLevelNode(root, current, &node)
		if err != nil {
			return err
		}
	}

	return nil
}

// The target return value is the target for the next top-level node. Mostly
// unchanged, except by table and array table.
func unmarshalTopLevelNode(root target, x target, node *ast.Node) (target, error) {
	switch node.Kind {
	case ast.KeyValue:
		return x, unmarshalKeyValue(x, node)
	case ast.Table:
		return scopeWithKey(root, node.Key())
	case ast.ArrayTable:
		return scopeWithArrayTable(root, node.Key())
	default:
		panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
	}
}

// scopeWithKey performs target scoping when unmarshaling an ast.KeyValue node.
//
// The goal is to hop from target to target recursively using the names in key.
// Parts of the key should be used to resolve field names for structs, and as
// keys when targeting maps.
//
// When encountering slices, it should always use its last element, and error
// if the slice does not have any.
func scopeWithKey(x target, key []ast.Node) (target, error) {
	var err error
	for _, n := range key {
		x, err = scopeTableTarget(false, x, string(n.Data))
		if err != nil {
			return nil, err
		}
	}
	return x, nil
}

// scopeWithArrayTable performs target scoping when unmarshaling an
// ast.ArrayTable node.
//
// It is the same as scopeWithKey, but when scoping the last part of the key
// it creates a new element in the array instead of using the last one.
func scopeWithArrayTable(x target, key []ast.Node) (target, error) {
	var err error
	if len(key) > 1 {
		for _, n := range key[:len(key)-1] {
			x, err = scopeTableTarget(false, x, string(n.Data))
			if err != nil {
				return nil, err
			}
		}
	}
	x, err = scopeTableTarget(false, x, string(key[len(key)-1].Data))
	if err != nil {
		return x, err
	}

	v := x.get()

	if v.Kind() == reflect.Interface {
		x, err = scopeInterface(true, x)
		if err != nil {
			return x, err
		}
		v = x.get()
	}

	if v.Kind() == reflect.Slice {
		return scopeSlice(true, x)
	}

	return x, err
}

func unmarshalKeyValue(x target, node *ast.Node) error {
	assertNode(ast.KeyValue, node)

	x, err := scopeWithKey(x, node.Key())
	if err != nil {
		return err
	}

	return unmarshalValue(x, node.Value())
}

func unmarshalValue(x target, node *ast.Node) error {
	switch node.Kind {
	case ast.String:
		return unmarshalString(x, node)
	case ast.Bool:
		return unmarshalBool(x, node)
	case ast.Integer:
		return unmarshalInteger(x, node)
	case ast.Float:
		return unmarshalFloat(x, node)
	case ast.Array:
		return unmarshalArray(x, node)
	case ast.InlineTable:
		return unmarshalInlineTable(x, node)
	default:
		panic(fmt.Errorf("unhandled unmarshalValue kind %s", node.Kind))
	}
}

func unmarshalString(x target, node *ast.Node) error {
	assertNode(ast.String, node)
	return setString(x, string(node.Data))
}

func unmarshalBool(x target, node *ast.Node) error {
	assertNode(ast.Bool, node)
	v := node.Data[0] == 't'
	return setBool(x, v)
}

func unmarshalInteger(x target, node *ast.Node) error {
	assertNode(ast.Integer, node)
	v, err := node.DecodeInteger()
	if err != nil {
		return err
	}
	return setInt64(x, v)
}

func unmarshalFloat(x target, node *ast.Node) error {
	assertNode(ast.Float, node)
	v, err := node.DecodeFloat()
	if err != nil {
		return err
	}
	return setFloat64(x, v)
}

func unmarshalInlineTable(x target, node *ast.Node) error {
	assertNode(ast.InlineTable, node)

	for _, kv := range node.Children {
		err := unmarshalKeyValue(x, &kv)
		if err != nil {
			return err
		}
	}
	return nil
}

func unmarshalArray(x target, node *ast.Node) error {
	assertNode(ast.Array, node)

	err := ensureSlice(x)
	if err != nil {
		return err
	}

	for _, n := range node.Children {
		v, err := pushNew(x)
		if err != nil {
			return err
		}
		err = unmarshalValue(v, &n)
		if err != nil {
			return err
		}
	}
	return nil
}

func assertNode(expected ast.Kind, node *ast.Node) {
	if node.Kind != expected {
		panic(fmt.Errorf("expected node of kind %s, not %s", expected, node.Kind))
	}
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"time"

	. "github.com/eyetoe/foobarbaz/colors"
)

func Banner() {

	ClearScreen()

	//Teletype("\nWelcome to ...\n")
	fmt.Printf("\nWelcome to ...\n")

	//time.Sleep(500 * time.Millisecond)

	foobarbaz :=
		`  █████▒▒█████   ▒█████   ▄▄▄▄    ▄▄▄       ██▀███   ▄▄▄▄    ▄▄▄     ▒███████▒` + "\n" +
			`▓██   ▒▒██▒  ██▒▒██▒  ██▒▓█████▄ ▒████▄    ▓██ ▒ ██▒▓█████▄ ▒████▄   ▒ ▒ ▒ ▄▀░` + "\n" +
			`▒████ ░▒██░  ██▒▒██░  ██▒▒██▒ ▄██▒██  ▀█▄  ▓██ ░▄█ ▒▒██▒ ▄██▒██  ▀█▄ ░ ▒ ▄▀▒░ ` + "\n" +
			`░▓█▒  ░▒██   ██░▒██   ██░▒██░█▀  ░██▄▄▄▄██ ▒██▀▀█▄  ▒██░█▀  ░██▄▄▄▄██  ▄▀▒   ░` + "\n" +
			`░▒█░   ░ ████▓▒░░ ████▓▒░░▓█  ▀█▓ ▓█   ▓██▒░██▓ ▒██▒░▓█  ▀█▓ ▓█   ▓██▒███████▒` + "\n" +
			` ▒ ░   ░ ▒░▒░▒░ ░ ▒░▒░▒░ ░▒▓███▀▒ ▒▒   ▓▒█░░ ▒▓ ░▒▓░░▒▓███▀▒ ▒▒   ▓▒█░▒▒ ▓░▒░▒` + "\n" +
			` ░       ░ ▒ ▒░   ░ ▒ ▒░ ▒░▒   ░   ▒   ▒▒ ░  ░▒ ░ ▒░▒░▒   ░   ▒   ▒▒ ░░▒ ▒ ░ ▒` + "\n" +
			` ░ ░   ░ ░ ░ ▒  ░ ░ ░ ▒   ░    ░   ░   ▒     ░░   ░  ░    ░   ░   ▒  ░ ░ ░ ░ ░` + "\n" +
			`           ░ ░      ░ ░   ░            ░  ░   ░      ░            ░  ░ ░ ░    ` + "\n" +
			`                               ░                          ░          ░        `

		//for i := 0; i <= 4; i++ {
	ClearScreen()
	fmt.Printf(White("\nWelcome to ...\n"))
	fmt.Println(ColorBanner(foobarbaz))
	//	time.Sleep(100 * time.Millisecond)
	//}

}

func StartBanner() {

	ClearScreen()
	//fmt.Printf(White("\nWelcome to ...\n"))

	Teletype("\nWelcome to ...\n")
	//for _, c := range "\nWelcome to ...\n" {
	//fmt.Printf(White(string(c)))
	//time.Sleep(100 * time.Millisecond)

	//}

	time.Sleep(500 * time.Millisecond)
	//	fmt.Println(Red(
	//		`   ______         ______           ______              ` + "\n" +
	//			`   |  ___|        | ___ \          | ___ \             ` + "\n" +
	//			`   | |_ ___   ___ | |_/ / __ _ _ __| |_/ / __ _ ____   ` + "\n" +
	//			`   |  _/ _ \ / _ \| ___ \/ _' | '__| ___ \/ _' |_  /   ` + "\n" +
	//			`   | || (_) | (_) | |_/ / (_| | |  | |_/ / (_| |/ /    ` + "\n" +
	//			`   \_| \___/ \___/\____/ \__,_|_|  \____/ \__,_/___|   ` + "\n" +
	//			`                                                       `))

	//fmt.Println(Red(
	foobarbaz :=
		`  █████▒▒█████   ▒█████   ▄▄▄▄    ▄▄▄       ██▀███   ▄▄▄▄    ▄▄▄     ▒███████▒` + "\n" +
			`▓██   ▒▒██▒  ██▒▒██▒  ██▒▓█████▄ ▒████▄    ▓██ ▒ ██▒▓█████▄ ▒████▄   ▒ ▒ ▒ ▄▀░` + "\n" +
			`▒████ ░▒██░  ██▒▒██░  ██▒▒██▒ ▄██▒██  ▀█▄  ▓██ ░▄█ ▒▒██▒ ▄██▒██  ▀█▄ ░ ▒ ▄▀▒░ ` + "\n" +
			`░▓█▒  ░▒██   ██░▒██   ██░▒██░█▀  ░██▄▄▄▄██ ▒██▀▀█▄  ▒██░█▀  ░██▄▄▄▄██  ▄▀▒   ░` + "\n" +
			`░▒█░   ░ ████▓▒░░ ████▓▒░░▓█  ▀█▓ ▓█   ▓██▒░██▓ ▒██▒░▓█  ▀█▓ ▓█   ▓██▒███████▒` + "\n" +
			` ▒ ░   ░ ▒░▒░▒░ ░ ▒░▒░▒░ ░▒▓███▀▒ ▒▒   ▓▒█░░ ▒▓ ░▒▓░░▒▓███▀▒ ▒▒   ▓▒█░▒▒ ▓░▒░▒` + "\n" +
			` ░       ░ ▒ ▒░   ░ ▒ ▒░ ▒░▒   ░   ▒   ▒▒ ░  ░▒ ░ ▒░▒░▒   ░   ▒   ▒▒ ░░▒ ▒ ░ ▒` + "\n" +
			` ░ ░   ░ ░ ░ ▒  ░ ░ ░ ▒   ░    ░   ░   ▒     ░░   ░  ░    ░   ░   ▒  ░ ░ ░ ░ ░` + "\n" +
			`           ░ ░      ░ ░   ░            ░  ░   ░      ░            ░  ░ ░ ░    ` + "\n" +
			`                               ░                          ░          ░        `

	for i := 0; i <= 20; i++ {
		ClearScreen()
		fmt.Printf(White("\nWelcome to ...\n"))
		fmt.Println(ColorBanner(foobarbaz))
		time.Sleep(100 * time.Millisecond)
	}

}
<commit_msg>cleanup<commit_after>package util

import (
	"fmt"
	"time"

	. "github.com/eyetoe/foobarbaz/colors"
)

func Banner() {

	ClearScreen()

	fmt.Printf("\nWelcome to ...\n")

	foobarbaz :=
		`  █████▒▒█████   ▒█████   ▄▄▄▄    ▄▄▄       ██▀███   ▄▄▄▄    ▄▄▄     ▒███████▒` + "\n" +
			`▓██   ▒▒██▒  ██▒▒██▒  ██▒▓█████▄ ▒████▄    ▓██ ▒ ██▒▓█████▄ ▒████▄   ▒ ▒ ▒ ▄▀░` + "\n" +
			`▒████ ░▒██░  ██▒▒██░  ██▒▒██▒ ▄██▒██  ▀█▄  ▓██ ░▄█ ▒▒██▒ ▄██▒██  ▀█▄ ░ ▒ ▄▀▒░ ` + "\n" +
			`░▓█▒  ░▒██   ██░▒██   ██░▒██░█▀  ░██▄▄▄▄██ ▒██▀▀█▄  ▒██░█▀  ░██▄▄▄▄██  ▄▀▒   ░` + "\n" +
			`░▒█░   ░ ████▓▒░░ ████▓▒░░▓█  ▀█▓ ▓█   ▓██▒░██▓ ▒██▒░▓█  ▀█▓ ▓█   ▓██▒███████▒` + "\n" +
			` ▒ ░   ░ ▒░▒░▒░ ░ ▒░▒░▒░ ░▒▓███▀▒ ▒▒   ▓▒█░░ ▒▓ ░▒▓░░▒▓███▀▒ ▒▒   ▓▒█░▒▒ ▓░▒░▒` + "\n" +
			` ░       ░ ▒ ▒░   ░ ▒ ▒░ ▒░▒   ░   ▒   ▒▒ ░  ░▒ ░ ▒░▒░▒   ░   ▒   ▒▒ ░░▒ ▒ ░ ▒` + "\n" +
			` ░ ░   ░ ░ ░ ▒  ░ ░ ░ ▒   ░    ░   ░   ▒     ░░   ░  ░    ░   ░   ▒  ░ ░ ░ ░ ░` + "\n" +
			`           ░ ░      ░ ░   ░            ░  ░   ░      ░            ░  ░ ░ ░    ` + "\n" +
			`                               ░                          ░          ░        `

	ClearScreen()
	fmt.Printf(White("\nWelcome to ...\n"))
	fmt.Println(ColorBanner(foobarbaz))
}

func StartBanner() {

	ClearScreen()

	Teletype("\nWelcome to ...\n")

	time.Sleep(500 * time.Millisecond)

	//	fmt.Println(Red(
	//		`   ______         ______           ______              ` + "\n" +
	//			`   |  ___|        | ___ \          | ___ \             ` + "\n" +
	//			`   | |_ ___   ___ | |_/ / __ _ _ __| |_/ / __ _ ____   ` + "\n" +
	//			`   |  _/ _ \ / _ \| ___ \/ _' | '__| ___ \/ _' |_  /   ` + "\n" +
	//			`   | || (_) | (_) | |_/ / (_| | |  | |_/ / (_| |/ /    ` + "\n" +
	//			`   \_| \___/ \___/\____/ \__,_|_|  \____/ \__,_/___|   ` + "\n" +
	//			`                                                       `))

	foobarbaz :=
		`  █████▒▒█████   ▒█████   ▄▄▄▄    ▄▄▄       ██▀███   ▄▄▄▄    ▄▄▄     ▒███████▒` + "\n" +
			`▓██   ▒▒██▒  ██▒▒██▒  ██▒▓█████▄ ▒████▄    ▓██ ▒ ██▒▓█████▄ ▒████▄   ▒ ▒ ▒ ▄▀░` + "\n" +
			`▒████ ░▒██░  ██▒▒██░  ██▒▒██▒ ▄██▒██  ▀█▄  ▓██ ░▄█ ▒▒██▒ ▄██▒██  ▀█▄ ░ ▒ ▄▀▒░ ` + "\n" +
			`░▓█▒  ░▒██   ██░▒██   ██░▒██░█▀  ░██▄▄▄▄██ ▒██▀▀█▄  ▒██░█▀  ░██▄▄▄▄██  ▄▀▒   ░` + "\n" +
			`░▒█░   ░ ████▓▒░░ ████▓▒░░▓█  ▀█▓ ▓█   ▓██▒░██▓ ▒██▒░▓█  ▀█▓ ▓█   ▓██▒███████▒` + "\n" +
			` ▒ ░   ░ ▒░▒░▒░ ░ ▒░▒░▒░ ░▒▓███▀▒ ▒▒   ▓▒█░░ ▒▓ ░▒▓░░▒▓███▀▒ ▒▒   ▓▒█░▒▒ ▓░▒░▒` + "\n" +
			` ░       ░ ▒ ▒░   ░ ▒ ▒░ ▒░▒   ░   ▒   ▒▒ ░  ░▒ ░ ▒░▒░▒   ░   ▒   ▒▒ ░░▒ ▒ ░ ▒` + "\n" +
			` ░ ░   ░ ░ ░ ▒  ░ ░ ░ ▒   ░    ░   ░   ▒     ░░   ░  ░    ░   ░   ▒  ░ ░ ░ ░ ░` + "\n" +
			`           ░ ░      ░ ░   ░            ░  ░   ░      ░            ░  ░ ░ ░    ` + "\n" +
			`                               ░                          ░          ░        `

	for i := 0; i <= 20; i++ {
		ClearScreen()
		fmt.Printf(White("\nWelcome to ...\n"))
		fmt.Println(ColorBanner(foobarbaz))
		time.Sleep(100 * time.Millisecond)
	}

}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//  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 query contains artifacts shared across other packages in query
processing.

*/
package query

import (
	"encoding/json"
	"fmt"
)

const (
	EXCEPTION = iota
	WARNING
	NOTICE
	INFO
	LOG
	DEBUG
)

// Error will eventually include code, message key, and internal error
// object (cause) and message
type Error interface {
	error
	Code() int32
	TranslationKey() string
	Cause() error
	Level() int
	IsFatal() bool
}

type ErrorChannel chan Error

func NewError(e error, internalMsg string) Error {
	return &err{level: EXCEPTION, ICode: 5000, IKey: "Internal Error", ICause: e, InternalMsg: internalMsg}
}

func NewWarning(internalMsg string) Error {
	return &err{level: WARNING, InternalMsg: internalMsg}
}

func NewNotice(internalMsg string) Error {
	return &err{level: NOTICE, InternalMsg: internalMsg}
}

func NewInfo(internalMsg string) Error {
	return &err{level: INFO, InternalMsg: internalMsg}
}

func NewLog(internalMsg string) Error {
	return &err{level: LOG, InternalMsg: internalMsg}
}

func NewDebug(internalMsg string) Error {
	return &err{level: DEBUG, InternalMsg: internalMsg}
}

type err struct {
	ICode       int32
	IKey        string
	ICause      error
	InternalMsg string
	level       int
}

func (e *err) Error() string {
	switch {
	default:
		return "Unspecified error."
	case e.InternalMsg != "" && e.ICause != nil:
		return e.InternalMsg + " - cause: " + e.ICause.Error()
	case e.InternalMsg != "":
		return e.InternalMsg
	case e.ICause != nil:
		return e.ICause.Error()
	}
}

func (e *err) MarshalJSON() ([]byte, error) {
	m := map[string]interface{}{
		"code":    e.ICode,
		"key":     e.IKey,
		"message": e.InternalMsg,
	}
	if e.ICause != nil {
		m["cause"] = e.ICause.Error()
	}
	return json.Marshal(m)
}

func (e *err) Level() int {
	return e.level
}

func (e *err) IsFatal() bool {
	if e.level == EXCEPTION {
		return true
	}
	return false
}

func (e *err) Code() int32 {
	return e.ICode
}

func (e *err) TranslationKey() string {
	return e.IKey
}

func (e *err) Cause() error {
	return e.ICause
}

func NewParseError(e error, msg string) Error {
	return &err{level: EXCEPTION, ICode: 4100, IKey: "parse_error", ICause: e, InternalMsg: msg}
}

func NewSemanticError(e error, msg string) Error {
	return &err{level: EXCEPTION, ICode: 4200, IKey: "semantic_error", ICause: e, InternalMsg: msg}
}

func NewBucketDoesNotExist(bucket string) Error {
	return &err{level: EXCEPTION, ICode: 4040, IKey: "bucket_not_found", InternalMsg: fmt.Sprintf("Bucket %s does not exist", bucket)}
}

func NewPoolDoesNotExist(pool string) Error {
	return &err{level: EXCEPTION, ICode: 4041, IKey: "pool_not_found", InternalMsg: fmt.Sprintf("Pool %s does not exist", pool)}
}

func NewTotalRowsInfo(rows int) Error {
	return &err{level: INFO, ICode: 100, IKey: "total_rows", InternalMsg: fmt.Sprintf("%d", rows)}
}

func NewTotalElapsedTimeInfo(time string) Error {
	return &err{level: INFO, ICode: 101, IKey: "total_elapsed_time", InternalMsg: fmt.Sprintf("%s", time)}
}
<commit_msg>added Caller() info to err<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  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 query contains artifacts shared across other packages in query
processing.

*/
package query

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/couchbaselabs/tuqtng/misc"
)

const (
	EXCEPTION = iota
	WARNING
	NOTICE
	INFO
	LOG
	DEBUG
)

// Error will eventually include code, message key, and internal error
// object (cause) and message
type Error interface {
	error
	Code() int32
	TranslationKey() string
	Cause() error
	Level() int
	IsFatal() bool
}

type ErrorChannel chan Error

func NewError(e error, internalMsg string) Error {
	return &err{level: EXCEPTION, ICode: 5000, IKey: "Internal Error", ICause: e, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

func NewWarning(internalMsg string) Error {
	return &err{level: WARNING, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

func NewNotice(internalMsg string) Error {
	return &err{level: NOTICE, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

func NewInfo(internalMsg string) Error {
	return &err{level: INFO, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

func NewLog(internalMsg string) Error {
	return &err{level: LOG, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

func NewDebug(internalMsg string) Error {
	return &err{level: DEBUG, InternalMsg: internalMsg, InternalCaller: misc.CallerN(1)}
}

type err struct {
	ICode          int32
	IKey           string
	ICause         error
	InternalMsg    string
	InternalCaller string
	level          int
}

func (e *err) Error() string {
	switch {
	default:
		return "Unspecified error."
	case e.InternalMsg != "" && e.ICause != nil:
		return e.InternalMsg + " - cause: " + e.ICause.Error()
	case e.InternalMsg != "":
		return e.InternalMsg
	case e.ICause != nil:
		return e.ICause.Error()
	}
}

func (e *err) MarshalJSON() ([]byte, error) {
	m := map[string]interface{}{
		"code":    e.ICode,
		"key":     e.IKey,
		"message": e.InternalMsg,
	}
	if e.ICause != nil {
		m["cause"] = e.ICause.Error()
	}
	if e.InternalCaller != "" &&
		!strings.HasPrefix("e.InternalCaller", "unknown:") {
		m["caller"] = e.InternalCaller
	}
	return json.Marshal(m)
}

func (e *err) Level() int {
	return e.level
}

func (e *err) IsFatal() bool {
	if e.level == EXCEPTION {
		return true
	}
	return false
}

func (e *err) Code() int32 {
	return e.ICode
}

func (e *err) TranslationKey() string {
	return e.IKey
}

func (e *err) Cause() error {
	return e.ICause
}

func NewParseError(e error, msg string) Error {
	return &err{level: EXCEPTION, ICode: 4100, IKey: "parse_error", ICause: e, InternalMsg: msg, InternalCaller: misc.CallerN(1)}
}

func NewSemanticError(e error, msg string) Error {
	return &err{level: EXCEPTION, ICode: 4200, IKey: "semantic_error", ICause: e, InternalMsg: msg, InternalCaller: misc.CallerN(1)}
}

func NewBucketDoesNotExist(bucket string) Error {
	return &err{level: EXCEPTION, ICode: 4040, IKey: "bucket_not_found", InternalMsg: fmt.Sprintf("Bucket %s does not exist", bucket), InternalCaller: misc.CallerN(1)}
}

func NewPoolDoesNotExist(pool string) Error {
	return &err{level: EXCEPTION, ICode: 4041, IKey: "pool_not_found", InternalMsg: fmt.Sprintf("Pool %s does not exist", pool), InternalCaller: misc.CallerN(1)}
}

func NewTotalRowsInfo(rows int) Error {
	return &err{level: INFO, ICode: 100, IKey: "total_rows", InternalMsg: fmt.Sprintf("%d", rows), InternalCaller: misc.CallerN(1)}
}

func NewTotalElapsedTimeInfo(time string) Error {
	return &err{level: INFO, ICode: 101, IKey: "total_elapsed_time", InternalMsg: fmt.Sprintf("%s", time), InternalCaller: misc.CallerN(1)}
}
<|endoftext|>