<commit_before>package interpreter

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"../dos"
)

type StatementT struct {
	Argv     []string
	Redirect []*Redirecter
	Term     string
}

var prefix []string = []string{" 0<", " 1>", " 2>"}

var PercentFunc = map[string]func() string{
	"CD": func() string {
		wd, err := os.Getwd()
		if err == nil {
			return wd
		} else {
			return ""
		}
	},
	"ERRORLEVEL": func() string {
		return ErrorLevelStr
	},
}

var rxUnicode = regexp.MustCompile("^[uU]\\+?([0-9a-fA-F]+)$")

func OurGetEnv(name string) (string, bool) {
	value := os.Getenv(name)
	if value != "" {
		return value, true
	} else if m := rxUnicode.FindStringSubmatch(name); m != nil {
		ucode, _ := strconv.ParseInt(m[1], 16, 32)
		return fmt.Sprintf("%c", rune(ucode)), true
	} else if f, ok := PercentFunc[strings.ToUpper(name)]; ok {
		return f(), true
	} else {
		return "", false
	}
}

func chomp(buffer *bytes.Buffer) {
	original := buffer.String()
	buffer.Reset()
	var lastchar rune
	for i, ch := range original {
		if i > 0 {
			buffer.WriteRune(lastchar)
		}
		lastchar = ch
	}
}

const NOTQUOTED = '\000'

const EMPTY_COMMAND_FOUND = "Empty command found"

func dequote(source *bytes.Buffer) string {
	var buffer bytes.Buffer

	lastchar := ' '
	quoteNow := NOTQUOTED
	yenCount := 0
	for {
		ch, _, err := source.ReadRune()
		if err != nil {
			break
		}
		if ch == '~' && unicode.IsSpace(lastchar) {
			if home := dos.GetHome(); home != "" {
				buffer.WriteString(home)
			} else {
				buffer.WriteRune('~')
			}
			lastchar = '~'
			continue
		}
		if ch == '%' && quoteNow != '\'' && yenCount%2 == 0 {
			var nameBuf bytes.Buffer
			for {
				ch, _, err = source.ReadRune()
				if err != nil {
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					return buffer.String()
				}
				if ch == '%' {
					nameStr := nameBuf.String()
					if value, ok := OurGetEnv(nameStr); ok {
						buffer.WriteString(value)
					} else {
						buffer.WriteRune('%')
						buffer.WriteString(nameStr)
						buffer.WriteRune('%')
					}
					break
				}
				if !unicode.IsLower(ch) && !unicode.IsUpper(ch) && !unicode.IsNumber(ch) && ch != '_' && ch != '+' {
					source.UnreadRune()
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					break
				}
				nameBuf.WriteRune(ch)
			}
			continue
		}

		if quoteNow != NOTQUOTED && ch == quoteNow && yenCount%2 == 0 {
			// Close Quotation.
			for ; yenCount >= 2; yenCount -= 2 {
				buffer.WriteRune('\\')
			}
			quoteNow = NOTQUOTED
		} else if (ch == '\'' || ch == '"') && quoteNow == NOTQUOTED && yenCount%2 == 0 {
			// Open Qutation.
			for ; yenCount >= 2; yenCount -= 2 {
				buffer.WriteRune('\\')
			}
			quoteNow = ch
			if ch == lastchar {
				buffer.WriteRune(ch)
			}
		} else {
			if ch == '\\' {
				yenCount++
			} else if ch == '\'' || ch == '"' {
				for ; yenCount >= 2; yenCount -= 2 {
					buffer.WriteRune('\\')
				}
				yenCount = 0
				buffer.WriteRune(ch)
			} else {
				for ; yenCount > 0; yenCount-- {
					buffer.WriteRune('\\')
				}
				buffer.WriteRune(ch)
			}
		}
		lastchar = ch
	}
	for ; yenCount > 0; yenCount-- {
		buffer.WriteRune('\\')
	}
	return buffer.String()
}

func terminate(statements *[]*StatementT,
	isRedirected *bool,
	redirect *[]*Redirecter,
	buffer *bytes.Buffer,
	argv *[]string,
	term string) {

	statement1 := new(StatementT)
	if buffer.Len() > 0 {
		if *isRedirected && len(*redirect) > 0 {
			(*redirect)[len(*redirect)-1].SetPath(dequote(buffer))
			*isRedirected = false
			statement1.Argv = *argv
		} else {
			statement1.Argv = append(*argv, dequote(buffer))
		}
		buffer.Reset()
	} else if len(*argv) <= 0 {
		return
	} else {
		statement1.Argv = *argv
	}
	statement1.Redirect = *redirect
	*redirect = make([]*Redirecter, 0, 3)
	*argv = make([]string, 0)
	statement1.Term = term
	*statements = append(*statements, statement1)
}

func parse1(text string) ([]*StatementT, error) {
	quoteNow := NOTQUOTED
	yenCount := 0
	statements := make([]*StatementT, 0)
	argv := make([]string, 0)
	lastchar := ' '
	var buffer bytes.Buffer
	isNextRedirect := false
	redirect := make([]*Redirecter, 0, 3)

	TermWord := func() {
		if isNextRedirect && len(redirect) > 0 {
			redirect[len(redirect)-1].SetPath(dequote(&buffer))
		} else {
			if buffer.Len() > 0 {
				argv = append(argv, dequote(&buffer))
			}
		}
		buffer.Reset()
	}

	reader := strings.NewReader(text)
	for reader.Len() > 0 {
		ch, chSize, chErr := reader.ReadRune()
		if chSize <= 0 {
			break
		}
		if chErr != nil {
			return nil, chErr
		}
		if quoteNow == NOTQUOTED {
			if yenCount%2 == 0 && (ch == '"' || ch == '\'') {
				quoteNow = ch
			}
		} else if yenCount%2 == 0 && ch == quoteNow {
			quoteNow = NOTQUOTED
		}
		if quoteNow != NOTQUOTED {
			buffer.WriteRune(ch)
		} else if ch == ' ' {
			if buffer.Len() > 0 {
				TermWord()
				isNextRedirect = false
			}
		} else if lastchar == ' ' && ch == ';' {
			terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, ";")
		} else if ch == '|' {
			if lastchar == '|' {
				if len(statements) <= 0 {
					return nil, errors.New(EMPTY_COMMAND_FOUND)
				}
				statements[len(statements)-1].Term = "||"
			} else {
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "|")
			}
		} else if ch == '&' {
			switch lastchar {
			case '&':
				if len(statements) <= 0 {
					return nil, errors.New(EMPTY_COMMAND_FOUND)
				}
				statements[len(statements)-1].Term = "&&"
			case '|':
				if len(statements) <= 0 {
					return nil, errors.New(EMPTY_COMMAND_FOUND)
				}
				statements[len(statements)-1].Term = "|&"
			case '>':
				// >&[n]
				ch2, ch2siz, ch2err := reader.ReadRune()
				if ch2err != nil {
					return nil, ch2err
				}
				if ch2siz <= 0 {
					return nil, errors.New("Too Near EOF for >&")
				}
				red := redirect[len(redirect)-1]
				switch ch2 {
				case '1':
					red.DupFrom(1)
				case '2':
					red.DupFrom(2)
				default:
					return nil, errors.New("Syntax error after >&")
				}
				isNextRedirect = false
			default:
				terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "&")
			}
		} else if ch == '>' {
			switch lastchar {
			case '1':
				// 1>
				chomp(&buffer)
				TermWord()
				redirect = append(redirect, NewRedirecter(1))
			case '2':
				// 2>
				chomp(&buffer)
				TermWord()
				redirect = append(redirect, NewRedirecter(2))
			case '>':
				// >>
				TermWord()
				if len(redirect) >= 0 {
					redirect[len(redirect)-1].SetAppend()
				}
			default:
				// >
				TermWord()
				redirect = append(redirect, NewRedirecter(1))
			}
			isNextRedirect = true
		} else if ch == '<' {
			TermWord()
			redirect = append(redirect, NewRedirecter(0))
			isNextRedirect = true
		} else {
			buffer.WriteRune(ch)
		}
		if ch == '\\' {
			yenCount++
		} else {
			yenCount = 0
		}
		lastchar = ch
	}
	terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, " ")
	return statements, nil
}

// Make arrays whose elements are pipelines
func parse2(statements []*StatementT) [][]*StatementT {
	result := make([][]*StatementT, 1)
	for _, statement1 := range statements {
		result[len(result)-1] = append(result[len(result)-1], statement1)
		switch statement1.Term {
		case "|", "|&":

		default:
			result = append(result, make([]*StatementT, 0))
		}
	}
	if len(result[len(result)-1]) <= 0 {
		result = result[0 : len(result)-1]
	}
	return result
}

func Parse(text string) ([][]*StatementT, error) {
	result1, err := parse1(text)
	if err != nil {
		return nil, err
	}
	result2 := parse2(result1)
	return result2, nil
}
<commit_msg>Fix: 'A | (empty)' was not errored and A was executed.<commit_after>package interpreter

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"

	"../dos"
)

type StatementT struct {
	Argv     []string
	Redirect []*Redirecter
	Term     string
}

var prefix []string = []string{" 0<", " 1>", " 2>"}

var PercentFunc = map[string]func() string{
	"CD": func() string {
		wd, err := os.Getwd()
		if err == nil {
			return wd
		} else {
			return ""
		}
	},
	"ERRORLEVEL": func() string {
		return ErrorLevelStr
	},
}

var rxUnicode = regexp.MustCompile("^[uU]\\+?([0-9a-fA-F]+)$")

func OurGetEnv(name string) (string, bool) {
	value := os.Getenv(name)
	if value != "" {
		return value, true
	} else if m := rxUnicode.FindStringSubmatch(name); m != nil {
		ucode, _ := strconv.ParseInt(m[1], 16, 32)
		return fmt.Sprintf("%c", rune(ucode)), true
	} else if f, ok := PercentFunc[strings.ToUpper(name)]; ok {
		return f(), true
	} else {
		return "", false
	}
}

func chomp(buffer *bytes.Buffer) {
	original := buffer.String()
	buffer.Reset()
	var lastchar rune
	for i, ch := range original {
		if i > 0 {
			buffer.WriteRune(lastchar)
		}
		lastchar = ch
	}
}

const NOTQUOTED = '\000'

var EmptyCommandFound = errors.New("Empty command found")

func dequote(source *bytes.Buffer) string {
	var buffer bytes.Buffer

	lastchar := ' '
	quoteNow := NOTQUOTED
	yenCount := 0
	for {
		ch, _, err := source.ReadRune()
		if err != nil {
			break
		}
		if ch == '~' && unicode.IsSpace(lastchar) {
			if home := dos.GetHome(); home != "" {
				buffer.WriteString(home)
			} else {
				buffer.WriteRune('~')
			}
			lastchar = '~'
			continue
		}
		if ch == '%' && quoteNow != '\'' && yenCount%2 == 0 {
			var nameBuf bytes.Buffer
			for {
				ch, _, err = source.ReadRune()
				if err != nil {
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					return buffer.String()
				}
				if ch == '%' {
					nameStr := nameBuf.String()
					if value, ok := OurGetEnv(nameStr); ok {
						buffer.WriteString(value)
					} else {
						buffer.WriteRune('%')
						buffer.WriteString(nameStr)
						buffer.WriteRune('%')
					}
					break
				}
				if !unicode.IsLower(ch) && !unicode.IsUpper(ch) && !unicode.IsNumber(ch) && ch != '_' && ch != '+' {
					source.UnreadRune()
					buffer.WriteRune('%')
					buffer.WriteString(nameBuf.String())
					break
				}
				nameBuf.WriteRune(ch)
			}
			continue
		}

		if quoteNow != NOTQUOTED && ch == quoteNow && yenCount%2 == 0 {
			// Close Quotation.
			for ; yenCount >= 2; yenCount -= 2 {
				buffer.WriteRune('\\')
			}
			quoteNow = NOTQUOTED
		} else if (ch == '\'' || ch == '"') && quoteNow == NOTQUOTED && yenCount%2 == 0 {
			// Open Qutation.
			for ; yenCount >= 2; yenCount -= 2 {
				buffer.WriteRune('\\')
			}
			quoteNow = ch
			if ch == lastchar {
				buffer.WriteRune(ch)
			}
		} else {
			if ch == '\\' {
				yenCount++
			} else if ch == '\'' || ch == '"' {
				for ; yenCount >= 2; yenCount -= 2 {
					buffer.WriteRune('\\')
				}
				yenCount = 0
				buffer.WriteRune(ch)
			} else {
				for ; yenCount > 0; yenCount-- {
					buffer.WriteRune('\\')
				}
				buffer.WriteRune(ch)
			}
		}
		lastchar = ch
	}
	for ; yenCount > 0; yenCount-- {
		buffer.WriteRune('\\')
	}
	return buffer.String()
}

func terminate(statements *[]*StatementT,
	isRedirected *bool,
	redirect *[]*Redirecter,
	buffer *bytes.Buffer,
	argv *[]string,
	term string) error {

	statement1 := new(StatementT)
	if buffer.Len() > 0 {
		if *isRedirected && len(*redirect) > 0 {
			(*redirect)[len(*redirect)-1].SetPath(dequote(buffer))
			*isRedirected = false
			statement1.Argv = *argv
		} else {
			statement1.Argv = append(*argv, dequote(buffer))
		}
		buffer.Reset()
	} else if len(*argv) <= 0 {
		return EmptyCommandFound
	} else {
		statement1.Argv = *argv
	}
	statement1.Redirect = *redirect
	*redirect = make([]*Redirecter, 0, 3)
	*argv = make([]string, 0)
	statement1.Term = term
	*statements = append(*statements, statement1)
	return nil
}

