<commit_before>// (c) 2011-2013 Alexander Solovyov
// under terms of ISC license

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

type Matcher interface {
	Match(fn string, isdir bool) bool
	Append(pats []string)
}

func dirExists(path string) bool {
	fi, err := os.Stat(path)
	if err != nil {
		return false
	}
	return fi.IsDir()
}

func NewMatcher(wd string, noIgnores bool) Matcher {
	path := wd
	if !filepath.IsAbs(path) {
		panic("Given path should be absolute")
	}

	for !noIgnores {
		if filepath.Dir(path) == path {
			break
		}

		if dirExists(filepath.Join(path, ".hg")) {
			return NewHgMatcher(wd, filepath.Join(path, ".hgignore"))
		}

		if dirExists(filepath.Join(path, ".git")) {
			return NewGitMatcher(wd, filepath.Join(path, ".gitignore"))
		}

		// f, err = os.Open(filepath.Join(path, ".git"))
		// if err == nil {
		// 	return NewGitMatcher(wd, f)
		// }

		path = filepath.Clean(filepath.Join(path, ".."))
	}

	return NewGeneralMatcher(generalDirs, generalPats)
}

// Ignore common patterns
type GeneralMatcher struct {
	dirs []string
	res  []*regexp.Regexp
	both []*regexp.Regexp
}

var generalDirs = []string{"autom4te.cache", "blib", "_build", ".bzr", ".cdv",
	"cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib",
	".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn", "_obj"}
var generalPats = []string{`~$`, `#.+#$`, `[._].*\.swp$`,
	`core\.[0-9]+$`, `\.pyc$`, `\.o$`, `\.6$`}

func NewGeneralMatcher(dirs []string, filePats []string) *GeneralMatcher {
	res := make([]*regexp.Regexp, len(filePats))
	for i, pat := range filePats {
		res[i] = regexp.MustCompile(pat)
	}
	return &GeneralMatcher{dirs, res, []*regexp.Regexp{}}
}

func (i *GeneralMatcher) Match(fn string, isdir bool) bool {
	if isdir {
		base := filepath.Base(fn)
		for _, x := range i.dirs {
			if base == x {
				return true
			}
		}
	}

	for _, x := range i.res {
		if x.Match([]byte(fn)) {
			return true
		}
	}

	return false
}

func (i *GeneralMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern %s\n", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *GeneralMatcher) String() string {
	return "General ignorer"
}

// read .hgignore and ignore patterns from there
type HgMatcher struct {
	prefix string
	fp     string
	res    []*regexp.Regexp
	globs  []string
}

var hgSyntaxes = map[string]bool{
	"re":     true,
	"regexp": true,
	"glob":   false,
}

func NewHgMatcher(wd string, fp string) *HgMatcher {
	var prefix string
	basepath := filepath.Clean(filepath.Join(fp, ".."))
	if strings.HasPrefix(wd, basepath) {
		prefix = wd[len(basepath):]
		if len(prefix) > 0 && prefix[0] == '/' {
			prefix = prefix[1:]
		}
	} else {
		prefix = ""
	}

	res := []*regexp.Regexp{}
	globs := []string{}

	f, err := os.Open(fp)
	if err != nil {
		return &HgMatcher{prefix, fp, res, globs}
	}

	reader := bufio.NewReader(f)
	isRe := true
	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		// strip comments
		comment := bytes.IndexByte(line, '#')
		switch comment {
		case 0:
			continue
		case -1:
		default:
			line = line[:comment]
		}

		line = bytes.TrimRight(line, " \t")
		if len(line) == 0 {
			continue
		}

		// if it's a syntax changer
		if bytes.HasPrefix(line, []byte("syntax:")) {
			s := bytes.TrimSpace(line[7:])
			if isre, ok := hgSyntaxes[string(s)]; ok {
				isRe = isre
			}
			continue
		}

		// actually append line
		pat := string(line)
		if isRe {
			re, err := regexp.Compile(pat)
			if errhandle(err, false, "can't compile pattern %s", pat) {
				continue
			}
			res = append(res, re)
		} else {
			globs = append(globs, pat)
		}
	}
	return &HgMatcher{prefix, fp, res, globs}
}

func (i *HgMatcher) Match(fn string, isdir bool) bool {
	if len(i.prefix) > 0 {
		fn = filepath.Join(i.prefix, fn)
	}
	base := filepath.Base(fn)

	if isdir && base == ".hg" {
		return true
	}

	for _, x := range i.res {
		if x.Match([]byte(fn)) {
			return true
		}
	}

	for _, x := range i.globs {
		if m, _ := filepath.Match(x, base); m {
			return true
		}
	}

	return false
}

func (i *HgMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern %s", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *HgMatcher) String() string {
	desc := fmt.Sprintf("Ignoring patterns from %s:", i.fp)
	if len(i.res) > 0 {
		desc += "\n\tregular expressions: "
		for _, x := range i.res {
			desc += x.String() + " "
		}
	}

	if len(i.globs) > 0 {
		desc += "\n\tglobs: " + strings.Join(i.globs, " ")
	}

	return desc
}

// read .gitignore and ignore patterns from there
type GitMatcher struct {
	basepath string
	prefix   string
	fp       string
	globs    []string // will be used for showing help only
	globres  []*regexp.Regexp
	res      []*regexp.Regexp
}

// many thanks to Steve Losh for this algorithm
func gitGlobRe(s string) *regexp.Regexp {
	var pat bytes.Buffer
	if strings.Contains(s, "/") {
		// Patterns with a slash have to match against the entire pathname, so
		// they need to be rooted at the beginning
		pat.WriteString("^./")
	} else {
		// Patterns without a slash match against basename, which is simulated
		// by including last path divider in the pattern
		pat.WriteString("/")
	}
	s = strings.TrimLeft(s, "/")

	i := 0
	n := len(s)

	for i < n {
		c := s[i]
		i += 1

		switch c {
		case '?':
			pat.WriteByte('.')
		case '*':
			if i == n {
				pat.WriteString(".*")
			} else {
				pat.WriteString("[^/]*")
			}
		case '[':
			j := i
			if j < n && (s[j] == '!' || s[j] == ']') {
				j += 1
			}
			for j < n && s[j] != ']' {
				j += 1
			}

			if j >= n {
				pat.WriteString("\\[")
			} else {
				stuff := strings.Replace(s[i:j], "\\", "\\\\", -1)
				i = j + 1
				if stuff[0] == '!' {
					stuff = "^" + stuff[1:]
				} else if stuff[0] == '^' {
					stuff = "\\" + stuff
				}
				pat.WriteString("[")
				pat.WriteString(stuff)
				pat.WriteString("]")
			}
		default:
			pat.WriteString(regexp.QuoteMeta(string(c)))
		}

		if i == n && c != '/' {
			pat.WriteByte('$')
		}
	}

	re, err := regexp.Compile(pat.String())
	errhandle(err, false, "can't parse pattern '%s'", s)
	return re
}

func NewGitMatcher(wd string, fp string) *GitMatcher {
	var prefix string
	basepath := filepath.Clean(filepath.Join(fp, ".."))
	if strings.HasPrefix(wd, basepath) {
		prefix = wd[len(basepath):]
		if len(prefix) > 0 && prefix[0] == '/' {
			prefix = prefix[1:]
		}
	} else {
		prefix = ""
	}

	globs := []string{}
	globres := []*regexp.Regexp{}

	f, err := os.Open(fp)
	if err != nil {
		return &GitMatcher{basepath, prefix, fp, globs, globres, []*regexp.Regexp{}}
	}

	reader := bufio.NewReader(f)
	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		line = bytes.TrimRight(line, " \t")
		if len(line) == 0 {
			continue
		}

		if line[0] == '#' {
			continue
		}

		globs = append(globs, string(line))
		globres = append(globres, gitGlobRe(string(line)))
	}

	return &GitMatcher{basepath, prefix, fp, globs, globres, []*regexp.Regexp{}}
}

func (i *GitMatcher) Match(fn string, isdir bool) bool {
	path := fmt.Sprintf(".%c", filepath.Separator) + filepath.Join(i.prefix, fn)
	base := filepath.Base(path)

	if isdir && base == ".git" {
		return true
	}

	for _, pat := range i.globres {
		if pat.MatchString(path) {
			return true
		}
	}

	for _, pat := range i.res {
		if pat.MatchString(path) {
			return true
		}
	}

	return false
}

func (i *GitMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern '%s'", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *GitMatcher) String() string {
	desc := fmt.Sprintf("Ignoring patterns from %s:", i.fp)
	if len(i.globs) > 0 {
		desc += "\n\tglobs: "
		for _, x := range i.globs {
			if strings.HasPrefix(x, i.basepath) {
				desc += x[len(i.basepath):] + " "
			} else {
				desc += x + " "
			}
		}
	}

	if len(i.res) > 0 {
		desc += "\n\tregular expressions: "
		for _, x := range i.res {
			desc += x.String() + " "
		}
	}

	return desc
}
<commit_msg>do not fail to match patterns on windows<commit_after>// (c) 2011-2013 Alexander Solovyov
// under terms of ISC license

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

type Matcher interface {
	Match(fn string, isdir bool) bool
	Append(pats []string)
}

func dirExists(path string) bool {
	fi, err := os.Stat(path)
	if err != nil {
		return false
	}
	return fi.IsDir()
}

func NewMatcher(wd string, noIgnores bool) Matcher {
	path := wd
	if !filepath.IsAbs(path) {
		panic("Given path should be absolute")
	}

	for !noIgnores {
		if filepath.Dir(path) == path {
			break
		}

		if dirExists(filepath.Join(path, ".hg")) {
			return NewHgMatcher(wd, filepath.Join(path, ".hgignore"))
		}

		if dirExists(filepath.Join(path, ".git")) {
			return NewGitMatcher(wd, filepath.Join(path, ".gitignore"))
		}

		// f, err = os.Open(filepath.Join(path, ".git"))
		// if err == nil {
		// 	return NewGitMatcher(wd, f)
		// }

		path = filepath.Clean(filepath.Join(path, ".."))
	}

	return NewGeneralMatcher(generalDirs, generalPats)
}

// Ignore common patterns
type GeneralMatcher struct {
	dirs []string
	res  []*regexp.Regexp
	both []*regexp.Regexp
}

var generalDirs = []string{"autom4te.cache", "blib", "_build", ".bzr", ".cdv",
	"cover_db", "CVS", "_darcs", "~.dep", "~.dot", ".git", ".hg", "~.nib",
	".pc", "~.plst", "RCS", "SCCS", "_sgbak", ".svn", "_obj"}
var generalPats = []string{`~$`, `#.+#$`, `[._].*\.swp$`,
	`core\.[0-9]+$`, `\.pyc$`, `\.o$`, `\.6$`}

func NewGeneralMatcher(dirs []string, filePats []string) *GeneralMatcher {
	res := make([]*regexp.Regexp, len(filePats))
	for i, pat := range filePats {
		res[i] = regexp.MustCompile(pat)
	}
	return &GeneralMatcher{dirs, res, []*regexp.Regexp{}}
}

func (i *GeneralMatcher) Match(fn string, isdir bool) bool {
	if isdir {
		base := filepath.Base(fn)
		for _, x := range i.dirs {
			if base == x {
				return true
			}
		}
	}

	for _, x := range i.res {
		if x.Match([]byte(fn)) {
			return true
		}
	}

	return false
}

func (i *GeneralMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern %s\n", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *GeneralMatcher) String() string {
	return "General ignorer"
}

// read .hgignore and ignore patterns from there
type HgMatcher struct {
	prefix string
	fp     string
	res    []*regexp.Regexp
	globs  []string
}

var hgSyntaxes = map[string]bool{
	"re":     true,
	"regexp": true,
	"glob":   false,
}

