<commit_before>// $G $F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

const (
	Bool = iota;
	Int;
	Float;
	String;
	Struct;
	Chan;
	Array;
	Map;
	Func;
	Last;
)

type S struct { a int }
var s S = S{1234}

var c = make(chan int);

var a	= []int{0,1,2,3}

var m = make(map[string]int)

func assert(b bool, s string) {
	if !b {
		println(s);
		sys.Exit(1);
	}
}

func f(i int) interface{} {
	switch i {
	case Bool:
		return true;
	case Int:
		return 7;
	case Float:
		return 7.4;
	case String:
		return "hello";
	case Struct:
		return s;
	case Chan:
		return c;
	case Array:
		return a;
	case Map:
		return m;
	case Func:
		return f;
	}
	panic("bad type number");
}

func main() {
	// type guard style
//	for i := Bool; i < Last; i++ {
//		switch v := f(i); true {
//		case x := v.(bool):
//			assert(x == true && i == Bool, "switch 1 bool");
//		case x := v.(int):
//			assert(x == 7 && i == Int, "switch 1 int");
//		case x := v.(float):
//			assert(x == 7.4 && i == Float, "switch 1 float");
//		case x := v.(string):
//			assert(x == "hello" && i == String, "switch 1 string");
//		case x := v.(S):
//			assert(x.a == 1234 && i == Struct, "switch 1 struct");
//		case x := v.(chan int):
//			assert(x == c && i == Chan, "switch 1 chan");
//		case x := v.([]int):
//			assert(x[3] == 3 && i == Array, "switch 1 array");
//		case x := v.(map[string]int):
//			assert(x == m && i == Map, "switch 1 map");
//		case x := v.(func(i int) interface{}):
//			assert(x == f && i == Func, "switch 1 fun");
//		default:
//			assert(false, "switch 1 unknown");
//		}
//	}

	// type switch style
	for i := Bool; i < Last; i++ {
		switch x := f(i).(type) {
		case bool:
			assert(x == true && i == Bool, "switch 2 bool");
		case int:
			assert(x == 7 && i == Int, "switch 2 int");
		case float:
			assert(x == 7.4 && i == Float, "switch 2 float");
		case string:
			assert(x == "hello" && i == String, "switch 2 string");
		case S:
			assert(x.a == 1234 && i == Struct, "switch 2 struct");
		case chan int:
			assert(x == c && i == Chan, "switch 2 chan");
		case []int:
			assert(x[3] == 3 && i == Array, "switch 2 array");
		case map[string]int:
			assert(x == m && i == Map, "switch 2 map");
		case func(i int) interface{}:
			assert(x == f && i == Func, "switch 2 fun");
		default:
			assert(false, "switch 2 unknown");
		}
	}

	// catch-all style in various forms
	switch {
	case true:
		assert(true, "switch 3 bool");
	default:
		assert(false, "switch 3 unknown");
	}

	switch true {
	case true:
		assert(true, "switch 3 bool");
	default:
		assert(false, "switch 3 unknown");
	}

	switch false {
	case false:
		assert(true, "switch 4 bool");
	default:
		assert(false, "switch 4 unknown");
	}

//	switch true {
//	case x := f(Int).(float):
//		assert(false, "switch 5 type guard wrong type");
//	case x := f(Int).(int):
//		assert(x == 7, "switch 5 type guard");
//	default:
//		assert(false, "switch 5 unknown");
//	}

	m["7"] = 7;
//	switch true {
//	case x := m["6"]:
//		assert(false, "switch 6 map reference wrong");
//	case x := m["7"]:
//		assert(x == 7, "switch 6 map reference");
//	default:
//		assert(false, "switch 6 unknown");
//	}

	go func() { <-c; c <- 77; } ();
	// guarantee the channel is ready
	c <- 77;
	for i := 0; i < 5; i++ {
		sys.Gosched();
	}
	dummyc := make(chan int);
//	switch true {
//	case x := <-dummyc:
//		assert(false, "switch 7 chan wrong");
//	case x := <-c:
//		assert(x == 77, "switch 7 chan");
//	default:
//		assert(false, "switch 7 unknown");
//	}

}
<commit_msg>simplify test to eliminate now-deprecated forms of switch.<commit_after>// $G $F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

const (
	Bool = iota;
	Int;
	Float;
	String;
	Struct;
	Chan;
	Array;
	Map;
	Func;
	Last;
)

type S struct { a int }
var s S = S{1234}

var c = make(chan int);

var a	= []int{0,1,2,3}

var m = make(map[string]int)

func assert(b bool, s string) {
	if !b {
		println(s);
		sys.Exit(1);
	}
}

func f(i int) interface{} {
	switch i {
	case Bool:
		return true;
	case Int:
		return 7;
	case Float:
		return 7.4;
	case String:
		return "hello";
	case Struct:
		return s;
	case Chan:
		return c;
	case Array:
		return a;
	case Map:
		return m;
	case Func:
		return f;
	}
	panic("bad type number");
}

func main() {
	for i := Bool; i < Last; i++ {
		switch x := f(i).(type) {
		case bool:
			assert(x == true && i == Bool, "bool");
		case int:
			assert(x == 7 && i == Int, "int");
		case float:
			assert(x == 7.4 && i == Float, "float");
		case string:
			assert(x == "hello"&& i == String, "string");
		case S:
			assert(x.a == 1234 && i == Struct, "struct");
		case chan int:
			assert(x == c && i == Chan, "chan");
		case []int:
			assert(x[3] == 3 && i == Array, "array");
		case map[string]int:
			assert(x == m && i == Map, "map");
		case func(i int) interface{}:
			assert(x == f && i == Func, "fun");
		default:
			assert(false, "unknown");
		}
	}

	// boolean switch (has had bugs in past; worth writing down)
	switch {
	case true:
		assert(true, "switch 2 bool");
	default:
		assert(false, "switch 2 unknown");
	}

	switch true {
	case true:
		assert(true, "switch 3 bool");
	default:
		assert(false, "switch 3 unknown");
	}

	switch false {
	case false:
		assert(true, "switch 4 bool");
	default:
		assert(false, "switch 4 unknown");
	}

}
<|endoftext|>


<commit_before>// Copyright 2010 Hannes Baldursson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file is part of go-idn

// This package contains methods for the preparation of internationalized strings ("stringprep") as described in RFC 3454
package stringprep

import (
	"bytes"
	"code.google.com/p/go-idn/idna/norm32"
	"unicode/utf8"
)

// Flags used when calling stringprep
const (
	NO_NFKC       = 1
	NO_BIDI       = 2
	NO_UNASSIGNED = 4
)

/* Steps in a stringprep profile. */
const (
	NFKC                = 1
	BIDI                = 2
	MAP_TABLE           = 3
	UNASSIGNED_TABLE    = 4
	PROHIBIT_TABLE      = 5
	BIDI_PROHIBIT_TABLE = 6
	BIDI_RAL_TABLE      = 7
	BIDI_L_TABLE        = 8
)

const (
	MAX_MAP_CHARS = 4
)

type TableElement struct {
	Lo  int
	Hi  int
	Map d // can be empty
}

type Table []TableElement
type Profile []ProfileElement
type d [MAX_MAP_CHARS]int

type ProfileElement struct {
	Step  int // see Step const's
	Table Table
}

// Exports tables
var Tables = map[string]Table{
	"A1":  _A1,
	"B1":  _B1,
	"B2":  _B2,
	"B3":  _B3,
	"C11": _C11,
	"C12": _C12,
	"C21": _C21,
	"C22": _C22,
	"C3":  _C3,
	"C4":  _C4,
	"C5":  _C5,
	"C6":  _C6,
	"C7":  _C7,
	"C8":  _C8,
	"C9":  _C9,
	"D1":  _D1,
	"D2":  _D2,
}

func Nameprep(label string) string {
	return Stringprep(label, Profiles["nameprep"])
}

func Nodeprep(label string) string {
	return Stringprep(label, Profiles["nodeprep"])
}

func Resourceprep(label string) string {
	return Stringprep(label, Profiles["resourceprep"])
}

func NameprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["nameprep"])
}

func NodeprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["nodeprep"])
}

func ResourceprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["resourceprep"])
}

func Stringprep(input string, profile Profile) string {
	input_runes := bytes.Runes([]byte(input))
	return stringify(StringprepRunes(input_runes, profile))
}

// Prepare the input rune array according to the stringprep profile,
// and return the results as a rune array.
func StringprepRunes(input []rune, profile Profile) []int {
	output := make([]int, len(input))
	copy(output[0:], input[0:])

	for i := 0; i < len(profile); i++ {
		switch profile[i].Step {
		case NFKC:
			output = normalization.NFKC(output)
			break
		case BIDI:
			done_prohibited := 0
			done_ral := 0
			done_l := 0
			contains_ral := -1
			contains_l := -1

			for j := 0; i < len(profile); j++ {
				switch profile[j].Step {
				case BIDI_PROHIBIT_TABLE:
					done_prohibited = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							return nil
						}
					}

				case BIDI_RAL_TABLE:
					done_ral = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							contains_ral = j
						}
					}

				case BIDI_L_TABLE:
					done_l = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							contains_l = j
						}
					}
				}
			}

			if done_prohibited != 1 || done_ral != 1 || done_l != 1 {
				return nil // PROFILE ERROR
			}

			if contains_ral != -1 && contains_l != -1 {
				return nil // BIDI BOTH L AND RAL
			}

			if contains_ral != -1 {
				return nil // Error?
			}

			break
		case MAP_TABLE:
			output = map_table(output, profile[i].Table)
			break
		case UNASSIGNED_TABLE:
			break
			//switch profile[i].Table
		case PROHIBIT_TABLE:
			for k := 0; k < len(output); k++ {
				if in_table(output[k], profile[i].Table) {
					return nil
				}
			}
			break
		case BIDI_PROHIBIT_TABLE:
			break
		case BIDI_RAL_TABLE:
			break
		case BIDI_L_TABLE:
			break
		default:
			return nil // PROFILE ERROR
		}
	}

	return output
}

// Returns true if the rune is in table
func in_table(c int, table Table) bool {
	for i := 0; i < len(table); i++ {
		if table[i].Lo <= c && c <= table[i].Hi {
			return true
		}
	}
	return false
}

// Returns a filtered rune sequence
func filter(input []int, table Table) []int {
	output := make([]int, len(input))
	c := 0 // count

	for i := 0; i < len(input); i++ {
		if !in_table(input[i], table) {
			output[c] = input[i]
			c++
		}
	}

	return output[0:len(output)]
}

// Iterates over the input rune array and replaces runes with their maps
func map_table(input []int, table Table) []int {

	output := make([]int, len(input))
	c := 0 // count

	for i := 0; i < len(input); i++ {
		// If rune is in table, replace it with its map
		if in_table(input[i], table) {
			for k := 0; k < len(table); k++ {
				if input[i] == table[k].Lo {
					copy(output[c:], table[k].Map[0:len(table[k].Map)])
					c += len(table[k].Map)
					break
				}
			}
		} else {
			output[c] = input[i]
			c++
		}

	}
	return output[0:len(output)]
}

// turn a slice of runes into an equivalent string
func stringify(runes []int) string {
	t := make([]byte, len(runes)*4) // kludge!
	i := 0
	for _, r := range runes {
		i += utf8.EncodeRune(t[i:], r)
	}
	return string(t)
}
<commit_msg>idna/stringprep: fix package description<commit_after>// Copyright 2010 Hannes Baldursson. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file is part of go-idn

// Package stringprep implements Stringprep as described in RFC 3454
package stringprep

import (
	"bytes"
	"code.google.com/p/go-idn/idna/norm32"
	"unicode/utf8"
)

// Flags used when calling stringprep
const (
	NO_NFKC       = 1
	NO_BIDI       = 2
	NO_UNASSIGNED = 4
)

/* Steps in a stringprep profile. */
const (
	NFKC                = 1
	BIDI                = 2
	MAP_TABLE           = 3
	UNASSIGNED_TABLE    = 4
	PROHIBIT_TABLE      = 5
	BIDI_PROHIBIT_TABLE = 6
	BIDI_RAL_TABLE      = 7
	BIDI_L_TABLE        = 8
)

const (
	MAX_MAP_CHARS = 4
)

type TableElement struct {
	Lo  int
	Hi  int
	Map d // can be empty
}

type Table []TableElement
type Profile []ProfileElement
type d [MAX_MAP_CHARS]int

type ProfileElement struct {
	Step  int // see Step const's
	Table Table
}

// Exports tables
var Tables = map[string]Table{
	"A1":  _A1,
	"B1":  _B1,
	"B2":  _B2,
	"B3":  _B3,
	"C11": _C11,
	"C12": _C12,
	"C21": _C21,
	"C22": _C22,
	"C3":  _C3,
	"C4":  _C4,
	"C5":  _C5,
	"C6":  _C6,
	"C7":  _C7,
	"C8":  _C8,
	"C9":  _C9,
	"D1":  _D1,
	"D2":  _D2,
}

func Nameprep(label string) string {
	return Stringprep(label, Profiles["nameprep"])
}

func Nodeprep(label string) string {
	return Stringprep(label, Profiles["nodeprep"])
}

func Resourceprep(label string) string {
	return Stringprep(label, Profiles["resourceprep"])
}

func NameprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["nameprep"])
}

func NodeprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["nodeprep"])
}

func ResourceprepRunes(label []int) []int {
	return StringprepRunes(label, Profiles["resourceprep"])
}

func Stringprep(input string, profile Profile) string {
	input_runes := bytes.Runes([]byte(input))
	return stringify(StringprepRunes(input_runes, profile))
}

