<commit_before>package command

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"unicode"

	"github.com/pkg/errors"
)

type constError string

func (e constError) Error() string {
	return string(e)
}

const (
	Default = ""

	ErrNotFound = constError("command not found")
)

type stringArgsCommand struct {
	command         string
	description     string
	args            Args
	commandFunc     interface{}
	stringArgsFunc  StringArgsFunc
	resultsHandlers []ResultsHandler
}

func checkCommandChars(command string) error {
	if strings.IndexFunc(command, unicode.IsSpace) != -1 {
		return errors.Errorf("Command contains space characters: '%s'", command)
	}
	if strings.IndexFunc(command, unicode.IsGraphic) == -1 {
		return errors.Errorf("Command contains non graphc characters: '%s'", command)
	}
	return nil
}

type StringArgsCommandLogger interface {
	LogStringArgsCommand(command string, args []string)
}

type StringArgsCommandLoggerFunc func(command string, args []string)

func (f StringArgsCommandLoggerFunc) LogStringArgsCommand(command string, args []string) {
	f(command, args)
}

type StringArgsDispatcher struct {
	comm    map[string]*stringArgsCommand
	loggers []StringArgsCommandLogger
}

func NewStringArgsDispatcher(loggers ...StringArgsCommandLogger) *StringArgsDispatcher {
	return &StringArgsDispatcher{
		comm:    make(map[string]*stringArgsCommand),
		loggers: loggers,
	}
}

func (disp StringArgsDispatcher) AddCommand(command, description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) error {
	if err := checkCommandChars(command); err != nil {
		return err
	}
	stringArgsFunc, err := GetStringArgsFunc(commandFunc, args, resultsHandlers...)
	if err != nil {
		return err
	}
	disp.comm[command] = &stringArgsCommand{
		command:         command,
		description:     description,
		args:            args,
		commandFunc:     commandFunc,
		stringArgsFunc:  stringArgsFunc,
		resultsHandlers: resultsHandlers,
	}
	return nil
}