func parse1(text string) ([]*StatementT, error) {
	quoteNow := NOTQUOTED
	yenCount := 0
	statements := make([]*StatementT, 0)
	argv := make([]string, 0)
	lastchar := ' '
	var buffer bytes.Buffer
	isNextRedirect := false
	redirect := make([]*Redirecter, 0, 3)

	TermWord := func() {
		if isNextRedirect && len(redirect) > 0 {
			redirect[len(redirect)-1].SetPath(dequote(&buffer))
		} else {
			if buffer.Len() > 0 {
				argv = append(argv, dequote(&buffer))
			}
		}
		buffer.Reset()
	}

	reader := strings.NewReader(text)
	for reader.Len() > 0 {
		ch, chSize, chErr := reader.ReadRune()
		if chSize <= 0 {
			break
		}
		if chErr != nil {
			return nil, chErr
		}
		if quoteNow == NOTQUOTED {
			if yenCount%2 == 0 && (ch == '"' || ch == '\'') {
				quoteNow = ch
			}
		} else if yenCount%2 == 0 && ch == quoteNow {
			quoteNow = NOTQUOTED
		}
		if quoteNow != NOTQUOTED {
			buffer.WriteRune(ch)
		} else if ch == ' ' {
			if buffer.Len() > 0 {
				TermWord()
				isNextRedirect = false
			}
		} else if lastchar == ' ' && ch == ';' {
			if err := terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, ";"); err != nil {
				return nil, err
			}
		} else if ch == '|' {
			if lastchar == '|' {
				if len(statements) <= 0 {
					return nil, EmptyCommandFound
				}
				statements[len(statements)-1].Term = "||"
			} else {
				if err := terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "|"); err != nil {
					return nil, err
				}
			}
		} else if ch == '&' {
			switch lastchar {
			case '&':
				if len(statements) <= 0 {
					return nil, EmptyCommandFound
				}
				statements[len(statements)-1].Term = "&&"
			case '|':
				if len(statements) <= 0 {
					return nil, EmptyCommandFound
				}
				statements[len(statements)-1].Term = "|&"
			case '>':
				// >&[n]
				ch2, ch2siz, ch2err := reader.ReadRune()
				if ch2err != nil {
					return nil, ch2err
				}
				if ch2siz <= 0 {
					return nil, errors.New("Too Near EOF for >&")
				}
				red := redirect[len(redirect)-1]
				switch ch2 {
				case '1':
					red.DupFrom(1)
				case '2':
					red.DupFrom(2)
				default:
					return nil, errors.New("Syntax error after >&")
				}
				isNextRedirect = false
			default:
				if err := terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, "&"); err != nil {
					return nil, err
				}
			}
		} else if ch == '>' {
			switch lastchar {
			case '1':
				// 1>
				chomp(&buffer)
				TermWord()
				redirect = append(redirect, NewRedirecter(1))
			case '2':
				// 2>
				chomp(&buffer)
				TermWord()
				redirect = append(redirect, NewRedirecter(2))
			case '>':
				// >>
				TermWord()
				if len(redirect) >= 0 {
					redirect[len(redirect)-1].SetAppend()
				}
			default:
				// >
				TermWord()
				redirect = append(redirect, NewRedirecter(1))
			}
			isNextRedirect = true
		} else if ch == '<' {
			TermWord()
			redirect = append(redirect, NewRedirecter(0))
			isNextRedirect = true
		} else {
			buffer.WriteRune(ch)
		}
		if ch == '\\' {
			yenCount++
		} else {
			yenCount = 0
		}
		lastchar = ch
	}
	if err := terminate(&statements, &isNextRedirect, &redirect, &buffer, &argv, " "); err != nil {
		return nil, err
	}
	return statements, nil
}

// Make arrays whose elements are pipelines
func parse2(statements []*StatementT) [][]*StatementT {
	result := make([][]*StatementT, 1)
	for _, statement1 := range statements {
		result[len(result)-1] = append(result[len(result)-1], statement1)
		switch statement1.Term {
		case "|", "|&":

		default:
			result = append(result, make([]*StatementT, 0))
		}
	}
	if len(result[len(result)-1]) <= 0 {
		result = result[0 : len(result)-1]
	}
	return result
}

func Parse(text string) ([][]*StatementT, error) {
	result1, err := parse1(text)
	if err != nil {
		return nil, err
	}
	result2 := parse2(result1)
	return result2, nil
}
<|endoftext|>


<commit_before>package expr

import (
	"testing"
)

func TestAPIExprSchemes(t *testing.T) {
	cases := map[string]struct {
		expr     APIExpr
		expected []string
	}{
		"default scheme": {
			expr: APIExpr{
				Servers: []*ServerExpr{&ServerExpr{}},
			},
			expected: nil,
		},
		"single scheme": {
			expr: APIExpr{
				Servers: []*ServerExpr{
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"http://example.com"}},
						},
					},
				},
			},
			expected: []string{"http"},
		},
		"multiple schemes": {
			expr: APIExpr{
				Servers: []*ServerExpr{
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"http://example.com"}},
						},
					},
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"https://example.net"}},
						},
					},
				},
			},
			expected: []string{"http", "https"},
		},
	}
	for k, tc := range cases {
		if actual := tc.expr.Schemes(); len(tc.expected) != len(actual) {
			t.Errorf("%s: expected the number of scheme values to match %d got %d ", k, len(tc.expected), len(actual))
		} else {
			for i, v := range actual {
				if v != tc.expected[i] {
					t.Errorf("%s: got %#v, expected %#v at index %d", k, v, tc.expected[i], i)
				}
			}
		}
	}
}

func TestAPIExprEvalName(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo": {name: "foo", expected: "API foo"},
	}

	for k, tc := range cases {
		api := APIExpr{Name: tc.name}
		if actual := api.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestAPIExprFinalize(t *testing.T) {
	cases := map[string]struct {
		api      *APIExpr
		expected []string
	}{
		"empty name, empty server": {
			api:      &APIExpr{},
			expected: []string{"Default server for api"},
		},
		"empty server": {
			api: &APIExpr{
				Name: "my api",
			},
			expected: []string{"Default server for my api"},
		},
		"with server": {
			api: &APIExpr{
				Name:    "my api",
				Servers: []*ServerExpr{{Description: "my server"}},
			},
			expected: []string{"my server"},
		},
	}

	for k, tc := range cases {
		tc.api.Finalize()

		if actual := tc.api.Servers; len(tc.expected) != len(actual) {
			t.Errorf("%s: expected the number of servers to match %d got %d ", k, len(tc.expected), len(actual))
		} else {
			for i, v := range actual {
				if v.Description != tc.expected[i] {
					t.Errorf("%s: got %#v, expected %#v at index %d", k, v, tc.expected[i], i)
				}
			}
		}
	}
}

func TestApiExpr_Hash(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo":   {name: "foo", expected: "_api_+foo"},
		"empty": {name: "", expected: "_api_+"},
	}

	for k, tc := range cases {
		api := APIExpr{Name: tc.name}
		if actual := api.Hash(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestLicenseExprEvalName(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo": {name: "foo", expected: "License foo"},
	}

	for k, tc := range cases {
		license := LicenseExpr{Name: tc.name}
		if actual := license.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}
<commit_msg>Add tests for expr.DocsExpr.EvalName() and expr.ContactExpr.EvalName() (#2012)<commit_after>package expr

import (
	"testing"
)

func TestAPIExprSchemes(t *testing.T) {
	cases := map[string]struct {
		expr     APIExpr
		expected []string
	}{
		"default scheme": {
			expr: APIExpr{
				Servers: []*ServerExpr{&ServerExpr{}},
			},
			expected: nil,
		},
		"single scheme": {
			expr: APIExpr{
				Servers: []*ServerExpr{
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"http://example.com"}},
						},
					},
				},
			},
			expected: []string{"http"},
		},
		"multiple schemes": {
			expr: APIExpr{
				Servers: []*ServerExpr{
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"http://example.com"}},
						},
					},
					&ServerExpr{
						Hosts: []*HostExpr{
							{URIs: []URIExpr{"https://example.net"}},
						},
					},
				},
			},
			expected: []string{"http", "https"},
		},
	}
	for k, tc := range cases {
		if actual := tc.expr.Schemes(); len(tc.expected) != len(actual) {
			t.Errorf("%s: expected the number of scheme values to match %d got %d ", k, len(tc.expected), len(actual))
		} else {
			for i, v := range actual {
				if v != tc.expected[i] {
					t.Errorf("%s: got %#v, expected %#v at index %d", k, v, tc.expected[i], i)
				}
			}
		}
	}
}