func NewHgMatcher(wd string, fp string) *HgMatcher {
	var prefix string
	basepath := filepath.Clean(filepath.Join(fp, ".."))
	if strings.HasPrefix(wd, basepath) {
		prefix = wd[len(basepath):]
		if len(prefix) > 0 && prefix[0] == '/' {
			prefix = prefix[1:]
		}
	} else {
		prefix = ""
	}

	res := []*regexp.Regexp{}
	globs := []string{}

	f, err := os.Open(fp)
	if err != nil {
		return &HgMatcher{prefix, fp, res, globs}
	}

	reader := bufio.NewReader(f)
	isRe := true
	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		// strip comments
		comment := bytes.IndexByte(line, '#')
		switch comment {
		case 0:
			continue
		case -1:
		default:
			line = line[:comment]
		}

		line = bytes.TrimRight(line, " \t")
		if len(line) == 0 {
			continue
		}

		// if it's a syntax changer
		if bytes.HasPrefix(line, []byte("syntax:")) {
			s := bytes.TrimSpace(line[7:])
			if isre, ok := hgSyntaxes[string(s)]; ok {
				isRe = isre
			}
			continue
		}

		// actually append line
		pat := string(line)
		if isRe {
			re, err := regexp.Compile(pat)
			if errhandle(err, false, "can't compile pattern %s", pat) {
				continue
			}
			res = append(res, re)
		} else {
			globs = append(globs, pat)
		}
	}
	return &HgMatcher{prefix, fp, res, globs}
}

func (i *HgMatcher) Match(fn string, isdir bool) bool {
	if len(i.prefix) > 0 {
		fn = filepath.Join(i.prefix, fn)
	}
	base := filepath.Base(fn)

	if isdir && base == ".hg" {
		return true
	}

	for _, x := range i.res {
		if x.Match([]byte(fn)) {
			return true
		}
	}

	for _, x := range i.globs {
		if m, _ := filepath.Match(x, base); m {
			return true
		}
	}

	return false
}

func (i *HgMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern %s", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *HgMatcher) String() string {
	desc := fmt.Sprintf("Ignoring patterns from %s:", i.fp)
	if len(i.res) > 0 {
		desc += "\n\tregular expressions: "
		for _, x := range i.res {
			desc += x.String() + " "
		}
	}

	if len(i.globs) > 0 {
		desc += "\n\tglobs: " + strings.Join(i.globs, " ")
	}

	return desc
}

// read .gitignore and ignore patterns from there
type GitMatcher struct {
	basepath string
	prefix   string
	fp       string
	globs    []string // will be used for showing help only
	globres  []*regexp.Regexp
	res      []*regexp.Regexp
}

// many thanks to Steve Losh for this algorithm
func gitGlobRe(s string) *regexp.Regexp {
	var pat bytes.Buffer
	if strings.Contains(s, "/") {
		// Patterns with a slash have to match against the entire pathname, so
		// they need to be rooted at the beginning
		pat.WriteString("^./")
	} else {
		// Patterns without a slash match against basename, which is simulated
		// by including last path divider in the pattern
		pat.WriteString("/")
	}
	s = strings.TrimLeft(s, "/")

	i := 0
	n := len(s)

	for i < n {
		c := s[i]
		i += 1

		switch c {
		case '?':
			pat.WriteByte('.')
		case '*':
			if i == n {
				pat.WriteString(".*")
			} else {
				pat.WriteString("[^/]*")
			}
		case '[':
			j := i
			if j < n && (s[j] == '!' || s[j] == ']') {
				j += 1
			}
			for j < n && s[j] != ']' {
				j += 1
			}

			if j >= n {
				pat.WriteString("\\[")
			} else {
				stuff := strings.Replace(s[i:j], "\\", "\\\\", -1)
				i = j + 1
				if stuff[0] == '!' {
					stuff = "^" + stuff[1:]
				} else if stuff[0] == '^' {
					stuff = "\\" + stuff
				}
				pat.WriteString("[")
				pat.WriteString(stuff)
				pat.WriteString("]")
			}
		default:
			pat.WriteString(regexp.QuoteMeta(string(c)))
		}

		if i == n && c != '/' {
			pat.WriteByte('$')
		}
	}

	re, err := regexp.Compile(pat.String())
	errhandle(err, false, "can't parse pattern '%s'", s)
	return re
}

func NewGitMatcher(wd string, fp string) *GitMatcher {
	var prefix string
	basepath := filepath.Clean(filepath.Join(fp, ".."))
	if strings.HasPrefix(wd, basepath) {
		prefix = wd[len(basepath):]
		if len(prefix) > 0 && prefix[0] == '/' {
			prefix = prefix[1:]
		}
	} else {
		prefix = ""
	}

	globs := []string{}
	globres := []*regexp.Regexp{}

	f, err := os.Open(fp)
	if err != nil {
		return &GitMatcher{basepath, prefix, fp, globs, globres, []*regexp.Regexp{}}
	}

	reader := bufio.NewReader(f)
	for {
		line, _, err := reader.ReadLine()
		if err != nil {
			break
		}

		line = bytes.TrimRight(line, " \t")
		if len(line) == 0 {
			continue
		}

		if line[0] == '#' {
			continue
		}

		globs = append(globs, string(line))
		globres = append(globres, gitGlobRe(string(line)))
	}

	return &GitMatcher{basepath, prefix, fp, globs, globres, []*regexp.Regexp{}}
}

func (i *GitMatcher) Match(fn string, isdir bool) bool {
	path := fmt.Sprintf(".%c", filepath.Separator) + filepath.Join(i.prefix, fn)
	base := filepath.Base(path)

	if filepath.Separator != '/' {
		path = strings.Replace(path, string(filepath.Separator), "/", -1)
	}

	if isdir && base == ".git" {
		return true
	}

	for _, pat := range i.globres {
		if pat.MatchString(path) {
			return true
		}
	}

	for _, pat := range i.res {
		if pat.MatchString(path) {
			return true
		}
	}

	return false
}

func (i *GitMatcher) Append(pats []string) {
	for _, pat := range pats {
		re, err := regexp.Compile(pat)
		if errhandle(err, false, "can't compile pattern '%s'", pat) {
			continue
		}
		i.res = append(i.res, re)
	}
}

func (i *GitMatcher) String() string {
	desc := fmt.Sprintf("Ignoring patterns from %s:", i.fp)
	if len(i.globs) > 0 {
		desc += "\n\tglobs: "
		for _, x := range i.globs {
			if strings.HasPrefix(x, i.basepath) {
				desc += x[len(i.basepath):] + " "
			} else {
				desc += x + " "
			}
		}
	}

	if len(i.res) > 0 {
		desc += "\n\tregular expressions: "
		for _, x := range i.res {
			desc += x.String() + " "
		}
	}

	return desc
}
<|endoftext|>


<commit_before>package match

import (
	"reflect"
	"regexp"
	"testing"
)

// Matcher is a helper object for chaining matcher conditions.
type Matcher struct {
	t     *testing.T
	value interface{}
}

// Fatal causes the unit test to immediately fail is one of the previous
// conditions has fail.
// Note: This will only affect previous conditions, not subsequent ones. You
// can build complex conditions this way.
// Ex: match.IsNotNil(t, value).Fatal().Equals(other)
func (m *Matcher) Fatal() *Matcher {
	if m.t.Failed() {
		m.t.FailNow()
	}
	return m
}

// IsNil asserts that the matched value is nil.
func (m *Matcher) IsNil() *Matcher {
	if m.value != nil {
		m.t.Errorf("expected == nil, got %v", m.value)
	}
	return m
}

// IsNotNil asserts that the matched value is not nil.
func (m *Matcher) IsNotNil() *Matcher {
	if m.value == nil {
		m.t.Error("expected != nil, got nil")
	}
	return m
}

// Equals asserts that the matched value is equal to value.
func (m *Matcher) Equals(value interface{}) *Matcher {
	if !reflect.DeepEqual(m.value, value) {
		m.t.Errorf("expected == %v, got %v", value, m.value)
	}
	return m
}

// NotEquals asserts that the match value is not equal to value.
func (m *Matcher) NotEquals(value interface{}) *Matcher {
	if reflect.DeepEqual(m.value, value) {
		m.t.Errorf("expected != %v, got %v", value, m.value)
	}
	return m
}

// LessThan asserts that the matched value is less than value.
// Note: This function will only work on numeric values.
// If a non-numeric value is passed, a fatal error will be thrown.
func (m *Matcher) LessThan(value interface{}) *Matcher {
	ok := true
	rv := reflect.ValueOf(m.value)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		ok = rv.Int() < reflect.ValueOf(value).Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ok = rv.Uint() < uint64(reflect.ValueOf(value).Int())
	case reflect.Float32, reflect.Float64:
		ok = rv.Float() < reflect.ValueOf(value).Float()
	default:
		m.t.Fatalf("expected numeric value, got %v", m.value)
	}
	if !ok {
		m.t.Errorf("expected < %v, got %v", value, m.value)
	}
	return m
}

// GreaterThan asserts that the matched value is greater then value.
// Note: This function will only work on numeric values.
// If a non-numeric value is passed, a fatal error will be thrown.
func (m *Matcher) GreaterThan(value interface{}) *Matcher {
	ok := true
	rv := reflect.ValueOf(m.value)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		ok = rv.Int() > reflect.ValueOf(value).Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ok = rv.Uint() > uint64(reflect.ValueOf(value).Int())
	case reflect.Float32, reflect.Float64:
		ok = rv.Float() > reflect.ValueOf(value).Float()
	default:
		m.t.Fatalf("expected numeric value, got %v", m.value)
	}
	if !ok {
		m.t.Errorf("expected < %v, got %v", value, m.value)
	}
	return m
}

// Contains asserts that the matched value contains value.
// If used on an array, asserts that the array contains value.
// If used on a map, asserts that the map contains a key with value.
// If used on a string, asserts that the string contains value.
func (m *Matcher) Contains(value interface{}) *Matcher {
	// TODO: Implement Matcher.Contains
	return m
}

// Matches asserts that the matched value matches the regex in pattern.
// Note: If the regex cannot be compiled, a fatal error will be thrown.
// If used on a non-string value, a fatal error will be thrown.
func (m *Matcher) Matches(pattern string) *Matcher {
	rv := reflect.ValueOf(m.value)
	if rv.Kind() != reflect.String {
		m.t.Fatalf("expected string, got %s", rv.Kind().String())
	}
	re, err := regexp.Compile(pattern)
	if err != nil {
		m.t.Fatal(err)
	}
	if !re.MatchString(rv.String()) {
		m.t.Errorf("expected %#q to match pattern %#q", rv.String(), pattern)
	}
	return m
}

// KindOf asserts that the matched value of the kind.
func (m *Matcher) KindOf(t reflect.Kind) *Matcher {
	// TODO: Implement Matcher.KindOf
	return m
}
<commit_msg>Implement KindOf matcher<commit_after>package match

import (
	"reflect"
	"regexp"
	"testing"
)

// Matcher is a helper object for chaining matcher conditions.
type Matcher struct {
	t     *testing.T
	value interface{}
}

// Fatal causes the unit test to immediately fail is one of the previous
// conditions has fail.
// Note: This will only affect previous conditions, not subsequent ones. You
// can build complex conditions this way.
// Ex: match.IsNotNil(t, value).Fatal().Equals(other)
func (m *Matcher) Fatal() *Matcher {
	if m.t.Failed() {
		m.t.FailNow()
	}
	return m
}

// IsNil asserts that the matched value is nil.
func (m *Matcher) IsNil() *Matcher {
	if m.value != nil {
		m.t.Errorf("expected == nil, got %v", m.value)
	}
	return m
}

// IsNotNil asserts that the matched value is not nil.
func (m *Matcher) IsNotNil() *Matcher {
	if m.value == nil {
		m.t.Error("expected != nil, got nil")
	}
	return m
}

// Equals asserts that the matched value is equal to value.
func (m *Matcher) Equals(value interface{}) *Matcher {
	if !reflect.DeepEqual(m.value, value) {
		m.t.Errorf("expected == %v, got %v", value, m.value)
	}
	return m
}

// NotEquals asserts that the match value is not equal to value.
func (m *Matcher) NotEquals(value interface{}) *Matcher {
	if reflect.DeepEqual(m.value, value) {
		m.t.Errorf("expected != %v, got %v", value, m.value)
	}
	return m
}

// LessThan asserts that the matched value is less than value.
// Note: This function will only work on numeric values.
// If a non-numeric value is passed, a fatal error will be thrown.
func (m *Matcher) LessThan(value interface{}) *Matcher {
	ok := true
	rv := reflect.ValueOf(m.value)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		ok = rv.Int() < reflect.ValueOf(value).Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ok = rv.Uint() < uint64(reflect.ValueOf(value).Int())
	case reflect.Float32, reflect.Float64:
		ok = rv.Float() < reflect.ValueOf(value).Float()
	default:
		m.t.Fatalf("expected numeric value, got %v", m.value)
	}
	if !ok {
		m.t.Errorf("expected < %v, got %v", value, m.value)
	}
	return m
}