// Prepare the input rune array according to the stringprep profile,
// and return the results as a rune array.
func StringprepRunes(input []rune, profile Profile) []int {
	output := make([]int, len(input))
	copy(output[0:], input[0:])

	for i := 0; i < len(profile); i++ {
		switch profile[i].Step {
		case NFKC:
			output = normalization.NFKC(output)
			break
		case BIDI:
			done_prohibited := 0
			done_ral := 0
			done_l := 0
			contains_ral := -1
			contains_l := -1

			for j := 0; i < len(profile); j++ {
				switch profile[j].Step {
				case BIDI_PROHIBIT_TABLE:
					done_prohibited = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							return nil
						}
					}

				case BIDI_RAL_TABLE:
					done_ral = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							contains_ral = j
						}
					}

				case BIDI_L_TABLE:
					done_l = 1
					for k := 0; k < len(output); k++ {
						if in_table(output[k], profile[j].Table) {
							contains_l = j
						}
					}
				}
			}

			if done_prohibited != 1 || done_ral != 1 || done_l != 1 {
				return nil // PROFILE ERROR
			}

			if contains_ral != -1 && contains_l != -1 {
				return nil // BIDI BOTH L AND RAL
			}

			if contains_ral != -1 {
				return nil // Error?
			}

			break
		case MAP_TABLE:
			output = map_table(output, profile[i].Table)
			break
		case UNASSIGNED_TABLE:
			break
			//switch profile[i].Table
		case PROHIBIT_TABLE:
			for k := 0; k < len(output); k++ {
				if in_table(output[k], profile[i].Table) {
					return nil
				}
			}
			break
		case BIDI_PROHIBIT_TABLE:
			break
		case BIDI_RAL_TABLE:
			break
		case BIDI_L_TABLE:
			break
		default:
			return nil // PROFILE ERROR
		}
	}

	return output
}

// Returns true if the rune is in table
func in_table(c int, table Table) bool {
	for i := 0; i < len(table); i++ {
		if table[i].Lo <= c && c <= table[i].Hi {
			return true
		}
	}
	return false
}

// Returns a filtered rune sequence
func filter(input []int, table Table) []int {
	output := make([]int, len(input))
	c := 0 // count

	for i := 0; i < len(input); i++ {
		if !in_table(input[i], table) {
			output[c] = input[i]
			c++
		}
	}

	return output[0:len(output)]
}

// Iterates over the input rune array and replaces runes with their maps
func map_table(input []int, table Table) []int {

	output := make([]int, len(input))
	c := 0 // count

	for i := 0; i < len(input); i++ {
		// If rune is in table, replace it with its map
		if in_table(input[i], table) {
			for k := 0; k < len(table); k++ {
				if input[i] == table[k].Lo {
					copy(output[c:], table[k].Map[0:len(table[k].Map)])
					c += len(table[k].Map)
					break
				}
			}
		} else {
			output[c] = input[i]
			c++
		}

	}
	return output[0:len(output)]
}

// turn a slice of runes into an equivalent string
func stringify(runes []int) string {
	t := make([]byte, len(runes)*4) // kludge!
	i := 0
	for _, r := range runes {
		i += utf8.EncodeRune(t[i:], r)
	}
	return string(t)
}
<|endoftext|>


<commit_before>package utils

import (
	"errors"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

type TagString reflect.StructTag

// Used for sorting
type tagInfo struct {
	name string
	val  string
}

type byName []tagInfo

func (a byName) Len() int      { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool {
	// Favor json tags as they are what tags are generally used for
	if a[i].name == "json" {
		return true
	}
	if a[j].name == "json" {
		return false
	}
	return a[i].name < a[j].name
}

// Initialise the sort regexp
var tagStringRegExp = regexp.MustCompile(`(?:^| )([^:"]+):"([^"]*)"`)

// Sort the tags alphabetically, except favor the json tag
func (tag *TagString) Sort() {
	matches := tagStringRegExp.FindAllStringSubmatch(string(*tag), -1)
	if len(matches) > 0 {
		var tags []tagInfo
		for _, match := range matches {
			tags = append(tags, tagInfo{match[1], match[2]})
		}

		sort.Sort(byName(tags))

		tmpTag := ""
		for _, tagInfo := range tags {
			tmpTag += tagInfo.name + `:"` + tagInfo.val + `" `
		}

		*tag = TagString(tmpTag[:len(tmpTag)-1])
	}
}

func (tag TagString) Get(key string) string {
	return reflect.StructTag(tag).Get(key)
}

// TODO(morphar) All of the following functions can easily be made faster
// Look at reflect's func (tag StructTag) Get(key string) string
// It iterates instead of doing regexps
// These are actually also wrong, as the values can't have " in them

// Set ONLY sets the tag identified by key, if it already exists
// Returns true if a tag was found and changed
func (tag *TagString) Set(key string, val string) (success bool) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		with := "${1}" + key + `:` + strconv.Quote(val)
		newTag := re.ReplaceAllString(string(*tag), with)
		*tag = TagString(newTag)
		success = true
	}
	return
}

// SetMulti ONLY sets the tags identified by the keys, if they already exists
// Returns false if one or more tag was not changed
func (tag *TagString) SetMulti(keyVals map[string]string) (success bool) {
	success = true
	for key, val := range keyVals {
		res := tag.Set(key, val)
		if !res {
			success = false
		}
	}
	return
}

// Add adds the tag to the TagString
func (tag *TagString) Add(key string, val string) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		tag.Set(key, val)

	} else {
		newTag := strings.Join([]string{string(*tag), " ", key, `:`, strconv.Quote(val)}, "")
		*tag = TagString(strings.Trim(newTag, " "))
	}
}

// AddMulti adds multiple tags to the TagString
func (tag *TagString) AddMulti(keyVals map[string]string) {
	for key, val := range keyVals {
		tag.Add(key, val)
	}
}

// Remove removes tags identified by key
// Returns an error if the key was not understood
func (tag *TagString) Remove(key string) (err error) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		newTag := re.ReplaceAllString(string(*tag), "")
		*tag = TagString(newTag)
	}
	return
}

// RemoveMulti removes all the tags identified by the keys in the keys array
// Returns an error if one or more keys was not understood
func (tag *TagString) RemoveMulti(keys []string) (err error) {
	var errorKeys []string
	for _, key := range keys {
		err := tag.Remove(key)
		if err != nil {
			errorKeys = append(errorKeys, key)
		}
	}
	if len(errorKeys) > 0 {
		err = errors.New("The following key(s) were not recognised: " + strings.Join(errorKeys, ", "))
	}
	return
}
<commit_msg>Thank you misspell<commit_after>package utils

import (
	"errors"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
)

type TagString reflect.StructTag

// Used for sorting
type tagInfo struct {
	name string
	val  string
}

type byName []tagInfo

func (a byName) Len() int      { return len(a) }
func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byName) Less(i, j int) bool {
	// Favor json tags as they are what tags are generally used for
	if a[i].name == "json" {
		return true
	}
	if a[j].name == "json" {
		return false
	}
	return a[i].name < a[j].name
}

// Initialize the sort regexp
var tagStringRegExp = regexp.MustCompile(`(?:^| )([^:"]+):"([^"]*)"`)

// Sort the tags alphabetically, except favor the json tag
func (tag *TagString) Sort() {
	matches := tagStringRegExp.FindAllStringSubmatch(string(*tag), -1)
	if len(matches) > 0 {
		var tags []tagInfo
		for _, match := range matches {
			tags = append(tags, tagInfo{match[1], match[2]})
		}

		sort.Sort(byName(tags))

		tmpTag := ""
		for _, tagInfo := range tags {
			tmpTag += tagInfo.name + `:"` + tagInfo.val + `" `
		}

		*tag = TagString(tmpTag[:len(tmpTag)-1])
	}
}

func (tag TagString) Get(key string) string {
	return reflect.StructTag(tag).Get(key)
}

// TODO(morphar) All of the following functions can easily be made faster
// Look at reflect's func (tag StructTag) Get(key string) string
// It iterates instead of doing regexps
// These are actually also wrong, as the values can't have " in them

// Set ONLY sets the tag identified by key, if it already exists
// Returns true if a tag was found and changed
func (tag *TagString) Set(key string, val string) (success bool) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		with := "${1}" + key + `:` + strconv.Quote(val)
		newTag := re.ReplaceAllString(string(*tag), with)
		*tag = TagString(newTag)
		success = true
	}
	return
}

// SetMulti ONLY sets the tags identified by the keys, if they already exists
// Returns false if one or more tag was not changed
func (tag *TagString) SetMulti(keyVals map[string]string) (success bool) {
	success = true
	for key, val := range keyVals {
		res := tag.Set(key, val)
		if !res {
			success = false
		}
	}
	return
}

// Add adds the tag to the TagString
func (tag *TagString) Add(key string, val string) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		tag.Set(key, val)

	} else {
		newTag := strings.Join([]string{string(*tag), " ", key, `:`, strconv.Quote(val)}, "")
		*tag = TagString(strings.Trim(newTag, " "))
	}
}

// AddMulti adds multiple tags to the TagString
func (tag *TagString) AddMulti(keyVals map[string]string) {
	for key, val := range keyVals {
		tag.Add(key, val)
	}
}

// Remove removes tags identified by key
// Returns an error if the key was not understood
func (tag *TagString) Remove(key string) (err error) {
	re, err := regexp.Compile(`(^| )` + key + `:"[^"]*"`)
	if err == nil && re.MatchString(string(*tag)) {
		newTag := re.ReplaceAllString(string(*tag), "")
		*tag = TagString(newTag)
	}
	return
}

// RemoveMulti removes all the tags identified by the keys in the keys array
// Returns an error if one or more keys was not understood
func (tag *TagString) RemoveMulti(keys []string) (err error) {
	var errorKeys []string
	for _, key := range keys {
		err := tag.Remove(key)
		if err != nil {
			errorKeys = append(errorKeys, key)
		}
	}
	if len(errorKeys) > 0 {
		err = errors.New("The following key(s) were not recognised: " + strings.Join(errorKeys, ", "))
	}
	return
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Yanko Bolanos
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */
package tail

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
)

const (
	SLEEP_TIMEOUT = time.Second * 1
	FD_TIMEOUT    = time.Minute * 5
)

var (
	gDelim = regexp.MustCompile(`\r?\n`)
)

type Tail struct {
	Filename       string
	LineChan       chan string
	Cancel         context.CancelFunc
	Follow         bool
	Context        context.Context
	RetryFileOpen  bool // keep trying to re-open the file, helpful when the file doesn't exist yet
	lineStartSplit bool // logic for handling begining of line split (splunk like, by timestamp)
	delim          *regexp.Regexp
	SeekToEnd      bool
}

func NewTail(path string) *Tail {

	ctx, cancel := context.WithCancel(context.Background())

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         true,
		Context:        ctx,
		RetryFileOpen:  true,
		lineStartSplit: false,
		delim:          gDelim,
		SeekToEnd:      false,
	}

	return t
}

func (t *Tail) Start() {
	go t.watchFile(t.Context, t.Filename)
}

func NewTailWithCtx(ctx context.Context, path string, follow, retryFileOpen bool, delim *regexp.Regexp, lineStartSplit bool, skipToEnd bool) *Tail {

	ctx, cancel := context.WithCancel(ctx)

	d := gDelim
	if delim != nil {
		d = delim
	}

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         follow,
		Context:        ctx,
		RetryFileOpen:  retryFileOpen,
		lineStartSplit: lineStartSplit,
		delim:          d,
		SeekToEnd:      skipToEnd,
	}

	t.Start()
	return t
}

func (t *Tail) Close() {
	defer func() {
		// this is a hack. Need to figure out the order of closing the channel.
		// sometimes its closing more than once
		if r := recover(); r != nil {
			log.WithField("file", t.Filename).
				Warnf("Recovered in Tail.Close(): %s", r)
		}
	}()
	close(t.LineChan)
}

func (t *Tail) openFile(path string) (*os.File, error) {

	var f *os.File
	var err error
	for {

		if !t.RetryFileOpen {
			select {
			case <-t.Context.Done():
				return nil, errors.New("Tail context cancelled.")
			default:
				break
			}
		}

		f, err = os.Open(path)
		if err != nil {
			log.Infof("Unable to open. %s. Waiting 5 seconds and retrying", err.Error())
			time.Sleep(time.Second * 5)
		} else {
			if finfo, err := os.Stat(path); err == nil && t.SeekToEnd {
				f.Seek(finfo.Size(), 0)
			}
			break
		}
	}

	return f, nil
}

func (t *Tail) watchFile(ctx context.Context, path string) {

	fileIn, err := t.openFile(path)
	if err != nil {
		log.Infof("1. Unable to openFile. %s", err.Error())
		os.Exit(0)
		return
	}
	defer fileIn.Close()

	r := bufio.NewReader(fileIn)

	accum := new(bytes.Buffer)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(path)
	if err != nil {
		log.Fatal(err)
	}
	done := make(chan bool)

	for {

		if t.lineStartSplit {
			readFrontSplit(ctx, t.delim, t.LineChan, r, accum)
		} else {
			buffer := read(ctx, t.delim, r, accum)
			reader := bufio.NewReader(buffer)
			for {
				select {
				case <-ctx.Done():
					return
				default:
					break
				}

				line, err := reader.ReadString('\n')
				if err != nil && err != io.EOF {
					log.WithField("file", path).Error(err.Error())
					break

				}

				if len(line) > 0 {
					t.LineChan <- string([]rune(strings.TrimRight(line, "\n")))
				}

				if err == io.EOF {
					if !t.Follow {
						t.Close()
						return
					}
					break
				}

			}
		}

		select {
		case <-time.After(SLEEP_TIMEOUT):
			if t.lineStartSplit && accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			break
		case event := <-watcher.Events:
			if event.Op&fsnotify.Rename == fsnotify.Rename {
				log.WithField("file", path).Info("File renamed. Monitoring old fd for 5 minutes")
				go t.watchFile(ctx, path)
				time.AfterFunc(FD_TIMEOUT, func() {
					done <- true
				})
			}
			break
		case err := <-watcher.Errors:
			log.WithField("file", path).Errorf("inotify error: %v", err)
			break
		case <-done:
			log.WithField("file", path).Info("Closing old fd")
			return
		case <-ctx.Done():
			if accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			t.Close()
			return
		}
	}
}