func TestAPIExprEvalName(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo": {name: "foo", expected: "API foo"},
	}

	for k, tc := range cases {
		api := APIExpr{Name: tc.name}
		if actual := api.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestAPIExprFinalize(t *testing.T) {
	cases := map[string]struct {
		api      *APIExpr
		expected []string
	}{
		"empty name, empty server": {
			api:      &APIExpr{},
			expected: []string{"Default server for api"},
		},
		"empty server": {
			api: &APIExpr{
				Name: "my api",
			},
			expected: []string{"Default server for my api"},
		},
		"with server": {
			api: &APIExpr{
				Name:    "my api",
				Servers: []*ServerExpr{{Description: "my server"}},
			},
			expected: []string{"my server"},
		},
	}

	for k, tc := range cases {
		tc.api.Finalize()

		if actual := tc.api.Servers; len(tc.expected) != len(actual) {
			t.Errorf("%s: expected the number of servers to match %d got %d ", k, len(tc.expected), len(actual))
		} else {
			for i, v := range actual {
				if v.Description != tc.expected[i] {
					t.Errorf("%s: got %#v, expected %#v at index %d", k, v, tc.expected[i], i)
				}
			}
		}
	}
}

func TestApiExpr_Hash(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo":   {name: "foo", expected: "_api_+foo"},
		"empty": {name: "", expected: "_api_+"},
	}

	for k, tc := range cases {
		api := APIExpr{Name: tc.name}
		if actual := api.Hash(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}

func TestDocsExprEvalName(t *testing.T) {
	cases := map[string]struct {
		url         string
		expected    string
		description string
	}{
		"test, only with url":       {url: "http://parrot.com", expected: "Documentation http://parrot.com"},
		"test, description and url": {url: "http://parrot.com", description: "A website for a parrot API", expected: "Documentation http://parrot.com"},
		"test, only description":    {description: "A website for a parrot API", expected: "Documentation "},
		"test, empty url":           {url: "", expected: "Documentation "},
	}
	for k, tc := range cases {
		docExpr := DocsExpr{URL: tc.url, Description: tc.description}
		if actual := docExpr.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}
func TestContactExprEvalName(t *testing.T) {
	cases := map[string]struct {
		name     string
		email    string
		url      string
		expected string
	}{
		"test, only with name":   {name: "parrot", expected: "Contact parrot"},
		"test, name and email":   {name: "parrot", email: "parrot@gopher.com", expected: "Contact parrot"},
		"test, name and url":     {name: "parrot", url: "https://parrot.com", expected: "Contact parrot"},
		"test, name, url, email": {name: "parrot", email: "parrot@gopher.com", url: "https://parrot.com", expected: "Contact parrot"},
		"test, empty name":       {name: "", expected: "Contact "},
	}
	for k, tc := range cases {
		contactExpr := ContactExpr{Name: tc.name, Email: tc.email, URL: tc.url}
		if actual := contactExpr.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}
func TestLicenseExprEvalName(t *testing.T) {
	cases := map[string]struct {
		name     string
		expected string
	}{
		"foo": {name: "foo", expected: "License foo"},
	}

	for k, tc := range cases {
		license := LicenseExpr{Name: tc.name}
		if actual := license.EvalName(); actual != tc.expected {
			t.Errorf("%s: got %#v, expected %#v", k, actual, tc.expected)
		}
	}
}
<|endoftext|>


<commit_before>package algoliasearch

func checkQuery(query Map, ignore ...string) error {
Outer:
	for k, v := range query {
		// Continue if `k` is to be ignored.
		for _, s := range ignore {
			if s == k {
				continue Outer
			}
		}

		switch k {
		case "query",
			"queryType",
			"typoTolerance",
			"removeWordsIfNoResults",
			"restrictSearchableAttributes",
			"highlightPreTag",
			"highlightPostTag",
			"snippetEllipsisText",
			"filters",
			"analyticsTags",
			"optionalWords",
			"numericFilters",
			"tagFilters",
			"facets",
			"facetFilters",
			"aroundLatLng",
			"insideBoundingBox",
			"insidePolygon",
			"exactOnSingleWordQuery":
			if _, ok := v.(string); !ok {
				return invalidType(k, "string")
			}

		case "attributesToRetrieve",
			"disableTypoToleranceOnAttributes",
			"attributesToSnippet",
			"attributesToHighlight",
			"alternativesAsExact",
			"responseFields":
			if _, ok := v.([]string); !ok {
				return invalidType(k, "[]string")
			}

		case "minWordSizefor1Typo",
			"minWordSizefor2Typos",
			"minProximity",
			"page",
			"hitsPerPage",
			"distinct",
			"maxValuesPerFacet",
			"aroundPrecision",
			"minimumAroundRadius",
			"maxFacetHits":
			if _, ok := v.(int); !ok {
				return invalidType(k, "int")
			}

		case "allowTyposOnNumericTokens",
			"advancedSyntax",
			"analytics",
			"synonyms",
			"replaceSynonymsInHighlight",
			"aroundLatLngViaIP",
			"facetingAfterDistinct":
			if _, ok := v.(bool); !ok {
				return invalidType(k, "bool")
			}

		case "removeStopWords",
			"ignorePlurals":
			switch v.(type) {
			case []string, bool:
				// OK
			default:
				return invalidType(k, "[]string or bool")
			}

		case "aroundRadius":
			switch v.(type) {
			case int, string:
				// OK
			default:
				return invalidType(k, "int or string")
			}

		case "getRankingInfo":
			switch v.(type) {
			case int, bool:
				// OK
			default:
				return invalidType(k, "int or bool")
			}

		default:
		}

	}
	return nil
}
<commit_msg>fix: Accept numericFilters query parameter as string or []interface{}<commit_after>package algoliasearch

func checkQuery(query Map, ignore ...string) error {
Outer:
	for k, v := range query {
		// Continue if `k` is to be ignored.
		for _, s := range ignore {
			if s == k {
				continue Outer
			}
		}

		switch k {
		case "query",
			"queryType",
			"typoTolerance",
			"removeWordsIfNoResults",
			"restrictSearchableAttributes",
			"highlightPreTag",
			"highlightPostTag",
			"snippetEllipsisText",
			"filters",
			"analyticsTags",
			"optionalWords",
			"tagFilters",
			"facets",
			"facetFilters",
			"aroundLatLng",
			"insideBoundingBox",
			"insidePolygon",
			"exactOnSingleWordQuery":
			if _, ok := v.(string); !ok {
				return invalidType(k, "string")
			}

		case "attributesToRetrieve",
			"disableTypoToleranceOnAttributes",
			"attributesToSnippet",
			"attributesToHighlight",
			"alternativesAsExact",
			"responseFields":
			if _, ok := v.([]string); !ok {
				return invalidType(k, "[]string")
			}

		case "minWordSizefor1Typo",
			"minWordSizefor2Typos",
			"minProximity",
			"page",
			"hitsPerPage",
			"distinct",
			"maxValuesPerFacet",
			"aroundPrecision",
			"minimumAroundRadius",
			"maxFacetHits":
			if _, ok := v.(int); !ok {
				return invalidType(k, "int")
			}

		case "allowTyposOnNumericTokens",
			"advancedSyntax",
			"analytics",
			"synonyms",
			"replaceSynonymsInHighlight",
			"aroundLatLngViaIP",
			"facetingAfterDistinct":
			if _, ok := v.(bool); !ok {
				return invalidType(k, "bool")
			}

		case "removeStopWords",
			"ignorePlurals":
			switch v.(type) {
			case []string, bool:
				// OK
			default:
				return invalidType(k, "[]string or bool")
			}

		case "aroundRadius":
			switch v.(type) {
			case int, string:
				// OK
			default:
				return invalidType(k, "int or string")
			}

		case "getRankingInfo":
			switch v.(type) {
			case int, bool:
				// OK
			default:
				return invalidType(k, "int or bool")
			}

		case "numericFilters":
			switch v.(type) {
			case string, []interface{}:
				// OK
			default:
				return invalidType(k, "string or []interface{}")
			}

		default:
		}

	}
	return nil
}
<|endoftext|>


<commit_before>package algoliasearch

type multipleQueriesRes struct {
	Results []MultipleQueryRes `json:"results"`
}

type MultipleQueryRes struct {
	Index string `json:"index"`
	QueryRes
}

type QueryRes struct {
	Hits             []Map  `json:"hits"`
	HitsPerPage      int    `json:"hitsPerPage"`
	NbHits           int    `json:"nbHits"`
	NbPages          int    `json:"nbPages"`
	Page             int    `json:"page"`
	Map              string `json:"params"`
	ParsedQuery      string `json:"parsedQuery,omitempty"`
	ProcessingTimeMS int    `json:"processingTimeMS"`
	Query            string `json:"query"`
}

type IndexedQuery struct {
	IndexName string
	Params    Map
}
<commit_msg>Add missing fields to QueryRes + Fix one field (params)<commit_after>package algoliasearch

type multipleQueriesRes struct {
	Results []MultipleQueryRes `json:"results"`
}

type MultipleQueryRes struct {
	Index string `json:"index"`
	QueryRes
}

type QueryRes struct {
	AroundLatLng          string `json:"aroundLatLng,omitempty"`
	AutomaticRadius       string `json:"automaticRadius,omitempty"`
	ExhaustiveFacetsCount bool   `json:"exhaustiveFacetsCount,omitempty"`
	Facets                Map    `json:"facets,omitempty"`
	FacetsStats           Map    `json:"facets_stats,omitempty"`
	Hits                  []Map  `json:"hits"`
	HitsPerPage           int    `json:"hitsPerPage"`
	Index                 string `json:"index,omitempty"`
	Length                int    `json:"length,omitempty"`
	Message               string `json:"message,omitempty"`
	NbHits                int    `json:"nbHits"`
	NbPages               int    `json:"nbPages"`
	Offset                int    `json:"offset,omitempty"`
	Page                  int    `json:"page"`
	Params                string `json:"params"`
	ParsedQuery           string `json:"parsedQuery,omitempty"`
	ProcessingTimeMS      int    `json:"processingTimeMS"`
	Query                 string `json:"query"`
	QueryAfterRemoval     string `json:"queryAfterRemoval,omitempty"`
	ServerUsed            string `json:"serverUsed,omitempty"`
	TimeoutCounts         bool   `json:"timeoutCounts,omitempty"`
	TimeoutHits           bool   `json:"timeoutHits,omitempty"`
}

type IndexedQuery struct {
	IndexName string
	Params    Map
}
<|endoftext|>


<commit_before>package runtime

import "unsafe"

// Atman implements a round-robin cooperative scheduler,
// heavily inspired by libtask.

var (
	taskid = 1
	taskn  = 1

	// taskcurrent is initialized as an empty Task with ID 0.
	// The first time a context switch is requested,
	// its context will be filled in and it will become
	// a normal Task.
	taskcurrent = &Task{ID: 0}

	taskrunqueue   TaskList
	tasksleepqueue TaskList
)

func init() {
	taskcurrent.semawaiter.task = taskcurrent
}

type Task struct {
	ID int

	Context Context

	WakeAt int64

	Next, Prev *Task

	semawaiter
}

func (t *Task) debug() {
	println("Task{ID: ", t.ID, ", WakeAt: ", t.WakeAt, "}")
}

// taskcreate spawns a new task,
// executing the argumentless function fn
// on the provided stack stk
func taskcreate(mp, g0, fn, stk unsafe.Pointer) {
	// create hole in stack
	stk = unsafe.Pointer(uintptr(stk) - 64)

	// reserve stack space to create Task.
	taskSize := unsafe.Sizeof(Task{})
	stk = unsafe.Pointer(uintptr(stk) - taskSize)
	memclr(stk, taskSize)
	t := (*Task)(unsafe.Pointer(stk))

	// create hole in stack
	stk = unsafe.Pointer(uintptr(stk) - 64)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(g0)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(mp)

	// reserve 8 bytes of space for return value,
	// for calling compatibility with contextsave.
	stk = unsafe.Pointer(uintptr(stk) - 8)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(fn)

	// reserve 8 bytes of space for return address,
	// to be filled in by contextload.
	stk = unsafe.Pointer(uintptr(stk) - 8)

	t.ID = taskid
	t.Context = Context{
		cpuRegisters: cpuRegisters{
			rsp: uintptr(stk),
			rip: funcPC(taskstart),
		},
	}
	t.semawaiter.task = t

	taskid++
	taskn++

	taskready(t)
}

//go:nosplit
func taskstart(fn, _, mp, gp unsafe.Pointer)

func taskready(t *Task) {
	t.WakeAt = 0
	taskrunqueue.Add(t)
}

func taskyield() {
	taskready(taskcurrent)
	taskswitch()
}

func taskswitch() {
	var (
		taskprev = taskcurrent
		tasknext *Task
	)

	saved := irqDisable()
	for {
		taskwakeready(nanotime())

		if tasknext = taskrunqueue.Head; tasknext != nil {
			break
		}

		if tasksleepqueue.Head == nil || tasksleepqueue.Head.WakeAt == -1 {
			panic("No runnable or timed sleep tasks to run")
		}

		HYPERVISOR_set_timer_op(tasksleepqueue.Head.WakeAt)
		HYPERVISOR_sched_op(1, nil) // block
		irqDisable()
	}
	irqRestore(saved)

	taskcurrent = tasknext
	taskrunqueue.Remove(taskcurrent)

	contextswitch(&taskprev.Context, &taskcurrent.Context)
}

func tasksleepus(us uint32) {
	ns := int64(us) * 1000

	for ns > 0 {
		ns = tasksleep(ns)
	}
}

// tasksleep puts the current task to sleep for up to ns.
// It returns the remaining sleep time if woken early.
// If ns is -1, rem will always be -1.
func tasksleep(ns int64) (rem int64) {
	sleepstart := nanotime()

	if ns == -1 {
		taskcurrent.WakeAt = -1
	} else {
		taskcurrent.WakeAt = sleepstart + ns
	}

	tasksleepqueue.AddByWakeAt(taskcurrent)
	taskswitch()

	sleepend := nanotime()

	if ns < 0 {
		return -1
	}

	if rem = ns - (sleepend - sleepstart); rem < 0 {
		rem = 0
	}

	return rem
}

// taskwake moves task from the sleep to the run queue.
func taskwake(task *Task) {
	tasksleepqueue.Remove(task)
	taskready(task)
}

func taskwakeready(at int64) {
	for {
		task := tasksleepqueue.Head
		if task == nil || task.WakeAt < 0 || task.WakeAt > at {
			return
		}
		taskwake(task)
	}
}

func taskexit() {
	throw("taskexit()")
	panic("taskexit()")
}

type TaskList struct {
	Head, Tail *Task
}

func (l *TaskList) debug() {
	println("[")
	for t := l.Head; t != nil; t = t.Next {
		print("  ")
		t.debug()
	}
	println("]")
}

func (l *TaskList) Add(t *Task) {
	if l.Tail != nil {
		l.Tail.Next = t
		t.Prev = l.Tail
	} else {
		l.Head = t
		t.Prev = nil
	}

	l.Tail = t
	t.Next = nil
}

func (l *TaskList) Remove(t *Task) {
	if t.Prev != nil {
		t.Prev.Next = t.Next
	} else {
		l.Head = t.Next
	}

	if t.Next != nil {
		t.Next.Prev = t.Prev
	} else {
		l.Tail = t.Prev
	}
}

func (l *TaskList) AddByWakeAt(t *Task) {
	if t.WakeAt < 0 {
		l.Add(t)
		return
	}

	for i := l.Head; i != nil; i = i.Next {
		if t.WakeAt > i.WakeAt && i.WakeAt >= 0 {
			continue
		}

		if i.Prev == nil {
			l.Head = t
		} else {
			i.Prev.Next = t
		}

		t.Prev = i.Prev
		t.Next = i
		i.Prev = t

		return
	}

	// no match, add to tail
	l.Add(t)
}

// Context describes the state of a task
// for saving or restoring a task's execution context.
type Context struct {
	cpuRegisters
	tls uintptr
}

func (c *Context) debug() {
	print(
		"Context{",
		"rsp=", unsafe.Pointer(c.rsp),
		" rip=", unsafe.Pointer(c.rip),
		" tls=", unsafe.Pointer(c.tls),
		"}", "\n",
	)
}

func contextswitch(from, to *Context) {
	if contextsave(from) == 0 {
		contextload(to)
	}
}

func contextsave(*Context) int
func contextload(*Context)

// cpuRegisters describes the state of a CPU
// on entry of a trap or interrupt.
type cpuRegisters struct {
	r15    uintptr
	r14    uintptr
	r13    uintptr
	r12    uintptr
	rbp    uintptr
	rbx    uintptr
	r11    uintptr
	r10    uintptr
	r9     uintptr
	r8     uintptr
	rax    uintptr
	rcx    uintptr
	rdx    uintptr
	rsi    uintptr
	rdi    uintptr
	code   uintptr // syscall number, error code, or IRQ number
	rip    uintptr
	cs     uintptr
	rflags uintptr
	rsp    uintptr
	ss     uintptr
}

func (r *cpuRegisters) debug() {
	print("cpuRegisters<", unsafe.Pointer(r), "> {")
	print(" r15=", unsafe.Pointer(r.r15))
	print(" r14=", unsafe.Pointer(r.r14))
	print(" r13=", unsafe.Pointer(r.r13))
	print(" r12=", unsafe.Pointer(r.r12))
	print(" rbp=", unsafe.Pointer(r.rbp))
	print(" rbx=", unsafe.Pointer(r.rbx))
	print(" r11=", unsafe.Pointer(r.r11))
	print(" r10=", unsafe.Pointer(r.r10))
	print(" r9=", unsafe.Pointer(r.r9))
	print(" r8=", unsafe.Pointer(r.r8))
	print(" rax=", unsafe.Pointer(r.rax))
	print(" rcx=", unsafe.Pointer(r.rcx))
	print(" rdx=", unsafe.Pointer(r.rdx))
	print(" rsi=", unsafe.Pointer(r.rsi))
	print(" rdi=", unsafe.Pointer(r.rdi))
	print(" code=", unsafe.Pointer(r.code))
	print(" rip=", unsafe.Pointer(r.rip))
	print(" cs=", unsafe.Pointer(r.cs))
	print(" rflags=", unsafe.Pointer(r.rflags))
	print(" rsp=", unsafe.Pointer(r.rsp))
	print(" ss=", unsafe.Pointer(r.ss))
	print(" }\n")
}
<commit_msg>Don't wake task that's already awake<commit_after>package runtime

import "unsafe"

// Atman implements a round-robin cooperative scheduler,
// heavily inspired by libtask.

var (
	taskid = 1
	taskn  = 1

	// taskcurrent is initialized as an empty Task with ID 0.
	// The first time a context switch is requested,
	// its context will be filled in and it will become
	// a normal Task.
	taskcurrent = &Task{ID: 0}

	taskrunqueue   TaskList
	tasksleepqueue TaskList
)

func init() {
	taskcurrent.semawaiter.task = taskcurrent
}

type Task struct {
	ID int

	Context Context

	WakeAt int64

	Next, Prev *Task

	semawaiter
}

func (t *Task) debug() {
	println("Task{ID: ", t.ID, ", WakeAt: ", t.WakeAt, "}")
}

// taskcreate spawns a new task,
// executing the argumentless function fn
// on the provided stack stk
func taskcreate(mp, g0, fn, stk unsafe.Pointer) {
	// create hole in stack
	stk = unsafe.Pointer(uintptr(stk) - 64)

	// reserve stack space to create Task.
	taskSize := unsafe.Sizeof(Task{})
	stk = unsafe.Pointer(uintptr(stk) - taskSize)
	memclr(stk, taskSize)
	t := (*Task)(unsafe.Pointer(stk))

	// create hole in stack
	stk = unsafe.Pointer(uintptr(stk) - 64)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(g0)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(mp)

	// reserve 8 bytes of space for return value,
	// for calling compatibility with contextsave.
	stk = unsafe.Pointer(uintptr(stk) - 8)

	stk = unsafe.Pointer(uintptr(stk) - 8)
	*(*uintptr)(stk) = uintptr(fn)

	// reserve 8 bytes of space for return address,
	// to be filled in by contextload.
	stk = unsafe.Pointer(uintptr(stk) - 8)

	t.ID = taskid
	t.Context = Context{
		cpuRegisters: cpuRegisters{
			rsp: uintptr(stk),
			rip: funcPC(taskstart),
		},
	}
	t.semawaiter.task = t

	taskid++
	taskn++

	taskready(t)
}

//go:nosplit
func taskstart(fn, _, mp, gp unsafe.Pointer)

func taskready(t *Task) {
	t.WakeAt = 0
	taskrunqueue.Add(t)
}

func taskyield() {
	taskready(taskcurrent)
	taskswitch()
}

func taskswitch() {
	var (
		taskprev = taskcurrent
		tasknext *Task
	)

	saved := irqDisable()
	for {
		taskwakeready(nanotime())

		if tasknext = taskrunqueue.Head; tasknext != nil {
			break
		}

		if tasksleepqueue.Head == nil || tasksleepqueue.Head.WakeAt == -1 {
			panic("No runnable or timed sleep tasks to run")
		}

		HYPERVISOR_set_timer_op(tasksleepqueue.Head.WakeAt)
		HYPERVISOR_sched_op(1, nil) // block
		irqDisable()
	}
	irqRestore(saved)

	taskcurrent = tasknext
	taskrunqueue.Remove(taskcurrent)

	contextswitch(&taskprev.Context, &taskcurrent.Context)
}

func tasksleepus(us uint32) {
	ns := int64(us) * 1000

	for ns > 0 {
		ns = tasksleep(ns)
	}
}

// tasksleep puts the current task to sleep for up to ns.
// It returns the remaining sleep time if woken early.
// If ns is -1, rem will always be -1.
func tasksleep(ns int64) (rem int64) {
	sleepstart := nanotime()

	if ns == -1 {
		taskcurrent.WakeAt = -1
	} else {
		taskcurrent.WakeAt = sleepstart + ns
	}

	tasksleepqueue.AddByWakeAt(taskcurrent)
	taskswitch()

	sleepend := nanotime()

	if ns < 0 {
		return -1
	}

	if rem = ns - (sleepend - sleepstart); rem < 0 {
		rem = 0
	}

	return rem
}

// taskwake moves task from the sleep to the run queue.
//
// If task is already marked as awake, it does nothing.
func taskwake(task *Task) {
	if task.WakeAt != 0 {
		tasksleepqueue.Remove(task)
		taskready(task)
	}
}

func taskwakeready(at int64) {
	for {
		task := tasksleepqueue.Head
		if task == nil || task.WakeAt < 0 || task.WakeAt > at {
			return
		}
		taskwake(task)
	}
}

func taskexit() {
	throw("taskexit()")
	panic("taskexit()")
}

type TaskList struct {
	Head, Tail *Task
}

func (l *TaskList) debug() {
	println("[")
	for t := l.Head; t != nil; t = t.Next {
		print("  ")
		t.debug()
	}
	println("]")
}

func (l *TaskList) Add(t *Task) {
	if l.Tail != nil {
		l.Tail.Next = t
		t.Prev = l.Tail
	} else {
		l.Head = t
		t.Prev = nil
	}

	l.Tail = t
	t.Next = nil
}

func (l *TaskList) Remove(t *Task) {
	if t.Prev != nil {
		t.Prev.Next = t.Next
	} else {
		l.Head = t.Next
	}

	if t.Next != nil {
		t.Next.Prev = t.Prev
	} else {
		l.Tail = t.Prev
	}
}

func (l *TaskList) AddByWakeAt(t *Task) {
	if t.WakeAt < 0 {
		l.Add(t)
		return
	}

	for i := l.Head; i != nil; i = i.Next {
		if t.WakeAt > i.WakeAt && i.WakeAt >= 0 {
			continue
		}

		if i.Prev == nil {
			l.Head = t
		} else {
			i.Prev.Next = t
		}

		t.Prev = i.Prev
		t.Next = i
		i.Prev = t

		return
	}

	// no match, add to tail
	l.Add(t)
}

// Context describes the state of a task
// for saving or restoring a task's execution context.
type Context struct {
	cpuRegisters
	tls uintptr
}

func (c *Context) debug() {
	print(
		"Context{",
		"rsp=", unsafe.Pointer(c.rsp),
		" rip=", unsafe.Pointer(c.rip),
		" tls=", unsafe.Pointer(c.tls),
		"}", "\n",
	)
}

func contextswitch(from, to *Context) {
	if contextsave(from) == 0 {
		contextload(to)
	}
}

func contextsave(*Context) int
func contextload(*Context)

// cpuRegisters describes the state of a CPU
// on entry of a trap or interrupt.
type cpuRegisters struct {
	r15    uintptr
	r14    uintptr
	r13    uintptr
	r12    uintptr
	rbp    uintptr
	rbx    uintptr
	r11    uintptr
	r10    uintptr
	r9     uintptr
	r8     uintptr
	rax    uintptr
	rcx    uintptr
	rdx    uintptr
	rsi    uintptr
	rdi    uintptr
	code   uintptr // syscall number, error code, or IRQ number
	rip    uintptr
	cs     uintptr
	rflags uintptr
	rsp    uintptr
	ss     uintptr
}

func (r *cpuRegisters) debug() {
	print("cpuRegisters<", unsafe.Pointer(r), "> {")
	print(" r15=", unsafe.Pointer(r.r15))
	print(" r14=", unsafe.Pointer(r.r14))
	print(" r13=", unsafe.Pointer(r.r13))
	print(" r12=", unsafe.Pointer(r.r12))
	print(" rbp=", unsafe.Pointer(r.rbp))
	print(" rbx=", unsafe.Pointer(r.rbx))
	print(" r11=", unsafe.Pointer(r.r11))
	print(" r10=", unsafe.Pointer(r.r10))
	print(" r9=", unsafe.Pointer(r.r9))
	print(" r8=", unsafe.Pointer(r.r8))
	print(" rax=", unsafe.Pointer(r.rax))
	print(" rcx=", unsafe.Pointer(r.rcx))
	print(" rdx=", unsafe.Pointer(r.rdx))
	print(" rsi=", unsafe.Pointer(r.rsi))
	print(" rdi=", unsafe.Pointer(r.rdi))
	print(" code=", unsafe.Pointer(r.code))
	print(" rip=", unsafe.Pointer(r.rip))
	print(" cs=", unsafe.Pointer(r.cs))
	print(" rflags=", unsafe.Pointer(r.rflags))
	print(" rsp=", unsafe.Pointer(r.rsp))
	print(" ss=", unsafe.Pointer(r.ss))
	print(" }\n")
}
<|endoftext|>


<commit_before>package logpeck

import (
	"encoding/json"
	"errors"
	log "github.com/Sirupsen/logrus"
	luajson "github.com/layeh/gopher-json"
	lua "github.com/yuin/gopher-lua"
)

type LuaExtractorConfig struct {
	LuaString string
	Fields    []PeckField
}

type LuaExtractor struct {
	state  *lua.LState
	fields map[string]bool
}

var LuaExtractorFuncName string = "extract"

func NewLuaExtractorConfig(configStr []byte) (LuaExtractorConfig, error) {
	c := LuaExtractorConfig{}
	err := json.Unmarshal(configStr, &c)
	if err != nil {
		return c, err
	}
	return c, nil
}

func NewLuaExtractor(config interface{}) (LuaExtractor, error) {
	c, ok := config.(LuaExtractorConfig)
	if !ok {
		return LuaExtractor{}, errors.New("LuaExtractor config error")
	}
	return newLuaExtractor(c)
}

func newLuaExtractor(c LuaExtractorConfig) (LuaExtractor, error) {
	l := LuaExtractor{
		state:  lua.NewState(),
		fields: make(map[string]bool),
	}
	c.LuaString = "local json = require(\"luajson.json\") " + c.LuaString
	l.state.PreloadModule("luajson.json", luajson.Loader)
	if err := l.state.DoString(c.LuaString); err != nil {
		return l, err
	}
	for _, f := range c.Fields {
		l.fields[f.Name] = true
	}
	log.Infof("[LuoExtractor] Init extractor finished %#v", l)
	return l, nil
}

func (le LuaExtractor) Extract(content string) (map[string]interface{}, error) {
	param := lua.P{
		Fn:      le.state.GetGlobal(LuaExtractorFuncName),
		NRet:    1,
		Protect: true,
	}
	if err := le.state.CallByParam(param, lua.LString(content)); err != nil {
		return nil, err
	}
	lRet := le.state.Get(-1)
	lT, ok := lRet.(*lua.LTable)
	if !ok {
		return nil, errors.New("lua return type error " + lRet.String())
	}
	le.state.Pop(1)
	log.Debugf("[LuaExtractor] %s %#v", content, lT)
	ret := make(map[string]interface{})
	enable := true
	key := ""
	lT.ForEach(func(k, v lua.LValue) {
		if _, ok := le.fields[k.String()]; !ok {
			enable = false
			key = k.String()
		}
		ret[k.String()] = v.String()
	})
	if !enable {
		return map[string]interface{}{}, errors.New(key + " is not in Fields")
	} else {
		return ret, nil
	}
}

func (le LuaExtractor) Close() {
	le.state.Close()
}
<commit_msg>extractor lua fix<commit_after>package logpeck

import (
	"encoding/json"
	"errors"
	log "github.com/Sirupsen/logrus"
	luajson "github.com/layeh/gopher-json"
	lua "github.com/yuin/gopher-lua"
)

type LuaExtractorConfig struct {
	LuaString string
	Fields    []PeckField
}

type LuaExtractor struct {
	state  *lua.LState
	fields map[string]bool
}

var LuaExtractorFuncName string = "extract"

func NewLuaExtractorConfig(configStr []byte) (LuaExtractorConfig, error) {
	c := LuaExtractorConfig{}
	err := json.Unmarshal(configStr, &c)
	if err != nil {
		return c, err
	}
	return c, nil
}

func NewLuaExtractor(config interface{}) (LuaExtractor, error) {
	c, ok := config.(LuaExtractorConfig)
	if !ok {
		return LuaExtractor{}, errors.New("LuaExtractor config error")
	}
	return newLuaExtractor(c)
}

func newLuaExtractor(c LuaExtractorConfig) (LuaExtractor, error) {
	l := LuaExtractor{
		state:  lua.NewState(),
		fields: make(map[string]bool),
	}
	c.LuaString = "json = require(\"luajson.json\") " + c.LuaString
	l.state.PreloadModule("luajson.json", luajson.Loader)
	if err := l.state.DoString(c.LuaString); err != nil {
		return l, err
	}
	for _, f := range c.Fields {
		l.fields[f.Name] = true
	}
	log.Infof("[LuoExtractor] Init extractor finished %#v", l)
	return l, nil
}

func (le LuaExtractor) Extract(content string) (map[string]interface{}, error) {
	param := lua.P{
		Fn:      le.state.GetGlobal(LuaExtractorFuncName),
		NRet:    1,
		Protect: true,
	}
	if err := le.state.CallByParam(param, lua.LString(content)); err != nil {
		return nil, err
	}
	lRet := le.state.Get(-1)
	lT, ok := lRet.(*lua.LTable)
	if !ok {
		return nil, errors.New("lua return type error " + lRet.String())
	}
	le.state.Pop(1)
	log.Debugf("[LuaExtractor] %s %#v", content, lT)
	ret := make(map[string]interface{})
	enable := true
	key := ""
	lT.ForEach(func(k, v lua.LValue) {
		if _, ok := le.fields[k.String()]; !ok {
			enable = false
			key = k.String()
		}
		ret[k.String()] = v.String()
	})
	if !enable {
		return map[string]interface{}{}, errors.New(key + " is not in Fields")
	} else {
		return ret, nil
	}
}

func (le LuaExtractor) Close() {
	le.state.Close()
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"sort"
	"time"

	"github.com/igungor/tlbot"
)

func init() {
	sort.Sort(byDate(holidays))
	register(cmdHoliday)
}

var cmdHoliday = &Command{
	Name:      "tatil",
	ShortLine: "ne zaman",
	Run:       runHoliday,
}

var day = 24 * time.Hour

var holidays = []h{
	// 2015
	{"Yılbaşı tatili", newdate("1 Jan 2015"), day},
	{"Çocuk Bayramı", newdate("23 Apr 2015"), day},
	{"İşçi Bayramı", newdate("1 May 2015"), day},
	{"Gençlik Bayramı", newdate("19 May 2015"), day},
	{"Ramazan Bayramı", newdate("18 Jul 2015"), 3 * day},
	{"Zafer Bayramı", newdate("30 Aug 2015"), day},
	{"Kurban Bayramı", newdate("25 Sep 2015"), 4 * day},
	{"Cumhuriyet Bayramı", newdate("29 Oct 2015"), day},
}

type h struct {
	name     string
	date     time.Time
	duration time.Duration
}

type byDate []h

func (d byDate) Len() int           { return len(d) }
func (d byDate) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d byDate) Less(i, j int) bool { return d[i].date.Before(d[j].date) }

func newdate(date string) time.Time {
	const timeformat = "2 Jan 2006"

	t, _ := time.Parse(timeformat, date)

	return t
}

func in(date, start, end time.Time) bool {
	if date.Equal(start) || date.Equal(end) {
		return true
	}

	return date.After(start) && date.Before(end)
}

func runHoliday(b *tlbot.Bot, msg *tlbot.Message) {
	const timeformat = "2 Jan 2006"
	now := time.Now().UTC()

	for _, t := range holidays {
		if in(now, t.date, t.date.Add(t.duration)) {
			b.SendMessage(msg.Chat, fmt.Sprintf("Bugün %v", t.name), tlbot.ModeNone, false, nil)
			return
		}

		if now.Before(t.date) {
			txt := fmt.Sprintf("En yakın tatil *%v* - %v (*%v* gün)", t.date.Format("_2/01/2006"), t.name, t.duration.Hours()/24)
			b.SendMessage(msg.Chat, txt, tlbot.ModeNone, false, nil)
			return
		}
	}

	b.SendMessage(msg.Chat, "yakın zamanda tatil görünmüyör :(", tlbot.ModeMarkdown, false, nil)
}
<commit_msg>Actual markdown fix.<commit_after>package command

import (
	"fmt"
	"sort"
	"time"

	"github.com/igungor/tlbot"
)

func init() {
	sort.Sort(byDate(holidays))
	register(cmdHoliday)
}

var cmdHoliday = &Command{
	Name:      "tatil",
	ShortLine: "ne zaman",
	Run:       runHoliday,
}

var day = 24 * time.Hour

var holidays = []h{
	// 2015
	{"Yılbaşı tatili", newdate("1 Jan 2015"), day},
	{"Çocuk Bayramı", newdate("23 Apr 2015"), day},
	{"İşçi Bayramı", newdate("1 May 2015"), day},
	{"Gençlik Bayramı", newdate("19 May 2015"), day},
	{"Ramazan Bayramı", newdate("18 Jul 2015"), 3 * day},
	{"Zafer Bayramı", newdate("30 Aug 2015"), day},
	{"Kurban Bayramı", newdate("25 Sep 2015"), 4 * day},
	{"Cumhuriyet Bayramı", newdate("29 Oct 2015"), day},
}

type h struct {
	name     string
	date     time.Time
	duration time.Duration
}

type byDate []h

func (d byDate) Len() int           { return len(d) }
func (d byDate) Swap(i, j int)      { d[i], d[j] = d[j], d[i] }
func (d byDate) Less(i, j int) bool { return d[i].date.Before(d[j].date) }

func newdate(date string) time.Time {
	const timeformat = "2 Jan 2006"

	t, _ := time.Parse(timeformat, date)

	return t
}

func in(date, start, end time.Time) bool {
	if date.Equal(start) || date.Equal(end) {
		return true
	}

	return date.After(start) && date.Before(end)
}

func runHoliday(b *tlbot.Bot, msg *tlbot.Message) {
	const timeformat = "2 Jan 2006"
	now := time.Now().UTC()

	for _, t := range holidays {
		if in(now, t.date, t.date.Add(t.duration)) {
			b.SendMessage(msg.Chat, fmt.Sprintf("Bugün %v", t.name), tlbot.ModeMarkdown, false, nil)
			return
		}

		if now.Before(t.date) {
			txt := fmt.Sprintf("En yakın tatil *%v* - %v (*%v* gün)", t.date.Format("_2/01/2006"), t.name, t.duration.Hours()/24)
			b.SendMessage(msg.Chat, txt, tlbot.ModeMarkdown, false, nil)
			return
		}
	}

	b.SendMessage(msg.Chat, "yakın zamanda tatil görünmüyör :(", tlbot.ModeMarkdown, false, nil)
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"time"
)

type importData struct {
	projectId uint64
	deviceId  string
	series    string
	timestamp int64
	value     float64
}

func (d *importData) IsValid() bool {
	return d.projectId > 0 && len(d.deviceId) > 0 && len(d.series) > 0 && d.timestamp > 0
}

// NewImportCommand returns the base 'import' command.
func NewImportCommand(ctx *Context) *Command {
	d := new(importData)
	pid := ctx.Profile.ActiveProject
	now := time.Now().UnixNano() / int64(time.Millisecond)

	cmd := &Command{
		Name:    "import",
		ApiPath: "/v1/imports",
		Usage:   "Add data to a project",
		Data:    d,
		Action:  sendImport,
	}

	flags := cmd.NewFlagSet("iobeam import")
	flags.Uint64Var(&d.projectId, "projectId", pid, "Project ID (if omitted, defaults to active project)")
	flags.StringVar(&d.deviceId, "deviceId", "", "Device ID (REQUIRED)")
	flags.StringVar(&d.series, "series", "", "Series name (REQUIRED)")
	flags.Int64Var(&d.timestamp, "time", now, "Timestamp, in milliseconds, of the data (if omitted, defaults to current time)")
	flags.Float64Var(&d.value, "value", 0.0, "Data value (REQUIRED)")

	return cmd
}

type dataPoint struct {
	Time  int64   `json:"time"`
	Value float64 `json:"value"`
}

type sourceObj struct {
	Name string      `json:"name"`
	Data []dataPoint `json:"data"`
}

type importObj struct {
	ProjectId uint64      `json:"project_id"`
	DeviceId  string      `json:"device_id"`
	Sources   []sourceObj `json:"sources"`
}

func sendImport(c *Command, ctx *Context) error {
	d := c.Data.(*importData)

	dp := dataPoint{
		Time:  d.timestamp,
		Value: d.value,
	}
	source1 := sourceObj{
		Name: d.series,
		Data: []dataPoint{dp},
	}
	obj := importObj{
		ProjectId: d.projectId,
		DeviceId:  d.deviceId,
		Sources:   []sourceObj{source1},
	}

	_, err := ctx.Client.
		Post(c.ApiPath).
		Expect(200).
		ProjectToken(ctx.Profile, d.projectId).
		Body(obj).
		Execute()

	if err == nil {
		fmt.Println("Data successfully imported.")
	}

	return err
}
<commit_msg>imports: 0 is a valid timestamp<commit_after>package command

import (
	"fmt"
	"time"
)

type importData struct {
	projectId uint64
	deviceId  string
	series    string
	timestamp int64
	value     float64
}

func (d *importData) IsValid() bool {
	return d.projectId > 0 && len(d.deviceId) > 0 && len(d.series) > 0 && d.timestamp >= 0
}

// NewImportCommand returns the base 'import' command.
func NewImportCommand(ctx *Context) *Command {
	d := new(importData)
	pid := ctx.Profile.ActiveProject
	now := time.Now().UnixNano() / int64(time.Millisecond)

	cmd := &Command{
		Name:    "import",
		ApiPath: "/v1/imports",
		Usage:   "Add data to a project",
		Data:    d,
		Action:  sendImport,
	}

	flags := cmd.NewFlagSet("iobeam import")
	flags.Uint64Var(&d.projectId, "projectId", pid, "Project ID (if omitted, defaults to active project)")
	flags.StringVar(&d.deviceId, "deviceId", "", "Device ID (REQUIRED)")
	flags.StringVar(&d.series, "series", "", "Series name (REQUIRED)")
	flags.Int64Var(&d.timestamp, "time", now, "Timestamp, in milliseconds, of the data (if omitted, defaults to current time)")
	flags.Float64Var(&d.value, "value", 0.0, "Data value (REQUIRED)")

	return cmd
}

type dataPoint struct {
	Time  int64   `json:"time"`
	Value float64 `json:"value"`
}

type sourceObj struct {
	Name string      `json:"name"`
	Data []dataPoint `json:"data"`
}

type importObj struct {
	ProjectId uint64      `json:"project_id"`
	DeviceId  string      `json:"device_id"`
	Sources   []sourceObj `json:"sources"`
}

func sendImport(c *Command, ctx *Context) error {
	d := c.Data.(*importData)

	dp := dataPoint{
		Time:  d.timestamp,
		Value: d.value,
	}
	source1 := sourceObj{
		Name: d.series,
		Data: []dataPoint{dp},
	}
	obj := importObj{
		ProjectId: d.projectId,
		DeviceId:  d.deviceId,
		Sources:   []sourceObj{source1},
	}

	_, err := ctx.Client.
		Post(c.ApiPath).
		Expect(200).
		ProjectToken(ctx.Profile, d.projectId).
		Body(obj).
		Execute()

	if err == nil {
		fmt.Println("Data successfully imported.")
	}

	return err
}
<|endoftext|>


<commit_before>package ari

// Mailbox is the communication path to an Asterisk server for
// operating on mailbox resources
type Mailbox interface {

	// Get gets a handle to the mailbox for further operations
	Get(name string) *MailboxHandle

	// List lists the mailboxes in asterisk
	List() ([]*MailboxHandle, error)

	// Data gets the current state of the mailbox
	Data(name string) (MailboxData, error)

	// Update updates the state of the mailbox, or creates if does not exist
	Update(name string, oldMessages int, newMessages int) error

	// Delete deletes the mailbox
	Delete(name string) error
}

// MailboxData respresents the state of an Asterisk (voice) mailbox
type MailboxData struct {
	Name        string `json:"name"`
	NewMessages int    `json:"new_messages"` // Number of new (unread) messages
	OldMessages int    `json:"old_messages"` // Number of old (read) messages
}

// NewMailboxHandle creates a new mailbox handle given the name and mailbox transport
func NewMailboxHandle(name string, m Mailbox) *MailboxHandle {
	return &MailboxHandle{
		name: name,
		m:    m,
	}
}

// A MailboxHandle is a handle to a mailbox instance attached to an
// ari transport
type MailboxHandle struct {
	name string
	m    Mailbox
}

// Data gets the current state of the mailbox
func (mh *MailboxHandle) Data() (MailboxData, error) {
	return mh.m.Data(mh.name)
}

// Update updates the state of the mailbox, or creates if does not exist
func (mh *MailboxHandle) Update(oldMessages int, newMessages int) error {
	return mh.m.Update(mh.name, oldMessages, newMessages)
}

// Delete deletes the mailbox
func (mh *MailboxHandle) Delete() error {
	return mh.m.Delete(mh.name)
}
<commit_msg>v3 - mailbox - add ID to mailbox<commit_after>package ari

// Mailbox is the communication path to an Asterisk server for
// operating on mailbox resources
type Mailbox interface {

	// Get gets a handle to the mailbox for further operations
	Get(name string) *MailboxHandle

	// List lists the mailboxes in asterisk
	List() ([]*MailboxHandle, error)

	// Data gets the current state of the mailbox
	Data(name string) (MailboxData, error)

	// Update updates the state of the mailbox, or creates if does not exist
	Update(name string, oldMessages int, newMessages int) error

	// Delete deletes the mailbox
	Delete(name string) error
}

// MailboxData respresents the state of an Asterisk (voice) mailbox
type MailboxData struct {
	Name        string `json:"name"`
	NewMessages int    `json:"new_messages"` // Number of new (unread) messages
	OldMessages int    `json:"old_messages"` // Number of old (read) messages
}

// NewMailboxHandle creates a new mailbox handle given the name and mailbox transport
func NewMailboxHandle(name string, m Mailbox) *MailboxHandle {
	return &MailboxHandle{
		name: name,
		m:    m,
	}
}

// A MailboxHandle is a handle to a mailbox instance attached to an
// ari transport
type MailboxHandle struct {
	name string
	m    Mailbox
}

// ID returns the identifier for the mailbox handle
func (mh *MailboxHandle) ID() string {
	return mh.name
}

// Data gets the current state of the mailbox
func (mh *MailboxHandle) Data() (MailboxData, error) {
	return mh.m.Data(mh.name)
}

// Update updates the state of the mailbox, or creates if does not exist
func (mh *MailboxHandle) Update(oldMessages int, newMessages int) error {
	return mh.m.Update(mh.name, oldMessages, newMessages)
}

// Delete deletes the mailbox
func (mh *MailboxHandle) Delete() error {
	return mh.m.Delete(mh.name)
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"compress/gzip"
	"expvar"
	"fmt"
	"io/ioutil"

	"google.golang.org/protobuf/proto"
)

const (
	defaultBatchThreshold = 5
	defaultSizeThreshold  = 150
)

// Requester is the interface objects must support to be marshaled
// successfully.
type Requester interface {
	proto.Message
	GetRequest() *Request
}

// RequestMarshaler marshals Request objects, potentially performing
// gzip compression.
type RequestMarshaler struct {
	BatchThreshold   int
	SizeThreshold    int
	ForceCompression bool
}

const (
	numRequests             = "num_requests"
	numCompressedRequests   = "num_compressed_requests"
	numUncompressedRequests = "num_uncompressed_requests"
	numCompressedBytes      = "num_compressed_bytes"
	numPrecompressedBytes   = "num_precompressed_bytes"
	numUncompressedBytes    = "num_uncompressed_bytes"
	numCompressionMisses    = "num_compression_misses"
)

// stats captures stats for the Proto marshaler.
var stats *expvar.Map

func init() {
	stats = expvar.NewMap("proto")
	stats.Add(numRequests, 0)
	stats.Add(numCompressedRequests, 0)
	stats.Add(numUncompressedRequests, 0)
	stats.Add(numCompressedBytes, 0)
	stats.Add(numUncompressedBytes, 0)
	stats.Add(numCompressionMisses, 0)
	stats.Add(numPrecompressedBytes, 0)
}

// NewRequestMarshaler returns an initialized RequestMarshaler.
func NewRequestMarshaler() *RequestMarshaler {
	return &RequestMarshaler{
		BatchThreshold: defaultBatchThreshold,
		SizeThreshold:  defaultSizeThreshold,
	}
}

// Marshal marshals a Requester object, returning a byte slice, a bool
// indicating whether the contents are compressed, or an error.
func (m *RequestMarshaler) Marshal(r Requester) ([]byte, bool, error) {
	stats.Add(numRequests, 0)
	compress := false

	stmts := r.GetRequest().GetStatements()
	if len(stmts) >= m.BatchThreshold {
		compress = true
	} else {
		for i := range stmts {
			if len(stmts[i].Sql) >= m.SizeThreshold {
				compress = true
				break
			}
		}
	}

	b, err := proto.Marshal(r)
	if err != nil {
		return nil, false, err
	}
	ubz := len(b)
	stats.Add(numPrecompressedBytes, int64(ubz))

	if compress {
		// Let's try compression.
		var buf bytes.Buffer
		gzw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
		if err != nil {
			return nil, false, fmt.Errorf("gzip new writer: %s", err)
		}

		if _, err := gzw.Write(b); err != nil {
			return nil, false, fmt.Errorf("gzip Write: %s", err)
		}
		if err := gzw.Close(); err != nil {
			return nil, false, fmt.Errorf("gzip Close: %s", err)
		}

		// Is compression better?
		if ubz > len(buf.Bytes()) || m.ForceCompression {
			// Yes! Let's keep it.
			b = buf.Bytes()
			stats.Add(numCompressedRequests, 1)
			stats.Add(numCompressedBytes, int64(len(b)))
		} else {
			// No. :-( Dump it.
			compress = false
			stats.Add(numCompressionMisses, 1)
		}
	} else {
		stats.Add(numUncompressedRequests, 1)
		stats.Add(numUncompressedBytes, int64(len(b)))
	}

	return b, compress, nil
}

// Stats returns status and diagnostic information about
// the RequestMarshaler.
func (m *RequestMarshaler) Stats() map[string]interface{} {
	return map[string]interface{}{
		"compression_size":  m.SizeThreshold,
		"compression_batch": m.BatchThreshold,
		"force_compression": m.ForceCompression,
	}
}

// Marshal marshals a Command.
func Marshal(c *Command) ([]byte, error) {
	return proto.Marshal(c)
}

// Unmarshal unmarshals a Command
func Unmarshal(b []byte, c *Command) error {
	return proto.Unmarshal(b, c)
}

// MarshalNoop marshals a Noop command
func MarshalNoop(c *Noop) ([]byte, error) {
	return proto.Marshal(c)
}

// UnmarshalNoop unmarshals a Noop command
func UnmarshalNoop(b []byte, c *Noop) error {
	return proto.Unmarshal(b, c)
}

// MarshalLoadRequest marshals a LoadRequest command
func MarshalLoadRequest(lr *LoadRequest) ([]byte, error) {
	// XXX Compress the SQLIte data!
	return proto.Marshal(lr)
}

// UnmarshalLoadRequest unmarshals a LoadRequest command
func UnmarshalLoadRequest(b []byte, lr *LoadRequest) error {
	return proto.Unmarshal(b, lr)
}

// UnmarshalSubCommand unmarshalls a sub command m. It assumes that
// m is the correct type.
func UnmarshalSubCommand(c *Command, m proto.Message) error {
	b := c.SubCommand
	if c.Compressed {
		gz, err := gzip.NewReader(bytes.NewReader(b))
		if err != nil {
			return fmt.Errorf("unmarshal sub gzip NewReader: %s", err)
		}

		ub, err := ioutil.ReadAll(gz)
		if err != nil {
			return fmt.Errorf("unmarshal sub gzip ReadAll: %s", err)
		}

		if err := gz.Close(); err != nil {
			return fmt.Errorf("unmarshal sub gzip Close: %s", err)
		}
		b = ub
	}

	if err := proto.Unmarshal(b, m); err != nil {
		return fmt.Errorf("proto unmarshal: %s", err)
	}
	return nil
}
<commit_msg>Use compression for LoadRequest marshalling<commit_after>package command

import (
	"bytes"
	"compress/gzip"
	"expvar"
	"fmt"
	"io/ioutil"

	"google.golang.org/protobuf/proto"
)

const (
	defaultBatchThreshold = 5
	defaultSizeThreshold  = 150
)

// Requester is the interface objects must support to be marshaled
// successfully.
type Requester interface {
	proto.Message
	GetRequest() *Request
}

// RequestMarshaler marshals Request objects, potentially performing
// gzip compression.
type RequestMarshaler struct {
	BatchThreshold   int
	SizeThreshold    int
	ForceCompression bool
}

const (
	numRequests             = "num_requests"
	numCompressedRequests   = "num_compressed_requests"
	numUncompressedRequests = "num_uncompressed_requests"
	numCompressedBytes      = "num_compressed_bytes"
	numPrecompressedBytes   = "num_precompressed_bytes"
	numUncompressedBytes    = "num_uncompressed_bytes"
	numCompressionMisses    = "num_compression_misses"
)

// stats captures stats for the Proto marshaler.
var stats *expvar.Map

func init() {
	stats = expvar.NewMap("proto")
	stats.Add(numRequests, 0)
	stats.Add(numCompressedRequests, 0)
	stats.Add(numUncompressedRequests, 0)
	stats.Add(numCompressedBytes, 0)
	stats.Add(numUncompressedBytes, 0)
	stats.Add(numCompressionMisses, 0)
	stats.Add(numPrecompressedBytes, 0)
}

// NewRequestMarshaler returns an initialized RequestMarshaler.
func NewRequestMarshaler() *RequestMarshaler {
	return &RequestMarshaler{
		BatchThreshold: defaultBatchThreshold,
		SizeThreshold:  defaultSizeThreshold,
	}
}

// Marshal marshals a Requester object, returning a byte slice, a bool
// indicating whether the contents are compressed, or an error.
func (m *RequestMarshaler) Marshal(r Requester) ([]byte, bool, error) {
	stats.Add(numRequests, 0)
	compress := false

	stmts := r.GetRequest().GetStatements()
	if len(stmts) >= m.BatchThreshold {
		compress = true
	} else {
		for i := range stmts {
			if len(stmts[i].Sql) >= m.SizeThreshold {
				compress = true
				break
			}
		}
	}

	b, err := proto.Marshal(r)
	if err != nil {
		return nil, false, err
	}
	ubz := len(b)
	stats.Add(numPrecompressedBytes, int64(ubz))

	if compress {
		// Let's try compression.
		gzData, err := gzCompress(b)
		if err != nil {
			return nil, false, err
		}

		// Is compression better?
		if ubz > len(gzData) || m.ForceCompression {
			// Yes! Let's keep it.
			b = gzData
			stats.Add(numCompressedRequests, 1)
			stats.Add(numCompressedBytes, int64(len(b)))
		} else {
			// No. :-( Dump it.
			compress = false
			stats.Add(numCompressionMisses, 1)
		}
	} else {
		stats.Add(numUncompressedRequests, 1)
		stats.Add(numUncompressedBytes, int64(len(b)))
	}

	return b, compress, nil
}

// Stats returns status and diagnostic information about
// the RequestMarshaler.
func (m *RequestMarshaler) Stats() map[string]interface{} {
	return map[string]interface{}{
		"compression_size":  m.SizeThreshold,
		"compression_batch": m.BatchThreshold,
		"force_compression": m.ForceCompression,
	}
}

// Marshal marshals a Command.
func Marshal(c *Command) ([]byte, error) {
	return proto.Marshal(c)
}

// Unmarshal unmarshals a Command
func Unmarshal(b []byte, c *Command) error {
	return proto.Unmarshal(b, c)
}

// MarshalNoop marshals a Noop command
func MarshalNoop(c *Noop) ([]byte, error) {
	return proto.Marshal(c)
}

// UnmarshalNoop unmarshals a Noop command
func UnmarshalNoop(b []byte, c *Noop) error {
	return proto.Unmarshal(b, c)
}

// MarshalLoadRequest marshals a LoadRequest command
func MarshalLoadRequest(lr *LoadRequest) ([]byte, error) {
	b, err := gzCompress(lr.Data)
	if err != nil {
		return nil, err
	}
	lr.Data = b
	return proto.Marshal(lr)
}

// UnmarshalLoadRequest unmarshals a LoadRequest command
func UnmarshalLoadRequest(b []byte, lr *LoadRequest) error {
	if err := proto.Unmarshal(b, lr); err != nil {
		return err
	}
	u, err := gzUncompress(lr.Data)
	if err != nil {
		return err
	}
	lr.Data = u
	return nil
}

// UnmarshalSubCommand unmarshalls a sub command m. It assumes that
// m is the correct type.
func UnmarshalSubCommand(c *Command, m proto.Message) error {
	b := c.SubCommand
	if c.Compressed {
		var err error
		b, err = gzUncompress(b)
		if err != nil {
			return fmt.Errorf("unmarshal sub uncompress: %s", err)
		}
	}

	if err := proto.Unmarshal(b, m); err != nil {
		return fmt.Errorf("proto unmarshal: %s", err)
	}
	return nil
}

// gzCompress compresses the given byte slice.
func gzCompress(b []byte) ([]byte, error) {
	var buf bytes.Buffer
	gzw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
	if err != nil {
		return nil, fmt.Errorf("gzip new writer: %s", err)
	}

	if _, err := gzw.Write(b); err != nil {
		return nil, fmt.Errorf("gzip Write: %s", err)
	}
	if err := gzw.Close(); err != nil {
		return nil, fmt.Errorf("gzip Close: %s", err)
	}
	return buf.Bytes(), nil
}

func gzUncompress(b []byte) ([]byte, error) {
	gz, err := gzip.NewReader(bytes.NewReader(b))
	if err != nil {
		return nil, fmt.Errorf("unmarshal gzip NewReader: %s", err)
	}

	ub, err := ioutil.ReadAll(gz)
	if err != nil {
		return nil, fmt.Errorf("unmarshal gzip ReadAll: %s", err)
	}

	if err := gz.Close(); err != nil {
		return nil, fmt.Errorf("unmarshal gzip Close: %s", err)
	}
	return ub, nil
}
<|endoftext|>


<commit_before>package plugins

import (
	"log"
	"os"
	"reflect"
	"runtime"
	"time"
)

var logger = log.New(os.Stderr, "[plugins::Manager] ", log.LstdFlags)

type Manager struct {
	plugins       plugins
	closers       map[string]chan<- struct{}
	subscriptions map[Event]plugins
	selects       []reflect.SelectCase
	handler       Handler
}

type plugins map[string]Plugin

// Returns a new plugin Manager ready for use.
// A default Muxer is installed as the handler
func NewManager() *Manager {
	return &Manager{
		plugins:       make(plugins),
		closers:       make(map[string]chan<- struct{}),
		subscriptions: make(map[Event]plugins),
		selects:       make([]reflect.SelectCase, 0, 16),
		handler:       make(mapMuxr),
	}
}

type packet struct {
	Event Event
	Args  Args
}

func (ph *Manager) Handle(pl Plugin) {
	ph.plugins[pl.Name()] = pl

	for _, sub := range pl.Subscribes() {
		if ph.subscriptions[sub] == nil {
			ph.subscriptions[sub] = make(plugins)
		}
		ph.subscriptions[sub][pl.Name()] = pl
	}

	f, ch, closer := generatefunc(pl)
	ph.closers[pl.Name()] = closer

	go f()

	rch := reflect.ValueOf(ch)
	ph.selects = append(ph.selects,
		reflect.SelectCase{
			Dir:  reflect.SelectRecv,
			Chan: rch,
		})
}

func (ph *Manager) HandleAll(pls ...Plugin) {
	for _, pl := range pls {
		ph.Handle(pl)
	}
}

func (ph Manager) Handler() Handler {
	return ph.handler
}

func (ph Manager) SetHandler(h Handler) {
	ph.handler = h
}

//Returns the installed handler if it is a Muxer
//Otherwise, returns nil
func (ph Manager) Muxer() Muxer {
	if muxr, ok := ph.handler.(Muxer); ok {
		return muxr
	}
	return nil
}

func generatefunc(pl Plugin) (func(), <-chan packet, chan<- struct{}) {
	ch, closer := make(chan packet), make(chan struct{})
	return func() {
		defer close(ch)

		if len(pl.Provides()) == 0 {
			return //Nothing is provided, so nothing to listen for.
		}

		for {
			select {
			case <-closer:
				return
			default:
				event, args, err := pl.Recieve() //Probably blocking. Hopefully not for to long.
				if err != nil {
					switch err {
					case Unblocking:
						time.Sleep(500 * time.Millisecond)
					case NotImplemented:
						fallthrough
					default:
						logger.Printf("Encountered a error recieving event from %s: \n%s", pl.Name(), err.Error())
						return
					}
					continue
				}
				ch <- packet{event, args}
			}
			runtime.Gosched() // Allow something else to run if tight loop.
		}
	}, ch, closer
}

func (ph *Manager) Unload(pl Plugin) {
	close(ph.closers[pl.Name()])
	delete(ph.closers, pl.Name())

	for _, sub := range pl.Subscribes() {
		delete(ph.subscriptions[sub], pl.Name())
	}

	delete(ph.plugins, pl.Name())
}

func (ph *Manager) ListenAndServe() error {
	for {
		if len(ph.selects) <= 0 {
			runtime.Gosched()
			continue
		}
		if chosen, recv, ok := reflect.Select(ph.selects); ok {
			pck := recv.Interface().(packet)
			ph.dispatch("plugin", pck.Event, pck.Args)
		} else if chosen >= 0 && chosen < len(ph.selects) {
			//Not ok
			//Removing select case from list
			if chosen == len(ph.selects)-1 {
				ph.selects = ph.selects[:len(ph.selects)-1]
			} else {
				ph.selects = append(ph.selects[:chosen], ph.selects[chosen+1:]...)
			}
		}
	}

	return nil
}

func (ph Manager) Dispatch(e Event, args Args) error {
	return ph.dispatch("local", e, args)
}

func (ph Manager) dispatch(identifier string, e Event, args Args) (err error) {
	ph.Handler().HandleEvent(e, args)
	for _, plugin := range ph.subscriptions[e] {
		go func(plugin Plugin) {
			tmp := plugin.Send(e, args)
			if err == nil && tmp != NotImplemented {
				err = tmp
			}
		}(plugin)
	}
	return
}
<commit_msg>Added some buffering to internal channels to improve performance.<commit_after>package plugins

import (
	"log"
	"os"
	"reflect"
	"runtime"
	"time"
)

var logger = log.New(os.Stderr, "[plugins::Manager] ", log.LstdFlags)

type Manager struct {
	plugins       plugins
	closers       map[string]chan<- struct{}
	subscriptions map[Event]plugins
	selects       []reflect.SelectCase
	handler       Handler
}

type plugins map[string]Plugin

// Returns a new plugin Manager ready for use.
// A default Muxer is installed as the handler
func NewManager() *Manager {
	return &Manager{
		plugins:       make(plugins),
		closers:       make(map[string]chan<- struct{}),
		subscriptions: make(map[Event]plugins),
		selects:       make([]reflect.SelectCase, 0, 16),
		handler:       make(mapMuxr),
	}
}

type packet struct {
	Event Event
	Args  Args
}

func (ph *Manager) Handle(pl Plugin) {
	ph.plugins[pl.Name()] = pl

	for _, sub := range pl.Subscribes() {
		if ph.subscriptions[sub] == nil {
			ph.subscriptions[sub] = make(plugins)
		}
		ph.subscriptions[sub][pl.Name()] = pl
	}

	f, ch, closer := generatefunc(pl)
	ph.closers[pl.Name()] = closer

	go f()

	rch := reflect.ValueOf(ch)
	ph.selects = append(ph.selects,
		reflect.SelectCase{
			Dir:  reflect.SelectRecv,
			Chan: rch,
		})
}

func (ph *Manager) HandleAll(pls ...Plugin) {
	for _, pl := range pls {
		ph.Handle(pl)
	}
}

func (ph Manager) Handler() Handler {
	return ph.handler
}

func (ph Manager) SetHandler(h Handler) {
	ph.handler = h
}

//Returns the installed handler if it is a Muxer
//Otherwise, returns nil
func (ph Manager) Muxer() Muxer {
	if muxr, ok := ph.handler.(Muxer); ok {
		return muxr
	}
	return nil
}

func generatefunc(pl Plugin) (func(), <-chan packet, chan<- struct{}) {
	ch, closer := make(chan packet, 3), make(chan struct{})
	return func() {
		defer close(ch)

		if len(pl.Provides()) == 0 {
			return //Nothing is provided, so nothing to listen for.
		}

		for {
			select {
			case <-closer:
				return
			default:
				event, args, err := pl.Recieve() //Probably blocking. Hopefully not for to long.
				if err != nil {
					switch err {
					case Unblocking:
						time.Sleep(500 * time.Millisecond)
					case NotImplemented:
						fallthrough
					default:
						logger.Printf("Encountered a error recieving event from %s: \n%s", pl.Name(), err.Error())
						return
					}
					continue
				}
				ch <- packet{event, args}
			}
			runtime.Gosched() // Allow something else to run if tight loop.
		}
	}, ch, closer
}

func (ph *Manager) Unload(pl Plugin) {
	close(ph.closers[pl.Name()])
	delete(ph.closers, pl.Name())

	for _, sub := range pl.Subscribes() {
		delete(ph.subscriptions[sub], pl.Name())
	}

	delete(ph.plugins, pl.Name())
}

func (ph *Manager) ListenAndServe() error {
	for {
		if len(ph.selects) <= 0 {
			runtime.Gosched()
			continue
		}
		if chosen, recv, ok := reflect.Select(ph.selects); ok {
			pck := recv.Interface().(packet)
			ph.dispatch("plugin", pck.Event, pck.Args)
		} else if chosen >= 0 && chosen < len(ph.selects) {
			//Not ok
			//Removing select case from list
			if chosen == len(ph.selects)-1 {
				ph.selects = ph.selects[:len(ph.selects)-1]
			} else {
				ph.selects = append(ph.selects[:chosen], ph.selects[chosen+1:]...)
			}
		}
	}

	return nil
}

func (ph Manager) Dispatch(e Event, args Args) error {
	return ph.dispatch("local", e, args)
}

func (ph Manager) dispatch(identifier string, e Event, args Args) (err error) {
	ph.Handler().HandleEvent(e, args)
	for _, plugin := range ph.subscriptions[e] {
		go func(plugin Plugin) {
			tmp := plugin.Send(e, args)
			if err == nil && tmp != NotImplemented {
				err = tmp
			}
		}(plugin)
	}
	return
}
<|endoftext|>


<commit_before>package command

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/hashicorp/nomad/api"
	"github.com/mitchellh/cli"
	"github.com/posener/complete"
)

type VarGetCommand struct {
	Meta
	outFmt string
	tmpl   string
}

func (c *VarGetCommand) Help() string {
	helpText := `
Usage: nomad var get [options] <path>

  The 'var get' command is used to get the contents of an existing variable.

  If ACLs are enabled, this command requires a token with the 'variables:read'
  capability for the target variable's namespace and path.

General Options:

  ` + generalOptionsUsage(usageOptsDefault) + `

Read Options:

  -item <item key>
     Print only the value of the given item. Specifying this option will
     take precedence over other formatting directives. The result will not
     have a trailing newline making it ideal for piping to other processes.

  -out ( go-template | hcl | json | none | table )
     Format to render the variable in. When using "go-template", you must
     provide the template content with the "-template" option. Defaults
     to "table" when stdout is a terminal and to "json" when stdout is
     redirected.

  -template
     Template to render output with. Required when output is "go-template".

`
	return strings.TrimSpace(helpText)
}

func (c *VarGetCommand) AutocompleteFlags() complete.Flags {
	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
		complete.Flags{
			"-out":      complete.PredictSet("go-template", "hcl", "json", "none", "table"),
			"-template": complete.PredictAnything,
		},
	)
}

func (c *VarGetCommand) AutocompleteArgs() complete.Predictor {
	return VariablePathPredictor(c.Meta.Client)
}

func (c *VarGetCommand) Synopsis() string {
	return "Read a variable"
}

func (c *VarGetCommand) Name() string { return "var read" }

func (c *VarGetCommand) Run(args []string) int {
	var out, item string

	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }

	flags.StringVar(&item, "item", "", "")
	flags.StringVar(&c.tmpl, "template", "", "")

	if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) != 0 {
		flags.StringVar(&c.outFmt, "out", "table", "")
	} else {
		flags.StringVar(&c.outFmt, "out", "json", "")
	}

	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we got one argument
	args = flags.Args()
	if len(args) != 1 {
		c.Ui.Error("This command takes one argument: <path>")
		c.Ui.Error(commandErrorText(c))
		return 1
	}

	if err := c.validateOutputFlag(); err != nil {
		c.Ui.Error(err.Error())
		c.Ui.Error(commandErrorText(c))
		return 1
	}

	if c.Meta.namespace == "*" {
		c.Ui.Error(errWildcardNamespaceNotAllowed)
		return 1
	}

	path := args[0]

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	qo := &api.QueryOptions{
		Namespace: c.Meta.namespace,
	}

	sv, _, err := client.Variables().Read(path, qo)
	if err != nil {
		if err.Error() == "variable not found" {
			c.Ui.Warn(errVariableNotFound)
			return 1
		}
		c.Ui.Error(fmt.Sprintf("Error retrieving variable: %s", err))
		return 1
	}
	// If the user provided an item key, return that value instead of the whole
	// object
	if item != "" {
		if v, ok := sv.Items[item]; ok {
			fmt.Print(v)
			return 0
		} else {
			c.Ui.Error(fmt.Sprintf("Variable does not contain %q item", args[1]))
			return 1
		}
	}

	// Output whole object
	switch c.outFmt {
	case "json":
		out = sv.AsPrettyJSON()
	case "hcl":
		out = renderAsHCL(sv)
	case "go-template":
		if out, err = renderWithGoTemplate(sv, c.tmpl); err != nil {
			c.Ui.Error(err.Error())
			return 1
		}
	case "none":
		// exit without more output
		return 0
	default:
		// the renderSVAsUiTable func writes directly to the ui and doesn't error.
		renderSVAsUiTable(sv, c)
		return 0
	}

	c.Ui.Output(out)
	return 0
}