// GreaterThan asserts that the matched value is greater then value.
// Note: This function will only work on numeric values.
// If a non-numeric value is passed, a fatal error will be thrown.
func (m *Matcher) GreaterThan(value interface{}) *Matcher {
	ok := true
	rv := reflect.ValueOf(m.value)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		ok = rv.Int() > reflect.ValueOf(value).Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		ok = rv.Uint() > uint64(reflect.ValueOf(value).Int())
	case reflect.Float32, reflect.Float64:
		ok = rv.Float() > reflect.ValueOf(value).Float()
	default:
		m.t.Fatalf("expected numeric value, got %v", m.value)
	}
	if !ok {
		m.t.Errorf("expected < %v, got %v", value, m.value)
	}
	return m
}

// Contains asserts that the matched value contains value.
// If used on an array, asserts that the array contains value.
// If used on a map, asserts that the map contains a key with value.
// If used on a string, asserts that the string contains value.
func (m *Matcher) Contains(value interface{}) *Matcher {
	// TODO: Implement Matcher.Contains
	return m
}

// Matches asserts that the matched value matches the regex in pattern.
// Note: If the regex cannot be compiled, a fatal error will be thrown.
// If used on a non-string value, a fatal error will be thrown.
func (m *Matcher) Matches(pattern string) *Matcher {
	rv := reflect.ValueOf(m.value)
	if rv.Kind() != reflect.String {
		m.t.Fatalf("expected string, got %s", rv.Kind().String())
	}
	re, err := regexp.Compile(pattern)
	if err != nil {
		m.t.Fatal(err)
	}
	if !re.MatchString(rv.String()) {
		m.t.Errorf("expected %#q to match pattern %#q", rv.String(), pattern)
	}
	return m
}

// KindOf asserts that the matched value of the kind.
func (m *Matcher) KindOf(kind reflect.Kind) *Matcher {
	rv := reflect.ValueOf(m.value)
	if rv.Kind() != kind {
		m.t.Errorf("expected kind %s, got %s", kind.String(), rv.Kind().String())
	}
	return m
}
<|endoftext|>


<commit_before>package crypto

import "testing"

func TestSigningRoundtrip(t *testing.T) {
	public, private := GenerateRandomEd25519Keypair()

	a := testSignable{
		hash: HashString("hello, world!"),
	}

	b := testSignable{
		hash: HashString("goodbye, world!"),
	}

	sigA, err := Sign(private, &a)
	if err != nil {
		t.Errorf("unexpected error signing: %s", err)
	}

	sigB, _ := Sign(private, &b)

	if err := Verify(public, &a, sigA); err != nil {
		t.Errorf("unexpected error verifying: %s", err)
	}

	if err := Verify(public, &a, sigB); err == nil || err.Error() != "bad signature" {
		t.Errorf("expected bad signature; got %s", err)
	}
}
<commit_msg>wrap/unwrap test<commit_after>package crypto

import "bytes"
import "testing"

func TestSigningRoundtrip(t *testing.T) {
	public, private := GenerateRandomEd25519Keypair()

	a := testSignable{
		hash: HashString("hello, world!"),
	}

	b := testSignable{
		hash: HashString("goodbye, world!"),
	}

	sigA, err := Sign(private, &a)
	if err != nil {
		t.Errorf("unexpected error signing: %s", err)
	}

	sigB, _ := Sign(private, &b)

	if err := Verify(public, &a, sigA); err != nil {
		t.Errorf("unexpected error verifying: %s", err)
	}

	if err := Verify(public, &a, sigB); err == nil || err.Error() != "bad signature" {
		t.Errorf("expected bad signature; got %s", err)
	}
}

var a = []byte{1, 2, 3}
var b = []byte{4, 5, 6, 7}

func TestWrapBase32(t *testing.T) {
	wrapA := wrap(a, "test-foo")
	expA := "test-foo(04106)"
	if wrapA != expA {
		t.Errorf("expected %s; got %s", expA, wrapA)
	}
}