func read(ctx context.Context, delim *regexp.Regexp, f io.Reader, accum *bytes.Buffer) io.Reader {

	r, w := io.Pipe()
	buffer_size := 1048576 // 1MB

	go func() {
		defer w.Close()

		buffer := make([]byte, buffer_size)
		for {

			select {
			case <-ctx.Done():
				return
			default:
				break
			}

			n, err := f.Read(buffer)
			if err != nil {
				w.Close()
				break
			}

			slice := buffer[:n]
			locs := delim.FindAllSubmatchIndex(slice, -1)

			if len(locs) == 0 {
				accum.Write(slice)
			} else {
				start_idx := 0
				end_idx := 0
				for _, loc := range locs {
					end_idx = loc[1]
					data := append(accum.Bytes(), slice[start_idx:end_idx]...)
					w.Write(data)
					accum.Reset()
					start_idx = end_idx
				}

				if end_idx < n {
					accum.Write(slice[end_idx:])
				}
			}
		}

	}()

	return r
}

func readFrontSplit(ctx context.Context, delim *regexp.Regexp, lineChan chan string, f io.Reader, accum *bytes.Buffer) {

	buffer_size := 1048576 // 1MB

	// go func() {
	// defer w.Close()

	buffer := make([]byte, buffer_size)
	first := true
	for {
		select {
		case <-ctx.Done():
			return
		default:
			break
		}

		n, err := f.Read(buffer)
		if err != nil {
			break
		}

		slice := buffer[:n]
		locs := delim.FindAllSubmatchIndex(slice, -1)

		if len(locs) == 0 {
			accum.Write(slice)
		} else {

			line_begin_idx := 0
			line_end_idx := 0
			next_start := 0
			for _, loc := range locs {
				if first {
					first = false
					next_start = loc[0]
					if loc[0] == 0 && accum.Len() > 0 {
						lineChan <- accum.String()
						accum.Reset()
					}
					continue
				} else {
					line_begin_idx = next_start
				}

				line_end_idx = loc[0]
				next_start = loc[1] - (loc[1] - loc[0])
				data := bytes.Replace(slice[line_begin_idx:line_end_idx], []byte("\x0A"), nil, -1)
				data = append(accum.Bytes(), data...)
				lineChan <- string(data)
				accum.Reset()
				// data_trim := bytes.TrimRight(data, "\n")
				// log.Printf("%v -> %v", line_begin_idx, line_end_idx)
				// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", line_begin_idx, data_trim, line_end_idx)

			}

			data := slice[next_start:n]
			accum.Write(data)
			// w.Write(data)
			// lineChan <- string(data)
			// data_trim := bytes.TrimRight(data, "\n")
			// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", next_start, data, n)
		}
	}

	// lineChan <- string(accum.Bytes())
	// accum.Reset()
	// }()

	// <-ctx.Done()

}
<commit_msg>fixes #5<commit_after>/*
 * Copyright (c) 2016 Yanko Bolanos
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */
package tail

import (
	"bufio"
	"bytes"
	"context"
	"errors"
	"io"
	"os"
	"regexp"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
)

const (
	SLEEP_TIMEOUT = time.Second * 1
	FD_TIMEOUT    = time.Minute * 5
)

var (
	gDelim = regexp.MustCompile(`\r?\n`)
)

type Tail struct {
	Filename       string
	LineChan       chan string
	Cancel         context.CancelFunc
	Follow         bool
	Context        context.Context
	RetryFileOpen  bool // keep trying to re-open the file, helpful when the file doesn't exist yet
	lineStartSplit bool // logic for handling begining of line split (splunk like, by timestamp)
	delim          *regexp.Regexp
	SeekToEnd      bool
}

func NewTail(path string) *Tail {

	ctx, cancel := context.WithCancel(context.Background())

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         true,
		Context:        ctx,
		RetryFileOpen:  true,
		lineStartSplit: false,
		delim:          gDelim,
		SeekToEnd:      false,
	}

	return t
}

func (t *Tail) Start() {
	go t.watchFile(t.Context, t.Filename)
}

func NewTailWithCtx(ctx context.Context, path string, follow, retryFileOpen bool, delim *regexp.Regexp, lineStartSplit bool, skipToEnd bool) *Tail {

	ctx, cancel := context.WithCancel(ctx)

	d := gDelim
	if delim != nil {
		d = delim
	}

	t := &Tail{
		Filename:       path,
		LineChan:       make(chan string),
		Cancel:         cancel,
		Follow:         follow,
		Context:        ctx,
		RetryFileOpen:  retryFileOpen,
		lineStartSplit: lineStartSplit,
		delim:          d,
		SeekToEnd:      skipToEnd,
	}

	t.Start()
	return t
}

func (t *Tail) Close() {
	defer func() {
		// this is a hack. Need to figure out the order of closing the channel.
		// sometimes its closing more than once
		if r := recover(); r != nil {
			log.WithField("file", t.Filename).
				Warnf("Recovered in Tail.Close(): %s", r)
		}
	}()
	close(t.LineChan)
}

func (t *Tail) openFile(path string) (*os.File, error) {

	var f *os.File
	var err error
	for {

		if !t.RetryFileOpen {
			select {
			case <-t.Context.Done():
				return nil, errors.New("Tail context cancelled.")
			default:
				break
			}
		}

		f, err = os.Open(path)
		if err != nil {
			log.Infof("Unable to open. %s. Waiting 5 seconds and retrying", err.Error())
			time.Sleep(time.Second * 5)
		} else {
			if finfo, err := os.Stat(path); err == nil && t.SeekToEnd {
				f.Seek(finfo.Size(), 0)
			}
			break
		}
	}

	return f, nil
}

func (t *Tail) watchFile(ctx context.Context, path string) {

	fileIn, err := t.openFile(path)
	if err != nil {
		log.Infof("1. Unable to openFile. %s", err.Error())
		//os.Exit(0)
		return
	}
	defer fileIn.Close()

	r := bufio.NewReader(fileIn)

	accum := new(bytes.Buffer)

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	err = watcher.Add(path)
	if err != nil {
		log.Fatal(err)
	}
	done := make(chan bool)

	for {

		if t.lineStartSplit {
			readFrontSplit(ctx, t.delim, t.LineChan, r, accum)
		} else {
			buffer := read(ctx, t.delim, r, accum)
			reader := bufio.NewReader(buffer)
			for {
				select {
				case <-ctx.Done():
					return
				default:
					break
				}

				line, err := reader.ReadString('\n')
				if err != nil && err != io.EOF {
					log.WithField("file", path).Error(err.Error())
					break

				}

				if len(line) > 0 {
					t.LineChan <- string([]rune(strings.TrimRight(line, "\n")))
				}

				if err == io.EOF {
					if !t.Follow {
						t.Close()
						return
					}
					break
				}

			}
		}

		select {
		case <-time.After(SLEEP_TIMEOUT):
			if t.lineStartSplit && accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			break
		case event := <-watcher.Events:
			if event.Op&fsnotify.Rename == fsnotify.Rename {
				log.WithField("file", path).Info("File renamed. Monitoring old fd for 5 minutes")
				go t.watchFile(ctx, path)
				time.AfterFunc(FD_TIMEOUT, func() {
					done <- true
				})
			}
			break
		case err := <-watcher.Errors:
			log.WithField("file", path).Errorf("inotify error: %v", err)
			break
		case <-done:
			log.WithField("file", path).Info("Closing old fd")
			return
		case <-ctx.Done():
			if accum.Len() > 0 {
				t.LineChan <- accum.String()
				accum.Reset()
			}
			t.Close()
			return
		}
	}
}

func read(ctx context.Context, delim *regexp.Regexp, f io.Reader, accum *bytes.Buffer) io.Reader {

	r, w := io.Pipe()
	buffer_size := 1048576 // 1MB

	go func() {
		defer w.Close()

		buffer := make([]byte, buffer_size)
		for {

			select {
			case <-ctx.Done():
				return
			default:
				break
			}

			n, err := f.Read(buffer)
			if err != nil {
				w.Close()
				break
			}

			slice := buffer[:n]
			locs := delim.FindAllSubmatchIndex(slice, -1)

			if len(locs) == 0 {
				accum.Write(slice)
			} else {
				start_idx := 0
				end_idx := 0
				for _, loc := range locs {
					end_idx = loc[1]
					data := append(accum.Bytes(), slice[start_idx:end_idx]...)
					w.Write(data)
					accum.Reset()
					start_idx = end_idx
				}

				if end_idx < n {
					accum.Write(slice[end_idx:])
				}
			}
		}

	}()

	return r
}

func readFrontSplit(ctx context.Context, delim *regexp.Regexp, lineChan chan string, f io.Reader, accum *bytes.Buffer) {

	buffer_size := 1048576 // 1MB

	// go func() {
	// defer w.Close()

	buffer := make([]byte, buffer_size)
	first := true
	for {
		select {
		case <-ctx.Done():
			return
		default:
			break
		}

		n, err := f.Read(buffer)
		if err != nil {
			break
		}

		slice := buffer[:n]
		locs := delim.FindAllSubmatchIndex(slice, -1)

		if len(locs) == 0 {
			accum.Write(slice)
		} else {

			line_begin_idx := 0
			line_end_idx := 0
			next_start := 0
			for _, loc := range locs {
				if first {
					first = false
					next_start = loc[0]
					if loc[0] == 0 && accum.Len() > 0 {
						lineChan <- accum.String()
						accum.Reset()
					}
					continue
				} else {
					line_begin_idx = next_start
				}

				line_end_idx = loc[0]
				next_start = loc[1] - (loc[1] - loc[0])
				data := bytes.Replace(slice[line_begin_idx:line_end_idx], []byte("\x0A"), nil, -1)
				data = append(accum.Bytes(), data...)
				lineChan <- string(data)
				accum.Reset()
				// data_trim := bytes.TrimRight(data, "\n")
				// log.Printf("%v -> %v", line_begin_idx, line_end_idx)
				// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", line_begin_idx, data_trim, line_end_idx)

			}

			data := slice[next_start:n]
			accum.Write(data)
			// w.Write(data)
			// lineChan <- string(data)
			// data_trim := bytes.TrimRight(data, "\n")
			// fmt.Printf("\n-----line start %v -----\n%s\n-----line end %v -----\n", next_start, data, n)
		}
	}

	// lineChan <- string(accum.Bytes())
	// accum.Reset()
	// }()

	// <-ctx.Done()

}
<|endoftext|>


<commit_before>package client

import (
	"strings"
	"testing"
)

func TestGetTunnelFlag(t *testing.T) {
	flag := getTunnelFlag()
	if flag != "" {
		t.Fatalf("got %v, expected \"\"", flag)
	}
	Flags.Tunnel = "hostname:2222"
	flag = getTunnelFlag()
	if flag != "hostname:2222" {
		t.Fatalf("got %v, expected \"hostname:2222\"", flag)
	}
	Flags.Tunnel = "hostname"
	flag = getTunnelFlag()
	if flag != "hostname:22" {
		t.Fatalf("got %v, expected \"hostname:22\"", flag)
	}
}

func TestGetChecker(t *testing.T) {
	Flags.StrictHostKeyChecking = false
	checker := getChecker()
	if checker != nil {
		t.Fatalf("expected nil checker, got %v", checker)
	}
}

func TestFakeClient(t *testing.T) {
	_, err := getFakeClient()
	if err != nil {
		t.Fatal(err)
	}
}

func TestRegistryClient(t *testing.T) {
	Flags.Endpoint = "http://127.0.0.1:4001"
	_, err := getRegistryClient()
	if err != nil && !strings.Contains(err.Error(), "no such host") {
		t.Fatal(err)
	}
}
<commit_msg>fix(tests): explicitly set tunnel to null<commit_after>package client

import (
	"strings"
	"testing"
)

func TestGetTunnelFlag(t *testing.T) {
	flag := getTunnelFlag()
	if flag != "" {
		t.Fatalf("got %v, expected \"\"", flag)
	}
	Flags.Tunnel = "hostname:2222"
	flag = getTunnelFlag()
	if flag != "hostname:2222" {
		t.Fatalf("got %v, expected \"hostname:2222\"", flag)
	}
	Flags.Tunnel = "hostname"
	flag = getTunnelFlag()
	if flag != "hostname:22" {
		t.Fatalf("got %v, expected \"hostname:22\"", flag)
	}
}

func TestGetChecker(t *testing.T) {
	Flags.StrictHostKeyChecking = false
	checker := getChecker()
	if checker != nil {
		t.Fatalf("expected nil checker, got %v", checker)
	}
}

func TestFakeClient(t *testing.T) {
	_, err := getFakeClient()
	if err != nil {
		t.Fatal(err)
	}
}