func (c *VarGetCommand) validateOutputFlag() error {
	if c.outFmt != "go-template" && c.tmpl != "" {
		return errors.New(errUnexpectedTemplate)
	}
	switch c.outFmt {
	case "hcl", "json", "none", "table":
		return nil
	case "go-template": //noop - needs more validation
		if c.tmpl == "" {
			return errors.New(errMissingTemplate)
		}
		return nil
	default:
		return errors.New(errInvalidOutFormat)
	}
}

func (c *VarGetCommand) GetConcurrentUI() cli.ConcurrentUi {
	return cli.ConcurrentUi{Ui: c.Ui}
}
<commit_msg>cli: fix doc strings for `var get` command (#14697)<commit_after>package command

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/hashicorp/nomad/api"
	"github.com/mitchellh/cli"
	"github.com/posener/complete"
)

type VarGetCommand struct {
	Meta
	outFmt string
	tmpl   string
}

func (c *VarGetCommand) Help() string {
	helpText := `
Usage: nomad var get [options] <path>

  The 'var get' command is used to get the contents of an existing variable.

  If ACLs are enabled, this command requires a token with the 'variables:read'
  capability for the target variable's namespace and path.

General Options:

  ` + generalOptionsUsage(usageOptsDefault) + `

Get Options:

  -item <item key>
     Print only the value of the given item. Specifying this option will
     take precedence over other formatting directives. The result will not
     have a trailing newline making it ideal for piping to other processes.

  -out ( go-template | hcl | json | none | table )
     Format to render the variable in. When using "go-template", you must
     provide the template content with the "-template" option. Defaults
     to "table" when stdout is a terminal and to "json" when stdout is
     redirected.

  -template
     Template to render output with. Required when output is "go-template".

`
	return strings.TrimSpace(helpText)
}