func TestWrapUnwrapRoundtrip(t *testing.T) {
	wrapA := wrap(a, "test-foo")

	unwrapA, err := unwrapSlice(wrapA, "test-foo")
	if err != nil {
		t.Errorf("unexpected error unwrapping: %s", err)
	}

	if bytes.Compare(unwrapA, a) != 0 {
		t.Errorf("unwrap-wrap did not roundtrip; got %v, expected %v", unwrapA, a)
	}

	if _, err := unwrapSlice(wrapA, "test-bar"); err == nil {
		t.Errorf("unexpected success unwrapping: %s", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 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 rest

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"testing"

	gContext "github.com/gorilla/context"
	"github.com/stretchr/testify/assert"
)

// Test Handlers
type TestResourceHandler struct {
	BaseResourceHandler
}

func (t TestResourceHandler) ResourceName() string {
	return "widgets"
}

func (t TestResourceHandler) CreateResource(r RequestContext, data Payload,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

func (t TestResourceHandler) ReadResource(r RequestContext, id string,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

type ComplexTestResourceHandler struct {
	BaseResourceHandler
}

func (t ComplexTestResourceHandler) ResourceName() string {
	return "resources"
}

func (t ComplexTestResourceHandler) CreateURI() string {
	return "/api/v{version:[^/]+}/{company}/{category}/resources"
}
func (t ComplexTestResourceHandler) CreateResource(r RequestContext, data Payload,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

// Ensures that if a limit doesn't exist on the context, the default is returned.
func TestLimitDefault(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	assert.Equal(100, ctx.Limit())
}

// Ensures that if an invalid limit value is on the context, the default is returned.
func TestLimitBadValue(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	ctx = ctx.WithValue(limitKey, "blah")
	assert.Equal(100, ctx.Limit())
}

// Ensures that the correct limit is returned from the context.
func TestLimit(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	ctx = ctx.WithValue(limitKey, "5")
	assert.Equal(5, ctx.Limit())
}

// Ensures that Messages returns the messages set on the context.
func TestMessagesNoError(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	message := "foo"

	assert.Equal(0, len(ctx.Messages()))

	ctx.AddMessage(message)

	if assert.Equal(1, len(ctx.Messages())) {
		assert.Equal(message, ctx.Messages()[0])
	}
}

// Ensures that Messages returns the messages set on the context and the error message
// when an error is set.
func TestMessagesWithError(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	message := "foo"
	errMessage := "blah"
	err := fmt.Errorf(errMessage)

	ctx = ctx.setError(err)
	if assert.Equal(1, len(ctx.Messages())) {
		assert.Equal(errMessage, ctx.Messages()[0])
	}

	ctx.AddMessage(message)

	if assert.Equal(2, len(ctx.Messages())) {
		assert.Equal(message, ctx.Messages()[0])
		assert.Equal(errMessage, ctx.Messages()[1])
	}
}

// Ensures that Header returns the request Header.
func TestHeader(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)

	assert.Equal(req.Header, ctx.Header())
}

func TestBuildURL(t *testing.T) {
	assert := assert.New(t)

	api := NewAPI(NewConfiguration())
	api.RegisterResourceHandler(TestResourceHandler{})
	api.RegisterResourceHandler(ComplexTestResourceHandler{})

	req, _ := http.NewRequest("GET", "https://example.com/api/v1/widgets", nil)
	gContext.Set(req, "version", "1")

	ctx := NewContextWithRouter(nil, req, api.(*muxAPI).router)

	url, _ := ctx.BuildURL("widgets", HandleCreate, nil)
	assert.Equal(url, "http://example.com/api/v1/widgets")

	url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "111"})
	assert.Equal(url, "http://example.com/api/v1/widgets/111")

	url, _ = ctx.BuildPath("widgets", HandleRead, RouteVars{"resource_id": "111"})
	assert.Equal(url, "/api/v1/widgets/111")

	// Secure request should produce https URL
	req.TLS = &tls.ConnectionState{}
	url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "222"})
	assert.Equal(url, "https://example.com/api/v1/widgets/222")

	url, _ = ctx.BuildURL("resources", HandleCreate, RouteVars{
		"company":  "acme",
		"category": "anvils"})
	assert.Equal(url, "https://example.com/api/v1/acme/anvils/resources")
}
<commit_msg>Add version change to tests.<commit_after>/*
Copyright 2014 Workiva, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 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 rest

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"testing"

	gContext "github.com/gorilla/context"
	"github.com/stretchr/testify/assert"
)

// Test Handlers
type TestResourceHandler struct {
	BaseResourceHandler
}

func (t TestResourceHandler) ResourceName() string {
	return "widgets"
}

func (t TestResourceHandler) CreateResource(r RequestContext, data Payload,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

func (t TestResourceHandler) ReadResource(r RequestContext, id string,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

type ComplexTestResourceHandler struct {
	BaseResourceHandler
}

func (t ComplexTestResourceHandler) ResourceName() string {
	return "resources"
}

func (t ComplexTestResourceHandler) CreateURI() string {
	return "/api/v{version:[^/]+}/{company}/{category}/resources"
}
func (t ComplexTestResourceHandler) CreateResource(r RequestContext, data Payload,
	version string) (Resource, error) {

	resource := map[string]string{"test": "resource"}
	return resource, nil
}

// Ensures that if a limit doesn't exist on the context, the default is returned.
func TestLimitDefault(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	assert.Equal(100, ctx.Limit())
}

// Ensures that if an invalid limit value is on the context, the default is returned.
func TestLimitBadValue(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	ctx = ctx.WithValue(limitKey, "blah")
	assert.Equal(100, ctx.Limit())
}

// Ensures that the correct limit is returned from the context.
func TestLimit(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	ctx = ctx.WithValue(limitKey, "5")
	assert.Equal(5, ctx.Limit())
}

// Ensures that Messages returns the messages set on the context.
func TestMessagesNoError(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	message := "foo"

	assert.Equal(0, len(ctx.Messages()))

	ctx.AddMessage(message)

	if assert.Equal(1, len(ctx.Messages())) {
		assert.Equal(message, ctx.Messages()[0])
	}
}

// Ensures that Messages returns the messages set on the context and the error message
// when an error is set.
func TestMessagesWithError(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)
	message := "foo"
	errMessage := "blah"
	err := fmt.Errorf(errMessage)

	ctx = ctx.setError(err)
	if assert.Equal(1, len(ctx.Messages())) {
		assert.Equal(errMessage, ctx.Messages()[0])
	}

	ctx.AddMessage(message)

	if assert.Equal(2, len(ctx.Messages())) {
		assert.Equal(message, ctx.Messages()[0])
		assert.Equal(errMessage, ctx.Messages()[1])
	}
}

// Ensures that Header returns the request Header.
func TestHeader(t *testing.T) {
	assert := assert.New(t)
	req, _ := http.NewRequest("GET", "http://example.com/foo", nil)
	ctx := NewContext(nil, req)

	assert.Equal(req.Header, ctx.Header())
}

func TestBuildURL(t *testing.T) {
	assert := assert.New(t)

	api := NewAPI(NewConfiguration())
	api.RegisterResourceHandler(TestResourceHandler{})
	api.RegisterResourceHandler(ComplexTestResourceHandler{})

	req, _ := http.NewRequest("GET", "https://example.com/api/v1/widgets", nil)
	gContext.Set(req, "version", "1")

	ctx := NewContextWithRouter(nil, req, api.(*muxAPI).router)

	url, _ := ctx.BuildURL("widgets", HandleCreate, nil)
	assert.Equal(url, "http://example.com/api/v1/widgets")

	url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "111"})
	assert.Equal(url, "http://example.com/api/v1/widgets/111")

	url, _ = ctx.BuildPath("widgets", HandleRead, RouteVars{"resource_id": "111"})
	assert.Equal(url, "/api/v1/widgets/111")

	// Secure request should produce https URL
	req.TLS = &tls.ConnectionState{}
	url, _ = ctx.BuildURL("widgets", HandleRead, RouteVars{"resource_id": "222"})
	assert.Equal(url, "https://example.com/api/v1/widgets/222")

	// Make sure this works with another version number
	gContext.Set(req, "version", "2")
	url, _ = ctx.BuildURL("resources", HandleCreate, RouteVars{
		"company":  "acme",
		"category": "anvils"})
	assert.Equal(url, "https://example.com/api/v2/acme/anvils/resources")
}
<|endoftext|>


<commit_before>package restconf

import (
	"crypto/tls"
	"fmt"
	"io"
	"mime"
	"net"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/c2stack/c2g/c2"
	"github.com/c2stack/c2g/meta"
	"github.com/c2stack/c2g/node"
	"golang.org/x/net/websocket"
)

type restconfError struct {
	Code int
	Msg  string
}

func (err *restconfError) Error() string {
	return err.Msg
}

func (err *restconfError) HttpCode() int {
	return err.Code
}

func NewService(yangPath meta.StreamSource, root *node.Browser) *Service {
	service := &Service{
		Path:     "/restconf/",
		Root:     root,
		mux:      http.NewServeMux(),
		yangPath: yangPath,
	}
	service.mux.HandleFunc("/.well-known/host-meta", service.resources)
	service.mux.Handle("/restconf/", http.StripPrefix("/restconf/", service))
	service.mux.HandleFunc("/meta/", service.meta)

	service.socketHandler = &WebSocketService{Factory: service}
	service.mux.Handle("/restsock/", websocket.Handler(service.socketHandler.Handle))
	return service
}

type Auth interface {
	ConstrainRoot(r *http.Request, constraints *node.Constraints) error
}

type Service struct {
	Path            string
	yangPath        meta.StreamSource
	Root            *node.Browser
	mux             *http.ServeMux
	docrootSource   *docRootImpl
	DocRoot         string
	Port            string
	Iface           string
	CallbackAddress string
	CallHome        *CallHome
	ReadTimeout     int
	WriteTimeout    int
	socketHandler   *WebSocketService
	Tls             *Tls
	Auth            Auth
}

func (service *Service) SetAppVersion(ver string) {
	service.mux.HandleFunc("/.ver", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(ver))
	})
}

func (service *Service) EffectiveCallbackAddress() string {
	if len(service.CallbackAddress) > 0 {
		return service.CallbackAddress
	}
	if len(service.Iface) == 0 {
		panic("No iface given for management port")
	}
	ip := c2.GetIpForIface(service.Iface)
	proto := "http://"
	if service.Tls != nil {
		proto = "https://"
	}
	return fmt.Sprintf("%s%s%s/", proto, ip, service.Port)
}

func (service *Service) GetHttpClient() *http.Client {
	var client *http.Client
	if service.Tls != nil {
		tlsConfig := &tls.Config{
			Certificates: service.Tls.Config.Certificates,
			RootCAs:      service.Tls.Config.RootCAs,
		}
		transport := &http.Transport{TLSClientConfig: tlsConfig}
		client = &http.Client{Transport: transport}
	} else {
		client = http.DefaultClient
	}
	return client
}

func (service *Service) handleError(err error, w http.ResponseWriter) {
	if httpErr, ok := err.(c2.HttpError); ok {
		if httpErr.HttpCode() >= 500 {
			c2.Err.Print(httpErr.Error() + "\n" + httpErr.Stack())
		}
		http.Error(w, httpErr.Error(), httpErr.HttpCode())
	} else {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (self *Service) Subscribe(sub *node.Subscription) error {
	if sel := self.Root.Root().Find(sub.Path); sel.LastErr == nil {
		closer, notifSel := sel.Notifications(sub)
		if notifSel.LastErr != nil {
			return notifSel.LastErr
		}
		sub.Notification = notifSel.Meta().(*meta.Notification)
		sub.Closer = closer
	} else {
		return sel.LastErr
	}
	return nil
}

func (self *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h := w.Header()
	h.Set("Access-Control-Allow-Headers", "origin, content-type, accept")
	h.Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE, PATCH")
	h.Set("Access-Control-Allow-Origin", "*")
	if r.Method == "OPTIONS" {
		return
	}
	var err error
	var payload node.Node
	sel := self.Root.Root()
	if self.Auth != nil {
		if err = self.Auth.ConstrainRoot(r, sel.Constraints); err != nil {
			self.handleError(err, w)
			return
		}
	}
	c2.Info.Printf("%s %s", r.Method, r.URL)
	if sel = sel.FindUrl(r.URL); sel.LastErr == nil {
		if sel.IsNil() {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
		if err != nil {
			self.handleError(err, w)
			return
		}
		switch r.Method {
		case "DELETE":
			err = sel.Delete()
		case "GET":
			w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
			output := node.NewJsonWriter(w).Node()
			err = sel.InsertInto(output).LastErr
		case "PUT":
			err = sel.UpsertFrom(node.NewJsonReader(r.Body).Node()).LastErr
		case "POST":
			if meta.IsAction(sel.Meta()) {
				input := node.NewJsonReader(r.Body).Node()
				if outputSel := sel.Action(input); !outputSel.IsNil() {
					w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
					err = outputSel.InsertInto(node.NewJsonWriter(w).Node()).LastErr
				} else {
					err = outputSel.LastErr
				}
			} else {
				payload = node.NewJsonReader(r.Body).Node()
				err = sel.InsertFrom(payload).LastErr
			}
		default:
			http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		}
	} else {
		err = sel.LastErr
	}

	if err != nil {
		self.handleError(err, w)
	}
}

type docRootImpl struct {
	docroot meta.StreamSource
}

func (service *Service) SetDocRoot(docroot meta.StreamSource) {
	service.docrootSource = &docRootImpl{docroot: docroot}
	service.mux.Handle("/ui/", http.StripPrefix("/ui/", service.docrootSource))
}

func (service *Service) AddHandler(pattern string, handler http.Handler) {
	service.mux.Handle(pattern, http.StripPrefix(pattern, handler))
}

func (service *Service) Listen() {
	c2.Info.Printf("Starting RESTCONF interface on port %s", service.Port)
	s := &http.Server{
		Addr:           service.Port,
		Handler:        service.mux,
		ReadTimeout:    time.Duration(service.ReadTimeout) * time.Millisecond,
		WriteTimeout:   time.Duration(service.WriteTimeout) * time.Millisecond,
		MaxHeaderBytes: 1 << 20,
	}
	if service.Tls != nil {
		s.TLSConfig = &service.Tls.Config
		conn, err := net.Listen("tcp", s.Addr)
		if err != nil {
			panic(err)
		}
		tlsListener := tls.NewListener(conn, &service.Tls.Config)
		c2.Err.Fatal(s.Serve(tlsListener))
	} else {
		c2.Err.Fatal(s.ListenAndServe())
	}
}

func (service *Service) Stop() {
	if service.docrootSource != nil && service.docrootSource.docroot != nil {
		meta.CloseResource(service.docrootSource.docroot)
	}
	// TODO - actually stop service
}

func (service *docRootImpl) ServeHTTP(wtr http.ResponseWriter, req *http.Request) {
	path := req.URL.Path
	if path == "" {
		path = "index.html"
	}
	if rdr, err := service.docroot.OpenStream(path, ""); err != nil {
		http.Error(wtr, err.Error(), http.StatusInternalServerError)
	} else {
		defer meta.CloseResource(rdr)
		ext := filepath.Ext(path)
		ctype := mime.TypeByExtension(ext)
		wtr.Header().Set("Content-Type", ctype)
		if _, err = io.Copy(wtr, rdr); err != nil {
			http.Error(wtr, err.Error(), http.StatusInternalServerError)
		}
		// Eventually support this but need file seeker to do that.
		// http.ServeContent(wtr, req, path, time.Now(), &ReaderPeeker{rdr})
	}
}

func (service *Service) meta(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
	}
	if p := strings.TrimPrefix(r.URL.Path, "/meta/"); len(p) < len(r.URL.Path) {
		r.URL.Path = p
	} else {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	m := service.Root.Meta.(*meta.Module)
	_, noexpand := r.URL.Query()["noexpand"]

	sel := node.SelectModule(service.yangPath, m, !noexpand).Root()
	if sel = sel.FindUrl(r.URL); sel.LastErr != nil {
		service.handleError(sel.LastErr, w)
		return
	} else if sel.IsNil() {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	} else {
		w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
		output := node.NewJsonWriter(w).Node()
		if err := sel.InsertInto(output).LastErr; err != nil {
			service.handleError(err, w)
			return
		}
	}
}

func (service *Service) resources(w http.ResponseWriter, r *http.Request) {
	// RESTCONF Sec. 3.1
	fmt.Fprintf(w, `"xrd" : { "link" : { "@rel" : "restconf", "@href" : "/restconf" } } }`)
}
<commit_msg>allow redirect of root for web apps<commit_after>package restconf

import (
	"crypto/tls"
	"fmt"
	"io"
	"mime"
	"net"
	"net/http"
	"path/filepath"
	"strings"
	"time"

	"github.com/c2stack/c2g/c2"
	"github.com/c2stack/c2g/meta"
	"github.com/c2stack/c2g/node"
	"golang.org/x/net/websocket"
)

type restconfError struct {
	Code int
	Msg  string
}

func (err *restconfError) Error() string {
	return err.Msg
}

func (err *restconfError) HttpCode() int {
	return err.Code
}

func NewService(yangPath meta.StreamSource, root *node.Browser) *Service {
	service := &Service{
		Path:     "/restconf/",
		Root:     root,
		mux:      http.NewServeMux(),
		yangPath: yangPath,
	}
	service.mux.HandleFunc("/.well-known/host-meta", service.resources)
	service.mux.Handle("/restconf/", http.StripPrefix("/restconf/", service))
	service.mux.HandleFunc("/meta/", service.meta)

	service.socketHandler = &WebSocketService{Factory: service}
	service.mux.Handle("/restsock/", websocket.Handler(service.socketHandler.Handle))
	return service
}

type Auth interface {
	ConstrainRoot(r *http.Request, constraints *node.Constraints) error
}

type Service struct {
	Path            string
	yangPath        meta.StreamSource
	Root            *node.Browser
	mux             *http.ServeMux
	docrootSource   *docRootImpl
	DocRoot         string
	Port            string
	Iface           string
	CallbackAddress string
	CallHome        *CallHome
	ReadTimeout     int
	WriteTimeout    int
	socketHandler   *WebSocketService
	Tls             *Tls
	Auth            Auth
}

// SetRootRedirect will direct "/" to any url you want. Useful when you want to server your user
// interface.  Example: SetRootRedirect("/ui/index.html")
func (service *Service) SetRootRedirect(path string) {
	service.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, path, 301)
	})
}

func (service *Service) SetAppVersion(ver string) {
	service.mux.HandleFunc("/.ver", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte(ver))
	})
}

func (service *Service) EffectiveCallbackAddress() string {
	if len(service.CallbackAddress) > 0 {
		return service.CallbackAddress
	}
	if len(service.Iface) == 0 {
		panic("No iface given for management port")
	}
	ip := c2.GetIpForIface(service.Iface)
	proto := "http://"
	if service.Tls != nil {
		proto = "https://"
	}
	return fmt.Sprintf("%s%s%s/", proto, ip, service.Port)
}

func (service *Service) GetHttpClient() *http.Client {
	var client *http.Client
	if service.Tls != nil {
		tlsConfig := &tls.Config{
			Certificates: service.Tls.Config.Certificates,
			RootCAs:      service.Tls.Config.RootCAs,
		}
		transport := &http.Transport{TLSClientConfig: tlsConfig}
		client = &http.Client{Transport: transport}
	} else {
		client = http.DefaultClient
	}
	return client
}

func (service *Service) handleError(err error, w http.ResponseWriter) {
	if httpErr, ok := err.(c2.HttpError); ok {
		if httpErr.HttpCode() >= 500 {
			c2.Err.Print(httpErr.Error() + "\n" + httpErr.Stack())
		}
		http.Error(w, httpErr.Error(), httpErr.HttpCode())
	} else {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func (self *Service) Subscribe(sub *node.Subscription) error {
	if sel := self.Root.Root().Find(sub.Path); sel.LastErr == nil {
		closer, notifSel := sel.Notifications(sub)
		if notifSel.LastErr != nil {
			return notifSel.LastErr
		}
		sub.Notification = notifSel.Meta().(*meta.Notification)
		sub.Closer = closer
	} else {
		return sel.LastErr
	}
	return nil
}

func (self *Service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h := w.Header()
	h.Set("Access-Control-Allow-Headers", "origin, content-type, accept")
	h.Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, DELETE, PATCH")
	h.Set("Access-Control-Allow-Origin", "*")
	if r.Method == "OPTIONS" {
		return
	}
	var err error
	var payload node.Node
	sel := self.Root.Root()
	if self.Auth != nil {
		if err = self.Auth.ConstrainRoot(r, sel.Constraints); err != nil {
			self.handleError(err, w)
			return
		}
	}
	c2.Info.Printf("%s %s", r.Method, r.URL)
	if sel = sel.FindUrl(r.URL); sel.LastErr == nil {
		if sel.IsNil() {
			http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
			return
		}
		if err != nil {
			self.handleError(err, w)
			return
		}
		switch r.Method {
		case "DELETE":
			err = sel.Delete()
		case "GET":
			w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
			output := node.NewJsonWriter(w).Node()
			err = sel.InsertInto(output).LastErr
		case "PUT":
			err = sel.UpsertFrom(node.NewJsonReader(r.Body).Node()).LastErr
		case "POST":
			if meta.IsAction(sel.Meta()) {
				input := node.NewJsonReader(r.Body).Node()
				if outputSel := sel.Action(input); !outputSel.IsNil() {
					w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
					err = outputSel.InsertInto(node.NewJsonWriter(w).Node()).LastErr
				} else {
					err = outputSel.LastErr
				}
			} else {
				payload = node.NewJsonReader(r.Body).Node()
				err = sel.InsertFrom(payload).LastErr
			}
		default:
			http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
		}
	} else {
		err = sel.LastErr
	}

	if err != nil {
		self.handleError(err, w)
	}
}

type docRootImpl struct {
	docroot meta.StreamSource
}

func (service *Service) SetDocRoot(docroot meta.StreamSource) {
	service.docrootSource = &docRootImpl{docroot: docroot}
	service.mux.Handle("/ui/", http.StripPrefix("/ui/", service.docrootSource))
}

func (service *Service) AddHandler(pattern string, handler http.Handler) {
	service.mux.Handle(pattern, http.StripPrefix(pattern, handler))
}

func (service *Service) Listen() {
	c2.Info.Printf("Starting RESTCONF interface on port %s", service.Port)
	s := &http.Server{
		Addr:           service.Port,
		Handler:        service.mux,
		ReadTimeout:    time.Duration(service.ReadTimeout) * time.Millisecond,
		WriteTimeout:   time.Duration(service.WriteTimeout) * time.Millisecond,
		MaxHeaderBytes: 1 << 20,
	}
	if service.Tls != nil {
		s.TLSConfig = &service.Tls.Config
		conn, err := net.Listen("tcp", s.Addr)
		if err != nil {
			panic(err)
		}
		tlsListener := tls.NewListener(conn, &service.Tls.Config)
		c2.Err.Fatal(s.Serve(tlsListener))
	} else {
		c2.Err.Fatal(s.ListenAndServe())
	}
}

func (service *Service) Stop() {
	if service.docrootSource != nil && service.docrootSource.docroot != nil {
		meta.CloseResource(service.docrootSource.docroot)
	}
	// TODO - actually stop service
}

func (service *docRootImpl) ServeHTTP(wtr http.ResponseWriter, req *http.Request) {
	path := req.URL.Path
	if path == "" {
		path = "index.html"
	}
	if rdr, err := service.docroot.OpenStream(path, ""); err != nil {
		http.Error(wtr, err.Error(), http.StatusInternalServerError)
	} else {
		defer meta.CloseResource(rdr)
		ext := filepath.Ext(path)
		ctype := mime.TypeByExtension(ext)
		wtr.Header().Set("Content-Type", ctype)
		if _, err = io.Copy(wtr, rdr); err != nil {
			http.Error(wtr, err.Error(), http.StatusInternalServerError)
		}
		// Eventually support this but need file seeker to do that.
		// http.ServeContent(wtr, req, path, time.Now(), &ReaderPeeker{rdr})
	}
}

func (service *Service) meta(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
	}
	if p := strings.TrimPrefix(r.URL.Path, "/meta/"); len(p) < len(r.URL.Path) {
		r.URL.Path = p
	} else {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	}
	m := service.Root.Meta.(*meta.Module)
	_, noexpand := r.URL.Query()["noexpand"]

	sel := node.SelectModule(service.yangPath, m, !noexpand).Root()
	if sel = sel.FindUrl(r.URL); sel.LastErr != nil {
		service.handleError(sel.LastErr, w)
		return
	} else if sel.IsNil() {
		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
		return
	} else {
		w.Header().Set("Content-Type", mime.TypeByExtension(".json"))
		output := node.NewJsonWriter(w).Node()
		if err := sel.InsertInto(output).LastErr; err != nil {
			service.handleError(err, w)
			return
		}
	}
}

func (service *Service) resources(w http.ResponseWriter, r *http.Request) {
	// RESTCONF Sec. 3.1
	fmt.Fprintf(w, `"xrd" : { "link" : { "@rel" : "restconf", "@href" : "/restconf" } } }`)
}
<|endoftext|>


<commit_before>package constants

// THIS FILE IS GENERATED AUTOMATICALLY, NO TOUCHING!!!!!

const (
	BOSHURL         = "https://s3.amazonaws.com/bbl-precompiled-bosh-releases/release-bosh-260.5-on-ubuntu-trusty-stemcell-3312.15.tgz"
	BOSHSHA1        = "2d6cdb684f1fc536d71ce076b90bc78a1ba190a4"
	BOSHAWSCPIURL   = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-aws-cpi-release?v=62"
	BOSHAWSCPISHA1  = "f36967927ceae09e5663a41fdda199edfe649dc6"
	AWSStemcellURL  = "https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-3312.15-aws-xen-hvm-ubuntu-trusty-go_agent.tgz"
	AWSStemcellSHA1 = "f5e78f61b8026377300db544e9d3ca0b89516af3"
	BOSHGCPCPIURL   = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-google-cpi-release?v=25.6.2"
	BOSHGCPCPISHA1  = "b4865397d867655fdcc112bc5a7f9a5025cdf311"
	GCPStemcellURL  = "https://s3.amazonaws.com/bosh-gce-light-stemcells/light-bosh-stemcell-3312.15-google-kvm-ubuntu-trusty-go_agent.tgz"
	GCPStemcellSHA1 = "3ac3ee83750f75bd74e8d3e3ad97808db23c30ba"
)
<commit_msg>Update constants<commit_after>package constants

// THIS FILE IS GENERATED AUTOMATICALLY, NO TOUCHING!!!!!

const (
	BOSHURL         = "https://s3.amazonaws.com/bbl-precompiled-bosh-releases/release-bosh-260.5-on-ubuntu-trusty-stemcell-3312.17.tgz"
	BOSHSHA1        = "2954125498eb400b06d66f973bd017777cfa640a"
	BOSHAWSCPIURL   = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-aws-cpi-release?v=62"
	BOSHAWSCPISHA1  = "f36967927ceae09e5663a41fdda199edfe649dc6"
	AWSStemcellURL  = "https://s3.amazonaws.com/bosh-aws-light-stemcells/light-bosh-stemcell-3312.17-aws-xen-hvm-ubuntu-trusty-go_agent.tgz"
	AWSStemcellSHA1 = "fa6908fee576ac86222a43700ce19c40051be403"
	BOSHGCPCPIURL   = "https://bosh.io/d/github.com/cloudfoundry-incubator/bosh-google-cpi-release?v=25.6.2"
	BOSHGCPCPISHA1  = "b4865397d867655fdcc112bc5a7f9a5025cdf311"
	GCPStemcellURL  = "https://s3.amazonaws.com/bosh-gce-light-stemcells/light-bosh-stemcell-3312.15-google-kvm-ubuntu-trusty-go_agent.tgz"
	GCPStemcellSHA1 = "3ac3ee83750f75bd74e8d3e3ad97808db23c30ba"
)
<|endoftext|>


<commit_before>package scenario

import (
	"time"

	"github.com/catatsuy/isucon6-final/bench/fails"
	"github.com/catatsuy/isucon6-final/bench/score"
	"github.com/catatsuy/isucon6-final/bench/seed"
	"github.com/catatsuy/isucon6-final/bench/session"
)

const (
	initialWatcherNum             = 10
	watcherIncreaseInterval       = 5
	StrokeReceiveScore      int64 = 1
)

// 一人がroomを作る→大勢がそのroomをwatchする
func Matsuri(origins []string, timeout int) {
	s := session.New(randomOrigin(origins))
	defer s.Bye()

	token, ok := fetchCSRFToken(s, "/")
	if !ok {
		return
	}

	room, ok := makeRoom(s, token)
	if !ok {
		return
	}

	seedStrokes := seed.GetStrokes("isu")

	postTimes := make(map[int64]time.Time)

	start := time.Now()

	postedStrokes := make([]Stroke, 0)

	go func() {
		// 2秒おきにstrokeをPOSTする
		for {
			for _, seedStroke := range seedStrokes {
				postTime := time.Now()

				stroke, ok := drawStroke(s, token, room.ID, seed.FluctuateStroke(seedStroke))
				if ok {
					postTimes[stroke.ID] = postTime
					postedStrokes = append(postedStrokes, *stroke)
				}
				time.Sleep(2 * time.Second)
				if time.Now().Sub(start).Seconds() > float64(timeout) {
					return
				}
			}
		}
	}()

	watchers := make([]*RoomWatcher, 0)

	for {
		// watcherIncreaseInterval秒おきに、 (まだ退室していないwatcherの数 - 既に退室したwatcherの数) の人数が入室する

		n := 0
		penalty := 0
		for _, w := range watchers {
			if len(w.StrokeLogs) > 0 && len(w.EndCh) == 0 { // 既に最初のStrokeLogを1つ以上受け取ってる、かつ、まだ退室してない
				n++
			}
			if len(w.EndCh) > 0 {
				penalty++
			}
		}

		// 既に退室した人数をペナルティとする
		n = n - penalty

		if n <= 0 { // ゼロならinitialWatcherNum人が入室する（特に初回）
			n = initialWatcherNum
		}

		for i := 0; i < n; i++ {
			watchers = append(watchers, NewRoomWatcher(randomOrigin(origins), room.ID))
		}

		time.Sleep(time.Duration(watcherIncreaseInterval) * time.Second)
		if time.Now().Sub(start).Seconds() > float64(timeout-watcherIncreaseInterval) {
			break
		}
	}

	// ここまでで最大 initialWatcherNum * 2 ^ ((timeout - watcherIncreaseInterval) / watcherIncreaseInterval) 人が入室してるはず
	// 例えば initialWatcherNum=10, timeout=55, watcherIncreaseInterval=5 なら 10 * 2 ^ ((55-5)/5) = 10240 人

	//fmt.Println("stop")
	for _, w := range watchers {
		w.Leave()
	}
	//fmt.Println("wait")
	for _, w := range watchers {
		<-w.EndCh
	}
	//fmt.Println("done")

	// TODO: watcher_countが正しいか

	for _, w := range watchers {
		for i, strokeLog := range w.StrokeLogs {
			postTime := postTimes[strokeLog.Stroke.ID]
			timeTaken := strokeLog.ReceivedTime.Sub(postTime).Seconds()

			if timeTaken < 2 {
				score.Increment(StrokeReceiveScore)
			}

			if i >= len(postedStrokes) {
				// 普通は起こらないはず
				break
			}
			if strokeLog.ID != postedStrokes[i].ID {
				fails.Critical("streamされたstrokeに抜け・狂いがあります", nil)
				break
			}
			if len(strokeLog.Points) != len(postedStrokes[i].Points) {
				fails.Critical("streamされたstrokeが間違っています", nil)
				break
			}
		}
	}
}
<commit_msg>Don't increment score when check failed<commit_after>package scenario

import (
	"time"

	"github.com/catatsuy/isucon6-final/bench/fails"
	"github.com/catatsuy/isucon6-final/bench/score"
	"github.com/catatsuy/isucon6-final/bench/seed"
	"github.com/catatsuy/isucon6-final/bench/session"
)

const (
	initialWatcherNum             = 10
	watcherIncreaseInterval       = 5
	StrokeReceiveScore      int64 = 1
)

// 一人がroomを作る→大勢がそのroomをwatchする
func Matsuri(origins []string, timeout int) {
	s := session.New(randomOrigin(origins))
	defer s.Bye()

	token, ok := fetchCSRFToken(s, "/")
	if !ok {
		return
	}

	room, ok := makeRoom(s, token)
	if !ok {
		return
	}

	seedStrokes := seed.GetStrokes("isu")

	postTimes := make(map[int64]time.Time)

	start := time.Now()

	postedStrokes := make([]Stroke, 0)

	go func() {
		// 2秒おきにstrokeをPOSTする
		for {
			for _, seedStroke := range seedStrokes {
				postTime := time.Now()

				stroke, ok := drawStroke(s, token, room.ID, seed.FluctuateStroke(seedStroke))
				if ok {
					postTimes[stroke.ID] = postTime
					postedStrokes = append(postedStrokes, *stroke)
				}
				time.Sleep(2 * time.Second)
				if time.Now().Sub(start).Seconds() > float64(timeout) {
					return
				}
			}
		}
	}()

	watchers := make([]*RoomWatcher, 0)

	for {
		// watcherIncreaseInterval秒おきに、 (まだ退室していないwatcherの数 - 既に退室したwatcherの数) の人数が入室する

		n := 0
		penalty := 0
		for _, w := range watchers {
			if len(w.StrokeLogs) > 0 && len(w.EndCh) == 0 { // 既に最初のStrokeLogを1つ以上受け取ってる、かつ、まだ退室してない
				n++
			}
			if len(w.EndCh) > 0 {
				penalty++
			}
		}

		// 既に退室した人数をペナルティとする
		n = n - penalty

		if n <= 0 { // ゼロならinitialWatcherNum人が入室する（特に初回）
			n = initialWatcherNum
		}

		for i := 0; i < n; i++ {
			watchers = append(watchers, NewRoomWatcher(randomOrigin(origins), room.ID))
		}

		time.Sleep(time.Duration(watcherIncreaseInterval) * time.Second)
		if time.Now().Sub(start).Seconds() > float64(timeout-watcherIncreaseInterval) {
			break
		}
	}

	// ここまでで最大 initialWatcherNum * 2 ^ ((timeout - watcherIncreaseInterval) / watcherIncreaseInterval) 人が入室してるはず
	// 例えば initialWatcherNum=10, timeout=55, watcherIncreaseInterval=5 なら 10 * 2 ^ ((55-5)/5) = 10240 人

	//fmt.Println("stop")
	for _, w := range watchers {
		w.Leave()
	}
	//fmt.Println("wait")
	for _, w := range watchers {
		<-w.EndCh
	}
	//fmt.Println("done")

	// TODO: watcher_countが正しいか

	for _, w := range watchers {
		for i, strokeLog := range w.StrokeLogs {
			postTime := postTimes[strokeLog.Stroke.ID]

			if i >= len(postedStrokes) {
				// 普通は起こらないはず
				break
			}
			if strokeLog.ID != postedStrokes[i].ID {
				fails.Critical("streamされたstrokeに抜け・狂いがあります", nil)
				break
			}
			if len(strokeLog.Points) != len(postedStrokes[i].Points) {
				fails.Critical("streamされたstrokeが間違っています", nil)
				break
			}

			timeTaken := strokeLog.ReceivedTime.Sub(postTime).Seconds()

			if timeTaken < 2 {
				score.Increment(StrokeReceiveScore)
			}
		}
	}
}
<|endoftext|>


<commit_before>package eth

import (
	"crypto/ecdsa"
	"fmt"
	"strings"

	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	ethlogger "github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/p2p/discover"
	"github.com/ethereum/go-ethereum/p2p/nat"
	"github.com/ethereum/go-ethereum/pow/ezp"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/ethereum/go-ethereum/whisper"
)

var logger = ethlogger.NewLogger("SERV")
var jsonlogger = ethlogger.NewJsonLogger()

type Config struct {
	Name      string
	KeyStore  string
	DataDir   string
	LogFile   string
	LogLevel  int
	KeyRing   string
	LogFormat string

	MaxPeers int
	Port     string

	// This should be a space-separated list of
	// discovery node URLs.
	BootNodes string

	// This key is used to identify the node on the network.
	// If nil, an ephemeral key is used.
	NodeKey *ecdsa.PrivateKey

	NAT  nat.Interface
	Shh  bool
	Dial bool

	KeyManager *crypto.KeyManager
}

func (cfg *Config) parseBootNodes() []*discover.Node {
	var ns []*discover.Node
	for _, url := range strings.Split(cfg.BootNodes, " ") {
		if url == "" {
			continue
		}
		n, err := discover.ParseNode(url)
		if err != nil {
			logger.Errorf("Bootstrap URL %s: %v\n", url, err)
			continue
		}
		ns = append(ns, n)
	}
	return ns
}

type Ethereum struct {
	// Channel for shutting down the ethereum
	shutdownChan chan bool
	quit         chan bool

	// DB interface
	db        ethutil.Database
	blacklist p2p.Blacklist

	//*** SERVICES ***
	// State manager for processing new blocks and managing the over all states
	blockProcessor *core.BlockProcessor
	txPool         *core.TxPool
	chainManager   *core.ChainManager
	blockPool      *BlockPool
	whisper        *whisper.Whisper

	net      *p2p.Server
	eventMux *event.TypeMux
	txSub    event.Subscription
	blockSub event.Subscription

	RpcServer  rpc.RpcServer
	WsServer   rpc.RpcServer
	keyManager *crypto.KeyManager

	logger ethlogger.LogSystem

	Mining bool
}

func New(config *Config) (*Ethereum, error) {
	// Boostrap database
	logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
	db, err := ethdb.NewLDBDatabase("blockchain")
	if err != nil {
		return nil, err
	}

	// Perform database sanity checks
	d, _ := db.Get([]byte("ProtocolVersion"))
	protov := ethutil.NewValue(d).Uint()
	if protov != ProtocolVersion && protov != 0 {
		return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
	}

	// Create new keymanager
	var keyManager *crypto.KeyManager
	switch config.KeyStore {
	case "db":
		keyManager = crypto.NewDBKeyManager(db)
	case "file":
		keyManager = crypto.NewFileKeyManager(config.DataDir)
	default:
		return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
	}
	// Initialise the keyring
	keyManager.Init(config.KeyRing, 0, false)

	saveProtocolVersion(db)
	//ethutil.Config.Db = db

	eth := &Ethereum{
		shutdownChan: make(chan bool),
		quit:         make(chan bool),
		db:           db,
		keyManager:   keyManager,
		blacklist:    p2p.NewBlacklist(),
		eventMux:     &event.TypeMux{},
		logger:       logger,
	}

	eth.chainManager = core.NewChainManager(db, eth.EventMux())
	eth.txPool = core.NewTxPool(eth.EventMux())
	eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux())
	eth.chainManager.SetProcessor(eth.blockProcessor)
	eth.whisper = whisper.New()

	hasBlock := eth.chainManager.HasBlock
	insertChain := eth.chainManager.InsertChain
	eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)

	ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
	protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()}
	netprv := config.NodeKey
	if netprv == nil {
		if netprv, err = crypto.GenerateKey(); err != nil {
			return nil, fmt.Errorf("could not generate server key: %v", err)
		}
	}
	eth.net = &p2p.Server{
		PrivateKey:     netprv,
		Name:           config.Name,
		MaxPeers:       config.MaxPeers,
		Protocols:      protocols,
		Blacklist:      eth.blacklist,
		NAT:            config.NAT,
		NoDial:         !config.Dial,
		BootstrapNodes: config.parseBootNodes(),
	}
	if len(config.Port) > 0 {
		eth.net.ListenAddr = ":" + config.Port
	}

	return eth, nil
}

func (s *Ethereum) KeyManager() *crypto.KeyManager {
	return s.keyManager
}

func (s *Ethereum) Logger() ethlogger.LogSystem {
	return s.logger
}

func (s *Ethereum) Name() string {
	return s.net.Name
}

func (s *Ethereum) ChainManager() *core.ChainManager {
	return s.chainManager
}

func (s *Ethereum) BlockProcessor() *core.BlockProcessor {
	return s.blockProcessor
}

func (s *Ethereum) TxPool() *core.TxPool {
	return s.txPool
}

func (s *Ethereum) BlockPool() *BlockPool {
	return s.blockPool
}

func (s *Ethereum) Whisper() *whisper.Whisper {
	return s.whisper
}

func (s *Ethereum) EventMux() *event.TypeMux {
	return s.eventMux
}
func (self *Ethereum) Db() ethutil.Database {
	return self.db
}

func (s *Ethereum) IsMining() bool {
	return s.Mining
}

func (s *Ethereum) IsListening() bool {
	// XXX TODO
	return false
}

func (s *Ethereum) PeerCount() int {
	return s.net.PeerCount()
}

func (s *Ethereum) Peers() []*p2p.Peer {
	return s.net.Peers()
}

func (s *Ethereum) MaxPeers() int {
	return s.net.MaxPeers
}

func (s *Ethereum) Coinbase() []byte {
	return nil // TODO
}

// Start the ethereum
func (s *Ethereum) Start() error {
	jsonlogger.LogJson(&ethlogger.LogStarting{
		ClientString:    s.net.Name,
		Coinbase:        ethutil.Bytes2Hex(s.KeyManager().Address()),
		ProtocolVersion: ProtocolVersion,
		LogEvent:        ethlogger.LogEvent{Guid: ethutil.Bytes2Hex(crypto.FromECDSAPub(&s.net.PrivateKey.PublicKey))},
	})

	err := s.net.Start()
	if err != nil {
		return err
	}

	// Start services
	s.txPool.Start()
	s.blockPool.Start()

	if s.whisper != nil {
		s.whisper.Start()
	}

	// broadcast transactions
	s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
	go s.txBroadcastLoop()

	// broadcast mined blocks
	s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go s.blockBroadcastLoop()

	logger.Infoln("Server started")
	return nil
}

func (self *Ethereum) SuggestPeer(nodeURL string) error {
	n, err := discover.ParseNode(nodeURL)
	if err != nil {
		return fmt.Errorf("invalid node URL: %v", err)
	}
	self.net.SuggestPeer(n)
	return nil
}

func (s *Ethereum) Stop() {
	// Close the database
	defer s.db.Close()

	close(s.quit)

	s.txSub.Unsubscribe()    // quits txBroadcastLoop
	s.blockSub.Unsubscribe() // quits blockBroadcastLoop

	if s.RpcServer != nil {
		s.RpcServer.Stop()
	}
	if s.WsServer != nil {
		s.WsServer.Stop()
	}
	s.txPool.Stop()
	s.eventMux.Stop()
	s.blockPool.Stop()
	if s.whisper != nil {
		s.whisper.Stop()
	}

	logger.Infoln("Server stopped")
	close(s.shutdownChan)
}

// This function will wait for a shutdown and resumes main thread execution
func (s *Ethereum) WaitForShutdown() {
	<-s.shutdownChan
}

// now tx broadcasting is taken out of txPool
// handled here via subscription, efficiency?
func (self *Ethereum) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
	}
}

func (self *Ethereum) blockBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.blockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
		}
	}
}

func saveProtocolVersion(db ethutil.Database) {
	d, _ := db.Get([]byte("ProtocolVersion"))
	protocolVersion := ethutil.NewValue(d).Uint()

	if protocolVersion == 0 {
		db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
	}
}
<commit_msg>eth: add default bootnode<commit_after>package eth

import (
	"crypto/ecdsa"
	"fmt"
	"strings"

	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethdb"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/event"
	ethlogger "github.com/ethereum/go-ethereum/logger"
	"github.com/ethereum/go-ethereum/p2p"
	"github.com/ethereum/go-ethereum/p2p/discover"
	"github.com/ethereum/go-ethereum/p2p/nat"
	"github.com/ethereum/go-ethereum/pow/ezp"
	"github.com/ethereum/go-ethereum/rpc"
	"github.com/ethereum/go-ethereum/whisper"
)

var (
	logger     = ethlogger.NewLogger("SERV")
	jsonlogger = ethlogger.NewJsonLogger()

	defaultBootNodes = []*discover.Node{
		discover.MustParseNode("enode://6cdd090303f394a1cac34ecc9f7cda18127eafa2a3a06de39f6d920b0e583e062a7362097c7c65ee490a758b442acd5c80c6fce4b148c6a391e946b45131365b@54.169.166.226:30303"),
	}
)

type Config struct {
	Name      string
	KeyStore  string
	DataDir   string
	LogFile   string
	LogLevel  int
	KeyRing   string
	LogFormat string

	MaxPeers int
	Port     string

	// This should be a space-separated list of
	// discovery node URLs.
	BootNodes string

	// This key is used to identify the node on the network.
	// If nil, an ephemeral key is used.
	NodeKey *ecdsa.PrivateKey

	NAT  nat.Interface
	Shh  bool
	Dial bool

	KeyManager *crypto.KeyManager
}

func (cfg *Config) parseBootNodes() []*discover.Node {
	if cfg.BootNodes == "" {
		return defaultBootNodes
	}
	var ns []*discover.Node
	for _, url := range strings.Split(cfg.BootNodes, " ") {
		if url == "" {
			continue
		}
		n, err := discover.ParseNode(url)
		if err != nil {
			logger.Errorf("Bootstrap URL %s: %v\n", url, err)
			continue
		}
		ns = append(ns, n)
	}
	return ns
}

type Ethereum struct {
	// Channel for shutting down the ethereum
	shutdownChan chan bool
	quit         chan bool

	// DB interface
	db        ethutil.Database
	blacklist p2p.Blacklist

	//*** SERVICES ***
	// State manager for processing new blocks and managing the over all states
	blockProcessor *core.BlockProcessor
	txPool         *core.TxPool
	chainManager   *core.ChainManager
	blockPool      *BlockPool
	whisper        *whisper.Whisper

	net      *p2p.Server
	eventMux *event.TypeMux
	txSub    event.Subscription
	blockSub event.Subscription

	RpcServer  rpc.RpcServer
	WsServer   rpc.RpcServer
	keyManager *crypto.KeyManager

	logger ethlogger.LogSystem

	Mining bool
}

func New(config *Config) (*Ethereum, error) {
	// Boostrap database
	logger := ethlogger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat)
	db, err := ethdb.NewLDBDatabase("blockchain")
	if err != nil {
		return nil, err
	}

	// Perform database sanity checks
	d, _ := db.Get([]byte("ProtocolVersion"))
	protov := ethutil.NewValue(d).Uint()
	if protov != ProtocolVersion && protov != 0 {
		return nil, fmt.Errorf("Database version mismatch. Protocol(%d / %d). `rm -rf %s`", protov, ProtocolVersion, ethutil.Config.ExecPath+"/database")
	}

	// Create new keymanager
	var keyManager *crypto.KeyManager
	switch config.KeyStore {
	case "db":
		keyManager = crypto.NewDBKeyManager(db)
	case "file":
		keyManager = crypto.NewFileKeyManager(config.DataDir)
	default:
		return nil, fmt.Errorf("unknown keystore type: %s", config.KeyStore)
	}
	// Initialise the keyring
	keyManager.Init(config.KeyRing, 0, false)

	saveProtocolVersion(db)
	//ethutil.Config.Db = db

	eth := &Ethereum{
		shutdownChan: make(chan bool),
		quit:         make(chan bool),
		db:           db,
		keyManager:   keyManager,
		blacklist:    p2p.NewBlacklist(),
		eventMux:     &event.TypeMux{},
		logger:       logger,
	}

	eth.chainManager = core.NewChainManager(db, eth.EventMux())
	eth.txPool = core.NewTxPool(eth.EventMux())
	eth.blockProcessor = core.NewBlockProcessor(db, eth.txPool, eth.chainManager, eth.EventMux())
	eth.chainManager.SetProcessor(eth.blockProcessor)
	eth.whisper = whisper.New()

	hasBlock := eth.chainManager.HasBlock
	insertChain := eth.chainManager.InsertChain
	eth.blockPool = NewBlockPool(hasBlock, insertChain, ezp.Verify)

	ethProto := EthProtocol(eth.txPool, eth.chainManager, eth.blockPool)
	protocols := []p2p.Protocol{ethProto, eth.whisper.Protocol()}
	netprv := config.NodeKey
	if netprv == nil {
		if netprv, err = crypto.GenerateKey(); err != nil {
			return nil, fmt.Errorf("could not generate server key: %v", err)
		}
	}
	eth.net = &p2p.Server{
		PrivateKey:     netprv,
		Name:           config.Name,
		MaxPeers:       config.MaxPeers,
		Protocols:      protocols,
		Blacklist:      eth.blacklist,
		NAT:            config.NAT,
		NoDial:         !config.Dial,
		BootstrapNodes: config.parseBootNodes(),
	}
	if len(config.Port) > 0 {
		eth.net.ListenAddr = ":" + config.Port
	}

	return eth, nil
}

func (s *Ethereum) KeyManager() *crypto.KeyManager {
	return s.keyManager
}

func (s *Ethereum) Logger() ethlogger.LogSystem {
	return s.logger
}

func (s *Ethereum) Name() string {
	return s.net.Name
}

func (s *Ethereum) ChainManager() *core.ChainManager {
	return s.chainManager
}

func (s *Ethereum) BlockProcessor() *core.BlockProcessor {
	return s.blockProcessor
}

func (s *Ethereum) TxPool() *core.TxPool {
	return s.txPool
}

func (s *Ethereum) BlockPool() *BlockPool {
	return s.blockPool
}

func (s *Ethereum) Whisper() *whisper.Whisper {
	return s.whisper
}

func (s *Ethereum) EventMux() *event.TypeMux {
	return s.eventMux
}
func (self *Ethereum) Db() ethutil.Database {
	return self.db
}

func (s *Ethereum) IsMining() bool {
	return s.Mining
}

func (s *Ethereum) IsListening() bool {
	// XXX TODO
	return false
}

func (s *Ethereum) PeerCount() int {
	return s.net.PeerCount()
}

func (s *Ethereum) Peers() []*p2p.Peer {
	return s.net.Peers()
}

func (s *Ethereum) MaxPeers() int {
	return s.net.MaxPeers
}

func (s *Ethereum) Coinbase() []byte {
	return nil // TODO
}

// Start the ethereum
func (s *Ethereum) Start() error {
	jsonlogger.LogJson(&ethlogger.LogStarting{
		ClientString:    s.net.Name,
		Coinbase:        ethutil.Bytes2Hex(s.KeyManager().Address()),
		ProtocolVersion: ProtocolVersion,
		LogEvent:        ethlogger.LogEvent{Guid: ethutil.Bytes2Hex(crypto.FromECDSAPub(&s.net.PrivateKey.PublicKey))},
	})

	err := s.net.Start()
	if err != nil {
		return err
	}

	// Start services
	s.txPool.Start()
	s.blockPool.Start()

	if s.whisper != nil {
		s.whisper.Start()
	}

	// broadcast transactions
	s.txSub = s.eventMux.Subscribe(core.TxPreEvent{})
	go s.txBroadcastLoop()

	// broadcast mined blocks
	s.blockSub = s.eventMux.Subscribe(core.NewMinedBlockEvent{})
	go s.blockBroadcastLoop()

	logger.Infoln("Server started")
	return nil
}

func (self *Ethereum) SuggestPeer(nodeURL string) error {
	n, err := discover.ParseNode(nodeURL)
	if err != nil {
		return fmt.Errorf("invalid node URL: %v", err)
	}
	self.net.SuggestPeer(n)
	return nil
}

func (s *Ethereum) Stop() {
	// Close the database
	defer s.db.Close()

	close(s.quit)

	s.txSub.Unsubscribe()    // quits txBroadcastLoop
	s.blockSub.Unsubscribe() // quits blockBroadcastLoop

	if s.RpcServer != nil {
		s.RpcServer.Stop()
	}
	if s.WsServer != nil {
		s.WsServer.Stop()
	}
	s.txPool.Stop()
	s.eventMux.Stop()
	s.blockPool.Stop()
	if s.whisper != nil {
		s.whisper.Stop()
	}

	logger.Infoln("Server stopped")
	close(s.shutdownChan)
}

// This function will wait for a shutdown and resumes main thread execution
func (s *Ethereum) WaitForShutdown() {
	<-s.shutdownChan
}

// now tx broadcasting is taken out of txPool
// handled here via subscription, efficiency?
func (self *Ethereum) txBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.txSub.Chan() {
		event := obj.(core.TxPreEvent)
		self.net.Broadcast("eth", TxMsg, event.Tx.RlpData())
	}
}

func (self *Ethereum) blockBroadcastLoop() {
	// automatically stops if unsubscribe
	for obj := range self.blockSub.Chan() {
		switch ev := obj.(type) {
		case core.NewMinedBlockEvent:
			self.net.Broadcast("eth", NewBlockMsg, ev.Block.RlpData(), ev.Block.Td)
		}
	}
}

func saveProtocolVersion(db ethutil.Database) {
	d, _ := db.Get([]byte("ProtocolVersion"))
	protocolVersion := ethutil.NewValue(d).Uint()

	if protocolVersion == 0 {
		db.Put([]byte("ProtocolVersion"), ethutil.NewValue(ProtocolVersion).Bytes())
	}
}
<|endoftext|>


<commit_before>package after

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

const (
	Regex = "^((\\+|\\-))?([1-9][0-9]*)\\s?(s|seconds?|m|minutes?|h|hours?|d|days?|w|weeks?)$"
	Day   = time.Hour * 24
	Week  = Day * 7
)

var compiledRegex *regexp.Regexp

// Parser is the service that will provide the package functionality
type Parser struct {}

// New will return pointer to a new Parser
func New() *Parser {
	return &Parser{}
}

// Duration returns a time.Duration object with the equivalent duration representation of the input
//
// The input string must contain a time unit and a signed multiplier ('+' sign by default if omitted)
//
// The accepted time unit are:
// - `s`, `second` or `seconds`
// - `m`, `minute` or `minutes`
// - `h`, `hour`   or `hours`
// - `d`, `day`    or `days`
// - `w`, `week`   or `weeks`
//
// Examples:
// - `10s`: after ten seconds
// - `+1 minute`: after one minute
// - `2 hours`: after two hours
// - `-1 day`: minus one day
// - `-2w`: minus two weeks
func (p *Parser) Duration(duration string) (time.Duration, error) {
	const (
		Sign       = 2
		Multiplier = 3
		Unit       = 4
	)

	regex, err := p.getRegex()
	if err != nil {
		return 0, err
	}

	matches := regex.FindStringSubmatch(duration)
	if matches == nil || len(matches) == 0 {
		return 0, fmt.Errorf("The provided string '%s' is not a valid duration indicator", duration)
	}

	multiplier, err := p.getMultiplier(matches[Sign], matches[Multiplier])
	if err != nil {
		return 0, err
	}

	return p.getDuration(matches[Unit], multiplier)
}

// SinceNow returns a time.Time object that represents the current point in time plus (or minus) the specified duration
func (p *Parser) SinceNow(duration string) (time.Time, error) {
	return p.Since(time.Now(), duration)
}

// Since returns a time.Time object that represents the given point in time plus (or minus) the specified duration
func (p *Parser) Since(moment time.Time, duration string) (time.Time, error) {
	result, err := p.Duration(duration)
	if err != nil {
		return moment, err
	}

	return moment.Add(result), nil
}

func (p *Parser) getMultiplier(sign string, multiplier string) (time.Duration, error) {
	result, err := strconv.Atoi(multiplier)
	if err != nil {
		return 0, err
	}

	if sign == "-" {
		result *= -1
	}

	return time.Duration(result), nil
}

func (p *Parser) getDuration(unit string, multiplier time.Duration) (time.Duration, error) {
	switch unit[:1] {
	case "s":
		return time.Second * multiplier, nil
	case "m":
		return time.Minute * multiplier, nil
	case "h":
		return time.Hour * multiplier, nil
	case "d":
		return Day * multiplier, nil
	case "w":
		return Week * multiplier, nil
	}

	return 0, fmt.Errorf("The duration unit '%s' is not supported", unit)
}

func (p *Parser) getRegex() (*regexp.Regexp, error) {
	if compiledRegex != nil {
		return compiledRegex, nil
	}

	regex, err := regexp.Compile(Regex)

	return regex, err
}<commit_msg>Improved doc<commit_after>package after

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

const (
	Regex = "^((\\+|\\-))?([1-9][0-9]*)\\s?(s|seconds?|m|minutes?|h|hours?|d|days?|w|weeks?)$"
	Day   = time.Hour * 24
	Week  = Day * 7
)

var compiledRegex *regexp.Regexp

// Parser is the service that will provide the package functionality
type Parser struct {}

// New will return pointer to a new Parser
func New() *Parser {
	return &Parser{}
}

// Duration returns a time.Duration object with the equivalent duration representation of the input
//
// The input string must contain a time unit and a signed multiplier ('+' sign by default if omitted)
//
// The accepted time unit are:
// * `s`, `second` or `seconds`
// * `m`, `minute` or `minutes`
// * `h`, `hour`   or `hours`
// * `d`, `day`    or `days`
// * `w`, `week`   or `weeks`
//
// Examples:
// * `10s`: after ten seconds
// * `+1 minute`: after one minute
// * `2 hours`: after two hours
// * `-1 day`: minus one day
// * `-2w`: minus two weeks
func (p *Parser) Duration(duration string) (time.Duration, error) {
	const (
		Sign       = 2
		Multiplier = 3
		Unit       = 4
	)

	regex, err := p.getRegex()
	if err != nil {
		return 0, err
	}

	matches := regex.FindStringSubmatch(duration)
	if matches == nil || len(matches) == 0 {
		return 0, fmt.Errorf("The provided string '%s' is not a valid duration indicator", duration)
	}

	multiplier, err := p.getMultiplier(matches[Sign], matches[Multiplier])
	if err != nil {
		return 0, err
	}

	return p.getDuration(matches[Unit], multiplier)
}

// SinceNow returns a time.Time object that represents the current point in time plus (or minus) the specified duration
func (p *Parser) SinceNow(duration string) (time.Time, error) {
	return p.Since(time.Now(), duration)
}

// Since returns a time.Time object that represents the given point in time plus (or minus) the specified duration
func (p *Parser) Since(moment time.Time, duration string) (time.Time, error) {
	result, err := p.Duration(duration)
	if err != nil {
		return moment, err
	}

	return moment.Add(result), nil
}

func (p *Parser) getMultiplier(sign string, multiplier string) (time.Duration, error) {
	result, err := strconv.Atoi(multiplier)
	if err != nil {
		return 0, err
	}

	if sign == "-" {
		result *= -1
	}

	return time.Duration(result), nil
}

func (p *Parser) getDuration(unit string, multiplier time.Duration) (time.Duration, error) {
	switch unit[:1] {
	case "s":
		return time.Second * multiplier, nil
	case "m":
		return time.Minute * multiplier, nil
	case "h":
		return time.Hour * multiplier, nil
	case "d":
		return Day * multiplier, nil
	case "w":
		return Week * multiplier, nil
	}

	return 0, fmt.Errorf("The duration unit '%s' is not supported", unit)
}

func (p *Parser) getRegex() (*regexp.Regexp, error) {
	if compiledRegex != nil {
		return compiledRegex, nil
	}

	regex, err := regexp.Compile(Regex)

	return regex, err
}<|endoftext|>


<commit_before>package semver

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type stateFn func(*lexer) stateFn

const (
	itemVersion  itemType = iota // Version string
	itemOperator                 // <, <=, >, >= =, ~, ^
	itemSet                      // Set seperated by whitespace
	itemRange                    // || , -
	itemError
	itemEOF // End of input

	versionDEL = '.'
	operatorGT = '>'
	operatorGE = ">="
	operatorLT = '<'
	operatorLE = "<="
	operatorEQ = '='
	operatorTR = '~'
	operatorCR = '^'

	operatorRG = '|'
	operatorST = ' '
	operatorHY = '-'

	eof = -1
)

type itemType int

type item struct {
	typ itemType
	val string
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	}
	return fmt.Sprintf("%v", i.val)
}

type lexer struct {
	name  string    // used only for error reports.
	input string    // the string being scanned.
	start int       // start position of this item.
	pos   int       // current position in the input.
	width int       // width of last rune read from input.
	items chan item // channel of scanned items.
}

func lex(name, input string) (*lexer, chan item) {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run() // Concurrently run state machine.
	return l, l.items
}

func (l *lexer) run() {
	for state := lexMain; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.input[l.start:l.pos]}
	l.start = l.pos
}

// next returns the next rune in the input.
func (l *lexer) next() (rn rune) {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}
	rn, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return rn
}

func (l *lexer) ignore() {
	l.start = l.pos
}

// peek returns but does not consume
// the next rune in the input.
func (l *lexer) peek() rune {
	rn := l.next()
	l.backup()
	return rn
}

func (l *lexer) backup() {
	l.pos -= l.width
}

// accept consumes the next rune
// if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{
		itemError,
		fmt.Sprintf(format, args...),
	}
	return nil
}

func lexMain(l *lexer) stateFn {
	// Correctly reached EOF.
	switch r := l.next(); {

	case r == eof || r == '\n':
		l.emit(itemEOF) // Useful to make EOF a token.
		return nil      // Stop the run loop.

	case '0' <= r && r <= '9':
		l.backup()
		return lexVersion

	case r == operatorLT:
		l.backup()
		return lexOperator
	case r == operatorGT:
		l.backup()
		return lexOperator
	case r == operatorEQ:
		l.backup()
		return lexOperator
	case r == operatorTR:
		l.backup()
		return lexOperator
	case r == operatorCR:
		l.backup()
		return lexOperator
	case r == operatorRG:
		l.backup()
		return lexRange
	case r == operatorST:
		l.backup()
		return lexRange
	default:
		l.errorf("no version data found")
	}
	return nil
}

func lexVersion(l *lexer) stateFn {
	l.acceptRun(numbers + dot)
	if l.accept("+-") {
		l.acceptRun(allchars)
	}
	l.emit(itemVersion)
	return lexMain
}

func lexOperator(l *lexer) stateFn {

	if l.accept(string(operatorGT)) {
		l.accept(string(operatorEQ))
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorLT)) {
		l.accept(string(operatorEQ))
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorEQ)) {
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorCR)) {
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorTR)) {
		l.emit(itemOperator)
	}
	return lexMain
}

func lexRange(l *lexer) stateFn {
	if l.accept(string(operatorRG)) {
		if l.accept(string(operatorRG)) {
			l.emit(itemRange)
			if l.peek() == operatorST {
				l.next()
				l.ignore()
			}
			return lexMain
		}
	}
	if l.accept(string(operatorST)) {
		if l.peek() == operatorRG || l.peek() == operatorHY {
			l.ignore()
			if l.accept(string(operatorRG)) {
				if l.accept(string(operatorRG)) {
					l.emit(itemRange)
					if l.peek() == operatorST {
						l.next()
						l.ignore()
					}
					return lexMain
				}
			}
			if l.accept(string(operatorHY)) {
				l.emit(itemRange)
				if l.peek() == operatorST {
					l.next()
					l.ignore()
				}
				return lexMain
			}
		}
		l.emit(itemSet)
	}
	return lexMain
}
<commit_msg>Added alphanumeric strings.<commit_after>package semver

import (
	"fmt"
	"strings"
	"unicode/utf8"
)

type stateFn func(*lexer) stateFn

const (
	itemVersion  itemType = iota // Version string
	itemOperator                 // <, <=, >, >= =, ~, ^
	itemSet                      // Set seperated by whitespace
	itemRange                    // || , -
	itemError
	itemEOF // End of input

	versionDEL = '.'
	operatorGT = '>'
	operatorGE = ">="
	operatorLT = '<'
	operatorLE = "<="
	operatorEQ = '='
	operatorTR = '~'
	operatorCR = '^'

	operatorRG = '|'
	operatorST = ' '
	operatorHY = '-'

	eof = -1

	numbers  string = "0123456789"
	letters         = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-"
	allchars        = alphanum + delimiters
	alphanum        = letters + numbers
)

type itemType int

type item struct {
	typ itemType
	val string
}

func (i item) String() string {
	switch {
	case i.typ == itemEOF:
		return "EOF"
	case i.typ == itemError:
		return i.val
	}
	return fmt.Sprintf("%v", i.val)
}

type lexer struct {
	name  string    // used only for error reports.
	input string    // the string being scanned.
	start int       // start position of this item.
	pos   int       // current position in the input.
	width int       // width of last rune read from input.
	items chan item // channel of scanned items.
}

func lex(name, input string) (*lexer, chan item) {
	l := &lexer{
		name:  name,
		input: input,
		items: make(chan item),
	}
	go l.run() // Concurrently run state machine.
	return l, l.items
}

func (l *lexer) run() {
	for state := lexMain; state != nil; {
		state = state(l)
	}
	close(l.items) // No more tokens will be delivered.
}

// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
	l.items <- item{t, l.input[l.start:l.pos]}
	l.start = l.pos
}

// next returns the next rune in the input.
func (l *lexer) next() (rn rune) {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}
	rn, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
	l.pos += l.width
	return rn
}

func (l *lexer) ignore() {
	l.start = l.pos
}

// peek returns but does not consume
// the next rune in the input.
func (l *lexer) peek() rune {
	rn := l.next()
	l.backup()
	return rn
}

func (l *lexer) backup() {
	l.pos -= l.width
}

// accept consumes the next rune
// if it's from the valid set.
func (l *lexer) accept(valid string) bool {
	if strings.IndexRune(valid, l.next()) >= 0 {
		return true
	}
	l.backup()
	return false
}

// acceptRun consumes a run of runes from the valid set.
func (l *lexer) acceptRun(valid string) {
	for strings.IndexRune(valid, l.next()) >= 0 {
	}
	l.backup()
}

func (l *lexer) errorf(format string, args ...interface{}) stateFn {
	l.items <- item{
		itemError,
		fmt.Sprintf(format, args...),
	}
	return nil
}

func lexMain(l *lexer) stateFn {
	// Correctly reached EOF.
	switch r := l.next(); {

	case r == eof || r == '\n':
		l.emit(itemEOF) // Useful to make EOF a token.
		return nil      // Stop the run loop.

	case '0' <= r && r <= '9':
		l.backup()
		return lexVersion

	case r == operatorLT:
		l.backup()
		return lexOperator
	case r == operatorGT:
		l.backup()
		return lexOperator
	case r == operatorEQ:
		l.backup()
		return lexOperator
	case r == operatorTR:
		l.backup()
		return lexOperator
	case r == operatorCR:
		l.backup()
		return lexOperator
	case r == operatorRG:
		l.backup()
		return lexRange
	case r == operatorST:
		l.backup()
		return lexRange
	default:
		l.errorf("no version data found")
	}
	return nil
}

func lexVersion(l *lexer) stateFn {
	l.acceptRun(numbers + dot)
	if l.accept("+-") {
		l.acceptRun(allchars)
	}
	l.emit(itemVersion)
	return lexMain
}

func lexOperator(l *lexer) stateFn {

	if l.accept(string(operatorGT)) {
		l.accept(string(operatorEQ))
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorLT)) {
		l.accept(string(operatorEQ))
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorEQ)) {
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorCR)) {
		l.emit(itemOperator)
		return lexMain
	}
	if l.accept(string(operatorTR)) {
		l.emit(itemOperator)
	}
	return lexMain
}

func lexRange(l *lexer) stateFn {
	if l.accept(string(operatorRG)) {
		if l.accept(string(operatorRG)) {
			l.emit(itemRange)
			if l.peek() == operatorST {
				l.next()
				l.ignore()
			}
			return lexMain
		}
	}
	if l.accept(string(operatorST)) {
		if l.peek() == operatorRG || l.peek() == operatorHY {
			l.ignore()
			if l.accept(string(operatorRG)) {
				if l.accept(string(operatorRG)) {
					l.emit(itemRange)
					if l.peek() == operatorST {
						l.next()
						l.ignore()
					}
					return lexMain
				}
			}
			if l.accept(string(operatorHY)) {
				l.emit(itemRange)
				if l.peek() == operatorST {
					l.next()
					l.ignore()
				}
				return lexMain
			}
		}
		l.emit(itemSet)
	}
	return lexMain
}
<|endoftext|>