func TestRegistryClient(t *testing.T) {
	Flags.Tunnel = ""
	Flags.Endpoint = "http://127.0.0.1:4001"
	_, err := getRegistryClient()
	if err != nil && !strings.Contains(err.Error(), "no such host") {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package queue

import "fmt"

type TestConnection struct {
	queues map[string]*TestQueue
}

func NewTestConnection() TestConnection {
	return TestConnection{
		queues: map[string]*TestQueue{},
	}
}

func (connection TestConnection) OpenQueue(name string) Queue {
	queue := NewTestQueue()
	connection.queues[name] = queue
	return queue
}

func (connection TestConnection) CollectStats() Stats {
	return Stats{}
}

func (connection TestConnection) GetDeliveries(queueName string) []string {
	queue, ok := connection.queues[queueName]
	if !ok {
		return []string{}
	}

	return queue.LastDeliveries
}

func (connection TestConnection) GetDelivery(queueName string, index int) string {
	queue, ok := connection.queues[queueName]
	if !ok || index < 0 || index >= len(queue.LastDeliveries) {
		return fmt.Sprintf("queue.TestConnection: delivery not found: %s[%d]", queueName, index)
	}

	return queue.LastDeliveries[index]
}

func (connection TestConnection) Reset() {
	for _, queue := range connection.queues {
		queue.Reset()
	}
}
<commit_msg>queue.TestConnection reuse queues instead of recreating them<commit_after>package queue

import "fmt"

type TestConnection struct {
	queues map[string]*TestQueue
}

func NewTestConnection() TestConnection {
	return TestConnection{
		queues: map[string]*TestQueue{},
	}
}

func (connection TestConnection) OpenQueue(name string) Queue {
	if queue, ok := connection.queues[name]; ok {
		return queue
	}

	queue := NewTestQueue()
	connection.queues[name] = queue
	return queue
}

func (connection TestConnection) CollectStats() Stats {
	return Stats{}
}

func (connection TestConnection) GetDeliveries(queueName string) []string {
	queue, ok := connection.queues[queueName]
	if !ok {
		return []string{}
	}

	return queue.LastDeliveries
}

func (connection TestConnection) GetDelivery(queueName string, index int) string {
	queue, ok := connection.queues[queueName]
	if !ok || index < 0 || index >= len(queue.LastDeliveries) {
		return fmt.Sprintf("queue.TestConnection: delivery not found: %s[%d]", queueName, index)
	}

	return queue.LastDeliveries[index]
}

func (connection TestConnection) Reset() {
	for _, queue := range connection.queues {
		queue.Reset()
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"testing"
)

var godocTests = []struct {
	args    []string
	matches []string // regular expressions
}{
	{
		[]string{"fmt"},
		[]string{
			`import "fmt"`,
			`Package fmt implements formatted I/O`,
		},
	},
	{
		[]string{"io", "WriteString"},
		[]string{
			`import "io"`,
			`func WriteString\(`,
		},
	},
}

// Basic regression test for godoc command-line tool.
func TestGodoc(t *testing.T) {
	tmp, err := ioutil.TempDir("", "godoc-regtest-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	bin := filepath.Join(tmp, "godoc")
	cmd := exec.Command("go", "build", "-o", bin)
	if err := cmd.Run(); err != nil {
		t.Fatalf("Building godoc: %v", err)
	}

	for _, test := range godocTests {
		cmd := exec.Command(bin, test.args...)
		cmd.Args[0] = "godoc"
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Errorf("Running with args %#v: %v", test.args, err)
			continue
		}
		logged := false
		for _, pat := range test.matches {
			re := regexp.MustCompile(pat)
			if !re.Match(out) {
				if !logged {
					t.Logf("Output of running with args %#v:\n%s", test.args, out)
					logged = true
				}
				t.Errorf("Did not match /%v/", pat)
			}
		}
	}
}
<commit_msg>cmd/godoc: Fix reg test on Windows.<commit_after>// Copyright 2013 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main_test

import (
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"testing"
)

var godocTests = []struct {
	args    []string
	matches []string // regular expressions
}{
	{
		[]string{"fmt"},
		[]string{
			`import "fmt"`,
			`Package fmt implements formatted I/O`,
		},
	},
	{
		[]string{"io", "WriteString"},
		[]string{
			`import "io"`,
			`func WriteString\(`,
		},
	},
}

// Basic regression test for godoc command-line tool.
func TestGodoc(t *testing.T) {
	tmp, err := ioutil.TempDir("", "godoc-regtest-")
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(tmp)

	bin := filepath.Join(tmp, "godoc")
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}
	cmd := exec.Command("go", "build", "-o", bin)
	if err := cmd.Run(); err != nil {
		t.Fatalf("Building godoc: %v", err)
	}

	for _, test := range godocTests {
		cmd := exec.Command(bin, test.args...)
		cmd.Args[0] = "godoc"
		out, err := cmd.CombinedOutput()
		if err != nil {
			t.Errorf("Running with args %#v: %v", test.args, err)
			continue
		}
		logged := false
		for _, pat := range test.matches {
			re := regexp.MustCompile(pat)
			if !re.Match(out) {
				if !logged {
					t.Logf("Output of running with args %#v:\n%s", test.args, out)
					logged = true
				}
				t.Errorf("Did not match /%v/", pat)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//+build ignore

// Release is a tool for building the NDK tarballs hosted on dl.google.com.
//
// The Go toolchain only needs the gcc compiler and headers, which are ~10MB.
// The entire NDK is ~400MB. Building smaller toolchain binaries reduces the
// run time of gomobile init significantly.
package main

import (
	"archive/tar"
	"bufio"
	"compress/gzip"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

const ndkVersion = "ndk-r10e"

type version struct {
	os   string
	arch string
}

var hosts = []version{
	{"darwin", "x86_64"},
	{"linux", "x86"},
	{"linux", "x86_64"},
	{"windows", "x86"},
	{"windows", "x86_64"},
}

var tmpdir string

func main() {
	var err error
	tmpdir, err = ioutil.TempDir("", "gomobile-release-")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	fmt.Println("var fetchHashes = map[string]string{")

	for _, host := range hosts {
		if err := mkpkg(host); err != nil {
			log.Fatal(err)
		}
	}

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

	fmt.Println("}")
}

func run(dir, path string, args ...string) error {
	cmd := exec.Command(path, args...)
	cmd.Dir = dir
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func mkALPkg() (err error) {
	alTmpDir, err := ioutil.TempDir("", "openal-release-")
	if err != nil {
		return err
	}
	defer os.RemoveAll(alTmpDir)

	if err := run(alTmpDir, "git", "clone", "-v", "git://repo.or.cz/openal-soft.git", alTmpDir); err != nil {
		return err
	}
	if err := run(alTmpDir, "git", "checkout", "19f79be57b8e768f44710b6d26017bc1f8c8fbda"); err != nil {
		return err
	}
	if err := run(filepath.Join(alTmpDir, "cmake"), "cmake", "..", "-DCMAKE_TOOLCHAIN_FILE=../XCompile-Android.txt", "-DHOST=arm-linux-androideabi"); err != nil {
		return err
	}
	if err := run(filepath.Join(alTmpDir, "cmake"), "make"); err != nil {
		return err
	}

	// Build the tarball.
	aw := newArchiveWriter("gomobile-openal-soft-1.16.0.1.tar.gz")
	defer func() {
		err2 := aw.Close()
		if err == nil {
			err = err2
		}
	}()

	files := map[string]string{
		"cmake/libopenal.so": "lib/armeabi/libopenal.so",
		"include/AL/al.h":    "include/AL/al.h",
		"include/AL/alc.h":   "include/AL/alc.h",
		"COPYING":            "include/AL/COPYING",
	}
	for src, dst := range files {
		f, err := os.Open(filepath.Join(alTmpDir, src))
		if err != nil {
			return err
		}
		fi, err := f.Stat()
		if err != nil {
			return err
		}
		aw.WriteHeader(&tar.Header{
			Name: dst,
			Mode: int64(fi.Mode()),
			Size: fi.Size(),
		})
		io.Copy(aw, f)
		f.Close()
	}
	return nil
}

func mkpkg(host version) (err error) {
	ndkName := "android-" + ndkVersion + "-" + host.os + "-" + host.arch + "."
	if host.os == "windows" {
		ndkName += "exe"
	} else {
		ndkName += "bin"
	}
	url := "http://dl.google.com/android/ndk/" + ndkName
	log.Printf("%s\n", url)
	binPath := tmpdir + "/" + ndkName
	binHash, err := fetch(binPath, url)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("\t%q: %q,\n", ndkName, binHash)

	src := tmpdir + "/" + host.os + "-" + host.arch + "-src"
	dst := tmpdir + "/" + host.os + "-" + host.arch + "-dst"
	if err := os.Mkdir(src, 0755); err != nil {
		return err
	}
	if err := inflate(src, binPath); err != nil {
		return err
	}

	// The NDK is unpacked into tmpdir/linux-x86_64-src/android-{{ndkVersion}}.
	// Move the files we want into tmpdir/linux-x86_64-dst/android-{{ndkVersion}}.
	// We preserve the same file layout to make the full NDK interchangable
	// with the cut down file.
	usr := "android-" + ndkVersion + "/platforms/android-15/arch-arm/usr"
	gcc := "android-" + ndkVersion + "/toolchains/arm-linux-androideabi-4.8/prebuilt/"
	if host.os == "windows" && host.arch == "x86" {
		gcc += "windows"
	} else {
		gcc += host.os + "-" + host.arch
	}

	if err := os.MkdirAll(dst+"/"+usr, 0755); err != nil {
		return err
	}
	if err := os.MkdirAll(dst+"/"+gcc, 0755); err != nil {
		return err
	}
	if err := move(dst+"/"+usr, src+"/"+usr, "include", "lib"); err != nil {
		return err
	}
	if err := move(dst+"/"+gcc, src+"/"+gcc, "bin", "lib", "libexec", "COPYING", "COPYING.LIB"); err != nil {
		return err
	}

	// Build the tarball.
	aw := newArchiveWriter("gomobile-" + ndkVersion + "-" + host.os + "-" + host.arch + ".tar.gz")
	defer func() {
		err2 := aw.Close()
		if err == nil {
			err = err2
		}
	}()

	readme := "Stripped down copy of:\n\n\t" + url + "\n\nGenerated by golang.org/x/mobile/cmd/gomobile/release.go."
	aw.WriteHeader(&tar.Header{
		Name: "README",
		Mode: 0644,
		Size: int64(len(readme)),
	})
	io.WriteString(aw, readme)

	return filepath.Walk(dst, func(path string, fi os.FileInfo, err error) error {
		defer func() {
			if err != nil {
				err = fmt.Errorf("%s: %v", path, err)
			}
		}()
		if err != nil {
			return err
		}
		if path == dst {
			return nil
		}
		name := path[len(dst)+1:]
		if fi.IsDir() {
			return nil
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			dst, err := os.Readlink(path)
			if err != nil {
				log.Printf("bad symlink: %s", name)
				return nil
			}
			aw.WriteHeader(&tar.Header{
				Name:     name,
				Linkname: dst,
				Typeflag: tar.TypeSymlink,
			})
			return nil
		}
		aw.WriteHeader(&tar.Header{
			Name: name,
			Mode: int64(fi.Mode()),
			Size: fi.Size(),
		})
		f, err := os.Open(path)
		if err != nil {
			return err
		}
		io.Copy(aw, f)
		f.Close()
		return nil
	})
}

func fetch(dst, url string) (string, error) {
	f, err := os.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0755)
	if err != nil {
		return "", err
	}
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	hashw := sha256.New()
	_, err = io.Copy(io.MultiWriter(hashw, f), resp.Body)
	err2 := resp.Body.Close()
	err3 := f.Close()
	if err != nil {
		return "", err
	}
	if err2 != nil {
		return "", err2
	}
	if err3 != nil {
		return "", err3
	}
	return hex.EncodeToString(hashw.Sum(nil)), nil
}

func inflate(dst, path string) error {
	p7zip := "7z"
	if runtime.GOOS == "darwin" {
		p7zip = "/Applications/Keka.app/Contents/Resources/keka7z"
	}
	cmd := exec.Command(p7zip, "x", path)
	cmd.Dir = dst
	out, err := cmd.CombinedOutput()
	if err != nil {
		os.Stderr.Write(out)
		return err
	}
	return nil
}

func move(dst, src string, names ...string) error {
	for _, name := range names {
		if err := os.Rename(src+"/"+name, dst+"/"+name); err != nil {
			return err
		}
	}
	return nil
}

// archiveWriter writes a .tar.gz archive and prints its SHA256 to stdout.
// If any error occurs, it continues as a no-op until Close, when it is reported.
type archiveWriter struct {
	name  string
	hashw hash.Hash
	f     *os.File
	zw    *gzip.Writer
	bw    *bufio.Writer
	tw    *tar.Writer
	err   error
}

func (aw *archiveWriter) WriteHeader(h *tar.Header) {
	if aw.err != nil {
		return
	}
	aw.err = aw.tw.WriteHeader(h)
}

func (aw *archiveWriter) Write(b []byte) (n int, err error) {
	if aw.err != nil {
		return len(b), nil
	}
	n, aw.err = aw.tw.Write(b)
	return n, nil
}

func (aw *archiveWriter) Close() (err error) {
	err = aw.tw.Close()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.zw.Close()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.bw.Flush()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.f.Close()
	if aw.err == nil {
		aw.err = err
	}
	if aw.err != nil {
		return aw.err
	}
	hash := hex.EncodeToString(aw.hashw.Sum(nil))
	fmt.Printf("\t%q: %q,\n", aw.name, hash)
	return nil
}

func newArchiveWriter(name string) *archiveWriter {
	aw := &archiveWriter{name: name}
	aw.f, aw.err = os.Create(name)
	if aw.err != nil {
		return aw
	}
	aw.hashw = sha256.New()
	aw.bw = bufio.NewWriter(io.MultiWriter(aw.f, aw.hashw))
	aw.zw, aw.err = gzip.NewWriterLevel(aw.bw, gzip.BestCompression)
	if aw.err != nil {
		return aw
	}
	aw.tw = tar.NewWriter(aw.zw)
	return aw
}
<commit_msg>cmd/gomobile/release.go: include x86, x86_64 toolchains<commit_after>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//+build ignore

// Release is a tool for building the NDK tarballs hosted on dl.google.com.
//
// The Go toolchain only needs the gcc compiler and headers, which are ~10MB.
// The entire NDK is ~400MB. Building smaller toolchain binaries reduces the
// run time of gomobile init significantly.
package main

import (
	"archive/tar"
	"bufio"
	"compress/gzip"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"hash"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
)

const ndkVersion = "ndk-r10e"

type version struct {
	os   string
	arch string
}

var hosts = []version{
	{"darwin", "x86_64"},
	{"linux", "x86"},
	{"linux", "x86_64"},
	{"windows", "x86"},
	{"windows", "x86_64"},
}

type target struct {
	arch       string
	platform   string
	gcc        string
	toolPrefix string
}

var targets = []target{
	{"arm", "android-15", "arm-linux-androideabi-4.8", "arm-linux-androideabi"},
	{"x86", "android-15", "x86-4.8", "i686-linux-android"},
	{"x86_64", "android-21", "x86_64-4.9", "x86_64-linux-android"},
}

var tmpdir string

func main() {
	var err error
	tmpdir, err = ioutil.TempDir("", "gomobile-release-")
	if err != nil {
		log.Panic(err)
	}
	defer os.RemoveAll(tmpdir)

	fmt.Println("var fetchHashes = map[string]string{")
	for _, host := range hosts {
		if err := mkpkg(host); err != nil {
			log.Panic(err)
		}
	}
	if err := mkALPkg(); err != nil {
		log.Panic(err)
	}

	fmt.Println("}")
}

func run(dir, path string, args ...string) error {
	cmd := exec.Command(path, args...)
	cmd.Dir = dir
	buf, err := cmd.CombinedOutput()
	if err != nil {
		fmt.Printf("%s\n", buf)
	}
	return err
}

func mkALPkg() (err error) {
	ndkPath, _, err := fetchNDK(version{os: hostOS, arch: hostArch})
	if err != nil {
		return err
	}
	ndkRoot := tmpdir + "/android-" + ndkVersion
	if err := inflate(tmpdir, ndkPath); err != nil {
		return err
	}

	alTmpDir, err := ioutil.TempDir("", "openal-release-")
	if err != nil {
		return err
	}
	defer os.RemoveAll(alTmpDir)

	if err := run(alTmpDir, "git", "clone", "-v", "git://repo.or.cz/openal-soft.git", alTmpDir); err != nil {
		return err
	}
	// TODO: use more recent revision?
	if err := run(alTmpDir, "git", "checkout", "19f79be57b8e768f44710b6d26017bc1f8c8fbda"); err != nil {
		return err
	}

	files := map[string]string{
		"include/AL/al.h":  "include/AL/al.h",
		"include/AL/alc.h": "include/AL/alc.h",
		"COPYING":          "include/AL/COPYING",
	}

	for _, t := range targets {
		abi := t.arch
		if abi == "arm" {
			abi = "armeabi"
		}
		buildDir := alTmpDir + "/build/" + abi
		toolchain := buildDir + "/toolchain"
		if err := os.MkdirAll(toolchain, 0755); err != nil {
			return err
		}
		// standalone ndk toolchains make openal-soft's build config easier.
		if err := run(ndkRoot, "env",
			"build/tools/make-standalone-toolchain.sh",
			"--arch="+t.arch,
			"--platform="+t.platform,
			"--install-dir="+toolchain); err != nil {
			return fmt.Errorf("make-standalone-toolchain.sh failed: %v", err)
		}

		orgPath := os.Getenv("PATH")
		os.Setenv("PATH", toolchain+"/bin"+string(os.PathListSeparator)+orgPath)
		if err := run(buildDir, "cmake",
			"../../",
			"-DCMAKE_TOOLCHAIN_FILE=../../XCompile-Android.txt",
			"-DHOST="+t.toolPrefix); err != nil {
			return fmt.Errorf("cmake failed: %v", err)
		}
		os.Setenv("PATH", orgPath)

		if err := run(buildDir, "make"); err != nil {
			return fmt.Errorf("make failed: %v", err)
		}

		files["build/"+abi+"/libopenal.so"] = "lib/" + abi + "/libopenal.so"
	}

	// Build the tarball.
	aw := newArchiveWriter("gomobile-openal-soft-1.16.0.1.tar.gz")
	defer func() {
		err2 := aw.Close()
		if err == nil {
			err = err2
		}
	}()

	for src, dst := range files {
		f, err := os.Open(filepath.Join(alTmpDir, src))
		if err != nil {
			return err
		}
		fi, err := f.Stat()
		if err != nil {
			return err
		}
		aw.WriteHeader(&tar.Header{
			Name: dst,
			Mode: int64(fi.Mode()),
			Size: fi.Size(),
		})
		io.Copy(aw, f)
		f.Close()
	}
	return nil
}

func fetchNDK(host version) (binPath, url string, err error) {
	ndkName := "android-" + ndkVersion + "-" + host.os + "-" + host.arch + "."
	if host.os == "windows" {
		ndkName += "exe"
	} else {
		ndkName += "bin"
	}

	url = "http://dl.google.com/android/ndk/" + ndkName
	binPath = tmpdir + "/" + ndkName

	if _, err := os.Stat(binPath); err == nil {
		log.Printf("\t%q: using cached NDK\n", ndkName)
		return binPath, url, nil
	}

	log.Printf("%s\n", url)
	binHash, err := fetch(binPath, url)
	if err != nil {
		return "", "", err
	}

	fmt.Printf("\t%q: %q,\n", ndkName, binHash)
	return binPath, url, nil
}

func mkpkg(host version) error {
	binPath, url, err := fetchNDK(host)
	if err != nil {
		return err
	}

	src := tmpdir + "/" + host.os + "-" + host.arch + "-src"
	dst := tmpdir + "/" + host.os + "-" + host.arch + "-dst"
	defer os.RemoveAll(src)
	defer os.RemoveAll(dst)

	if err := os.Mkdir(src, 0755); err != nil {
		return err
	}

	if err := inflate(src, binPath); err != nil {
		return err
	}

	// The NDK is unpacked into tmpdir/linux-x86_64-src/android-{{ndkVersion}}.
	// Move the files we want into tmpdir/linux-x86_64-dst/android-{{ndkVersion}}.
	// We preserve the same file layout to make the full NDK interchangable
	// with the cut down file.
	for _, t := range targets {
		usr := fmt.Sprintf("android-%s/platforms/%s/arch-%s/usr/", ndkVersion, t.platform, t.arch)
		gcc := fmt.Sprintf("android-%s/toolchains/%s/prebuilt/", ndkVersion, t.gcc)

		if host.os == "windows" && host.arch == "x86" {
			gcc += "windows"
		} else {
			gcc += host.os + "-" + host.arch
		}

		if err := os.MkdirAll(dst+"/"+usr, 0755); err != nil {
			return err
		}
		if err := os.MkdirAll(dst+"/"+gcc, 0755); err != nil {
			return err
		}

		subdirs := []string{"include", "lib"}
		switch t.arch {
		case "x86_64":
			subdirs = append(subdirs, "lib64", "libx32")
		}
		if err := move(dst+"/"+usr, src+"/"+usr, subdirs...); err != nil {
			return err
		}

		if err := move(dst+"/"+gcc, src+"/"+gcc, "bin", "lib", "libexec", "COPYING", "COPYING.LIB"); err != nil {
			return err
		}
	}

	// Build the tarball.
	aw := newArchiveWriter("gomobile-" + ndkVersion + "-" + host.os + "-" + host.arch + ".tar.gz")
	defer func() {
		err2 := aw.Close()
		if err == nil {
			err = err2
		}
	}()

	readme := "Stripped down copy of:\n\n\t" + url + "\n\nGenerated by golang.org/x/mobile/cmd/gomobile/release.go."
	aw.WriteHeader(&tar.Header{
		Name: "README",
		Mode: 0644,
		Size: int64(len(readme)),
	})
	io.WriteString(aw, readme)

	return filepath.Walk(dst, func(path string, fi os.FileInfo, err error) error {
		defer func() {
			if err != nil {
				err = fmt.Errorf("%s: %v", path, err)
			}
		}()
		if err != nil {
			return err
		}
		if path == dst {
			return nil
		}
		name := path[len(dst)+1:]
		if fi.IsDir() {
			return nil
		}
		if fi.Mode()&os.ModeSymlink != 0 {
			dst, err := os.Readlink(path)
			if err != nil {
				log.Printf("bad symlink: %s", name)
				return nil
			}
			aw.WriteHeader(&tar.Header{
				Name:     name,
				Linkname: dst,
				Typeflag: tar.TypeSymlink,
			})
			return nil
		}
		aw.WriteHeader(&tar.Header{
			Name: name,
			Mode: int64(fi.Mode()),
			Size: fi.Size(),
		})
		f, err := os.Open(path)
		if err != nil {
			return err
		}
		io.Copy(aw, f)
		f.Close()
		return nil
	})
}

func fetch(dst, url string) (string, error) {
	f, err := os.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0755)
	if err != nil {
		return "", err
	}
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	hashw := sha256.New()
	_, err = io.Copy(io.MultiWriter(hashw, f), resp.Body)
	err2 := resp.Body.Close()
	err3 := f.Close()
	if err != nil {
		return "", err
	}
	if err2 != nil {
		return "", err2
	}
	if err3 != nil {
		return "", err3
	}
	return hex.EncodeToString(hashw.Sum(nil)), nil
}

func inflate(dst, path string) error {
	p7zip := "7z"
	if runtime.GOOS == "darwin" {
		p7zip = "/Applications/Keka.app/Contents/Resources/keka7z"
	}
	cmd := exec.Command(p7zip, "x", path)
	cmd.Dir = dst
	out, err := cmd.CombinedOutput()
	if err != nil {
		os.Stderr.Write(out)
		return err
	}
	return nil
}

func move(dst, src string, names ...string) error {
	for _, name := range names {
		if err := os.Rename(src+"/"+name, dst+"/"+name); err != nil {
			return err
		}
	}
	return nil
}

// archiveWriter writes a .tar.gz archive and prints its SHA256 to stdout.
// If any error occurs, it continues as a no-op until Close, when it is reported.
type archiveWriter struct {
	name  string
	hashw hash.Hash
	f     *os.File
	zw    *gzip.Writer
	bw    *bufio.Writer
	tw    *tar.Writer
	err   error
}

func (aw *archiveWriter) WriteHeader(h *tar.Header) {
	if aw.err != nil {
		return
	}
	aw.err = aw.tw.WriteHeader(h)
}

func (aw *archiveWriter) Write(b []byte) (n int, err error) {
	if aw.err != nil {
		return len(b), nil
	}
	n, aw.err = aw.tw.Write(b)
	return n, nil
}

func (aw *archiveWriter) Close() (err error) {
	err = aw.tw.Close()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.zw.Close()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.bw.Flush()
	if aw.err == nil {
		aw.err = err
	}
	err = aw.f.Close()
	if aw.err == nil {
		aw.err = err
	}
	if aw.err != nil {
		return aw.err
	}
	hash := hex.EncodeToString(aw.hashw.Sum(nil))
	fmt.Printf("\t%q: %q,\n", aw.name, hash)
	return nil
}

func newArchiveWriter(name string) *archiveWriter {
	aw := &archiveWriter{name: name}
	aw.f, aw.err = os.Create(name)
	if aw.err != nil {
		return aw
	}
	aw.hashw = sha256.New()
	aw.bw = bufio.NewWriter(io.MultiWriter(aw.f, aw.hashw))
	aw.zw, aw.err = gzip.NewWriterLevel(aw.bw, gzip.BestCompression)
	if aw.err != nil {
		return aw
	}
	aw.tw = tar.NewWriter(aw.zw)
	return aw
}

var hostOS, hostArch string

func init() {
	switch runtime.GOOS {
	case "linux", "darwin":
		hostOS = runtime.GOOS
	}
	switch runtime.GOARCH {
	case "386":
		hostArch = "x86"
	case "amd64":
		hostArch = "x86_64"
	}
	if hostOS == "" || hostArch == "" {
		panic(fmt.Sprintf("cannot run release from OS/Arch: %s/%s", hostOS, hostArch))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/opencontainers/ocitools/cmd/runtimetest/mount"
	rspec "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/syndtr/gocapability/capability"
	"github.com/urfave/cli"
)

// PR_GET_NO_NEW_PRIVS isn't exposed in Golang so we define it ourselves copying the value from
// the kernel
const PR_GET_NO_NEW_PRIVS = 39

var (
	defaultFS = map[string]string{
		"/proc":    "proc",
		"/sys":     "sysfs",
		"/dev/pts": "devpts",
		"/dev/shm": "tmpfs",
	}

	defaultDevices = []string{
		"/dev/null",
		"/dev/zero",
		"/dev/full",
		"/dev/random",
		"/dev/urandom",
		"/dev/tty",
		"/dev/console",
		"/dev/ptmx",
	}
)

type validation func(*rspec.Spec) error

func loadSpecConfig() (spec *rspec.Spec, err error) {
	cPath := "config.json"
	cf, err := os.Open(cPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("config.json not found")
		}
	}
	defer cf.Close()

	if err = json.NewDecoder(cf).Decode(&spec); err != nil {
		return
	}
	return spec, nil
}

func validateProcess(spec *rspec.Spec) error {
	logrus.Debugf("validating container process")
	uid := os.Getuid()
	if uint32(uid) != spec.Process.User.UID {
		return fmt.Errorf("UID expected: %v, actual: %v", spec.Process.User.UID, uid)
	}
	gid := os.Getgid()
	if uint32(gid) != spec.Process.User.GID {
		return fmt.Errorf("GID expected: %v, actual: %v", spec.Process.User.GID, gid)
	}

	groups, err := os.Getgroups()
	if err != nil {
		return err
	}

	groupsMap := make(map[int]bool)
	for _, g := range groups {
		groupsMap[g] = true
	}

	for _, g := range spec.Process.User.AdditionalGids {
		if !groupsMap[int(g)] {
			return fmt.Errorf("Groups expected: %v, actual (should be superset): %v", spec.Process.User.AdditionalGids, groups)
		}
	}

	if spec.Process.Cwd != "" {
		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		if cwd != spec.Process.Cwd {
			return fmt.Errorf("Cwd expected: %v, actual: %v", spec.Process.Cwd, cwd)
		}
	}

	cmdlineBytes, err := ioutil.ReadFile("/proc/1/cmdline")
	if err != nil {
		return err
	}

	args := bytes.Split(bytes.Trim(cmdlineBytes, "\x00"), []byte("\x00"))
	if len(args) != len(spec.Process.Args) {
		return fmt.Errorf("Process arguments expected: %v, actual: %v", len(spec.Process.Args), len(args))
	}
	for i, a := range args {
		if string(a) != spec.Process.Args[i] {
			return fmt.Errorf("Process arguments expected: %v, actual: %v", string(a), spec.Process.Args[i])
		}
	}

	for _, env := range spec.Process.Env {
		parts := strings.Split(env, "=")
		key := parts[0]
		expectedValue := parts[1]
		actualValue := os.Getenv(key)
		if actualValue != expectedValue {
			return fmt.Errorf("Env %v expected: %v, actual: %v", key, expectedValue, actualValue)
		}
	}

	ret, _, errno := syscall.Syscall6(syscall.SYS_PRCTL, PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0)
	if errno != 0 {
		return errno
	}
	if spec.Process.NoNewPrivileges && ret != 1 {
		return fmt.Errorf("NoNewPrivileges expected: true, actual: false")
	}
	if !spec.Process.NoNewPrivileges && ret != 0 {
		return fmt.Errorf("NoNewPrivileges expected: false, actual: true")
	}

	return nil
}

func validateCapabilities(spec *rspec.Spec) error {
	logrus.Debugf("validating capabilities")

	last := capability.CAP_LAST_CAP
	// workaround for RHEL6 which has no /proc/sys/kernel/cap_last_cap
	if last == capability.Cap(63) {
		last = capability.CAP_BLOCK_SUSPEND
	}

	processCaps, err := capability.NewPid(1)
	if err != nil {
		return err
	}

	expectedCaps := make(map[string]bool)
	for _, ec := range spec.Process.Capabilities {
		expectedCaps[ec] = true
	}

	for _, cap := range capability.List() {
		if cap > last {
			continue
		}

		capKey := fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))
		expectedSet := expectedCaps[capKey]
		actuallySet := processCaps.Get(capability.EFFECTIVE, cap)
		if expectedSet != actuallySet {
			if expectedSet {
				return fmt.Errorf("Expected Capability %v not set for process", cap.String())
			}
			return fmt.Errorf("Unexpected Capability %v set for process", cap.String())
		}
	}

	return nil
}

func validateHostname(spec *rspec.Spec) error {
	logrus.Debugf("validating hostname")
	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	if spec.Hostname != "" && hostname != spec.Hostname {
		return fmt.Errorf("Hostname expected: %v, actual: %v", spec.Hostname, hostname)
	}
	return nil
}

func validateRlimits(spec *rspec.Spec) error {
	logrus.Debugf("validating rlimits")
	for _, r := range spec.Process.Rlimits {
		rl, err := strToRlimit(r.Type)
		if err != nil {
			return err
		}

		var rlimit syscall.Rlimit
		if err := syscall.Getrlimit(rl, &rlimit); err != nil {
			return err
		}

		if rlimit.Cur != r.Soft {
			return fmt.Errorf("%v rlimit soft expected: %v, actual: %v", r.Type, r.Soft, rlimit.Cur)
		}
		if rlimit.Max != r.Hard {
			return fmt.Errorf("%v rlimit hard expected: %v, actual: %v", r.Type, r.Hard, rlimit.Max)
		}
	}
	return nil
}

func validateSysctls(spec *rspec.Spec) error {
	logrus.Debugf("validating sysctls")
	for k, v := range spec.Linux.Sysctl {
		keyPath := filepath.Join("/proc/sys", strings.Replace(k, ".", "/", -1))
		vBytes, err := ioutil.ReadFile(keyPath)
		if err != nil {
			return err
		}
		value := strings.TrimSpace(string(bytes.Trim(vBytes, "\x00")))
		if value != v {
			return fmt.Errorf("Sysctl %v value expected: %v, actual: %v", k, v, value)
		}
	}
	return nil
}

func testWriteAccess(path string) error {
	tmpfile, err := ioutil.TempFile(path, "Test")
	if err != nil {
		return err
	}

	tmpfile.Close()
	os.RemoveAll(filepath.Join(path, tmpfile.Name()))

	return nil
}

func validateRootFS(spec *rspec.Spec) error {
	logrus.Debugf("validating root filesystem")
	if spec.Root.Readonly {
		err := testWriteAccess("/")
		if err == nil {
			return fmt.Errorf("Rootfs should be readonly")
		}
	}

	return nil
}

func validateDefaultFS(spec *rspec.Spec) error {
	logrus.Debugf("validating linux default filesystem")

	mountInfos, err := mount.GetMounts()
	if err != nil {
		return err
	}

	mountsMap := make(map[string]string)
	for _, mountInfo := range mountInfos {
		mountsMap[mountInfo.Mountpoint] = mountInfo.Fstype
	}

	for fs, fstype := range defaultFS {
		if !(mountsMap[fs] == fstype) {
			return fmt.Errorf("%v must exist and expected type is %v", fs, fstype)
		}
	}

	return nil
}

func validateDefaultDevices(spec *rspec.Spec) error {
	logrus.Debugf("validating linux default devices")

	for _, device := range defaultDevices {
		fi, err := os.Stat(device)
		if err != nil {
			if os.IsNotExist(err) {
				return fmt.Errorf("device node %v not found", device)
			} else {
				return err
			}
		} else {
			if fi.Mode() != os.ModeDevice {
				return fmt.Errorf("file %v is not a device as expected", device)
			}
		}
	}

	return nil
}

func validateMaskedPaths(spec *rspec.Spec) error {
	logrus.Debugf("validating maskedPaths")
	for _, maskedPath := range spec.Linux.MaskedPaths {
		f, err := os.Open(maskedPath)
		if err != nil {
			return err
		}
		defer f.Close()
		b := make([]byte, 1)
		_, err = f.Read(b)
		if err != io.EOF {
			return fmt.Errorf("%v should not be readable", maskedPath)
		}
	}
	return nil
}

func validateROPaths(spec *rspec.Spec) error {
	logrus.Debugf("validating readonlyPaths")
	for _, v := range spec.Linux.ReadonlyPaths {
		err := testWriteAccess(v)
		if err == nil {
			return fmt.Errorf("%v should be readonly", v)
		}
	}

	return nil
}

func mountMatch(specMount rspec.Mount, sysMount rspec.Mount) error {
	if specMount.Destination != sysMount.Destination {
		return fmt.Errorf("mount destination expected: %v, actual: %v", specMount.Destination, sysMount.Destination)
	}

	if specMount.Type != sysMount.Type {
		return fmt.Errorf("mount %v type expected: %v, actual: %v", specMount.Destination, specMount.Type, sysMount.Type)
	}

	if specMount.Source != sysMount.Source {
		return fmt.Errorf("mount %v source expected: %v, actual: %v", specMount.Destination, specMount.Source, sysMount.Source)
	}

	return nil
}

func validateMountsExist(spec *rspec.Spec) error {
	logrus.Debugf("validating mounts exist")

	mountInfos, err := mount.GetMounts()
	if err != nil {
		return err
	}

	mountsMap := make(map[string][]rspec.Mount)
	for _, mountInfo := range mountInfos {
		m := rspec.Mount{
			Destination: mountInfo.Mountpoint,
			Type:        mountInfo.Fstype,
			Source:      mountInfo.Source,
		}
		mountsMap[mountInfo.Mountpoint] = append(mountsMap[mountInfo.Mountpoint], m)
	}

	for _, specMount := range spec.Mounts {
		found := false
		for _, sysMount := range mountsMap[specMount.Destination] {
			if err := mountMatch(specMount, sysMount); err == nil {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("Expected mount %v does not exist", specMount)
		}
	}

	return nil
}

func validate(context *cli.Context) error {
	logLevelString := context.String("log-level")
	logLevel, err := logrus.ParseLevel(logLevelString)
	if err != nil {
		return err
	}
	logrus.SetLevel(logLevel)

	spec, err := loadSpecConfig()
	if err != nil {
		return err
	}

	defaultValidations := []validation{
		validateRootFS,
		validateProcess,
		validateCapabilities,
		validateHostname,
		validateRlimits,
		validateMountsExist,
	}

	linuxValidations := []validation{
		validateDefaultFS,
		validateDefaultDevices,
		validateSysctls,
		validateMaskedPaths,
		validateROPaths,
	}

	for _, v := range defaultValidations {
		if err := v(spec); err != nil {
			return err
		}
	}

	if spec.Platform.OS == "linux" {
		for _, v := range linuxValidations {
			if err := v(spec); err != nil {
				return err
			}
		}
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "runtimetest"
	app.Version = "0.0.1"
	app.Usage = "Compare the environment with an OCI configuration"
	app.UsageText = "runtimetest [options]"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "log-level",
			Value: "error",
			Usage: "Log level (panic, fatal, error, warn, info, or debug)",
		},
	}

	app.Action = validate
	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}
<commit_msg>runtimetest: Fix check for device node<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/opencontainers/ocitools/cmd/runtimetest/mount"
	rspec "github.com/opencontainers/runtime-spec/specs-go"
	"github.com/syndtr/gocapability/capability"
	"github.com/urfave/cli"
)

// PR_GET_NO_NEW_PRIVS isn't exposed in Golang so we define it ourselves copying the value from
// the kernel
const PR_GET_NO_NEW_PRIVS = 39

var (
	defaultFS = map[string]string{
		"/proc":    "proc",
		"/sys":     "sysfs",
		"/dev/pts": "devpts",
		"/dev/shm": "tmpfs",
	}

	defaultDevices = []string{
		"/dev/null",
		"/dev/zero",
		"/dev/full",
		"/dev/random",
		"/dev/urandom",
		"/dev/tty",
		"/dev/console",
		"/dev/ptmx",
	}
)

type validation func(*rspec.Spec) error

func loadSpecConfig() (spec *rspec.Spec, err error) {
	cPath := "config.json"
	cf, err := os.Open(cPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, fmt.Errorf("config.json not found")
		}
	}
	defer cf.Close()

	if err = json.NewDecoder(cf).Decode(&spec); err != nil {
		return
	}
	return spec, nil
}

func validateProcess(spec *rspec.Spec) error {
	logrus.Debugf("validating container process")
	uid := os.Getuid()
	if uint32(uid) != spec.Process.User.UID {
		return fmt.Errorf("UID expected: %v, actual: %v", spec.Process.User.UID, uid)
	}
	gid := os.Getgid()
	if uint32(gid) != spec.Process.User.GID {
		return fmt.Errorf("GID expected: %v, actual: %v", spec.Process.User.GID, gid)
	}

	groups, err := os.Getgroups()
	if err != nil {
		return err
	}

	groupsMap := make(map[int]bool)
	for _, g := range groups {
		groupsMap[g] = true
	}

	for _, g := range spec.Process.User.AdditionalGids {
		if !groupsMap[int(g)] {
			return fmt.Errorf("Groups expected: %v, actual (should be superset): %v", spec.Process.User.AdditionalGids, groups)
		}
	}

	if spec.Process.Cwd != "" {
		cwd, err := os.Getwd()
		if err != nil {
			return err
		}
		if cwd != spec.Process.Cwd {
			return fmt.Errorf("Cwd expected: %v, actual: %v", spec.Process.Cwd, cwd)
		}
	}

	cmdlineBytes, err := ioutil.ReadFile("/proc/1/cmdline")
	if err != nil {
		return err
	}

	args := bytes.Split(bytes.Trim(cmdlineBytes, "\x00"), []byte("\x00"))
	if len(args) != len(spec.Process.Args) {
		return fmt.Errorf("Process arguments expected: %v, actual: %v", len(spec.Process.Args), len(args))
	}
	for i, a := range args {
		if string(a) != spec.Process.Args[i] {
			return fmt.Errorf("Process arguments expected: %v, actual: %v", string(a), spec.Process.Args[i])
		}
	}

	for _, env := range spec.Process.Env {
		parts := strings.Split(env, "=")
		key := parts[0]
		expectedValue := parts[1]
		actualValue := os.Getenv(key)
		if actualValue != expectedValue {
			return fmt.Errorf("Env %v expected: %v, actual: %v", key, expectedValue, actualValue)
		}
	}

	ret, _, errno := syscall.Syscall6(syscall.SYS_PRCTL, PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0, 0)
	if errno != 0 {
		return errno
	}
	if spec.Process.NoNewPrivileges && ret != 1 {
		return fmt.Errorf("NoNewPrivileges expected: true, actual: false")
	}
	if !spec.Process.NoNewPrivileges && ret != 0 {
		return fmt.Errorf("NoNewPrivileges expected: false, actual: true")
	}

	return nil
}

func validateCapabilities(spec *rspec.Spec) error {
	logrus.Debugf("validating capabilities")

	last := capability.CAP_LAST_CAP
	// workaround for RHEL6 which has no /proc/sys/kernel/cap_last_cap
	if last == capability.Cap(63) {
		last = capability.CAP_BLOCK_SUSPEND
	}

	processCaps, err := capability.NewPid(1)
	if err != nil {
		return err
	}

	expectedCaps := make(map[string]bool)
	for _, ec := range spec.Process.Capabilities {
		expectedCaps[ec] = true
	}

	for _, cap := range capability.List() {
		if cap > last {
			continue
		}

		capKey := fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String()))
		expectedSet := expectedCaps[capKey]
		actuallySet := processCaps.Get(capability.EFFECTIVE, cap)
		if expectedSet != actuallySet {
			if expectedSet {
				return fmt.Errorf("Expected Capability %v not set for process", cap.String())
			}
			return fmt.Errorf("Unexpected Capability %v set for process", cap.String())
		}
	}

	return nil
}