func (c *VarGetCommand) AutocompleteFlags() complete.Flags {
	return mergeAutocompleteFlags(c.Meta.AutocompleteFlags(FlagSetClient),
		complete.Flags{
			"-out":      complete.PredictSet("go-template", "hcl", "json", "none", "table"),
			"-template": complete.PredictAnything,
		},
	)
}

func (c *VarGetCommand) AutocompleteArgs() complete.Predictor {
	return VariablePathPredictor(c.Meta.Client)
}

func (c *VarGetCommand) Synopsis() string {
	return "Read a variable"
}

func (c *VarGetCommand) Name() string { return "var get" }

func (c *VarGetCommand) Run(args []string) int {
	var out, item string

	flags := c.Meta.FlagSet(c.Name(), FlagSetClient)
	flags.Usage = func() { c.Ui.Output(c.Help()) }

	flags.StringVar(&item, "item", "", "")
	flags.StringVar(&c.tmpl, "template", "", "")

	if fileInfo, _ := os.Stdout.Stat(); (fileInfo.Mode() & os.ModeCharDevice) != 0 {
		flags.StringVar(&c.outFmt, "out", "table", "")
	} else {
		flags.StringVar(&c.outFmt, "out", "json", "")
	}

	if err := flags.Parse(args); err != nil {
		return 1
	}

	// Check that we got one argument
	args = flags.Args()
	if len(args) != 1 {
		c.Ui.Error("This command takes one argument: <path>")
		c.Ui.Error(commandErrorText(c))
		return 1
	}

	if err := c.validateOutputFlag(); err != nil {
		c.Ui.Error(err.Error())
		c.Ui.Error(commandErrorText(c))
		return 1
	}

	if c.Meta.namespace == "*" {
		c.Ui.Error(errWildcardNamespaceNotAllowed)
		return 1
	}

	path := args[0]

	// Get the HTTP client
	client, err := c.Meta.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
		return 1
	}

	qo := &api.QueryOptions{
		Namespace: c.Meta.namespace,
	}

	sv, _, err := client.Variables().Read(path, qo)
	if err != nil {
		if err.Error() == "variable not found" {
			c.Ui.Warn(errVariableNotFound)
			return 1
		}
		c.Ui.Error(fmt.Sprintf("Error retrieving variable: %s", err))
		return 1
	}
	// If the user provided an item key, return that value instead of the whole
	// object
	if item != "" {
		if v, ok := sv.Items[item]; ok {
			fmt.Print(v)
			return 0
		} else {
			c.Ui.Error(fmt.Sprintf("Variable does not contain %q item", args[1]))
			return 1
		}
	}

	// Output whole object
	switch c.outFmt {
	case "json":
		out = sv.AsPrettyJSON()
	case "hcl":
		out = renderAsHCL(sv)
	case "go-template":
		if out, err = renderWithGoTemplate(sv, c.tmpl); err != nil {
			c.Ui.Error(err.Error())
			return 1
		}
	case "none":
		// exit without more output
		return 0
	default:
		// the renderSVAsUiTable func writes directly to the ui and doesn't error.
		renderSVAsUiTable(sv, c)
		return 0
	}

	c.Ui.Output(out)
	return 0
}