func (disp StringArgsDispatcher) MustAddCommand(command, description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) {
	err := disp.AddCommand(command, description, commandFunc, args, resultsHandlers...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) AddDefaultCommand(description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) error {
	stringArgsFunc, err := GetStringArgsFunc(commandFunc, args, resultsHandlers...)
	if err != nil {
		return err
	}
	disp.comm[Default] = &stringArgsCommand{
		command:         Default,
		description:     description,
		args:            args,
		commandFunc:     commandFunc,
		stringArgsFunc:  stringArgsFunc,
		resultsHandlers: resultsHandlers,
	}
	return nil
}

func (disp StringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) {
	err := disp.AddDefaultCommand(description, commandFunc, args, resultsHandlers...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) HasCommnd(command string) bool {
	_, found := disp.comm[command]
	return found
}

func (disp StringArgsDispatcher) HasDefaultCommnd() bool {
	_, found := disp.comm[Default]
	return found
}

func (disp StringArgsDispatcher) Dispatch(command string, args ...string) error {
	cmd, found := disp.comm[command]
	if !found {
		return ErrNotFound
	}
	for _, logger := range disp.loggers {
		logger.LogStringArgsCommand(command, args)
	}
	return cmd.stringArgsFunc(args...)
}

func (disp StringArgsDispatcher) MustDispatch(command string, args ...string) {
	err := disp.Dispatch(command, args...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) DispatchDefaultCommand() error {
	return disp.Dispatch(Default)
}

func (disp StringArgsDispatcher) MustDispatchDefaultCommand() {
	err := disp.DispatchDefaultCommand()
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) DispatchCombined(commandAndArgs []string) (command string, err error) {
	if len(commandAndArgs) == 0 {
		return Default, disp.DispatchDefaultCommand()
	}
	command = commandAndArgs[0]
	args := commandAndArgs[1:]
	return command, disp.Dispatch(command, args...)
}

func (disp StringArgsDispatcher) MustDispatchCombined(commandAndArgs []string) (command string) {
	command, err := disp.DispatchCombined(commandAndArgs)
	if err != nil {
		panic(err)
	}
	return command
}

func (disp StringArgsDispatcher) PrintCommands(appName string) {
	list := make([]*stringArgsCommand, 0, len(disp.comm))
	for _, cmd := range disp.comm {
		list = append(list, cmd)
	}
	sort.Slice(list, func(i, j int) bool {
		return list[i].command < list[j].command
	})

	for _, cmd := range list {
		CommandUsageColor.Printf("  %s %s %s\n", appName, cmd.command, cmd.args)
		if len(cmd.description) == 0 {
			CommandDescriptionColor.Println()
		} else {
			CommandDescriptionColor.Printf("      %s\n", cmd.description)
		}
	}
}

func (disp StringArgsDispatcher) PrintCommandsUsageIntro(appName string, output io.Writer) {
	if len(disp.comm) > 0 {
		fmt.Fprint(output, "Commands:\n")
		disp.PrintCommands(appName)
		fmt.Fprint(output, "Flags:\n")
	}
}
<commit_msg>more verbose StringArgsDispatcher.PrintCommands()<commit_after>package command

import (
	"fmt"
	"io"
	"sort"
	"strings"
	"unicode"

	"github.com/pkg/errors"
)

type constError string

func (e constError) Error() string {
	return string(e)
}

const (
	Default = ""

	ErrNotFound = constError("command not found")
)

type stringArgsCommand struct {
	command         string
	description     string
	args            Args
	commandFunc     interface{}
	stringArgsFunc  StringArgsFunc
	resultsHandlers []ResultsHandler
}

func checkCommandChars(command string) error {
	if strings.IndexFunc(command, unicode.IsSpace) != -1 {
		return errors.Errorf("Command contains space characters: '%s'", command)
	}
	if strings.IndexFunc(command, unicode.IsGraphic) == -1 {
		return errors.Errorf("Command contains non graphc characters: '%s'", command)
	}
	return nil
}

type StringArgsCommandLogger interface {
	LogStringArgsCommand(command string, args []string)
}

type StringArgsCommandLoggerFunc func(command string, args []string)

func (f StringArgsCommandLoggerFunc) LogStringArgsCommand(command string, args []string) {
	f(command, args)
}

type StringArgsDispatcher struct {
	comm    map[string]*stringArgsCommand
	loggers []StringArgsCommandLogger
}

func NewStringArgsDispatcher(loggers ...StringArgsCommandLogger) *StringArgsDispatcher {
	return &StringArgsDispatcher{
		comm:    make(map[string]*stringArgsCommand),
		loggers: loggers,
	}
}

func (disp StringArgsDispatcher) AddCommand(command, description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) error {
	if err := checkCommandChars(command); err != nil {
		return err
	}
	stringArgsFunc, err := GetStringArgsFunc(commandFunc, args, resultsHandlers...)
	if err != nil {
		return err
	}
	disp.comm[command] = &stringArgsCommand{
		command:         command,
		description:     description,
		args:            args,
		commandFunc:     commandFunc,
		stringArgsFunc:  stringArgsFunc,
		resultsHandlers: resultsHandlers,
	}
	return nil
}

func (disp StringArgsDispatcher) MustAddCommand(command, description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) {
	err := disp.AddCommand(command, description, commandFunc, args, resultsHandlers...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) AddDefaultCommand(description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) error {
	stringArgsFunc, err := GetStringArgsFunc(commandFunc, args, resultsHandlers...)
	if err != nil {
		return err
	}
	disp.comm[Default] = &stringArgsCommand{
		command:         Default,
		description:     description,
		args:            args,
		commandFunc:     commandFunc,
		stringArgsFunc:  stringArgsFunc,
		resultsHandlers: resultsHandlers,
	}
	return nil
}

func (disp StringArgsDispatcher) MustAddDefaultCommand(description string, commandFunc interface{}, args Args, resultsHandlers ...ResultsHandler) {
	err := disp.AddDefaultCommand(description, commandFunc, args, resultsHandlers...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) HasCommnd(command string) bool {
	_, found := disp.comm[command]
	return found
}

func (disp StringArgsDispatcher) HasDefaultCommnd() bool {
	_, found := disp.comm[Default]
	return found
}

func (disp StringArgsDispatcher) Dispatch(command string, args ...string) error {
	cmd, found := disp.comm[command]
	if !found {
		return ErrNotFound
	}
	for _, logger := range disp.loggers {
		logger.LogStringArgsCommand(command, args)
	}
	return cmd.stringArgsFunc(args...)
}

func (disp StringArgsDispatcher) MustDispatch(command string, args ...string) {
	err := disp.Dispatch(command, args...)
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) DispatchDefaultCommand() error {
	return disp.Dispatch(Default)
}

func (disp StringArgsDispatcher) MustDispatchDefaultCommand() {
	err := disp.DispatchDefaultCommand()
	if err != nil {
		panic(err)
	}
}

func (disp StringArgsDispatcher) DispatchCombined(commandAndArgs []string) (command string, err error) {
	if len(commandAndArgs) == 0 {
		return Default, disp.DispatchDefaultCommand()
	}
	command = commandAndArgs[0]
	args := commandAndArgs[1:]
	return command, disp.Dispatch(command, args...)
}

func (disp StringArgsDispatcher) MustDispatchCombined(commandAndArgs []string) (command string) {
	command, err := disp.DispatchCombined(commandAndArgs)
	if err != nil {
		panic(err)
	}
	return command
}

func (disp StringArgsDispatcher) PrintCommands(appName string) {
	list := make([]*stringArgsCommand, 0, len(disp.comm))
	for _, cmd := range disp.comm {
		list = append(list, cmd)
	}
	sort.Slice(list, func(i, j int) bool {
		return list[i].command < list[j].command
	})

	for _, cmd := range list {
		CommandUsageColor.Printf("  %s %s %s\n", appName, cmd.command, cmd.args)
		if cmd.description != "" {
			CommandDescriptionColor.Printf("      %s\n", cmd.description)
		}
		hasAnyArgDesc := false
		for i := 0; i < cmd.args.NumArgs(); i++ {
			if cmd.args.ArgDescription(i) != "" {
				hasAnyArgDesc = true
			}
		}
		if hasAnyArgDesc {
			for i := 0; i < cmd.args.NumArgs(); i++ {
				CommandDescriptionColor.Printf("          <%s:%s> %s\n", cmd.args.ArgName(i), cmd.args.ArgType(i), cmd.args.ArgDescription(i))
			}
		}
		CommandDescriptionColor.Println()
	}
}

func (disp StringArgsDispatcher) PrintCommandsUsageIntro(appName string, output io.Writer) {
	if len(disp.comm) > 0 {
		fmt.Fprint(output, "Commands:\n")
		disp.PrintCommands(appName)
		fmt.Fprint(output, "Flags:\n")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strings"
)

type apiService struct {
	AliasDomain string            `json:"alias-domain,omitempty"`
	OpsType     string            `json:"type,omitempty"`
	DomainIps   []string          `json:"ips,omitempty"`
	DomainAlias string            `json:"alias,omitempty"`
	UpdateMap   map[string]string `json:"update,omitempty"`
}

var cmdToken string = ""
var cmdAddr string = ""
var cmdMethod string = ""
var cmdDomain string = ""
var cmdIps string = ""
var cmdAlias string = ""
var cmdUpdates string = ""
var cmdShow string = ""
var cmdList bool = false

func env(key, def string) string {
	if x := os.Getenv(key); x != "" {
		return x
	}
	return def
}
func init() {
	flag.StringVar(&cmdDomain, "domain", "", "domain to operation")
	flag.StringVar(&cmdMethod, "method", "", " create, update, or delete")
	flag.StringVar(&cmdShow, "show", "", "show the domain ")
	flag.BoolVar(&cmdList, "list", false, "show the domain ")
	flag.StringVar(&cmdAddr, "addr", env("SKYDNS_API_ADDR", ""), "the api addr to access such as 127.0.0.1:9001 or form env(SKYDNS_API_ADDR)")
	flag.StringVar(&cmdToken, "token", env("SKYDNS_API_TOKEN", ""), "the token to auth, or from env(SKYDNS_API_TOKEN)")
	flag.StringVar(&cmdIps, "ips", "", "the ips of domain for create ,such as  10.0.0.0;10.0.0.1")
	flag.StringVar(&cmdAlias, "alias", "", "the alias of domain for create ")
	flag.StringVar(&cmdUpdates, "updates", "", "the data to update,such as ips:10.0.0.0->192.168.0.1;10.0.0.1->192.168.0.2  or alias: baidu->baidu1 ")
}

func doreq(a apiService) (error, string) {
	b, err := json.Marshal(a)
	if err != nil {
		return err, ""
	}

	body := bytes.NewBuffer([]byte(b))

	client := &http.Client{}
	cmdUrl := cmdAddr + cmdDomain + "?token=" + cmdToken
	req, err := http.NewRequest(cmdMethod, cmdUrl, body)
	if err != nil {
		return err, ""
	}
	req.Header.Set("Content-Type", "application/json;charset=UTF-8")

	res, err := client.Do(req)
	defer res.Body.Close()
	if err != nil {
		return err, ""
	}
	result, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return err, ""
	}
	ret := fmt.Sprintf("%s", result)
	return err, ret

}
func cmdApiCreate() {
	if cmdDomain == "" {
		fmt.Print("domain must be input\n")
		return
	}
	if cmdIps == "" && cmdAlias == "" {
		fmt.Print("either ips or alias must be offered\n")
		return
	}
	if cmdIps != "" && cmdAlias != "" {
		fmt.Print("either ips or alias must be offered\n")
		return
	}
	var a apiService
	if cmdIps != "" {
		a.OpsType = "A"
		a.DomainIps = strings.Split(cmdIps, ";")
	}
	if cmdAlias != "" {
		a.OpsType = "CNAME"
		a.DomainAlias = cmdAlias
	}
	err, ret := doreq(a)
	if err != nil {
		fmt.Printf("err :%s\n", err.Error())
	} else {
		fmt.Print(ret)
	}
}
func doShowResult(ret string) {
	svc := make(map[string]apiService)
	if err := json.Unmarshal([]byte(ret), &svc); err == nil {
		for k, v := range svc {
			fmt.Printf("domain:  %56s       val: { ", k)
			if v.OpsType == "A" {
				fmt.Printf("type:A  ips:%s }\n", v.DomainIps)
			} else {
				fmt.Printf("type:Cname  alias:%s }\n", v.AliasDomain)
			}
		}
	} else {
		fmt.Printf("domain :%s not found\n", cmdShow)
	}

}
func cmdApiList() {
	var a apiService
	err, ret := doreq(a)
	if err != nil {
		fmt.Printf("err :%s\n", err.Error())
	} else {
		doShowResult(ret)
	}
}
func cmdApiShow() {
	var a apiService
	cmdDomain = cmdShow
	err, ret := doreq(a)
	if err != nil {
		fmt.Printf("domain :%s not found \n", cmdDomain)
	} else {
		doShowResult(ret)
	}
}
func cmdApiDelete() {
	var a apiService
	if cmdDomain == "" {
		fmt.Print("domain must be input\n")
		return
	}
	err, ret := doreq(a)
	if err != nil {
		fmt.Printf("err :%s\n", err.Error())
	} else {
		fmt.Print(ret)
	}
}
func cmdApiUpdate() {

	if cmdDomain == "" {
		fmt.Print("domain must be input\n")
		return
	}
	if cmdUpdates == "" {
		fmt.Print("updates must be offered\n")
		return
	}
	var a apiService
	if strings.HasPrefix(cmdUpdates, "ips:") {
		a.OpsType = "A"
		ips := strings.Split(cmdUpdates[4:], ";")
		a.UpdateMap = make(map[string]string, len(ips))
		for _, ip := range ips {
			data := strings.Split(ip, "->")
			if len(data) != 2 {
				fmt.Print("updates data err,input like ips:10.0.0.0->192.168.0.1;10.0.0.1->192.168.0.2 \n")
				return
			}
			a.UpdateMap[data[0]] = data[1]
		}
		err, ret := doreq(a)
		if err != nil {
			fmt.Printf("err :%s\n", err.Error())
		} else {
			fmt.Print(ret)
		}
	} else if strings.HasPrefix(cmdUpdates, "alias:") {
		a.OpsType = "CNAME"
		a.UpdateMap = make(map[string]string, 1)
		skipN := len("alias:")
		data := strings.Split(cmdUpdates[skipN:], "->")
		if len(data) != 2 {
			fmt.Print("updates data err,input like alias: baidu->baidu1 \n")
			return
		}
		a.UpdateMap[data[0]] = data[1]
		err, ret := doreq(a)
		if err != nil {
			fmt.Printf("err :%s\n", err.Error())
		} else {
			fmt.Print(ret)
		}
	} else {
		fmt.Print("updates data err,input like ips:10.0.0.0->192.168.0.1;10.0.0.1->192.168.0.2    or    alias: baidu->baidu1  \n")
		return
	}
}

func main() {
	flag.Parse()
	if cmdToken == "" {
		fmt.Print("token must be input\n")
		return
	}
	if cmdAddr == "" {
		fmt.Print("url must be input \n")
		return
	} else {
		_, err := net.Dial("tcp", cmdAddr)
		if err != nil {
			fmt.Printf(" the addr : %s can not access \n", cmdAddr)
			return
		}
	}
	if !strings.HasSuffix(cmdAddr, "/skydns/api/") {
		cmdAddr = "http://" + cmdAddr + "/skydns/api/"
	}
	if cmdList {
		cmdMethod = "GET"
		cmdApiList()
		return
	}
	if cmdShow != "" {
		cmdMethod = "GET"
		cmdApiShow()
		return
	}
	switch strings.ToLower(cmdMethod) {
	case "create":
		cmdMethod = "POST"
		cmdApiCreate()
	case "delete":
		cmdMethod = "DELETE"
		cmdApiDelete()
	case "update":
		cmdMethod = "PUT"
		cmdApiUpdate()
	default:
		fmt.Print("method must be  create delete or update \n")
	}

}
<commit_msg>Delete main.go<commit_after><|endoftext|>


<commit_before>// Copyright 2010 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 token

import (
	"fmt"
	"testing"
)

func checkPos(t *testing.T, msg string, p, q Position) {
	if p.Filename != q.Filename {
		t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
	}
	if p.Offset != q.Offset {
		t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
	}
	if p.Line != q.Line {
		t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
	}
	if p.Column != q.Column {
		t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
	}
}

func TestNoPos(t *testing.T) {
	if NoPos.IsValid() {
		t.Errorf("NoPos should not be valid")
	}
	var fset *FileSet
	checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
	fset = NewFileSet()
	checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
}

var tests = []struct {
	filename string
	source   []byte // may be nil
	size     int
	lines    []int
}{
	{"a", []byte{}, 0, []int{}},
	{"b", []byte("01234"), 5, []int{0}},
	{"c", []byte("\n\n\n\n\n\n\n\n\n"), 9, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}},
	{"d", nil, 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
	{"e", nil, 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
	{"f", []byte("package p\n\nimport \"fmt\""), 23, []int{0, 10, 11}},
	{"g", []byte("package p\n\nimport \"fmt\"\n"), 24, []int{0, 10, 11}},
	{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
}

func linecol(lines []int, offs int) (int, int) {
	prevLineOffs := 0
	for line, lineOffs := range lines {
		if offs < lineOffs {
			return line, offs - prevLineOffs + 1
		}
		prevLineOffs = lineOffs
	}
	return len(lines), offs - prevLineOffs + 1
}

func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
	for offs := 0; offs < f.Size(); offs++ {
		p := f.Pos(offs)
		offs2 := f.Offset(p)
		if offs2 != offs {
			t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
		}
		line, col := linecol(lines, offs)
		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
		checkPos(t, msg, f.Position(f.Pos(offs)), Position{f.Name(), offs, line, col})
		checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
	}
}

func makeTestSource(size int, lines []int) []byte {
	src := make([]byte, size)
	for _, offs := range lines {
		if offs > 0 {
			src[offs-1] = '\n'
		}
	}
	return src
}

func TestPositions(t *testing.T) {
	const delta = 7 // a non-zero base offset increment
	fset := NewFileSet()
	for _, test := range tests {
		// verify consistency of test case
		if test.source != nil && len(test.source) != test.size {
			t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source))
		}

		// add file and verify name and size
		f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
		if f.Name() != test.filename {
			t.Errorf("expected filename %q; got %q", test.filename, f.Name())
		}
		if f.Size() != test.size {
			t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
		}
		if fset.File(f.Pos(0)) != f {
			t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
		}

		// add lines individually and verify all positions
		for i, offset := range test.lines {
			f.AddLine(offset)
			if f.LineCount() != i+1 {
				t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
			}
			// adding the same offset again should be ignored
			f.AddLine(offset)
			if f.LineCount() != i+1 {
				t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
			}
			verifyPositions(t, fset, f, test.lines[0:i+1])
		}

		// add lines with SetLines and verify all positions
		if ok := f.SetLines(test.lines); !ok {
			t.Errorf("%s: SetLines failed", f.Name())
		}
		if f.LineCount() != len(test.lines) {
			t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
		}
		verifyPositions(t, fset, f, test.lines)

		// add lines with SetLinesForContent and verify all positions
		src := test.source
		if src == nil {
			// no test source available - create one from scratch
			src = makeTestSource(test.size, test.lines)
		}
		f.SetLinesForContent(src)
		if f.LineCount() != len(test.lines) {
			t.Errorf("%s, SetLinesForContent: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
		}
		verifyPositions(t, fset, f, test.lines)
	}
}

func TestLineInfo(t *testing.T) {
	fset := NewFileSet()
	f := fset.AddFile("foo", fset.Base(), 500)
	lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
	// add lines individually and provide alternative line information
	for _, offs := range lines {
		f.AddLine(offs)
		f.AddLineInfo(offs, "bar", 42)
	}
	// verify positions for all offsets
	for offs := 0; offs <= f.Size(); offs++ {
		p := f.Pos(offs)
		_, col := linecol(lines, offs)
		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
		checkPos(t, msg, f.Position(f.Pos(offs)), Position{"bar", offs, 42, col})
		checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
	}
}

func TestFiles(t *testing.T) {
	fset := NewFileSet()
	for i, test := range tests {
		fset.AddFile(test.filename, fset.Base(), test.size)
		j := 0
		fset.Iterate(func(f *File) bool {
			if f.Name() != tests[j].filename {
				t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name())
			}
			j++
			return true
		})
		if j != i+1 {
			t.Errorf("expected %d files; got %d", i+1, j)
		}
	}
}
<commit_msg>go/token: add test for concurrent use of FileSet.Pos<commit_after>// Copyright 2010 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 token

import (
	"fmt"
	"math/rand"
	"sync"
	"testing"
)

func checkPos(t *testing.T, msg string, p, q Position) {
	if p.Filename != q.Filename {
		t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
	}
	if p.Offset != q.Offset {
		t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
	}
	if p.Line != q.Line {
		t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
	}
	if p.Column != q.Column {
		t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
	}
}

func TestNoPos(t *testing.T) {
	if NoPos.IsValid() {
		t.Errorf("NoPos should not be valid")
	}
	var fset *FileSet
	checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
	fset = NewFileSet()
	checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
}

var tests = []struct {
	filename string
	source   []byte // may be nil
	size     int
	lines    []int
}{
	{"a", []byte{}, 0, []int{}},
	{"b", []byte("01234"), 5, []int{0}},
	{"c", []byte("\n\n\n\n\n\n\n\n\n"), 9, []int{0, 1, 2, 3, 4, 5, 6, 7, 8}},
	{"d", nil, 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
	{"e", nil, 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
	{"f", []byte("package p\n\nimport \"fmt\""), 23, []int{0, 10, 11}},
	{"g", []byte("package p\n\nimport \"fmt\"\n"), 24, []int{0, 10, 11}},
	{"h", []byte("package p\n\nimport \"fmt\"\n "), 25, []int{0, 10, 11, 24}},
}

func linecol(lines []int, offs int) (int, int) {
	prevLineOffs := 0
	for line, lineOffs := range lines {
		if offs < lineOffs {
			return line, offs - prevLineOffs + 1
		}
		prevLineOffs = lineOffs
	}
	return len(lines), offs - prevLineOffs + 1
}

func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
	for offs := 0; offs < f.Size(); offs++ {
		p := f.Pos(offs)
		offs2 := f.Offset(p)
		if offs2 != offs {
			t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
		}
		line, col := linecol(lines, offs)
		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
		checkPos(t, msg, f.Position(f.Pos(offs)), Position{f.Name(), offs, line, col})
		checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
	}
}

func makeTestSource(size int, lines []int) []byte {
	src := make([]byte, size)
	for _, offs := range lines {
		if offs > 0 {
			src[offs-1] = '\n'
		}
	}
	return src
}

func TestPositions(t *testing.T) {
	const delta = 7 // a non-zero base offset increment
	fset := NewFileSet()
	for _, test := range tests {
		// verify consistency of test case
		if test.source != nil && len(test.source) != test.size {
			t.Errorf("%s: inconsistent test case: expected file size %d; got %d", test.filename, test.size, len(test.source))
		}

		// add file and verify name and size
		f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
		if f.Name() != test.filename {
			t.Errorf("expected filename %q; got %q", test.filename, f.Name())
		}
		if f.Size() != test.size {
			t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
		}
		if fset.File(f.Pos(0)) != f {
			t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
		}

		// add lines individually and verify all positions
		for i, offset := range test.lines {
			f.AddLine(offset)
			if f.LineCount() != i+1 {
				t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
			}
			// adding the same offset again should be ignored
			f.AddLine(offset)
			if f.LineCount() != i+1 {
				t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
			}
			verifyPositions(t, fset, f, test.lines[0:i+1])
		}

		// add lines with SetLines and verify all positions
		if ok := f.SetLines(test.lines); !ok {
			t.Errorf("%s: SetLines failed", f.Name())
		}
		if f.LineCount() != len(test.lines) {
			t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
		}
		verifyPositions(t, fset, f, test.lines)

		// add lines with SetLinesForContent and verify all positions
		src := test.source
		if src == nil {
			// no test source available - create one from scratch
			src = makeTestSource(test.size, test.lines)
		}
		f.SetLinesForContent(src)
		if f.LineCount() != len(test.lines) {
			t.Errorf("%s, SetLinesForContent: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
		}
		verifyPositions(t, fset, f, test.lines)
	}
}

func TestLineInfo(t *testing.T) {
	fset := NewFileSet()
	f := fset.AddFile("foo", fset.Base(), 500)
	lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
	// add lines individually and provide alternative line information
	for _, offs := range lines {
		f.AddLine(offs)
		f.AddLineInfo(offs, "bar", 42)
	}
	// verify positions for all offsets
	for offs := 0; offs <= f.Size(); offs++ {
		p := f.Pos(offs)
		_, col := linecol(lines, offs)
		msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
		checkPos(t, msg, f.Position(f.Pos(offs)), Position{"bar", offs, 42, col})
		checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
	}
}

func TestFiles(t *testing.T) {
	fset := NewFileSet()
	for i, test := range tests {
		fset.AddFile(test.filename, fset.Base(), test.size)
		j := 0
		fset.Iterate(func(f *File) bool {
			if f.Name() != tests[j].filename {
				t.Errorf("expected filename = %s; got %s", tests[j].filename, f.Name())
			}
			j++
			return true
		})
		if j != i+1 {
			t.Errorf("expected %d files; got %d", i+1, j)
		}
	}
}

// issue 4345. Test concurrent use of FileSet.Pos does not trigger a
// race in the FileSet position cache.
func TestFileSetRace(t *testing.T) {
	fset := NewFileSet()
	for i := 0; i < 100; i++ {
		fset.AddFile(fmt.Sprintf("file-%d", i), fset.Base(), 1031)
	}
	max := int32(fset.Base())
	var stop sync.WaitGroup
	r := rand.New(rand.NewSource(7))
	for i := 0; i < 2; i++ {
		r := rand.New(rand.NewSource(r.Int63()))
		stop.Add(1)
		go func() {
			for i := 0; i < 1000; i++ {
				fset.Position(Pos(r.Int31n(max)))
			}
			stop.Done()
		}()
	}
	stop.Wait()
}
<|endoftext|>


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

package snippets

import (
	"context"
	"fmt"
	"log"
	"time"

	"firebase.google.com/go"
	"firebase.google.com/go/messaging"
)

func sendToToken(app *firebase.App) {
	// [START send_to_token_golang]
	// Obtain a messaging.Client from the App.
	ctx := context.Background()
	client, err := app.Messaging(ctx)
	if err != nil {
		log.Fatalf("error getting Messaging client: %v\n", err)
	}

	// This registration token comes from the client FCM SDKs.
	registrationToken := "YOUR_REGISTRATION_TOKEN"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Token: registrationToken,
	}

	// Send a message to the device corresponding to the provided
	// registration token.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_token_golang]
}

func sendToTopic(ctx context.Context, client *messaging.Client) {
	// [START send_to_topic_golang]
	// The topic name can be optionally prefixed with "/topics/".
	topic := "highScores"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Topic: topic,
	}

	// Send a message to the devices subscribed to the provided topic.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_topic_golang]
}

func sendToCondition(ctx context.Context, client *messaging.Client) {
	// [START send_to_condition_golang]
	// Define a condition which will send to devices which are subscribed
	// to either the Google stock or the tech industry topics.
	condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Condition: condition,
	}

	// Send a message to devices subscribed to the combination of topics
	// specified by the provided condition.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_condition_golang]
}

func sendDryRun(ctx context.Context, client *messaging.Client) {
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Token: "token",
	}

	// [START send_dry_run_golang]
	// Send a message in the dry run mode.
	response, err := client.SendDryRun(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Dry run successful:", response)
	// [END send_dry_run_golang]
}

func androidMessage() *messaging.Message {
	// [START android_message_golang]
	oneHour := time.Duration(1) * time.Hour
	message := &messaging.Message{
		Android: &messaging.AndroidConfig{
			TTL:      &oneHour,
			Priority: "normal",
			Notification: &messaging.AndroidNotification{
				Title: "$GOOG up 1.43% on the day",
				Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
				Icon:  "stock_ticker_update",
				Color: "#f45342",
			},
		},
		Topic: "industry-tech",
	}
	// [END android_message_golang]
	return message
}

func apnsMessage() *messaging.Message {
	// [START apns_message_golang]
	badge := 42
	message := &messaging.Message{
		APNS: &messaging.APNSConfig{
			Headers: map[string]string{
				"apns-priority": "10",
			},
			Payload: &messaging.APNSPayload{
				Aps: &messaging.Aps{
					Alert: &messaging.ApsAlert{
						Title: "$GOOG up 1.43% on the day",
						Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
					},
					Badge: &badge,
				},
			},
		},
		Topic: "industry-tech",
	}
	// [END apns_message_golang]
	return message
}

func webpushMessage() *messaging.Message {
	// [START webpush_message_golang]
	message := &messaging.Message{
		Webpush: &messaging.WebpushConfig{
			Notification: &messaging.WebpushNotification{
				Title: "$GOOG up 1.43% on the day",
				Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
				Icon:  "https://my-server/icon.png",
			},
		},
		Topic: "industry-tech",
	}
	// [END webpush_message_golang]
	return message
}

func allPlatformsMessage() *messaging.Message {
	// [START multi_platforms_message_golang]
	oneHour := time.Duration(1) * time.Hour
	badge := 42
	message := &messaging.Message{
		Notification: &messaging.Notification{
			Title: "$GOOG up 1.43% on the day",
			Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
		},
		Android: &messaging.AndroidConfig{
			TTL: &oneHour,
			Notification: &messaging.AndroidNotification{
				Icon:  "stock_ticker_update",
				Color: "#f45342",
			},
		},
		APNS: &messaging.APNSConfig{
			Payload: &messaging.APNSPayload{
				Aps: &messaging.Aps{
					Badge: &badge,
				},
			},
		},
		Topic: "industry-tech",
	}
	// [END multi_platforms_message_golang]
	return message
}

func subscribeToTopic(ctx context.Context, client *messaging.Client) {
	topic := "highScores"

	// [START subscribe_golang]
	// These registration tokens come from the client FCM SDKs.
	registrationTokens := []string{
		"YOUR_REGISTRATION_TOKEN_1",
		// ...
		"YOUR_REGISTRATION_TOKEN_n",
	}

	// Subscribe the devices corresponding to the registration tokens to the
	// topic.
	response, err := client.SubscribeToTopic(ctx, registrationTokens, topic)
	if err != nil {
		log.Fatalln(err)
	}
	// See the TopicManagementResponse reference documentation
	// for the contents of response.
	fmt.Println(response.SuccessCount, "tokens were subscribed successfully")
	// [END subscribe_golang]
}

func unsubscribeFromTopic(ctx context.Context, client *messaging.Client) {
	topic := "highScores"

	// [START unsubscribe_golang]
	// These registration tokens come from the client FCM SDKs.
	registrationTokens := []string{
		"YOUR_REGISTRATION_TOKEN_1",
		// ...
		"YOUR_REGISTRATION_TOKEN_n",
	}

	// Unsubscribe the devices corresponding to the registration tokens from
	// the topic.
	response, err := client.UnsubscribeFromTopic(ctx, registrationTokens, topic)
	if err != nil {
		log.Fatalln(err)
	}
	// See the TopicManagementResponse reference documentation
	// for the contents of response.
	fmt.Println(response.SuccessCount, "tokens were unsubscribed successfully")
	// [END unsubscribe_golang]
}
<commit_msg>add snippets for Send a batch of messages (#264)<commit_after>// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package snippets

import (
	"context"
	"fmt"
	"log"
	"time"

	firebase "firebase.google.com/go"
	"firebase.google.com/go/messaging"
)

func sendToToken(app *firebase.App) {
	// [START send_to_token_golang]
	// Obtain a messaging.Client from the App.
	ctx := context.Background()
	client, err := app.Messaging(ctx)
	if err != nil {
		log.Fatalf("error getting Messaging client: %v\n", err)
	}

	// This registration token comes from the client FCM SDKs.
	registrationToken := "YOUR_REGISTRATION_TOKEN"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Token: registrationToken,
	}

	// Send a message to the device corresponding to the provided
	// registration token.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_token_golang]
}

func sendToTopic(ctx context.Context, client *messaging.Client) {
	// [START send_to_topic_golang]
	// The topic name can be optionally prefixed with "/topics/".
	topic := "highScores"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Topic: topic,
	}

	// Send a message to the devices subscribed to the provided topic.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_topic_golang]
}

func sendToCondition(ctx context.Context, client *messaging.Client) {
	// [START send_to_condition_golang]
	// Define a condition which will send to devices which are subscribed
	// to either the Google stock or the tech industry topics.
	condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

	// See documentation on defining a message payload.
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Condition: condition,
	}

	// Send a message to devices subscribed to the combination of topics
	// specified by the provided condition.
	response, err := client.Send(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Successfully sent message:", response)
	// [END send_to_condition_golang]
}

func sendAll(ctx context.Context, client *messaging.Client) {
	// This registration token comes from the client FCM SDKs.
	registrationToken := "YOUR_REGISTRATION_TOKEN"

	// [START send_a_batch_golang]
	// Create a list containing up to 100 messages.
	messages := []*messaging.Message{
		{
			Notification: &messaging.Notification{
				Title: "Price drop",
				Body:  "5% off all electronics",
			},
			Token: registrationToken,
		},
		{
			Notification: &messaging.Notification{
				Title: "Price drop",
				Body:  "2% off all books",
			},
			Topic: "readers-club",
		},
	}

	br, err := client.SendAll(context.Background(), messages)
	if err != nil {
		log.Fatalln(err)
	}

	// See the BatchResponse reference documentation
	// for the contents of response.
	fmt.Println(br.SuccessCount, " messages were sent successfully")
	// [END send_a_batch_golang]
}

func sendDryRun(ctx context.Context, client *messaging.Client) {
	message := &messaging.Message{
		Data: map[string]string{
			"score": "850",
			"time":  "2:45",
		},
		Token: "token",
	}

	// [START send_dry_run_golang]
	// Send a message in the dry run mode.
	response, err := client.SendDryRun(ctx, message)
	if err != nil {
		log.Fatalln(err)
	}
	// Response is a message ID string.
	fmt.Println("Dry run successful:", response)
	// [END send_dry_run_golang]
}

func androidMessage() *messaging.Message {
	// [START android_message_golang]
	oneHour := time.Duration(1) * time.Hour
	message := &messaging.Message{
		Android: &messaging.AndroidConfig{
			TTL:      &oneHour,
			Priority: "normal",
			Notification: &messaging.AndroidNotification{
				Title: "$GOOG up 1.43% on the day",
				Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
				Icon:  "stock_ticker_update",
				Color: "#f45342",
			},
		},
		Topic: "industry-tech",
	}
	// [END android_message_golang]
	return message
}

func apnsMessage() *messaging.Message {
	// [START apns_message_golang]
	badge := 42
	message := &messaging.Message{
		APNS: &messaging.APNSConfig{
			Headers: map[string]string{
				"apns-priority": "10",
			},
			Payload: &messaging.APNSPayload{
				Aps: &messaging.Aps{
					Alert: &messaging.ApsAlert{
						Title: "$GOOG up 1.43% on the day",
						Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
					},
					Badge: &badge,
				},
			},
		},
		Topic: "industry-tech",
	}
	// [END apns_message_golang]
	return message
}

func webpushMessage() *messaging.Message {
	// [START webpush_message_golang]
	message := &messaging.Message{
		Webpush: &messaging.WebpushConfig{
			Notification: &messaging.WebpushNotification{
				Title: "$GOOG up 1.43% on the day",
				Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
				Icon:  "https://my-server/icon.png",
			},
		},
		Topic: "industry-tech",
	}
	// [END webpush_message_golang]
	return message
}

func allPlatformsMessage() *messaging.Message {
	// [START multi_platforms_message_golang]
	oneHour := time.Duration(1) * time.Hour
	badge := 42
	message := &messaging.Message{
		Notification: &messaging.Notification{
			Title: "$GOOG up 1.43% on the day",
			Body:  "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
		},
		Android: &messaging.AndroidConfig{
			TTL: &oneHour,
			Notification: &messaging.AndroidNotification{
				Icon:  "stock_ticker_update",
				Color: "#f45342",
			},
		},
		APNS: &messaging.APNSConfig{
			Payload: &messaging.APNSPayload{
				Aps: &messaging.Aps{
					Badge: &badge,
				},
			},
		},
		Topic: "industry-tech",
	}
	// [END multi_platforms_message_golang]
	return message
}

func subscribeToTopic(ctx context.Context, client *messaging.Client) {
	topic := "highScores"

	// [START subscribe_golang]
	// These registration tokens come from the client FCM SDKs.
	registrationTokens := []string{
		"YOUR_REGISTRATION_TOKEN_1",
		// ...
		"YOUR_REGISTRATION_TOKEN_n",
	}

	// Subscribe the devices corresponding to the registration tokens to the
	// topic.
	response, err := client.SubscribeToTopic(ctx, registrationTokens, topic)
	if err != nil {
		log.Fatalln(err)
	}
	// See the TopicManagementResponse reference documentation
	// for the contents of response.
	fmt.Println(response.SuccessCount, "tokens were subscribed successfully")
	// [END subscribe_golang]
}

func unsubscribeFromTopic(ctx context.Context, client *messaging.Client) {
	topic := "highScores"

	// [START unsubscribe_golang]
	// These registration tokens come from the client FCM SDKs.
	registrationTokens := []string{
		"YOUR_REGISTRATION_TOKEN_1",
		// ...
		"YOUR_REGISTRATION_TOKEN_n",
	}

	// Unsubscribe the devices corresponding to the registration tokens from
	// the topic.
	response, err := client.UnsubscribeFromTopic(ctx, registrationTokens, topic)
	if err != nil {
		log.Fatalln(err)
	}
	// See the TopicManagementResponse reference documentation
	// for the contents of response.
	fmt.Println(response.SuccessCount, "tokens were unsubscribed successfully")
	// [END unsubscribe_golang]
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Mirantis

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

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"strings"
	"time"

	. "github.com/onsi/gomega"

	"github.com/Mirantis/virtlet/tests/e2e/framework"
	. "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext"
)

var _ = Describe("Basic cirros tests", func() {
	var (
		vm    *framework.VMInterface
		vmPod *framework.PodInterface
	)

	BeforeAll(func() {
		vm = controller.VM("cirros-vm")
		Expect(vm.Create(VMOptions{}.applyDefaults(), time.Minute*5, nil)).To(Succeed())
		var err error
		vmPod, err = vm.Pod()
		Expect(err).NotTo(HaveOccurred())
	})

	AfterAll(func() {
		deleteVM(vm)
	})

	Context("VM guest OS", func() {
		var ssh framework.Executor
		scheduleWaitSSH(&vm, &ssh)

		It("Should have default route [Conformance]", func() {
			Expect(framework.RunSimple(ssh, "ip r")).To(SatisfyAll(
				ContainSubstring("default via"),
				ContainSubstring("src "+vmPod.Pod.Status.PodIP),
			))
		})

		It("Should have internet connectivity [Conformance]", func(done Done) {
			defer close(done)
			Expect(framework.RunSimple(ssh, "ping -c1 8.8.8.8")).To(MatchRegexp(
				"1 .*transmitted, 1 .*received, 0% .*loss"))
		}, 5)

		Context("With nginx server", func() {
			var nginxPod *framework.PodInterface

			BeforeAll(func() {
				p, err := controller.RunPod("nginx", "nginx", nil, time.Minute*4, 80)
				Expect(err).NotTo(HaveOccurred())
				Expect(p).NotTo(BeNil())
				nginxPod = p
			})

			AfterAll(func() {
				Expect(nginxPod.Delete()).To(Succeed())
			})

			It("Should be able to access another k8s endpoint [Conformance]", func(done Done) {
				defer close(done)
				cmd := fmt.Sprintf("curl -s --connect-timeout 5 http://nginx.%s.svc.cluster.local", controller.Namespace())
				Eventually(func() (string, error) {
					return framework.RunSimple(ssh, cmd)
				}, 60).Should(ContainSubstring("Thank you for using nginx."))
			}, 60*5)
		})

		It("Should have hostname equal to the pod name [Conformance]", func() {
			Expect(framework.RunSimple(ssh, "hostname")).To(Equal(vmPod.Pod.Name))
		})

		It("Should have CPU count that was specified for the pod [Conformance]", func() {
			checkCPUCount(vm, ssh, 1)
		})
	})

	Context("Virtlet logs", func() {
		var (
			filename     string
			sandboxID    string
			nodeExecutor framework.Executor
		)

		BeforeAll(func() {
			virtletPod, err := vm.VirtletPod()
			Expect(err).NotTo(HaveOccurred())
			nodeExecutor, err = virtletPod.DinDNodeExecutor()
			Expect(err).NotTo(HaveOccurred())

			domain, err := vm.Domain()
			Expect(err).NotTo(HaveOccurred())
			var vmName, attempt string
			for _, env := range domain.QEMUCommandline.Envs {
				if env.Name == "VIRTLET_POD_NAME" {
					vmName = env.Value
				} else if env.Name == "CONTAINER_ATTEMPTS" {
					attempt = env.Value
				} else if env.Name == "VIRTLET_POD_UID" {
					sandboxID = env.Value
				}
			}
			Expect(sandboxID).NotTo(BeEmpty())
			Expect(vmName).NotTo(BeEmpty())
			Expect(attempt).NotTo(BeEmpty())
			filename = fmt.Sprintf("%s_%s.log", vmName, attempt)
		})

		It("Should contain login string in pod log and each line of that log must be a valid JSON", func() {
			Eventually(func() error {
				out, err := framework.RunSimple(nodeExecutor, "cat",
					fmt.Sprintf("/var/log/pods/%s/%s", sandboxID, filename))
				if err != nil {
					return err
				}
				found := 0
				for _, line := range strings.Split(out, "\n") {
					var entry map[string]string
					if err := json.Unmarshal([]byte(line), &entry); err != nil {
						return fmt.Errorf("error unmarshalling json: %v", err)
					}
					if strings.HasPrefix(entry["log"], "login as 'cirros' user. default password") {
						found++
					}
				}
				if found != 1 {
					return fmt.Errorf("expected login prompt to appear exactly once in the log, but got %d occurrences", found)
				}
				return nil
			})
		})
	})

	It("Should provide VNC interface [Conformance]", func(done Done) {
		defer close(done)
		pod, err := vm.VirtletPod()
		Expect(err).NotTo(HaveOccurred())

		virtletPodExecutor, err := pod.Container("virtlet")
		Expect(err).NotTo(HaveOccurred())

		display, err := vm.VirshCommand("vncdisplay", "<domain>")
		Expect(err).NotTo(HaveOccurred())

		By(fmt.Sprintf("Taking VNC display snapshot from %s", display))
		do(framework.RunSimple(virtletPodExecutor, "vncsnapshot", "-allowblank", display, "/vm.jpg"))
	}, 60)

	It("Should start port forwarding", func(done Done) {
		defer close(done)
		podName := "nginx-pf"
		localPort := rand.Intn(899) + 100
		portMapping := fmt.Sprintf("18%d:80", localPort)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By(fmt.Sprintf("Starting nginx pod"))
		nginxPod, err := controller.RunPod(podName, "nginx", nil, time.Minute*4, 80)
		Expect(err).NotTo(HaveOccurred())
		Expect(nginxPod).NotTo(BeNil())

		By(fmt.Sprintf("Running command: kubectl -n %s port-forward %s %s", controller.Namespace(), podName, portMapping))
		cmd, err := localExecutor.Start(nil, nil, nil, "kubectl", "-n", controller.Namespace(), "port-forward", podName, portMapping)
		Expect(err).NotTo(HaveOccurred())
		defer cmd.Kill()

		// give it a chance to start
		time.Sleep(3 * time.Second)

		By(fmt.Sprintf("Checking if nginx is available via localhost"))
		data, err := framework.Curl(fmt.Sprintf("http://localhost:18%d", localPort))
		Expect(err).NotTo(HaveOccurred())
		Expect(data).Should(ContainSubstring("nginx web server"))

		Expect(nginxPod.Delete()).To(Succeed())
	}, 60)
})
<commit_msg>Fix e2e test naming<commit_after>/*
Copyright 2017 Mirantis

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

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package e2e

import (
	"context"
	"encoding/json"
	"fmt"
	"math/rand"
	"strings"
	"time"

	. "github.com/onsi/gomega"

	"github.com/Mirantis/virtlet/tests/e2e/framework"
	. "github.com/Mirantis/virtlet/tests/e2e/ginkgo-ext"
)

var _ = Describe("Virtlet [Basic cirros tests]", func() {
	var (
		vm    *framework.VMInterface
		vmPod *framework.PodInterface
	)

	BeforeAll(func() {
		vm = controller.VM("cirros-vm")
		Expect(vm.Create(VMOptions{}.applyDefaults(), time.Minute*5, nil)).To(Succeed())
		var err error
		vmPod, err = vm.Pod()
		Expect(err).NotTo(HaveOccurred())
	})

	AfterAll(func() {
		deleteVM(vm)
	})

	Context("VM guest OS", func() {
		var ssh framework.Executor
		scheduleWaitSSH(&vm, &ssh)

		It("Should have default route [Conformance]", func() {
			Expect(framework.RunSimple(ssh, "ip r")).To(SatisfyAll(
				ContainSubstring("default via"),
				ContainSubstring("src "+vmPod.Pod.Status.PodIP),
			))
		})

		It("Should have internet connectivity [Conformance]", func(done Done) {
			defer close(done)
			Expect(framework.RunSimple(ssh, "ping -c1 8.8.8.8")).To(MatchRegexp(
				"1 .*transmitted, 1 .*received, 0% .*loss"))
		}, 5)

		Context("With nginx server", func() {
			var nginxPod *framework.PodInterface

			BeforeAll(func() {
				p, err := controller.RunPod("nginx", "nginx", nil, time.Minute*4, 80)
				Expect(err).NotTo(HaveOccurred())
				Expect(p).NotTo(BeNil())
				nginxPod = p
			})

			AfterAll(func() {
				Expect(nginxPod.Delete()).To(Succeed())
			})

			It("Should be able to access another k8s endpoint [Conformance]", func(done Done) {
				defer close(done)
				cmd := fmt.Sprintf("curl -s --connect-timeout 5 http://nginx.%s.svc.cluster.local", controller.Namespace())
				Eventually(func() (string, error) {
					return framework.RunSimple(ssh, cmd)
				}, 60).Should(ContainSubstring("Thank you for using nginx."))
			}, 60*5)
		})

		It("Should have hostname equal to the pod name [Conformance]", func() {
			Expect(framework.RunSimple(ssh, "hostname")).To(Equal(vmPod.Pod.Name))
		})

		It("Should have CPU count that was specified for the pod [Conformance]", func() {
			checkCPUCount(vm, ssh, 1)
		})
	})

	Context("Virtlet logs", func() {
		var (
			filename     string
			sandboxID    string
			nodeExecutor framework.Executor
		)

		BeforeAll(func() {
			virtletPod, err := vm.VirtletPod()
			Expect(err).NotTo(HaveOccurred())
			nodeExecutor, err = virtletPod.DinDNodeExecutor()
			Expect(err).NotTo(HaveOccurred())

			domain, err := vm.Domain()
			Expect(err).NotTo(HaveOccurred())
			var vmName, attempt string
			for _, env := range domain.QEMUCommandline.Envs {
				if env.Name == "VIRTLET_POD_NAME" {
					vmName = env.Value
				} else if env.Name == "CONTAINER_ATTEMPTS" {
					attempt = env.Value
				} else if env.Name == "VIRTLET_POD_UID" {
					sandboxID = env.Value
				}
			}
			Expect(sandboxID).NotTo(BeEmpty())
			Expect(vmName).NotTo(BeEmpty())
			Expect(attempt).NotTo(BeEmpty())
			filename = fmt.Sprintf("%s_%s.log", vmName, attempt)
		})

		It("Should contain login string in pod log and each line of that log must be a valid JSON", func() {
			Eventually(func() error {
				out, err := framework.RunSimple(nodeExecutor, "cat",
					fmt.Sprintf("/var/log/pods/%s/%s", sandboxID, filename))
				if err != nil {
					return err
				}
				found := 0
				for _, line := range strings.Split(out, "\n") {
					var entry map[string]string
					if err := json.Unmarshal([]byte(line), &entry); err != nil {
						return fmt.Errorf("error unmarshalling json: %v", err)
					}
					if strings.HasPrefix(entry["log"], "login as 'cirros' user. default password") {
						found++
					}
				}
				if found != 1 {
					return fmt.Errorf("expected login prompt to appear exactly once in the log, but got %d occurrences", found)
				}
				return nil
			})
		})
	})

	It("Should provide VNC interface [Conformance]", func(done Done) {
		defer close(done)
		pod, err := vm.VirtletPod()
		Expect(err).NotTo(HaveOccurred())

		virtletPodExecutor, err := pod.Container("virtlet")
		Expect(err).NotTo(HaveOccurred())

		display, err := vm.VirshCommand("vncdisplay", "<domain>")
		Expect(err).NotTo(HaveOccurred())

		By(fmt.Sprintf("Taking VNC display snapshot from %s", display))
		do(framework.RunSimple(virtletPodExecutor, "vncsnapshot", "-allowblank", display, "/vm.jpg"))
	}, 60)

	It("Should support port forwarding", func(done Done) {
		defer close(done)
		podName := "nginx-pf"
		localPort := rand.Intn(899) + 100
		portMapping := fmt.Sprintf("18%d:80", localPort)

		ctx, closeFunc := context.WithCancel(context.Background())
		defer closeFunc()
		localExecutor := framework.LocalExecutor(ctx)

		By(fmt.Sprintf("Starting nginx pod"))
		nginxPod, err := controller.RunPod(podName, "nginx", nil, time.Minute*4, 80)
		Expect(err).NotTo(HaveOccurred())
		Expect(nginxPod).NotTo(BeNil())

		By(fmt.Sprintf("Running command: kubectl -n %s port-forward %s %s", controller.Namespace(), podName, portMapping))
		cmd, err := localExecutor.Start(nil, nil, nil, "kubectl", "-n", controller.Namespace(), "port-forward", podName, portMapping)
		Expect(err).NotTo(HaveOccurred())
		defer cmd.Kill()

		// give it a chance to start
		time.Sleep(3 * time.Second)

		By(fmt.Sprintf("Checking if nginx is available via localhost"))
		data, err := framework.Curl(fmt.Sprintf("http://localhost:18%d", localPort))
		Expect(err).NotTo(HaveOccurred())
		Expect(data).Should(ContainSubstring("nginx web server"))

		Expect(nginxPod.Delete()).To(Succeed())
	}, 60)
})
<|endoftext|>


<commit_before>// Package memfs provides an interface for an in-memory filesystem.
package memfs

import (
	"bytes"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/rjeczalik/tools/fs"
)

const sep = string(os.PathSeparator)

// Directory represents an in-memory directory
type Directory map[string]interface{}

// File represents an in-memory file.
type File []byte

// FS provides an implementation for Filesystem interface, operating on
// an in-memory file tree.
// TODO(rjeczalik): sync.RWMutex
type FS struct {
	Tree Directory
}

var _ fs.Filesystem = FS{}

var (
	errDir       = errors.New("is a directory")
	errNotDir    = errors.New("not a directory")
	errCorrupted = errors.New("tree is corrupted")
)

// Cd gives new filesystem with a root starting at the path of the old filesystem.
func (fs FS) Cd(path string) (FS, error) {
	dir, perr := fs.lookup(path)
	if perr != nil {
		return FS{}, perr
	}
	return FS{Tree: dir}, nil
}

// Create creates an in-memory file under the given path.
func (fs FS) Create(name string) (fs.File, error) {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Create"
		return nil, perr
	}
	if base == "" {
		return nil, &os.PathError{"Create", name, errDir}
	}
	if v, ok := dir[base]; ok {
		if _, ok = v.(Directory); ok {
			return nil, &os.PathError{"Create", name, errDir}
		}
	}
	dir[base] = File{}
	return file{s: name, f: fs.flushcb(dir, base), r: new(bytes.Reader)}, nil
}

// Mkdir creates an in-memory directory under the given path.
func (fs FS) Mkdir(name string, _ os.FileMode) error {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Mkdir"
		return perr
	}
	if base == "" {
		return nil
	}
	if v, ok := dir[base]; ok {
		if _, ok = v.(File); ok {
			return &os.PathError{"Mkdir", name, errNotDir}
		}
	}
	dir[base] = Directory{}
	return nil
}

// MkdirAll creates new in-memory directory and all its parents, if needed.
func (fs FS) MkdirAll(name string, _ os.FileMode) error {
	var (
		dir = fs.Tree
		err error
	)
	fn := func(s string) bool {
		v, ok := dir[s]
		if !ok {
			d := Directory{}
			dir[s], dir = d, d
		} else if dir, ok = v.(Directory); !ok {
			err = &os.PathError{"MkdirAll", name, errNotDir}
			return false
		}
		return true
	}
	fs.dirwalk(name, fn)
	return err
}

// Open opens a file or directory given by the path.
func (fs FS) Open(name string) (fs.File, error) {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Open"
		return nil, perr
	}
	if base == "" {
		return directory{s: name, d: dir}, nil
	}
	if _, ok := dir[base]; !ok {
		return nil, &os.PathError{"Open", name, os.ErrNotExist}
	}
	switch v := dir[base].(type) {
	case File:
		return file{s: name, f: fs.flushcb(dir, base), r: bytes.NewReader([]byte(v))}, nil
	case Directory:
		return directory{s: name, d: v}, nil
	}
	return nil, &os.PathError{"Open", name, errCorrupted}
}

// Remove removes a file from the tree given by the path.
func (fs FS) Remove(name string) error {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Remove"
		return perr
	}
	if base == "" {
		return &os.PathError{"Remove", name, os.ErrPermission}
	}
	if _, ok := dir[base]; !ok {
		return &os.PathError{"Remove", name, os.ErrNotExist}
	}
	if _, ok := dir[base].(Directory); ok {
		return &os.PathError{"Remove", name, os.ErrPermission}
	}
	delete(dir, base)
	return nil
}

// Stat gives the details of a file or a directory given by the path.
func (fs FS) Stat(name string) (os.FileInfo, error) {
	f, err := fs.Open(name)
	if err != nil {
		return nil, err
	}
	return f.Stat()
}

func (fs FS) dirwalk(p string, fn func(string) bool) {
	if p == "" || p == "." {
		return
	}
	i := strings.Index(p, sep) + 1
	if i == 0 || i == len(p) {
		return
	}
	for i < len(p) {
		j := strings.Index(p[i:], sep)
		if j == -1 {
			j = len(p) - i
		}
		if !fn(p[i : i+j]) {
			return
		}
		i += j + 1
	}
}

func (fs FS) lookup(p string) (dir Directory, perr *os.PathError) {
	dir = fs.Tree
	fn := func(name string) bool {
		v, ok := dir[name]
		if !ok {
			perr = &os.PathError{Err: os.ErrNotExist}
			return false
		}
		if dir, ok = v.(Directory); !ok {
			perr = &os.PathError{Err: errNotDir}
			return false
		}
		return true
	}
	fs.dirwalk(p, fn)
	return
}

func (fs FS) dirbase(p string) (Directory, string, *os.PathError) {
	i := strings.LastIndex(p, sep)
	if i == -1 {
		return fs.Tree, "", nil
	}
	if i == 0 {
		return fs.Tree, p[1:], nil
	}
	dir, perr := fs.lookup(p[:i])
	if perr != nil {
		perr.Path = p
		return nil, "", perr
	}
	return dir, p[i+1:], nil
}

func (fs FS) flushcb(dir Directory, name string) func([]byte) {
	return func(p []byte) {
		dir[name] = File(p)
	}
}

type file struct {
	s string        // name
	f func([]byte)  // flush callback
	r *bytes.Reader // for reading (io.Seeker)
	w *bytes.Buffer // for writing - merge?
}

func (f file) Close() (err error) {
	if f.w != nil {
		f.f(f.w.Bytes())
		f.w = nil
	}
	return
}

func (f file) Read(p []byte) (int, error) {
	return f.r.Read(p)
}

func (f file) Readdir(int) ([]os.FileInfo, error) {
	return nil, &os.PathError{"Readdir", f.s, nil}
}

func (f file) Seek(offset int64, whence int) (int64, error) {
	return f.r.Seek(offset, whence)
}

func (f file) Stat() (os.FileInfo, error) {
	return fileinfo{f.s, int64(f.r.Len()), false}, nil
}

func (f file) Write(p []byte) (int, error) {
	if f.w == nil {
		f.w = new(bytes.Buffer)
	}
	return f.w.Write(p)
}

type directory struct {
	s string
	d Directory
}

func (d directory) Close() (err error) {
	return
}

func (d directory) Read(p []byte) (int, error) {
	return 0, &os.PathError{"Read", d.s, nil}
}

// TODO(rjeczalik): make it ordered so it actually works
func (d directory) Readdir(n int) (fi []os.FileInfo, err error) {
	if len(d.d) == 0 {
		return nil, errors.New("Readdir: directory is empty")
	}
	if n > 0 {
		return nil, errors.New("Readdir: not implemented")
	}
	fi = make([]os.FileInfo, 0, len(d.d))
	for k, v := range d.d {
		if f, ok := v.(File); ok {
			fi = append(fi, fileinfo{filepath.Join(d.s, k), int64(len(f)), false})
		} else {
			fi = append(fi, fileinfo{filepath.Join(d.s, k), 0, true})
		}
	}
	return
}

func (d directory) Seek(int64, int) (int64, error) {
	return 0, &os.PathError{"Seek", d.s, nil}
}

func (d directory) Stat() (os.FileInfo, error) {
	return fileinfo{d.s, 0, true}, nil
}

func (d directory) Write([]byte) (int, error) {
	return 0, &os.PathError{"Write", d.s, nil}
}

type fileinfo struct {
	s string
	n int64
	d bool
}

func (fi fileinfo) Name() string       { return fi.s }
func (fi fileinfo) Size() int64        { return fi.n }
func (fi fileinfo) Mode() os.FileMode  { return 0755 }
func (fi fileinfo) ModTime() time.Time { return time.Time{} }
func (fi fileinfo) IsDir() bool        { return fi.d }
func (fi fileinfo) Sys() interface{}   { return nil }
<commit_msg>fs/memfs: Add New<commit_after>// Package memfs provides an interface for an in-memory filesystem.
package memfs

import (
	"bytes"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/rjeczalik/tools/fs"
)

const sep = string(os.PathSeparator)

// Directory represents an in-memory directory
type Directory map[string]interface{}

// File represents an in-memory file.
type File []byte

// FS provides an implementation for Filesystem interface, operating on
// an in-memory file tree.
// TODO(rjeczalik): sync.RWMutex
type FS struct {
	Tree Directory
}

// New returns an empty filesystem.
func New() FS {
	return FS{
		Tree: Directory{},
	}
}

var _ fs.Filesystem = FS{}

var (
	errDir       = errors.New("is a directory")
	errNotDir    = errors.New("not a directory")
	errCorrupted = errors.New("tree is corrupted")
)

// Cd gives new filesystem with a root starting at the path of the old filesystem.
func (fs FS) Cd(path string) (FS, error) {
	dir, perr := fs.lookup(path)
	if perr != nil {
		return FS{}, perr
	}
	return FS{Tree: dir}, nil
}

// Create creates an in-memory file under the given path.
func (fs FS) Create(name string) (fs.File, error) {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Create"
		return nil, perr
	}
	if base == "" {
		return nil, &os.PathError{"Create", name, errDir}
	}
	if v, ok := dir[base]; ok {
		if _, ok = v.(Directory); ok {
			return nil, &os.PathError{"Create", name, errDir}
		}
	}
	dir[base] = File{}
	return file{s: name, f: fs.flushcb(dir, base), r: new(bytes.Reader)}, nil
}

// Mkdir creates an in-memory directory under the given path.
func (fs FS) Mkdir(name string, _ os.FileMode) error {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Mkdir"
		return perr
	}
	if base == "" {
		return nil
	}
	if v, ok := dir[base]; ok {
		if _, ok = v.(File); ok {
			return &os.PathError{"Mkdir", name, errNotDir}
		}
	}
	dir[base] = Directory{}
	return nil
}

// MkdirAll creates new in-memory directory and all its parents, if needed.
func (fs FS) MkdirAll(name string, _ os.FileMode) error {
	var (
		dir = fs.Tree
		err error
	)
	fn := func(s string) bool {
		v, ok := dir[s]
		if !ok {
			d := Directory{}
			dir[s], dir = d, d
		} else if dir, ok = v.(Directory); !ok {
			err = &os.PathError{"MkdirAll", name, errNotDir}
			return false
		}
		return true
	}
	fs.dirwalk(name, fn)
	return err
}

// Open opens a file or directory given by the path.
func (fs FS) Open(name string) (fs.File, error) {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Open"
		return nil, perr
	}
	if base == "" {
		return directory{s: name, d: dir}, nil
	}
	if _, ok := dir[base]; !ok {
		return nil, &os.PathError{"Open", name, os.ErrNotExist}
	}
	switch v := dir[base].(type) {
	case File:
		return file{s: name, f: fs.flushcb(dir, base), r: bytes.NewReader([]byte(v))}, nil
	case Directory:
		return directory{s: name, d: v}, nil
	}
	return nil, &os.PathError{"Open", name, errCorrupted}
}

// Remove removes a file from the tree given by the path.
func (fs FS) Remove(name string) error {
	dir, base, perr := fs.dirbase(name)
	if perr != nil {
		perr.Op = "Remove"
		return perr
	}
	if base == "" {
		return &os.PathError{"Remove", name, os.ErrPermission}
	}
	if _, ok := dir[base]; !ok {
		return &os.PathError{"Remove", name, os.ErrNotExist}
	}
	if _, ok := dir[base].(Directory); ok {
		return &os.PathError{"Remove", name, os.ErrPermission}
	}
	delete(dir, base)
	return nil
}

// Stat gives the details of a file or a directory given by the path.
func (fs FS) Stat(name string) (os.FileInfo, error) {
	f, err := fs.Open(name)
	if err != nil {
		return nil, err
	}
	return f.Stat()
}

func (fs FS) dirwalk(p string, fn func(string) bool) {
	if p == "" || p == "." {
		return
	}
	i := strings.Index(p, sep) + 1
	if i == 0 || i == len(p) {
		return
	}
	for i < len(p) {
		j := strings.Index(p[i:], sep)
		if j == -1 {
			j = len(p) - i
		}
		if !fn(p[i : i+j]) {
			return
		}
		i += j + 1
	}
}

func (fs FS) lookup(p string) (dir Directory, perr *os.PathError) {
	dir = fs.Tree
	fn := func(name string) bool {
		v, ok := dir[name]
		if !ok {
			perr = &os.PathError{Err: os.ErrNotExist}
			return false
		}
		if dir, ok = v.(Directory); !ok {
			perr = &os.PathError{Err: errNotDir}
			return false
		}
		return true
	}
	fs.dirwalk(p, fn)
	return
}

func (fs FS) dirbase(p string) (Directory, string, *os.PathError) {
	i := strings.LastIndex(p, sep)
	if i == -1 {
		return fs.Tree, "", nil
	}
	if i == 0 {
		return fs.Tree, p[1:], nil
	}
	dir, perr := fs.lookup(p[:i])
	if perr != nil {
		perr.Path = p
		return nil, "", perr
	}
	return dir, p[i+1:], nil
}

func (fs FS) flushcb(dir Directory, name string) func([]byte) {
	return func(p []byte) {
		dir[name] = File(p)
	}
}

type file struct {
	s string        // name
	f func([]byte)  // flush callback
	r *bytes.Reader // for reading (io.Seeker)
	w *bytes.Buffer // for writing - merge?
}

func (f file) Close() (err error) {
	if f.w != nil {
		f.f(f.w.Bytes())
		f.w = nil
	}
	return
}

func (f file) Read(p []byte) (int, error) {
	return f.r.Read(p)
}

func (f file) Readdir(int) ([]os.FileInfo, error) {
	return nil, &os.PathError{"Readdir", f.s, nil}
}

func (f file) Seek(offset int64, whence int) (int64, error) {
	return f.r.Seek(offset, whence)
}

func (f file) Stat() (os.FileInfo, error) {
	return fileinfo{f.s, int64(f.r.Len()), false}, nil
}

func (f file) Write(p []byte) (int, error) {
	if f.w == nil {
		f.w = new(bytes.Buffer)
	}
	return f.w.Write(p)
}

type directory struct {
	s string
	d Directory
}

func (d directory) Close() (err error) {
	return
}

func (d directory) Read(p []byte) (int, error) {
	return 0, &os.PathError{"Read", d.s, nil}
}

// TODO(rjeczalik): make it ordered so it actually works
func (d directory) Readdir(n int) (fi []os.FileInfo, err error) {
	if len(d.d) == 0 {
		return nil, errors.New("Readdir: directory is empty")
	}
	if n > 0 {
		return nil, errors.New("Readdir: not implemented")
	}
	fi = make([]os.FileInfo, 0, len(d.d))
	for k, v := range d.d {
		if f, ok := v.(File); ok {
			fi = append(fi, fileinfo{filepath.Join(d.s, k), int64(len(f)), false})
		} else {
			fi = append(fi, fileinfo{filepath.Join(d.s, k), 0, true})
		}
	}
	return
}

func (d directory) Seek(int64, int) (int64, error) {
	return 0, &os.PathError{"Seek", d.s, nil}
}

func (d directory) Stat() (os.FileInfo, error) {
	return fileinfo{d.s, 0, true}, nil
}

func (d directory) Write([]byte) (int, error) {
	return 0, &os.PathError{"Write", d.s, nil}
}

type fileinfo struct {
	s string
	n int64
	d bool
}

func (fi fileinfo) Name() string       { return fi.s }
func (fi fileinfo) Size() int64        { return fi.n }
func (fi fileinfo) Mode() os.FileMode  { return 0755 }
func (fi fileinfo) ModTime() time.Time { return time.Time{} }
func (fi fileinfo) IsDir() bool        { return fi.d }
func (fi fileinfo) Sys() interface{}   { return nil }
<|endoftext|>


<commit_before>package soyhtml

import (
	"bytes"
	"fmt"
	"net/url"
	"regexp"
	"text/template"
	"unicode/utf8"
	"encoding/json"

	"github.com/robfig/soy/data"
)

// PrintDirective represents a transformation applied when printing a value.
type PrintDirective struct {
	Apply            func(value data.Value, args []data.Value) data.Value
	ValidArgLengths  []int
	CancelAutoescape bool
}

// PrintDirectives are the builtin print directives.
// Callers may add their own print directives to this map.
var PrintDirectives = map[string]PrintDirective{
	"insertWordBreaks":  {directiveInsertWordBreaks, []int{1}, true},
	"changeNewlineToBr": {directiveChangeNewlineToBr, []int{0}, true},
	"truncate":          {directiveTruncate, []int{1, 2}, false},
	"id":                {directiveNoAutoescape, []int{0}, true},
	"noAutoescape":      {directiveNoAutoescape, []int{0}, true},
	"escapeHtml":        {directiveEscapeHtml, []int{0}, true},
	"escapeUri":         {directiveEscapeUri, []int{0}, true},
	"escapeJsString":    {directiveEscapeJsString, []int{0}, true},
	"bidiSpanWrap":      {nil, []int{0}, false}, // unimplemented
	"bidiUnicodeWrap":   {nil, []int{0}, false}, // unimplemented
	"json":        {directiveJson, []int{0}, true},
}

func directiveInsertWordBreaks(value data.Value, args []data.Value) data.Value {
	var (
		input    = template.HTMLEscapeString(value.String())
		maxChars = int(args[0].(data.Int))
		chars    = 0
		output   *bytes.Buffer // create the buffer lazily
	)
	for i, ch := range input {
		switch {
		case ch == ' ':
			chars = 0
		case chars >= maxChars:
			if output == nil {
				output = bytes.NewBufferString(input[:i])
			}
			output.WriteString("<wbr>")
			chars = 1
		default:
			chars++
		}
		if output != nil {
			output.WriteRune(ch)
		}
	}
	if output == nil {
		return value
	}
	return data.String(output.String())
}

var newlinePattern = regexp.MustCompile(`\r\n|\r|\n`)

func directiveChangeNewlineToBr(value data.Value, _ []data.Value) data.Value {
	return data.String(newlinePattern.ReplaceAllString(
		template.HTMLEscapeString(value.String()),
		"
"))
}

func directiveTruncate(value data.Value, args []data.Value) data.Value {
	if !isInt(args[0]) {
		panic(fmt.Errorf("First parameter of '|truncate' is not an integer: %v", args[0]))
	}
	var maxLen = int(args[0].(data.Int))
	var str = value.String()
	if len(str) <= maxLen {
		return value
	}

	var ellipsis = data.Bool(true)
	if len(args) == 2 {
		var ok bool
		ellipsis, ok = args[1].(data.Bool)
		if !ok {
			panic(fmt.Errorf("Second parameter of '|truncate' is not a bool: %v", args[1]))
		}
	}

	if ellipsis {
		if maxLen > 3 {
			maxLen -= 3
		} else {
			ellipsis = false
		}
	}

	for !utf8.RuneStart(str[maxLen]) {
		maxLen--
	}

	str = str[:maxLen]
	if ellipsis {
		str += "..."
	}
	return data.String(str)
}

func directiveNoAutoescape(value data.Value, _ []data.Value) data.Value {
	return value
}

func directiveEscapeHtml(value data.Value, _ []data.Value) data.Value {
	return data.String(template.HTMLEscapeString(value.String()))
}

func directiveEscapeUri(value data.Value, _ []data.Value) data.Value {
	return data.String(url.QueryEscape(value.String()))
}

func directiveEscapeJsString(value data.Value, _ []data.Value) data.Value {
	return data.String(template.JSEscapeString(value.String()))
}

func directiveJson(value data.Value, _ []data.Value) data.Value {
	j, err := json.Marshal(value)
	if err != nil {
		panic(fmt.Errorf("Error JSON encoding value: %v", err))
	}
	return data.String(j)
}
<commit_msg>Run gofmt<commit_after>package soyhtml

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"
	"text/template"
	"unicode/utf8"

	"github.com/robfig/soy/data"
)

// PrintDirective represents a transformation applied when printing a value.
type PrintDirective struct {
	Apply            func(value data.Value, args []data.Value) data.Value
	ValidArgLengths  []int
	CancelAutoescape bool
}

// PrintDirectives are the builtin print directives.
// Callers may add their own print directives to this map.
var PrintDirectives = map[string]PrintDirective{
	"insertWordBreaks":  {directiveInsertWordBreaks, []int{1}, true},
	"changeNewlineToBr": {directiveChangeNewlineToBr, []int{0}, true},
	"truncate":          {directiveTruncate, []int{1, 2}, false},
	"id":                {directiveNoAutoescape, []int{0}, true},
	"noAutoescape":      {directiveNoAutoescape, []int{0}, true},
	"escapeHtml":        {directiveEscapeHtml, []int{0}, true},
	"escapeUri":         {directiveEscapeUri, []int{0}, true},
	"escapeJsString":    {directiveEscapeJsString, []int{0}, true},
	"bidiSpanWrap":      {nil, []int{0}, false}, // unimplemented
	"bidiUnicodeWrap":   {nil, []int{0}, false}, // unimplemented
	"json":              {directiveJson, []int{0}, true},
}

func directiveInsertWordBreaks(value data.Value, args []data.Value) data.Value {
	var (
		input    = template.HTMLEscapeString(value.String())
		maxChars = int(args[0].(data.Int))
		chars    = 0
		output   *bytes.Buffer // create the buffer lazily
	)
	for i, ch := range input {
		switch {
		case ch == ' ':
			chars = 0
		case chars >= maxChars:
			if output == nil {
				output = bytes.NewBufferString(input[:i])
			}
			output.WriteString("<wbr>")
			chars = 1
		default:
			chars++
		}
		if output != nil {
			output.WriteRune(ch)
		}
	}
	if output == nil {
		return value
	}
	return data.String(output.String())
}

var newlinePattern = regexp.MustCompile(`\r\n|\r|\n`)

func directiveChangeNewlineToBr(value data.Value, _ []data.Value) data.Value {
	return data.String(newlinePattern.ReplaceAllString(
		template.HTMLEscapeString(value.String()),
		"
"))
}

func directiveTruncate(value data.Value, args []data.Value) data.Value {
	if !isInt(args[0]) {
		panic(fmt.Errorf("First parameter of '|truncate' is not an integer: %v", args[0]))
	}
	var maxLen = int(args[0].(data.Int))
	var str = value.String()
	if len(str) <= maxLen {
		return value
	}

	var ellipsis = data.Bool(true)
	if len(args) == 2 {
		var ok bool
		ellipsis, ok = args[1].(data.Bool)
		if !ok {
			panic(fmt.Errorf("Second parameter of '|truncate' is not a bool: %v", args[1]))
		}
	}

	if ellipsis {
		if maxLen > 3 {
			maxLen -= 3
		} else {
			ellipsis = false
		}
	}

	for !utf8.RuneStart(str[maxLen]) {
		maxLen--
	}

	str = str[:maxLen]
	if ellipsis {
		str += "..."
	}
	return data.String(str)
}

func directiveNoAutoescape(value data.Value, _ []data.Value) data.Value {
	return value
}

func directiveEscapeHtml(value data.Value, _ []data.Value) data.Value {
	return data.String(template.HTMLEscapeString(value.String()))
}

func directiveEscapeUri(value data.Value, _ []data.Value) data.Value {
	return data.String(url.QueryEscape(value.String()))
}

func directiveEscapeJsString(value data.Value, _ []data.Value) data.Value {
	return data.String(template.JSEscapeString(value.String()))
}

func directiveJson(value data.Value, _ []data.Value) data.Value {
	j, err := json.Marshal(value)
	if err != nil {
		panic(fmt.Errorf("Error JSON encoding value: %v", err))
	}
	return data.String(j)
}
<|endoftext|>


<commit_before>package lang

type Tokenizer struct {
    chars RuneStream
    headToken *Token
    ahead bool
    firstToken bool
}

func StringTokenizer(source string) *Tokenizer {
    return &Tokenizer{chars: &StringRuneStream{source: source}, ahead: false, firstToken: true}
}

func (this *Tokenizer) Has() bool {
    return this.Head() != EofToken
}

func (this *Tokenizer) Head() *Token {
    if !this.ahead {
        this.headToken = this.next()
        this.ahead = true
    }
    return this.headToken
}

func (this *Tokenizer) Advance() {
    this.Head()
    this.ahead = false
}

func (this *Tokenizer) next() *Token {
    var token *Token = EofToken
    if (this.firstToken) {
        // First token can be indentation, which in this case
        // is not after a new line
        if isLineWhiteSpace(this.chars.Head()) {
            token = Indentation(consumeIndentation(this.chars))
        }
        for consumeIgnored(this.chars) {
            // Remove trailing comments and whitespace
        }
        this.firstToken = false
    }
    for this.chars.Has() && token == EofToken {
        if isNewLineChar(this.chars.Head()) {
            consumeNewLine(this.chars)
            // Just after a new line, try to consume indentation
            if isLineWhiteSpace(this.chars.Head()) {
                token = Indentation(consumeIndentation(this.chars))
            }
        } else if this.chars.Head() == ';' {
            // A terminator breaks a line but doesn't need indentation
            this.chars.Advance()
            token = TerminatorToken
        } else if isIdentifierStart(this.chars.Head()) {
            this.chars.Collect()
            identifier := consumeIdentifierBody(this.chars)
            // An indentifier can also be a keyword
            if isKeyword(identifier) {
                token = Keyword(identifier)
            } else if isBooleanLiteral(identifier) {
                token = BooleanLiteral(identifier)
            } else {
                token = Identifier(identifier)
            }
        } else if isSymbol(this.chars.Head()) {
            token = Symbol(consumeSymbol(this.chars))
        } else if this.chars.Head() == '"' {
            token = StringLiteral(collectStringLiteral(this.chars))
        }
        for consumeIgnored(this.chars) {
            // Remove trailing comments and whitespace
        }
    }
    return token
}

func consumeIdentifierBody(chars RuneStream) []rune {
    for isIdentifierBody(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func consumeIgnored(chars RuneStream) bool {
    if isLineWhiteSpace(chars.Head()) {
        // Consume a line whitespace character
        chars.Advance()
        return true
    }
    if chars.Head() == '#' {
        // Consume a comment
        chars.Advance()
        if (chars.Head() == '#') {
            chars.Advance()
            completeBlockComment(chars)
        } else {
            completeLineComment(chars)
        }
        return true
    }
    if chars.Head() == '\\' {
        // Consume an escaped new line
        chars.Advance()
        if !isNewLineChar(chars.Head()) {
            panic("Expected new line character")
        }
        chars.Advance()
        // Consume more escaped new lines
        for isNewLineChar(chars.Head()) {
            chars.Advance()
        }
        return true
    }
    return false
}

func completeBlockComment(chars RuneStream) {
    // Count and consume leading # symbols
    leading := 2
    for chars.Head() == '#' {
        leading++
        chars.Advance()
    }
    // Consume print and white space characters
    // and look for a matching count of consecutive #
    trailing := 0
    for trailing < leading {
        if chars.Head() == '#' {
            trailing++
        } else if isPrintChar(chars.Head()) || isWhiteSpace(chars.Head()) {
            trailing = 0
        } else {
            panic("Unexpected character")
        }
        chars.Advance()
    }
}

func completeLineComment(chars RuneStream) {
    for isPrintChar(chars.Head()) || isLineWhiteSpace(chars.Head()) {
        chars.Advance()
    }
}

func consumeNewLine(chars RuneStream) {
    if chars.Head() == '\r'{
        // CR
        chars.Advance()
        if chars.Head() == '\n' {
            // CR LF
            chars.Advance()
        }
    } else if chars.Head() == '\n' {
        // LF
        chars.Advance()
    }
}

func consumeIndentation(chars RuneStream) []rune {
    for isLineWhiteSpace(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func consumeSymbol(chars RuneStream) []rune {
    for isSymbol(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func collectStringLiteral(chars RuneStream) []rune {
    // Opening "
    if chars.Head() != '"' {
        panic("Expected opening \"")
    }
    chars.Collect()
    // String contents
    for {
        if isPrintChar(chars.Head()) && chars.Head() != '"' && chars.Head() != '\\' {
            chars.Collect()
        } else if isLineWhiteSpace(chars.Head()) {
            chars.Collect()
        } else if collectEscapeSequence(chars) {
            // Nothing to do, it is already collected
        } else {
            // Not part of a string literal body, end here
            break
        }
    }
    // Closing "
    if chars.Head() != '"' {
        panic("Expected closing \"")
    }
    chars.Collect()
    return chars.PopCollected()
}

func collectEscapeSequence(chars RuneStream) bool {
    if chars.Head() != '\\' {
        return false
    }
    chars.Collect()
    if chars.Head() == 'u' {
        chars.Collect()
        // Unicode sequence, collect at least 1 hex digit and at most 8
        if !isHexDigit(chars.Head()) {
            panic("Expected at least one hexadecimal digit in Unicode sequence")
        }
        chars.Collect()
        for i := 1; i < 8 && isHexDigit(chars.Head()); i++ {
            chars.Collect()
        }
        return true
    }
    if runesContain(ESCAPE_LITERALS, chars.Head()) {
        chars.Collect()
        return true
    }
    return false
}

func isIdentifierStart(c rune) bool {
    return c == '_' || isLetter(c)
}

func isIdentifierBody(c rune) bool {
    return isIdentifierStart(c) || isDigit(c)
}

func isLetter(c rune) bool {
    return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
}

func isBinaryDigit(c rune) bool {
    return c == '0' || c == '1'
}

func isDigit(c rune) bool {
    return isBinaryDigit(c) || c >= '2' && c <= '9'
}

func isHexDigit(c rune) bool {
    return isDigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
}

func isPrintChar(c rune) bool {
    return c >= '!' && c <= '~'
}

func isNewLineChar(c rune) bool {
    return c == '\n' || c == '\r'
}

func isLineWhiteSpace(c rune) bool {
    return c == ' ' || c == '\t'
}

func isWhiteSpace(c rune) bool {
    return isNewLineChar(c) || isLineWhiteSpace(c)
}

var SYMBOLS = []rune{
    '!', '@', '%', '?', '&', '*', '(', ')', '-', '=', '+', '/', '^', ':', '<', '>', '[', ']', '.', ',', '~',
}

func isSymbol(c rune) bool {
    return runesContain(SYMBOLS, c)
}

var KEYWORDS = [][]rune{
    []rune("when"), []rune("with"), []rune("then"), []rune("match"), []rune("if"), []rune("else"), []rune("for"), []rune("for_rev"), []rune("while"),
    []rune("do"), []rune("try"), []rune("catch"), []rune("finally"), []rune("let"), []rune("var"), []rune("class"), []rune("void"), []rune("break"),
    []rune("continue"), []rune("throw"), []rune("bool"), []rune("byte"), []rune("char"), []rune("short"), []rune("int"), []rune("long"), []rune("float"),
    []rune("double"), []rune("static"), []rune("import"), []rune("package"), []rune("new"), []rune("is"), []rune("throws"), []rune("public"), []rune("return"),
    []rune("this"), []rune("super"),
}

func isKeyword(cs []rune) bool {
    for _, keyword := range KEYWORDS {
        if (runesEquals(cs, keyword)) {
            return true
        }
    }
    return false
}

var FALSE_LITERAL = []rune("false")
var TRUE_LITERAL = []rune("true")

func isBooleanLiteral(cs []rune) bool {
    return runesEquals(cs, FALSE_LITERAL) || runesEquals(cs, TRUE_LITERAL)
}

var ESCAPE_LITERALS = []rune{
    'a', 'b', 't', 'n', 'v', 'f', 'r', '"', '\\',
}

func runesContain(a []rune, b rune) bool {
    for _, r := range a {
        if r == b {
            return true
        }
    }
    return false
}

func runesEquals(a []rune, b []rune) bool {
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}
<commit_msg>Rename consume to collect in Tokenizer where relevant<commit_after>package lang

type Tokenizer struct {
    chars RuneStream
    headToken *Token
    ahead bool
    firstToken bool
}

func StringTokenizer(source string) *Tokenizer {
    return &Tokenizer{chars: &StringRuneStream{source: source}, ahead: false, firstToken: true}
}

func (this *Tokenizer) Has() bool {
    return this.Head() != EofToken
}

func (this *Tokenizer) Head() *Token {
    if !this.ahead {
        this.headToken = this.next()
        this.ahead = true
    }
    return this.headToken
}

func (this *Tokenizer) Advance() {
    this.Head()
    this.ahead = false
}

func (this *Tokenizer) next() *Token {
    var token *Token = EofToken
    if (this.firstToken) {
        // First token can be indentation, which in this case
        // is not after a new line
        if isLineWhiteSpace(this.chars.Head()) {
            token = Indentation(collectIndentation(this.chars))
        }
        for consumeIgnored(this.chars) {
            // Remove trailing comments and whitespace
        }
        this.firstToken = false
    }
    for this.chars.Has() && token == EofToken {
        if isNewLineChar(this.chars.Head()) {
            consumeNewLine(this.chars)
            // Just after a new line, try to consume indentation
            if isLineWhiteSpace(this.chars.Head()) {
                token = Indentation(collectIndentation(this.chars))
            }
        } else if this.chars.Head() == ';' {
            // A terminator breaks a line but doesn't need indentation
            this.chars.Advance()
            token = TerminatorToken
        } else if isIdentifierStart(this.chars.Head()) {
            this.chars.Collect()
            identifier := collectIdentifierBody(this.chars)
            // An indentifier can also be a keyword
            if isKeyword(identifier) {
                token = Keyword(identifier)
            } else if isBooleanLiteral(identifier) {
                token = BooleanLiteral(identifier)
            } else {
                token = Identifier(identifier)
            }
        } else if isSymbol(this.chars.Head()) {
            token = Symbol(collectSymbol(this.chars))
        } else if this.chars.Head() == '"' {
            token = StringLiteral(collectStringLiteral(this.chars))
        }
        for consumeIgnored(this.chars) {
            // Remove trailing comments and whitespace
        }
    }
    return token
}

func collectIdentifierBody(chars RuneStream) []rune {
    for isIdentifierBody(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func consumeIgnored(chars RuneStream) bool {
    if isLineWhiteSpace(chars.Head()) {
        // Consume a line whitespace character
        chars.Advance()
        return true
    }
    if chars.Head() == '#' {
        // Consume a comment
        chars.Advance()
        if (chars.Head() == '#') {
            chars.Advance()
            completeBlockComment(chars)
        } else {
            completeLineComment(chars)
        }
        return true
    }
    if chars.Head() == '\\' {
        // Consume an escaped new line
        chars.Advance()
        if !isNewLineChar(chars.Head()) {
            panic("Expected new line character")
        }
        chars.Advance()
        // Consume more escaped new lines
        for isNewLineChar(chars.Head()) {
            chars.Advance()
        }
        return true
    }
    return false
}

func completeBlockComment(chars RuneStream) {
    // Count and consume leading # symbols
    leading := 2
    for chars.Head() == '#' {
        leading++
        chars.Advance()
    }
    // Consume print and white space characters
    // and look for a matching count of consecutive #
    trailing := 0
    for trailing < leading {
        if chars.Head() == '#' {
            trailing++
        } else if isPrintChar(chars.Head()) || isWhiteSpace(chars.Head()) {
            trailing = 0
        } else {
            panic("Unexpected character")
        }
        chars.Advance()
    }
}

func completeLineComment(chars RuneStream) {
    for isPrintChar(chars.Head()) || isLineWhiteSpace(chars.Head()) {
        chars.Advance()
    }
}

func consumeNewLine(chars RuneStream) {
    if chars.Head() == '\r'{
        // CR
        chars.Advance()
        if chars.Head() == '\n' {
            // CR LF
            chars.Advance()
        }
    } else if chars.Head() == '\n' {
        // LF
        chars.Advance()
    }
}

func collectIndentation(chars RuneStream) []rune {
    for isLineWhiteSpace(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func collectSymbol(chars RuneStream) []rune {
    for isSymbol(chars.Head()) {
        chars.Collect()
    }
    return chars.PopCollected()
}

func collectStringLiteral(chars RuneStream) []rune {
    // Opening "
    if chars.Head() != '"' {
        panic("Expected opening \"")
    }
    chars.Collect()
    // String contents
    for {
        if isPrintChar(chars.Head()) && chars.Head() != '"' && chars.Head() != '\\' {
            chars.Collect()
        } else if isLineWhiteSpace(chars.Head()) {
            chars.Collect()
        } else if collectEscapeSequence(chars) {
            // Nothing to do, it is already collected
        } else {
            // Not part of a string literal body, end here
            break
        }
    }
    // Closing "
    if chars.Head() != '"' {
        panic("Expected closing \"")
    }
    chars.Collect()
    return chars.PopCollected()
}

func collectEscapeSequence(chars RuneStream) bool {
    if chars.Head() != '\\' {
        return false
    }
    chars.Collect()
    if chars.Head() == 'u' {
        chars.Collect()
        // Unicode sequence, collect at least 1 hex digit and at most 8
        if !isHexDigit(chars.Head()) {
            panic("Expected at least one hexadecimal digit in Unicode sequence")
        }
        chars.Collect()
        for i := 1; i < 8 && isHexDigit(chars.Head()); i++ {
            chars.Collect()
        }
        return true
    }
    if runesContain(ESCAPE_LITERALS, chars.Head()) {
        chars.Collect()
        return true
    }
    return false
}

func isIdentifierStart(c rune) bool {
    return c == '_' || isLetter(c)
}

func isIdentifierBody(c rune) bool {
    return isIdentifierStart(c) || isDigit(c)
}

func isLetter(c rune) bool {
    return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'
}

func isBinaryDigit(c rune) bool {
    return c == '0' || c == '1'
}

func isDigit(c rune) bool {
    return isBinaryDigit(c) || c >= '2' && c <= '9'
}

func isHexDigit(c rune) bool {
    return isDigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
}

func isPrintChar(c rune) bool {
    return c >= '!' && c <= '~'
}

func isNewLineChar(c rune) bool {
    return c == '\n' || c == '\r'
}

func isLineWhiteSpace(c rune) bool {
    return c == ' ' || c == '\t'
}

func isWhiteSpace(c rune) bool {
    return isNewLineChar(c) || isLineWhiteSpace(c)
}

var SYMBOLS = []rune{
    '!', '@', '%', '?', '&', '*', '(', ')', '-', '=', '+', '/', '^', ':', '<', '>', '[', ']', '.', ',', '~',
}

func isSymbol(c rune) bool {
    return runesContain(SYMBOLS, c)
}

var KEYWORDS = [][]rune{
    []rune("when"), []rune("with"), []rune("then"), []rune("match"), []rune("if"), []rune("else"), []rune("for"), []rune("for_rev"), []rune("while"),
    []rune("do"), []rune("try"), []rune("catch"), []rune("finally"), []rune("let"), []rune("var"), []rune("class"), []rune("void"), []rune("break"),
    []rune("continue"), []rune("throw"), []rune("bool"), []rune("byte"), []rune("char"), []rune("short"), []rune("int"), []rune("long"), []rune("float"),
    []rune("double"), []rune("static"), []rune("import"), []rune("package"), []rune("new"), []rune("is"), []rune("throws"), []rune("public"), []rune("return"),
    []rune("this"), []rune("super"),
}

func isKeyword(cs []rune) bool {
    for _, keyword := range KEYWORDS {
        if (runesEquals(cs, keyword)) {
            return true
        }
    }
    return false
}

var FALSE_LITERAL = []rune("false")
var TRUE_LITERAL = []rune("true")

func isBooleanLiteral(cs []rune) bool {
    return runesEquals(cs, FALSE_LITERAL) || runesEquals(cs, TRUE_LITERAL)
}

var ESCAPE_LITERALS = []rune{
    'a', 'b', 't', 'n', 'v', 'f', 'r', '"', '\\',
}

func runesContain(a []rune, b rune) bool {
    for _, r := range a {
        if r == b {
            return true
        }
    }
    return false
}

func runesEquals(a []rune, b []rune) bool {
    if len(a) != len(b) {
        return false
    }
    for i := range a {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}
<|endoftext|>


<commit_before>package namespace

import (
	"fmt"
	"strings"

	ds "github.com/ipfs/go-datastore"
	ktds "github.com/ipfs/go-datastore/keytransform"
	dsq "github.com/ipfs/go-datastore/query"
)

// PrefixTransform constructs a KeyTransform with a pair of functions that
// add or remove the given prefix key.
//
// Warning: will panic if prefix not found when it should be there. This is
// to avoid insidious data inconsistency errors.
func PrefixTransform(prefix ds.Key) ktds.KeyTransform {
	return &ktds.Pair{

		// Convert adds the prefix
		Convert: func(k ds.Key) ds.Key {
			return prefix.Child(k)
		},

		// Invert removes the prefix. panics if prefix not found.
		Invert: func(k ds.Key) ds.Key {
			if !prefix.IsAncestorOf(k) {
				fmt.Errorf("Expected prefix (%s) in key (%s)", prefix, k)
				panic("expected prefix not found")
			}

			s := strings.TrimPrefix(k.String(), prefix.String())
			return ds.NewKey(s)
		},
	}
}

// Wrap wraps a given datastore with a key-prefix.
func Wrap(child ds.Datastore, prefix ds.Key) *datastore {
	if child == nil {
		panic("child (ds.Datastore) is nil")
	}

	d := ktds.Wrap(child, PrefixTransform(prefix))
	return &datastore{Datastore: d, raw: child, prefix: prefix}
}

type datastore struct {
	prefix ds.Key
	raw    ds.Datastore
	ktds.Datastore
}

// Query implements Query, inverting keys on the way back out.
func (d *datastore) Query(q dsq.Query) (dsq.Results, error) {
	qr, err := d.raw.Query(q)
	if err != nil {
		return nil, err
	}

	ch := make(chan dsq.Result)
	go func() {
		defer close(ch)
		defer qr.Close()

		for r := range qr.Next() {
			if r.Error != nil {
				ch <- r
				continue
			}

			k := ds.NewKey(r.Entry.Key)
			if !d.prefix.IsAncestorOf(k) {
				continue
			}

			r.Entry.Key = d.Datastore.InvertKey(k).String()
			ch <- r
		}
	}()

	return dsq.DerivedResults(qr, ch), nil
}

func (d *datastore) Batch() (ds.Batch, error) {
	if bds, ok := d.Datastore.(ds.Batching); ok {
		return bds.Batch()
	}

	return nil, ds.ErrBatchUnsupported
}
<commit_msg>Fix channel buffer size in namespace datastore to use KeysOnlyBufSize<commit_after>package namespace

import (
	"fmt"
	"strings"

	ds "github.com/ipfs/go-datastore"
	ktds "github.com/ipfs/go-datastore/keytransform"
	dsq "github.com/ipfs/go-datastore/query"
)

// PrefixTransform constructs a KeyTransform with a pair of functions that
// add or remove the given prefix key.
//
// Warning: will panic if prefix not found when it should be there. This is
// to avoid insidious data inconsistency errors.
func PrefixTransform(prefix ds.Key) ktds.KeyTransform {
	return &ktds.Pair{

		// Convert adds the prefix
		Convert: func(k ds.Key) ds.Key {
			return prefix.Child(k)
		},

		// Invert removes the prefix. panics if prefix not found.
		Invert: func(k ds.Key) ds.Key {
			if !prefix.IsAncestorOf(k) {
				fmt.Errorf("Expected prefix (%s) in key (%s)", prefix, k)
				panic("expected prefix not found")
			}

			s := strings.TrimPrefix(k.String(), prefix.String())
			return ds.NewKey(s)
		},
	}
}

// Wrap wraps a given datastore with a key-prefix.
func Wrap(child ds.Datastore, prefix ds.Key) *datastore {
	if child == nil {
		panic("child (ds.Datastore) is nil")
	}

	d := ktds.Wrap(child, PrefixTransform(prefix))
	return &datastore{Datastore: d, raw: child, prefix: prefix}
}

type datastore struct {
	prefix ds.Key
	raw    ds.Datastore
	ktds.Datastore
}

// Query implements Query, inverting keys on the way back out.
func (d *datastore) Query(q dsq.Query) (dsq.Results, error) {
	qr, err := d.raw.Query(q)
	if err != nil {
		return nil, err
	}

	var ch chan dsq.Result
	if q.KeysOnly {
		ch = make(chan dsq.Result, dsq.KeysOnlyBufSize)
	} else {
		ch = make(chan dsq.Result)
	}

	go func() {
		defer close(ch)
		defer qr.Close()

		for r := range qr.Next() {
			if r.Error != nil {
				ch <- r
				continue
			}

			k := ds.NewKey(r.Entry.Key)
			if !d.prefix.IsAncestorOf(k) {
				continue
			}

			r.Entry.Key = d.Datastore.InvertKey(k).String()
			ch <- r
		}
	}()

	return dsq.DerivedResults(qr, ch), nil
}

func (d *datastore) Batch() (ds.Batch, error) {
	if bds, ok := d.Datastore.(ds.Batching); ok {
		return bds.Batch()
	}

	return nil, ds.ErrBatchUnsupported
}
<|endoftext|>


<commit_before>package main

import "net/http"

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe(":8080", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello!"))
}
<commit_msg>throwing an error to test build system<commit_after>package main

import "net/http"

func main() {
	http.HandleFunc("/", hello)
	http.ListenAndServe("127.0.0.1:8080", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
	http.Error(w, "Error", http.StatusInternalServerError)

	//	w.Write([]byte("hello!"))
}
<|endoftext|>