func validateHostname(spec *rspec.Spec) error {
	logrus.Debugf("validating hostname")
	hostname, err := os.Hostname()
	if err != nil {
		return err
	}
	if spec.Hostname != "" && hostname != spec.Hostname {
		return fmt.Errorf("Hostname expected: %v, actual: %v", spec.Hostname, hostname)
	}
	return nil
}

func validateRlimits(spec *rspec.Spec) error {
	logrus.Debugf("validating rlimits")
	for _, r := range spec.Process.Rlimits {
		rl, err := strToRlimit(r.Type)
		if err != nil {
			return err
		}

		var rlimit syscall.Rlimit
		if err := syscall.Getrlimit(rl, &rlimit); err != nil {
			return err
		}

		if rlimit.Cur != r.Soft {
			return fmt.Errorf("%v rlimit soft expected: %v, actual: %v", r.Type, r.Soft, rlimit.Cur)
		}
		if rlimit.Max != r.Hard {
			return fmt.Errorf("%v rlimit hard expected: %v, actual: %v", r.Type, r.Hard, rlimit.Max)
		}
	}
	return nil
}

func validateSysctls(spec *rspec.Spec) error {
	logrus.Debugf("validating sysctls")
	for k, v := range spec.Linux.Sysctl {
		keyPath := filepath.Join("/proc/sys", strings.Replace(k, ".", "/", -1))
		vBytes, err := ioutil.ReadFile(keyPath)
		if err != nil {
			return err
		}
		value := strings.TrimSpace(string(bytes.Trim(vBytes, "\x00")))
		if value != v {
			return fmt.Errorf("Sysctl %v value expected: %v, actual: %v", k, v, value)
		}
	}
	return nil
}