func (c *VarGetCommand) validateOutputFlag() error {
	if c.outFmt != "go-template" && c.tmpl != "" {
		return errors.New(errUnexpectedTemplate)
	}
	switch c.outFmt {
	case "hcl", "json", "none", "table":
		return nil
	case "go-template": //noop - needs more validation
		if c.tmpl == "" {
			return errors.New(errMissingTemplate)
		}
		return nil
	default:
		return errors.New(errInvalidOutFormat)
	}
}

func (c *VarGetCommand) GetConcurrentUI() cli.ConcurrentUi {
	return cli.ConcurrentUi{Ui: c.Ui}
}
<|endoftext|>


<commit_before>package upload

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/subutai-io/base/agent/log"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
)

type share struct {
	Token  string   `json:"token"`
	Id     string   `json:"id"`
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
}

//Handler function works with income upload requests, makes sanity checks, etc
func Handler(w http.ResponseWriter, r *http.Request) (hash, owner string) {
	r.ParseMultipartForm(32 << 20)
	if len(r.MultipartForm.Value["token"]) == 0 || len(db.CheckToken(r.MultipartForm.Value["token"][0])) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Not authorized"))
		log.Warn(r.RemoteAddr + " - rejecting unauthorized upload request")
		return
	}

	owner = db.CheckToken(r.MultipartForm.Value["token"][0])

	file, header, err := r.FormFile("file")
	defer file.Close()
	if log.Check(log.WarnLevel, "Failed to parse POST form", err) {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Cannot get file from request"))
		return
	}

	out, err := os.Create(config.Filepath + header.Filename)
	if log.Check(log.WarnLevel, "Unable to create the file for writing", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Cannot create file"))
		return
	}
	defer out.Close()

	// write the content from POST to the file
	_, err = io.Copy(out, file)
	if log.Check(log.WarnLevel, "Writing file", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to write file"))
		return
	}

	hash = genHash(config.Filepath + header.Filename)
	if len(hash) == 0 {
		log.Warn("Failed to calculate hash for " + header.Filename)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to calculate hash"))
		return
	}

	os.Rename(config.Filepath+header.Filename, config.Filepath+hash)
	log.Info("File uploaded successfully: " + header.Filename + "(" + hash + ")")

	return hash, owner
}