func testWriteAccess(path string) error {
	tmpfile, err := ioutil.TempFile(path, "Test")
	if err != nil {
		return err
	}

	tmpfile.Close()
	os.RemoveAll(filepath.Join(path, tmpfile.Name()))

	return nil
}

func validateRootFS(spec *rspec.Spec) error {
	logrus.Debugf("validating root filesystem")
	if spec.Root.Readonly {
		err := testWriteAccess("/")
		if err == nil {
			return fmt.Errorf("Rootfs should be readonly")
		}
	}

	return nil
}

func validateDefaultFS(spec *rspec.Spec) error {
	logrus.Debugf("validating linux default filesystem")

	mountInfos, err := mount.GetMounts()
	if err != nil {
		return err
	}

	mountsMap := make(map[string]string)
	for _, mountInfo := range mountInfos {
		mountsMap[mountInfo.Mountpoint] = mountInfo.Fstype
	}

	for fs, fstype := range defaultFS {
		if !(mountsMap[fs] == fstype) {
			return fmt.Errorf("%v must exist and expected type is %v", fs, fstype)
		}
	}

	return nil
}

func validateDefaultDevices(spec *rspec.Spec) error {
	logrus.Debugf("validating linux default devices")

	for _, device := range defaultDevices {
		fi, err := os.Stat(device)
		if err != nil {
			if os.IsNotExist(err) {
				return fmt.Errorf("device node %v not found", device)
			} else {
				return err
			}
		} else {
			if fi.Mode()&os.ModeDevice != os.ModeDevice {
				return fmt.Errorf("file %v is not a device as expected", device)
			}
		}
	}

	return nil
}