func genHash(file string) string {
	f, err := os.Open(file)
	log.Check(log.WarnLevel, "Opening file"+file, err)
	defer f.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, f); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func Delete(w http.ResponseWriter, r *http.Request) string {
	hash := r.URL.Query().Get("id")
	token := r.URL.Query().Get("token")
	if len(hash) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty file id"))
		log.Warn(r.RemoteAddr + " - empty file id")
		return ""
	}
	if len(token) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Empty token"))
		log.Warn(r.RemoteAddr + " - empty token")
		return ""
	}
	user := db.CheckToken(token)
	info := db.Info(hash)
	if len(info) == 0 {
		log.Warn("File not found by hash")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File not found"))
		return ""
	}

	if !db.CheckOwner(user, hash) {
		log.Warn("File " + info["name"] + "(" + hash + ") is not owned by " + user + ", rejecting deletion request")
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("File " + info["name"] + " is not owned by " + user))
		return ""
	}
	if db.Delete(user, hash) <= 0 {
		if log.Check(log.WarnLevel, "Removing "+info["name"]+"from disk", os.Remove(config.Filepath+hash)) {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("Failed to remove file"))
			return ""
		}
	}
	log.Info("Removing " + info["name"])
	return hash
}

func Share(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		if len(r.MultipartForm.Value["json"]) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty json"))
			log.Warn("Share request: empty json, nothing to do")
			return
		}
		var data share
		if log.Check(log.WarnLevel, "Parsing share request json", json.Unmarshal([]byte(r.MultipartForm.Value["json"][0]), &data)) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Failed to parse json body"))
			return
		}
		if len(data.Token) == 0 || len(db.CheckToken(data.Token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			log.Warn("Empty or invalid token, rejecting share request")
			return
		}
		if len(data.Id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			log.Warn("Empty file id, rejecting share request")
			return
		}
		owner := db.CheckToken(data.Token)
		if !db.CheckOwner(owner, data.Id) {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to share another's file, rejecting")
			return
		}
		for _, v := range data.Add {
			db.ShareWith(data.Id, owner, v)
		}
		for _, v := range data.Remove {
			db.UnshareWith(data.Id, owner, v)
		}
	} else if r.Method == "GET" {
		request := r.URL.Query().Get("json")
		if len(request) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty json"))
			log.Warn("Share request: empty json, nothing to do")
			return
		}
		var data share
		if log.Check(log.WarnLevel, "Parsing share request json", json.Unmarshal([]byte(request), &data)) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Failed to parse json body"))
			return
		}
		if len(data.Token) == 0 || len(db.CheckToken(data.Token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			log.Warn("Empty or invalid token, rejecting scope list request")
			return
		}
		if len(data.Id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			log.Warn("Empty file id, rejecting scope list request")
			return
		}
		owner := db.CheckToken(data.Token)
		if !db.CheckOwner(owner, data.Id) {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to request scope of another's file, rejecting")
			return
		}
		js, _ := json.Marshal(db.GetScope(data.Id, owner))
		w.Write(js)
	}
}
<commit_msg>Scope parameter format changed<commit_after>package upload

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/subutai-io/base/agent/log"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
)

type share struct {
	Token  string   `json:"token"`
	Id     string   `json:"id"`
	Add    []string `json:"add"`
	Remove []string `json:"remove"`
}

//Handler function works with income upload requests, makes sanity checks, etc
func Handler(w http.ResponseWriter, r *http.Request) (hash, owner string) {
	r.ParseMultipartForm(32 << 20)
	if len(r.MultipartForm.Value["token"]) == 0 || len(db.CheckToken(r.MultipartForm.Value["token"][0])) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Not authorized"))
		log.Warn(r.RemoteAddr + " - rejecting unauthorized upload request")
		return
	}

	owner = db.CheckToken(r.MultipartForm.Value["token"][0])

	file, header, err := r.FormFile("file")
	defer file.Close()
	if log.Check(log.WarnLevel, "Failed to parse POST form", err) {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Cannot get file from request"))
		return
	}

	out, err := os.Create(config.Filepath + header.Filename)
	if log.Check(log.WarnLevel, "Unable to create the file for writing", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Cannot create file"))
		return
	}
	defer out.Close()

	// write the content from POST to the file
	_, err = io.Copy(out, file)
	if log.Check(log.WarnLevel, "Writing file", err) {
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to write file"))
		return
	}

	hash = genHash(config.Filepath + header.Filename)
	if len(hash) == 0 {
		log.Warn("Failed to calculate hash for " + header.Filename)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to calculate hash"))
		return
	}

	os.Rename(config.Filepath+header.Filename, config.Filepath+hash)
	log.Info("File uploaded successfully: " + header.Filename + "(" + hash + ")")

	return hash, owner
}

func genHash(file string) string {
	f, err := os.Open(file)
	log.Check(log.WarnLevel, "Opening file"+file, err)
	defer f.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, f); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", hash.Sum(nil))
}

func Delete(w http.ResponseWriter, r *http.Request) string {
	hash := r.URL.Query().Get("id")
	token := r.URL.Query().Get("token")
	if len(hash) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty file id"))
		log.Warn(r.RemoteAddr + " - empty file id")
		return ""
	}
	if len(token) == 0 {
		w.WriteHeader(http.StatusUnauthorized)
		w.Write([]byte("Empty token"))
		log.Warn(r.RemoteAddr + " - empty token")
		return ""
	}
	user := db.CheckToken(token)
	info := db.Info(hash)
	if len(info) == 0 {
		log.Warn("File not found by hash")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte("File not found"))
		return ""
	}

	if !db.CheckOwner(user, hash) {
		log.Warn("File " + info["name"] + "(" + hash + ") is not owned by " + user + ", rejecting deletion request")
		w.WriteHeader(http.StatusForbidden)
		w.Write([]byte("File " + info["name"] + " is not owned by " + user))
		return ""
	}
	if db.Delete(user, hash) <= 0 {
		if log.Check(log.WarnLevel, "Removing "+info["name"]+"from disk", os.Remove(config.Filepath+hash)) {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("Failed to remove file"))
			return ""
		}
	}
	log.Info("Removing " + info["name"])
	return hash
}

func Share(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		r.ParseMultipartForm(32 << 20)
		if len(r.MultipartForm.Value["json"]) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty json"))
			log.Warn("Share request: empty json, nothing to do")
			return
		}
		var data share
		if log.Check(log.WarnLevel, "Parsing share request json", json.Unmarshal([]byte(r.MultipartForm.Value["json"][0]), &data)) {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Failed to parse json body"))
			return
		}
		if len(data.Token) == 0 || len(db.CheckToken(data.Token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			log.Warn("Empty or invalid token, rejecting share request")
			return
		}
		if len(data.Id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			log.Warn("Empty file id, rejecting share request")
			return
		}
		owner := db.CheckToken(data.Token)
		if !db.CheckOwner(owner, data.Id) {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to share another's file, rejecting")
			return
		}
		for _, v := range data.Add {
			db.ShareWith(data.Id, owner, v)
		}
		for _, v := range data.Remove {
			db.UnshareWith(data.Id, owner, v)
		}
	} else if r.Method == "GET" {
		id := r.URL.Query().Get("id")
		if len(id) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			w.Write([]byte("Empty file id"))
			return
		}
		token := r.URL.Query().Get("token")
		if len(token) == 0 || len(db.CheckToken(token)) == 0 {
			w.WriteHeader(http.StatusUnauthorized)
			w.Write([]byte("Not authorized"))
			return
		}
		owner := db.CheckToken(token)
		if !db.CheckOwner(owner, id) {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("File is not owned by authorized user"))
			log.Warn("User tried to request scope of another's file, rejecting")
			return
		}
		js, _ := json.Marshal(db.GetScope(id, owner))
		w.Write(js)
	}
}
<|endoftext|>