func validateMaskedPaths(spec *rspec.Spec) error {
	logrus.Debugf("validating maskedPaths")
	for _, maskedPath := range spec.Linux.MaskedPaths {
		f, err := os.Open(maskedPath)
		if err != nil {
			return err
		}
		defer f.Close()
		b := make([]byte, 1)
		_, err = f.Read(b)
		if err != io.EOF {
			return fmt.Errorf("%v should not be readable", maskedPath)
		}
	}
	return nil
}

func validateROPaths(spec *rspec.Spec) error {
	logrus.Debugf("validating readonlyPaths")
	for _, v := range spec.Linux.ReadonlyPaths {
		err := testWriteAccess(v)
		if err == nil {
			return fmt.Errorf("%v should be readonly", v)
		}
	}

	return nil
}

func mountMatch(specMount rspec.Mount, sysMount rspec.Mount) error {
	if specMount.Destination != sysMount.Destination {
		return fmt.Errorf("mount destination expected: %v, actual: %v", specMount.Destination, sysMount.Destination)
	}

	if specMount.Type != sysMount.Type {
		return fmt.Errorf("mount %v type expected: %v, actual: %v", specMount.Destination, specMount.Type, sysMount.Type)
	}

	if specMount.Source != sysMount.Source {
		return fmt.Errorf("mount %v source expected: %v, actual: %v", specMount.Destination, specMount.Source, sysMount.Source)
	}

	return nil
}

func validateMountsExist(spec *rspec.Spec) error {
	logrus.Debugf("validating mounts exist")

	mountInfos, err := mount.GetMounts()
	if err != nil {
		return err
	}

	mountsMap := make(map[string][]rspec.Mount)
	for _, mountInfo := range mountInfos {
		m := rspec.Mount{
			Destination: mountInfo.Mountpoint,
			Type:        mountInfo.Fstype,
			Source:      mountInfo.Source,
		}
		mountsMap[mountInfo.Mountpoint] = append(mountsMap[mountInfo.Mountpoint], m)
	}

	for _, specMount := range spec.Mounts {
		found := false
		for _, sysMount := range mountsMap[specMount.Destination] {
			if err := mountMatch(specMount, sysMount); err == nil {
				found = true
				break
			}
		}
		if !found {
			return fmt.Errorf("Expected mount %v does not exist", specMount)
		}
	}

	return nil
}

func validate(context *cli.Context) error {
	logLevelString := context.String("log-level")
	logLevel, err := logrus.ParseLevel(logLevelString)
	if err != nil {
		return err
	}
	logrus.SetLevel(logLevel)

	spec, err := loadSpecConfig()
	if err != nil {
		return err
	}

	defaultValidations := []validation{
		validateRootFS,
		validateProcess,
		validateCapabilities,
		validateHostname,
		validateRlimits,
		validateMountsExist,
	}

	linuxValidations := []validation{
		validateDefaultFS,
		validateDefaultDevices,
		validateSysctls,
		validateMaskedPaths,
		validateROPaths,
	}

	for _, v := range defaultValidations {
		if err := v(spec); err != nil {
			return err
		}
	}

	if spec.Platform.OS == "linux" {
		for _, v := range linuxValidations {
			if err := v(spec); err != nil {
				return err
			}
		}
	}

	return nil
}

func main() {
	app := cli.NewApp()
	app.Name = "runtimetest"
	app.Version = "0.0.1"
	app.Usage = "Compare the environment with an OCI configuration"
	app.UsageText = "runtimetest [options]"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "log-level",
			Value: "error",
			Usage: "Log level (panic, fatal, error, warn, info, or debug)",
		},
	}

	app.Action = validate
	if err := app.Run(os.Args); err != nil {
		logrus.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package libkb

// Can either be a RemoteProofChainLink or one of the identities
// listed in a tracking statement
type TrackIdComponent interface {
	GetIdString() string
}

type TrackSet map[string]bool

func (ts TrackSet) Add(t TrackIdComponent) {
	ts[t.GetIdString()] = true
}

func (a TrackSet) SubsetOf(b TrackSet) bool {
	for k,_ := range(a) {
		if inset, found := b[k]; !inset || !found {
			return false
		}
	}
	return true
}

func (a TrackSet) Equal(b TrackSet) bool {
	return ((len(a) == len(b)) && a.SubsetOf(b))
}
<commit_msg>refactor track code out<commit_after>package libkb

import (
	"fmt"
	"github.com/keybase/go-jsonw"
)

// Can either be a RemoteProofChainLink or one of the identities
// listed in a tracking statement
type TrackIdComponent interface {
	GetIdString() string
}

type TrackSet map[string]bool

func (ts TrackSet) Add(t TrackIdComponent) {
	ts[t.GetIdString()] = true
}

func (a TrackSet) SubsetOf(b TrackSet) bool {
	for k,_ := range(a) {
		if inset, found := b[k]; !inset || !found {
			return false
		}
	}
	return true
}

func (a TrackSet) Equal(b TrackSet) bool {
	return ((len(a) == len(b)) && a.SubsetOf(b))
}

//=====================================================================

type TrackEngine struct {
	TheirName string
	Them *User
	Me *User
	Interactive bool
	NoSelf bool
	StrictProofs bool
}

func (e *TrackEngine) LoadThem() error {

	if e.Them == nil && len(e.TheirName) == 0 {
		return fmt.Errorf("No 'them' passed to TrackEngine")
	}
	if e.Them == nil {
		if u, err := LoadUser(LoadUserArg{
			Name:             e.TheirName,
			RequirePublicKey: true,
			Self:             false,
			LoadSecrets:      false,
			ForceReload:      false,
			SkipVerify:       false,
		}); err != nil {
			return err
		} else {
			e.Them = u
		}
	}
	return nil
}

func (e *TrackEngine) LoadMe() error {
	if e.Me == nil {
		if me, err := LoadMe(); err != nil {
			return err
		} else {
			e.Me = me
		}
	}
	return nil
}

func (e *TrackEngine) Run() error {

	var err error

	if err = e.LoadThem(); err != nil {
		return err
	} else if err = e.LoadMe(); err != nil {
		return err
	} else if e.NoSelf && e.Me.Equal(*e.Them) {
		return fmt.Errorf("Cannot track yourself")
	}

	err = e.Them.Identify()
	if err != nil {
		if e.StrictProofs {
			return err
		} else {
			G.Log.Warning("Some proofs failed")
		}
	}

	var jw *jsonw.Wrapper
	jw, err = e.Me.TrackingProofFor(e.Them)
	if err != nil {
		return err
	}
	fmt.Printf("%v\n", jw.MarshalPretty())
	fmt.Printf("%v\n", e.Them.IdTable.MakeTrackSet())

	return nil
}

//=====================================================================

<|endoftext|>


<commit_before>package decorator

import (
	"github.com/bmatsuo/lark/internal/module"
	"github.com/yuin/gopher-lua"
)

// Module is a module.Module that loads the "decorator" module.
var Module = module.New("decorator", Loader)

// Loader is a lua.LGFunction that loads the module.
func Loader(l *lua.LState) int {
	mod := l.NewTable()

	mt := metatable(l)
	create := l.NewClosure(luaCreate(mt), mt)
	/*
		doc.Go(l, create, &doc.GoDocs{
			Desc: `
				Create a new decorator.  A callable object is returned that
				decorates its argument.  The returned object can instead be
				concatenated with an object to decorate it.
				`,
			Sig: "fn => obj",
			Params: []string{
				`fn
				function -- The decorator function with signature a => b.
				Typically fn(x) == x but that is not an requirement.
				`,
			},
		})
	*/
	l.SetField(mod, "create", create)

	annotator := l.NewClosure(luaAnnotator(create), create)
	/*
		doc.Go(l, annotator, &doc.GoDocs{
			Desc: `
				Create a new annotating decorator.  The retured
				`,
			Sig: "(t, prepend) => obj",
			Params: []string{
				`t
				table -- A map to store annotations.  Typically the map will use
				weak references on either keys or values (potentially both).
				`,
				`prepend
				boolean -- Annotation values are prepended to a table when stored.
				When prepend is true table should not have weak value references.
				`,
			},
		})
	*/
	l.SetField(mod, "annotator", annotator)

	l.Push(mod)
	return 1
}

func metatable(l *lua.LState) *lua.LTable {
	mt := l.NewTable()
	l.SetField(mt, "__concat", l.NewFunction(luaConcatMeta))
	l.SetField(mt, "__call", l.NewFunction(luaCallMeta))
	return mt
}

func luaCreate(mt *lua.LTable) lua.LGFunction {
	return func(l *lua.LState) int {
		fn := l.CheckFunction(1)
		dec := l.NewTable()
		l.SetField(dec, "fn", fn)
		l.Push(l.GetGlobal("setmetatable"))
		l.Push(dec)
		l.Push(mt)
		l.Call(2, 1)
		return 1
	}
}

func luaAnnotator(create *lua.LFunction) lua.LGFunction {
	return func(l *lua.LState) int {
		t := l.CheckTable(1)
		prepend := l.OptBool(2, false)

		var fn *lua.LFunction
		if prepend {
			fn = l.NewClosure(prepender(create, t), create)
		} else {
			fn = l.NewClosure(setter(create, t), create)
		}

		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func luaConcatMeta(l *lua.LState) int {
	dec := l.Get(1)
	if l.GetTop() < 2 {
		l.RaiseError("nothing to concatenate")
	}
	l.SetTop(2)
	fn := l.GetField(dec, "fn")
	l.Replace(1, fn)
	l.Call(1, 1)
	return 1
}

func luaCallMeta(l *lua.LState) int {
	dec := l.Get(1)
	if l.GetTop() < 1 {
		l.RaiseError("nothing to call")
	}
	l.Replace(1, l.GetField(dec, "fn"))
	narg := l.GetTop() - 1
	l.Call(narg, 1)
	return 1
}

func setter(create *lua.LFunction, table lua.LValue) lua.LGFunction {
	return func(l *lua.LState) int {
		s := l.CheckString(1)
		l.SetTop(0)
		fn := l.NewClosure(setFunc(table, s), table) // close variable ``s''?
		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func prepender(create *lua.LFunction, table lua.LValue) lua.LGFunction {
	return func(l *lua.LState) int {
		s := l.CheckString(1)
		l.SetTop(0)
		fn := l.NewClosure(prependFunc(table, s), table)
		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func setFunc(table lua.LValue, s string) lua.LGFunction {
	return func(l *lua.LState) int {
		val := l.Get(1)
		l.SetTable(table, val, lua.LString(s))
		return 1
	}
}

func prependFunc(table lua.LValue, s string) lua.LGFunction {
	return func(l *lua.LState) int {
		val := l.Get(1)
		t := l.GetTable(table, val)
		if t == lua.LNil {
			t = l.NewTable()
		}
		l.Push(l.GetField(l.GetGlobal("table"), "insert"))
		l.Push(t)
		l.Push(lua.LNumber(1))
		l.Push(lua.LString(s))
		l.Call(3, 0)
		l.SetTable(table, val, t)
		return 1
	}
}
<commit_msg>decorator.lua: export metadata creation function<commit_after>package decorator

import (
	"github.com/bmatsuo/lark/internal/module"
	"github.com/yuin/gopher-lua"
)

// Module is a module.Module that loads the "decorator" module.
var Module = module.New("decorator", Loader)

// Loader is a lua.LGFunction that loads the module.
func Loader(l *lua.LState) int {
	mod := l.NewTable()

	alias := l.NewClosure(luaCallAlias)
	metatable := l.NewClosure(luaMetatable(alias), alias)

	l.Push(metatable)
	l.Push(l.NewClosure(luaCall))
	l.Call(1, 1)
	mt := l.Get(-1).(*lua.LTable)
	l.Pop(0)

	create := l.NewClosure(luaCreate(mt), mt)
	l.SetField(mod, "metatable", metatable)
	l.SetField(mod, "create", create)
	l.SetField(mod, "annotator", l.NewClosure(luaAnnotator(create), create))

	l.Push(mod)
	return 1
}

func luaMetatable(alias *lua.LFunction) lua.LGFunction {
	return func(l *lua.LState) int {
		fn := l.CheckFunction(1)
		l.SetTop(0)

		mt := l.NewTable()
		l.SetField(mt, "__concat", alias)
		l.SetField(mt, "__call", fn)
		l.Push(mt)
		return 1
	}
}

func luaCallAlias(l *lua.LState) int {
	l.CheckAny(1)
	l.CheckAny(2)
	l.SetTop(2)
	l.Call(1, lua.MultRet)
	return l.GetTop()
}

func luaCall(l *lua.LState) int {
	l.Replace(1, l.GetField(l.Get(1), "fn"))
	narg := l.GetTop() - 1
	l.Call(narg, lua.MultRet)
	return l.GetTop()
}

func metatable(l *lua.LState) *lua.LTable {
	mt := l.NewTable()
	l.SetField(mt, "__concat", l.NewFunction(luaConcatMeta))
	l.SetField(mt, "__call", l.NewFunction(luaCallMeta))
	return mt
}

func luaCreate(mt *lua.LTable) lua.LGFunction {
	return func(l *lua.LState) int {
		fn := l.CheckFunction(1)
		dec := l.NewTable()
		l.SetField(dec, "fn", fn)
		l.Push(l.GetGlobal("setmetatable"))
		l.Push(dec)
		l.Push(mt)
		l.Call(2, 1)
		return 1
	}
}

func luaAnnotator(create *lua.LFunction) lua.LGFunction {
	return func(l *lua.LState) int {
		t := l.CheckTable(1)
		prepend := l.OptBool(2, false)

		var fn *lua.LFunction
		if prepend {
			fn = l.NewClosure(prepender(create, t), create)
		} else {
			fn = l.NewClosure(setter(create, t), create)
		}

		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func luaConcatMeta(l *lua.LState) int {
	dec := l.Get(1)
	if l.GetTop() < 2 {
		l.RaiseError("nothing to concatenate")
	}
	l.SetTop(2)
	fn := l.GetField(dec, "fn")
	l.Replace(1, fn)
	l.Call(1, 1)
	return 1
}

func luaCallMeta(l *lua.LState) int {
	dec := l.Get(1)
	if l.GetTop() < 1 {
		l.RaiseError("nothing to call")
	}
	l.Replace(1, l.GetField(dec, "fn"))
	narg := l.GetTop() - 1
	l.Call(narg, 1)
	return 1
}

func setter(create *lua.LFunction, table lua.LValue) lua.LGFunction {
	return func(l *lua.LState) int {
		s := l.CheckString(1)
		l.SetTop(0)
		fn := l.NewClosure(setFunc(table, s), table) // close variable ``s''?
		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func prepender(create *lua.LFunction, table lua.LValue) lua.LGFunction {
	return func(l *lua.LState) int {
		s := l.CheckString(1)
		l.SetTop(0)
		fn := l.NewClosure(prependFunc(table, s), table)
		l.Push(create)
		l.Push(fn)
		l.Call(1, 1)
		return 1
	}
}

func setFunc(table lua.LValue, s string) lua.LGFunction {
	return func(l *lua.LState) int {
		val := l.Get(1)
		l.SetTable(table, val, lua.LString(s))
		return 1
	}
}

func prependFunc(table lua.LValue, s string) lua.LGFunction {
	return func(l *lua.LState) int {
		val := l.Get(1)
		t := l.GetTable(table, val)
		if t == lua.LNil {
			t = l.NewTable()
		}
		l.Push(l.GetField(l.GetGlobal("table"), "insert"))
		l.Push(t)
		l.Push(lua.LNumber(1))
		l.Push(lua.LString(s))
		l.Call(3, 0)
		l.SetTable(table, val, t)
		return 1
	}
}
<|endoftext|>


<commit_before>// +build linux

package tcp_test

import (
	"context"
	"strings"
	"testing"

	"v2ray.com/core/testing/servers/tcp"
	"v2ray.com/core/transport/internet"
	. "v2ray.com/core/transport/internet/tcp"
	. "v2ray.com/ext/assert"
)

func TestGetOriginalDestination(t *testing.T) {
	assert := With(t)

	tcpServer := tcp.Server{}
	dest, err := tcpServer.Start()
	assert(err, IsNil)
	defer tcpServer.Close()

	conn, err := Dial(context.Background(), dest, internet.ToMemoryStreamConfig(nil))
	assert(err, IsNil)
	defer conn.Close()

	originalDest, err := GetOriginalDestination(conn)
	assert(dest == originalDest || strings.Contains(err.Error(), "failed to call getsockopt"), IsTrue)
}
<commit_msg>fix test last time<commit_after>// +build linux

package tcp_test

import (
	"context"
	"strings"
	"testing"

	"v2ray.com/core/common"
	"v2ray.com/core/testing/servers/tcp"
	"v2ray.com/core/transport/internet"
	. "v2ray.com/core/transport/internet/tcp"
	. "v2ray.com/ext/assert"
)

func TestGetOriginalDestination(t *testing.T) {
	assert := With(t)

	tcpServer := tcp.Server{}
	dest, err := tcpServer.Start()
	assert(err, IsNil)
	defer tcpServer.Close()

	config, err := internet.ToMemoryStreamConfig(nil)
	common.Must(err)
	conn, err := Dial(context.Background(), dest, config)
	assert(err, IsNil)
	defer conn.Close()

	originalDest, err := GetOriginalDestination(conn)
	assert(dest == originalDest || strings.Contains(err.Error(), "failed to call getsockopt"), IsTrue)
}
<|endoftext|>


<commit_before>package gokalman

import (
	"fmt"

	"github.com/gonum/matrix/mat64"
)

// BatchGroundTruth computes the error of a given estimate from a known batch of states and measurements.
type BatchGroundTruth struct {
	states       []*mat64.Vector
	measurements []*mat64.Vector
}

// Error returns an ErrorEstimate after comparing the provided state and measurements with the ground truths.
func (t *BatchGroundTruth) Error(k int, est Estimate) Estimate {
	return t.ErrorWithOffset(k, est, nil)
}

// ErrorWithOffset returns an ErrorEstimate after comparing the provided state, adding the offset and measurements with the ground truths.
func (t *BatchGroundTruth) ErrorWithOffset(k int, est Estimate, offset *mat64.Vector) Estimate {
	esR, _ := est.State().Dims()
	estState := mat64.NewVector(esR, nil)
	estState.CopyVec(est.State())
	if offset != nil {
		estState.AddVec(estState, offset)
	}
	trueState := mat64.NewVector(esR, nil)
	if t.states != nil {
		trueState = t.states[k]
		tsR, _ := trueState.Dims()
		if esR != tsR {
			panic(fmt.Errorf("ground truth state size different from estimated state size (k=%d)", k))
		}
		// Inline modification of the estimated state.
		for i := 0; i < tsR; i++ {
			estState.SetVec(i, estState.At(i, 0)-trueState.At(i, 0))
		}
	}

	emR, _ := est.Measurement().Dims()
	estMeas := mat64.NewVector(emR, nil)
	estMeas.CopyVec(est.Measurement())
	trueMeas := mat64.NewVector(esR, nil)
	if t.states != nil {
		trueMeas = t.measurements[k]
		tmR, _ := trueMeas.Dims()
		if emR != tmR {
			panic(fmt.Errorf("ground truth measurement size different from estimated measurement size (k=%d)", k))
		}
		// Inline modification of the estimated measurement.
		for i := 0; i < tmR; i++ {
			estMeas.SetVec(i, estMeas.At(i, 0)-trueMeas.At(i, 0))
		}
	}
	return ErrorEstimate{VanillaEstimate{state: estState, meas: estMeas, covar: est.Covariance()}}
}

// NewBatchGroundTruth initializes a new batch ground truth.
func NewBatchGroundTruth(states, measurements []*mat64.Vector) *BatchGroundTruth {
	return &BatchGroundTruth{states, measurements}
}

// ErrorEstimate implements the Estimate interface and is used to show the error of an estimate.
type ErrorEstimate struct {
	VanillaEstimate // This is effectively the same as a VanillaEstimate, so no change.
}
<commit_msg>Plotting of additional values done by specifying a negative k<commit_after>package gokalman

import (
	"fmt"

	"github.com/gonum/matrix/mat64"
)

// BatchGroundTruth computes the error of a given estimate from a known batch of states and measurements.
type BatchGroundTruth struct {
	states       []*mat64.Vector
	measurements []*mat64.Vector
}

// Error returns an ErrorEstimate after comparing the provided state and measurements with the ground truths.
func (t *BatchGroundTruth) Error(k int, est Estimate) Estimate {
	return t.ErrorWithOffset(k, est, nil)
}

// ErrorWithOffset returns an ErrorEstimate after comparing the provided state, adding the offset and measurements with the ground truths.
func (t *BatchGroundTruth) ErrorWithOffset(k int, est Estimate, offset *mat64.Vector) Estimate {
	esR, _ := est.State().Dims()
	estState := mat64.NewVector(esR, nil)
	if k > 0 {
		estState.CopyVec(est.State())
		if offset != nil {
			estState.AddVec(estState, offset)
		}
		trueState := mat64.NewVector(esR, nil)
		if t.states != nil {
			trueState = t.states[k]
			tsR, _ := trueState.Dims()
			if esR != tsR {
				panic(fmt.Errorf("ground truth state size different from estimated state size (k=%d: %d != %d)", k, esR, tsR))
			}
			estState.SubVec(estState, trueState)
		}
	}

	emR, _ := est.Measurement().Dims()
	estMeas := mat64.NewVector(emR, nil)
	if k > 0 {
		estMeas.CopyVec(est.Measurement())
		trueMeas := mat64.NewVector(esR, nil)
		if t.states != nil {
			trueMeas = t.measurements[k]
			tmR, _ := trueMeas.Dims()
			if emR != tmR {
				panic(fmt.Errorf("ground truth measurement size different from estimated measurement size (k=%d)", k))
			}
			estMeas.SubVec(estMeas, trueMeas)
		}
	}
	return ErrorEstimate{VanillaEstimate{state: estState, meas: estMeas, covar: est.Covariance()}}
}

// NewBatchGroundTruth initializes a new batch ground truth.
func NewBatchGroundTruth(states, measurements []*mat64.Vector) *BatchGroundTruth {
	return &BatchGroundTruth{states, measurements}
}

// ErrorEstimate implements the Estimate interface and is used to show the error of an estimate.
type ErrorEstimate struct {
	VanillaEstimate // This is effectively the same as a VanillaEstimate, so no change.
}
<|endoftext|>