mirror of
https://github.com/Threnklyn/jira.git
synced 2026-05-18 20:23:28 +02:00
running dep prune
This commit is contained in:
-2
@@ -1,2 +0,0 @@
|
||||
{{define "x"}}TEXT{{end}}
|
||||
{{define "dotV"}}{{.V}}{{end}}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
{{define "dot"}}{{.}}{{end}}
|
||||
{{define "nested"}}{{template "dot" .}}{{end}}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
template1
|
||||
{{define "x"}}x{{end}}
|
||||
{{template "y"}}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
template2
|
||||
{{define "y"}}y{{end}}
|
||||
{{template "x"}}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package math
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type ThisNumberType generic.Number
|
||||
|
||||
func ThisNumberTypeMax(fn func(a, b ThisNumberType) bool, a, b ThisNumberType) ThisNumberType {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
cat ./generic_max.go | ../../genny gen "NumberType=NUMBERS" > numbers_max_get.go
|
||||
cat ./func_thing.go | ../../genny gen "ThisNumberType=NUMBERS" > numbers_func_thing.go
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package math
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type NumberType generic.Number
|
||||
|
||||
// NumberTypeMax gets the maximum number from the
|
||||
// two specified.
|
||||
func NumberTypeMax(a, b NumberType) NumberType {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package math_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cheekybits/genny/examples/davechaney"
|
||||
)
|
||||
|
||||
func TestNumberTypeMax(t *testing.T) {
|
||||
|
||||
var v math.NumberType
|
||||
v = math.NumberTypeMax(10, 20)
|
||||
if v != 20 {
|
||||
t.Errorf("Max of 10 and 20 is 20")
|
||||
}
|
||||
|
||||
v = math.NumberTypeMax(20, 20)
|
||||
if v != 20 {
|
||||
t.Errorf("Max of 20 and 20 is 20")
|
||||
}
|
||||
|
||||
v = math.NumberTypeMax(25, 20)
|
||||
if v != 25 {
|
||||
t.Errorf("Max of 25 and 20 is 25")
|
||||
}
|
||||
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package math
|
||||
|
||||
func Float32Max(fn func(a, b float32) bool, a, b float32) float32 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Float64Max(fn func(a, b float64) bool, a, b float64) float64 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func IntMax(fn func(a, b int) bool, a, b int) int {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Int16Max(fn func(a, b int16) bool, a, b int16) int16 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Int32Max(fn func(a, b int32) bool, a, b int32) int32 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Int64Max(fn func(a, b int64) bool, a, b int64) int64 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Int8Max(fn func(a, b int8) bool, a, b int8) int8 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func UintMax(fn func(a, b uint) bool, a, b uint) uint {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Uint16Max(fn func(a, b uint16) bool, a, b uint16) uint16 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Uint32Max(fn func(a, b uint32) bool, a, b uint32) uint32 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Uint64Max(fn func(a, b uint64) bool, a, b uint64) uint64 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Uint8Max(fn func(a, b uint8) bool, a, b uint8) uint8 {
|
||||
if fn(a, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package gogenerate
|
||||
|
||||
type StringStringMap map[string]string
|
||||
|
||||
func NewStringStringMap() map[string]string {
|
||||
return make(map[string]string)
|
||||
}
|
||||
|
||||
type StringIntMap map[string]int
|
||||
|
||||
func NewStringIntMap() map[string]int {
|
||||
return make(map[string]int)
|
||||
}
|
||||
|
||||
type IntStringMap map[int]string
|
||||
|
||||
func NewIntStringMap() map[int]string {
|
||||
return make(map[int]string)
|
||||
}
|
||||
|
||||
type IntIntMap map[int]int
|
||||
|
||||
func NewIntIntMap() map[int]int {
|
||||
return make(map[int]int)
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package gogenerate
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
//go:generate genny -in=$GOFILE -out=gen-$GOFILE gen "KeyType=string,int ValueType=string,int"
|
||||
|
||||
type KeyType generic.Type
|
||||
type ValueType generic.Type
|
||||
|
||||
type KeyTypeValueTypeMap map[KeyType]ValueType
|
||||
|
||||
func NewKeyTypeValueTypeMap() map[KeyType]ValueType {
|
||||
return make(map[KeyType]ValueType)
|
||||
}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
cat ./queue_generic.go | ../../genny gen "Generic=string,int" > queue_generic_gen.go
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package example
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type Generic generic.Type
|
||||
|
||||
// GenericQueue represents a queue of Generic types.
|
||||
type GenericQueue struct {
|
||||
items []Generic
|
||||
}
|
||||
|
||||
// NewGenericQueue makes a new empty Generic queue.
|
||||
func NewGenericQueue() *GenericQueue {
|
||||
return &GenericQueue{items: make([]Generic, 0)}
|
||||
}
|
||||
|
||||
// Enq adds an item to the queue.
|
||||
func (q *GenericQueue) Enq(obj Generic) *GenericQueue {
|
||||
q.items = append(q.items, obj)
|
||||
return q
|
||||
}
|
||||
|
||||
// Deq removes and returns the next item in the queue.
|
||||
func (q *GenericQueue) Deq() Generic {
|
||||
obj := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return obj
|
||||
}
|
||||
|
||||
// Len gets the current number of Generic items in the queue.
|
||||
func (q *GenericQueue) Len() int {
|
||||
return len(q.items)
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
q := NewGenericQueue()
|
||||
assert.NotNil(t, q)
|
||||
|
||||
}
|
||||
|
||||
func TestEnqueueAndDequeue(t *testing.T) {
|
||||
|
||||
item1 := new(Generic)
|
||||
item2 := new(Generic)
|
||||
q := NewGenericQueue()
|
||||
|
||||
assert.Equal(t, q, q.Enq(item1), "Enq should return the queue")
|
||||
assert.Equal(t, 1, q.Len())
|
||||
assert.Equal(t, q, q.Enq(item2), "Enq should return the queue")
|
||||
assert.Equal(t, 2, q.Len())
|
||||
|
||||
assert.Equal(t, item1, q.Deq())
|
||||
assert.Equal(t, 1, q.Len())
|
||||
assert.Equal(t, item2, q.Deq())
|
||||
assert.Equal(t, 0, q.Len())
|
||||
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package parse
|
||||
|
||||
// Builtins contains a slice of all built-in Go types.
|
||||
var Builtins = []string{
|
||||
"bool",
|
||||
"byte",
|
||||
"complex128",
|
||||
"complex64",
|
||||
"error",
|
||||
"float32",
|
||||
"float64",
|
||||
"int",
|
||||
"int16",
|
||||
"int32",
|
||||
"int64",
|
||||
"int8",
|
||||
"rune",
|
||||
"string",
|
||||
"uint",
|
||||
"uint16",
|
||||
"uint32",
|
||||
"uint64",
|
||||
"uint8",
|
||||
"uintptr",
|
||||
}
|
||||
|
||||
// Numbers contains a slice of all built-in number types.
|
||||
var Numbers = []string{
|
||||
"float32",
|
||||
"float64",
|
||||
"int",
|
||||
"int16",
|
||||
"int32",
|
||||
"int64",
|
||||
"int8",
|
||||
"uint",
|
||||
"uint16",
|
||||
"uint32",
|
||||
"uint64",
|
||||
"uint8",
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// Package parse contains the generic code generation capabilities
|
||||
// that power genny.
|
||||
//
|
||||
// genny gen "{types}"
|
||||
//
|
||||
// gen - generates type specific code (to stdout) from generic code (via stdin)
|
||||
//
|
||||
// {types} - (required) Specific types for each generic type in the source
|
||||
// {types} format: {generic}={specific}[,another][ {generic2}={specific2}]
|
||||
// Examples:
|
||||
// Generic=Specific
|
||||
// Generic1=Specific1 Generic2=Specific2
|
||||
// Generic1=Specific1,Specific2 Generic2=Specific3,Specific4
|
||||
package parse
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// errMissingSpecificType represents an error when a generic type is not
|
||||
// satisfied by a specific type.
|
||||
type errMissingSpecificType struct {
|
||||
GenericType string
|
||||
}
|
||||
|
||||
// Error gets a human readable string describing this error.
|
||||
func (e errMissingSpecificType) Error() string {
|
||||
return "Missing specific type for '" + e.GenericType + "' generic type"
|
||||
}
|
||||
|
||||
// errImports represents an error from goimports.
|
||||
type errImports struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error gets a human readable string describing this error.
|
||||
func (e errImports) Error() string {
|
||||
return "Failed to goimports the generated code: " + e.Err.Error()
|
||||
}
|
||||
|
||||
// errSource represents an error with the source file.
|
||||
type errSource struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error gets a human readable string describing this error.
|
||||
func (e errSource) Error() string {
|
||||
return "Failed to parse source file: " + e.Err.Error()
|
||||
}
|
||||
|
||||
type errBadTypeArgs struct {
|
||||
Message string
|
||||
Arg string
|
||||
}
|
||||
|
||||
func (e errBadTypeArgs) Error() string {
|
||||
return "\"" + e.Arg + "\" is bad: " + e.Message
|
||||
}
|
||||
|
||||
var errMissingTypeInformation = errors.New("No type arguments were specified and no \"// +gogen\" tag was found in the source.")
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
type isExported bool
|
||||
|
||||
var header = []byte(`
|
||||
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
`)
|
||||
|
||||
var (
|
||||
packageKeyword = []byte("package")
|
||||
importKeyword = []byte("import")
|
||||
openBrace = []byte("(")
|
||||
closeBrace = []byte(")")
|
||||
space = " "
|
||||
genericPackage = "generic"
|
||||
genericType = "generic.Type"
|
||||
genericNumber = "generic.Number"
|
||||
linefeed = "\r\n"
|
||||
)
|
||||
var unwantedLinePrefixes = [][]byte{
|
||||
[]byte("//go:generate genny "),
|
||||
}
|
||||
|
||||
func generateSpecific(filename string, in io.ReadSeeker, typeSet map[string]string) ([]byte, error) {
|
||||
|
||||
// ensure we are at the beginning of the file
|
||||
in.Seek(0, os.SEEK_SET)
|
||||
|
||||
// parse the source file
|
||||
fs := token.NewFileSet()
|
||||
file, err := parser.ParseFile(fs, filename, in, 0)
|
||||
if err != nil {
|
||||
return nil, &errSource{Err: err}
|
||||
}
|
||||
|
||||
// make sure every generic.Type is represented in the types
|
||||
// argument.
|
||||
for _, decl := range file.Decls {
|
||||
switch it := decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
for _, spec := range it.Specs {
|
||||
ts, ok := spec.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch tt := ts.Type.(type) {
|
||||
case *ast.SelectorExpr:
|
||||
if name, ok := tt.X.(*ast.Ident); ok {
|
||||
if name.Name == genericPackage {
|
||||
if _, ok := typeSet[ts.Name.Name]; !ok {
|
||||
return nil, &errMissingSpecificType{GenericType: ts.Name.Name}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// go back to the start of the file
|
||||
in.Seek(0, os.SEEK_SET)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
comment := ""
|
||||
scanner := bufio.NewScanner(in)
|
||||
for scanner.Scan() {
|
||||
|
||||
l := scanner.Text()
|
||||
|
||||
// does this line contain generic.Type?
|
||||
if strings.Contains(l, genericType) || strings.Contains(l, genericNumber) {
|
||||
comment = ""
|
||||
continue
|
||||
}
|
||||
|
||||
for t, specificType := range typeSet {
|
||||
|
||||
// does the line contain our type
|
||||
if strings.Contains(l, t) {
|
||||
|
||||
var newLine string
|
||||
// check each word
|
||||
for _, word := range strings.Fields(l) {
|
||||
|
||||
i := 0
|
||||
for {
|
||||
i = strings.Index(word[i:], t) // find out where
|
||||
|
||||
if i > -1 {
|
||||
|
||||
// if this isn't an exact match
|
||||
if i > 0 && isAlphaNumeric(rune(word[i-1])) || i < len(word)-len(t) && isAlphaNumeric(rune(word[i+len(t)])) {
|
||||
// replace the word with a capitolized version
|
||||
word = strings.Replace(word, t, wordify(specificType, unicode.IsUpper(rune(strings.TrimLeft(word, "*&")[0]))), 1)
|
||||
} else {
|
||||
// replace the word as is
|
||||
word = strings.Replace(word, t, specificType, 1)
|
||||
}
|
||||
|
||||
} else {
|
||||
newLine = newLine + word + space
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
l = newLine
|
||||
}
|
||||
}
|
||||
|
||||
if comment != "" {
|
||||
buf.WriteString(line(comment))
|
||||
comment = ""
|
||||
}
|
||||
|
||||
// is this line a comment?
|
||||
// TODO: should we handle /* */ comments?
|
||||
if strings.HasPrefix(l, "//") {
|
||||
// record this line to print later
|
||||
comment = l
|
||||
continue
|
||||
}
|
||||
|
||||
// write the line
|
||||
buf.WriteString(line(l))
|
||||
}
|
||||
|
||||
// write it out
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Generics parses the source file and generates the bytes replacing the
|
||||
// generic types for the keys map with the specific types (its value).
|
||||
func Generics(filename, pkgName string, in io.ReadSeeker, typeSets []map[string]string) ([]byte, error) {
|
||||
|
||||
totalOutput := header
|
||||
|
||||
for _, typeSet := range typeSets {
|
||||
|
||||
// generate the specifics
|
||||
parsed, err := generateSpecific(filename, in, typeSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalOutput = append(totalOutput, parsed...)
|
||||
|
||||
}
|
||||
|
||||
// clean up the code line by line
|
||||
packageFound := false
|
||||
insideImportBlock := false
|
||||
var cleanOutputLines []string
|
||||
scanner := bufio.NewScanner(bytes.NewReader(totalOutput))
|
||||
for scanner.Scan() {
|
||||
|
||||
// end of imports block?
|
||||
if insideImportBlock {
|
||||
if bytes.HasSuffix(scanner.Bytes(), closeBrace) {
|
||||
insideImportBlock = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.HasPrefix(scanner.Bytes(), packageKeyword) {
|
||||
if packageFound {
|
||||
continue
|
||||
} else {
|
||||
packageFound = true
|
||||
}
|
||||
} else if bytes.HasPrefix(scanner.Bytes(), importKeyword) {
|
||||
if bytes.HasSuffix(scanner.Bytes(), openBrace) {
|
||||
insideImportBlock = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// check all unwantedLinePrefixes - and skip them
|
||||
skipline := false
|
||||
for _, prefix := range unwantedLinePrefixes {
|
||||
if bytes.HasPrefix(scanner.Bytes(), prefix) {
|
||||
skipline = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if skipline {
|
||||
continue
|
||||
}
|
||||
|
||||
cleanOutputLines = append(cleanOutputLines, line(scanner.Text()))
|
||||
}
|
||||
|
||||
cleanOutput := strings.Join(cleanOutputLines, "")
|
||||
|
||||
output := []byte(cleanOutput)
|
||||
var err error
|
||||
|
||||
// change package name
|
||||
if pkgName != "" {
|
||||
output = changePackage(bytes.NewReader([]byte(output)), pkgName)
|
||||
}
|
||||
// fix the imports
|
||||
output, err = imports.Process(filename, output, nil)
|
||||
if err != nil {
|
||||
return nil, &errImports{Err: err}
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func line(s string) string {
|
||||
return fmt.Sprintln(strings.TrimRight(s, linefeed))
|
||||
}
|
||||
|
||||
// isAlphaNumeric gets whether the rune is alphanumeric or _.
|
||||
func isAlphaNumeric(r rune) bool {
|
||||
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
|
||||
}
|
||||
|
||||
// wordify turns a type into a nice word for function and type
|
||||
// names etc.
|
||||
func wordify(s string, exported bool) string {
|
||||
s = strings.TrimRight(s, "{}")
|
||||
s = strings.TrimLeft(s, "*&")
|
||||
s = strings.Replace(s, ".", "", -1)
|
||||
if !exported {
|
||||
return s
|
||||
}
|
||||
return strings.ToUpper(string(s[0])) + s[1:]
|
||||
}
|
||||
|
||||
func changePackage(r io.Reader, pkgName string) []byte {
|
||||
var out bytes.Buffer
|
||||
sc := bufio.NewScanner(r)
|
||||
done := false
|
||||
|
||||
for sc.Scan() {
|
||||
s := sc.Text()
|
||||
|
||||
if !done && strings.HasPrefix(s, "package") {
|
||||
parts := strings.Split(s, " ")
|
||||
parts[1] = pkgName
|
||||
s = strings.Join(parts, " ")
|
||||
done = true
|
||||
}
|
||||
|
||||
fmt.Fprintln(&out, s)
|
||||
}
|
||||
return out.Bytes()
|
||||
}
|
||||
-35
@@ -1,35 +0,0 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestIsAlphaNumeric(t *testing.T) {
|
||||
|
||||
for _, r := range []rune{'a', '1', '_', 'A', 'Z'} {
|
||||
assert.True(t, isAlphaNumeric(r))
|
||||
}
|
||||
for _, r := range []rune{' ', '[', ']', '!', '"'} {
|
||||
assert.False(t, isAlphaNumeric(r))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestWordify(t *testing.T) {
|
||||
|
||||
for word, wordified := range map[string]string{
|
||||
"int": "Int",
|
||||
"*int": "Int",
|
||||
"string": "String",
|
||||
"*MyType": "MyType",
|
||||
"*myType": "MyType",
|
||||
"interface{}": "Interface",
|
||||
"pack.type": "Packtype",
|
||||
"*pack.type": "Packtype",
|
||||
} {
|
||||
assert.Equal(t, wordified, wordify(word, true))
|
||||
}
|
||||
|
||||
}
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
package parse_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/cheekybits/genny/parse"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var tests = []struct {
|
||||
// input
|
||||
filename string
|
||||
pkgName string
|
||||
in string
|
||||
types []map[string]string
|
||||
|
||||
// expectations
|
||||
expectedOut string
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
filename: "generic_queue.go",
|
||||
in: `test/queue/generic_queue.go`,
|
||||
types: []map[string]string{{"Something": "int"}},
|
||||
expectedOut: `test/queue/int_queue.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_queue.go",
|
||||
pkgName: "changed",
|
||||
in: `test/queue/generic_queue.go`,
|
||||
types: []map[string]string{{"Something": "int"}},
|
||||
expectedOut: `test/queue/changed/int_queue.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_queue.go",
|
||||
in: `test/queue/generic_queue.go`,
|
||||
types: []map[string]string{{"Something": "float32"}},
|
||||
expectedOut: `test/queue/float32_queue.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_simplemap.go",
|
||||
in: `test/multipletypes/generic_simplemap.go`,
|
||||
types: []map[string]string{{"KeyType": "string", "ValueType": "int"}},
|
||||
expectedOut: `test/multipletypes/string_int_simplemap.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_simplemap.go",
|
||||
in: `test/multipletypes/generic_simplemap.go`,
|
||||
types: []map[string]string{{"KeyType": "interface{}", "ValueType": "int"}},
|
||||
expectedOut: `test/multipletypes/interface_int_simplemap.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_simplemap.go",
|
||||
in: `test/multipletypes/generic_simplemap.go`,
|
||||
types: []map[string]string{{"KeyType": "*MyType1", "ValueType": "*MyOtherType"}},
|
||||
expectedOut: `test/multipletypes/custom_types_simplemap.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_internal.go",
|
||||
in: `test/unexported/generic_internal.go`,
|
||||
types: []map[string]string{{"secret": "*myType"}},
|
||||
expectedOut: `test/unexported/mytype_internal.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_simplemap.go",
|
||||
in: `test/multipletypesets/generic_simplemap.go`,
|
||||
types: []map[string]string{
|
||||
{"KeyType": "int", "ValueType": "string"},
|
||||
{"KeyType": "float64", "ValueType": "bool"},
|
||||
},
|
||||
expectedOut: `test/multipletypesets/many_simplemaps.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_number.go",
|
||||
in: `test/numbers/generic_number.go`,
|
||||
types: []map[string]string{{"NumberType": "int"}},
|
||||
expectedOut: `test/numbers/int_number.go`,
|
||||
},
|
||||
{
|
||||
filename: "generic_digraph.go",
|
||||
in: `test/bugreports/generic_digraph.go`,
|
||||
types: []map[string]string{{"Node": "int"}},
|
||||
expectedOut: `test/bugreports/int_digraph.go`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
test.in = contents(test.in)
|
||||
test.expectedOut = contents(test.expectedOut)
|
||||
|
||||
bytes, err := parse.Generics(test.filename, test.pkgName, strings.NewReader(test.in), test.types)
|
||||
|
||||
// check the error
|
||||
if test.expectedErr == nil {
|
||||
assert.NoError(t, err, "(%s) No error was expected but got: %s", test.filename, err)
|
||||
} else {
|
||||
assert.NotNil(t, err, "(%s) No error was returned by one was expected: %s", test.filename, test.expectedErr)
|
||||
assert.IsType(t, test.expectedErr, err, "(%s) Generate should return object of type %v", test.filename, test.expectedErr)
|
||||
}
|
||||
|
||||
// assert the response
|
||||
if !assert.Equal(t, string(bytes), test.expectedOut, "Parse didn't generate the expected output.") {
|
||||
log.Println("EXPECTED: " + test.expectedOut)
|
||||
log.Println("ACTUAL: " + string(bytes))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func contents(s string) string {
|
||||
if strings.HasSuffix(s, "go") {
|
||||
file, err := ioutil.ReadFile(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return string(file)
|
||||
}
|
||||
return s
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package bugreports
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type Node generic.Type
|
||||
|
||||
type DigraphNode struct {
|
||||
nodes map[Node][]Node
|
||||
}
|
||||
|
||||
func NewDigraphNode() *DigraphNode {
|
||||
return &DigraphNode{
|
||||
nodes: make(map[Node][]Node),
|
||||
}
|
||||
}
|
||||
|
||||
func (dig *DigraphNode) Add(n Node) {
|
||||
if _, exists := dig.nodes[n]; exists {
|
||||
return
|
||||
}
|
||||
|
||||
dig.nodes[n] = nil
|
||||
}
|
||||
|
||||
func (dig *DigraphNode) Connect(a, b Node) {
|
||||
dig.Add(a)
|
||||
dig.Add(b)
|
||||
|
||||
dig.nodes[a] = append(dig.nodes[a], b)
|
||||
}
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package bugreports
|
||||
|
||||
type DigraphInt struct {
|
||||
nodes map[int][]int
|
||||
}
|
||||
|
||||
func NewDigraphInt() *DigraphInt {
|
||||
return &DigraphInt{
|
||||
nodes: make(map[int][]int),
|
||||
}
|
||||
}
|
||||
|
||||
func (dig *DigraphInt) Add(n int) {
|
||||
if _, exists := dig.nodes[n]; exists {
|
||||
return
|
||||
}
|
||||
|
||||
dig.nodes[n] = nil
|
||||
}
|
||||
|
||||
func (dig *DigraphInt) Connect(a, b int) {
|
||||
dig.Add(a)
|
||||
dig.Add(b)
|
||||
|
||||
dig.nodes[a] = append(dig.nodes[a], b)
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
package multipletypes
|
||||
|
||||
type MyType1 struct{}
|
||||
|
||||
type MyOtherType struct{}
|
||||
Generated
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package multipletypes
|
||||
|
||||
type MyType1MyOtherTypeMap map[*MyType1]*MyOtherType
|
||||
|
||||
func (m MyType1MyOtherTypeMap) Has(key *MyType1) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m MyType1MyOtherTypeMap) Get(key *MyType1) *MyOtherType {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m MyType1MyOtherTypeMap) Set(key *MyType1, value *MyOtherType) MyType1MyOtherTypeMap {
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package multipletypes
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type KeyType generic.Type
|
||||
type ValueType generic.Type
|
||||
|
||||
type KeyTypeValueTypeMap map[KeyType]ValueType
|
||||
|
||||
func (m KeyTypeValueTypeMap) Has(key KeyType) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m KeyTypeValueTypeMap) Get(key KeyType) ValueType {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m KeyTypeValueTypeMap) Set(key KeyType, value ValueType) KeyTypeValueTypeMap {
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-35
@@ -1,35 +0,0 @@
|
||||
package multipletypes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSimpleMap(t *testing.T) {
|
||||
|
||||
key1 := new(KeyType)
|
||||
key2 := new(KeyType)
|
||||
value1 := new(ValueType)
|
||||
m := make(KeyTypeValueTypeMap)
|
||||
|
||||
assert.Equal(t, m, m.Set(key1, value1))
|
||||
assert.True(t, m.Has(key1))
|
||||
assert.False(t, m.Has(key2))
|
||||
assert.Equal(t, value1, m.Get(key1))
|
||||
|
||||
}
|
||||
|
||||
func TestCustomTypesMap(t *testing.T) {
|
||||
|
||||
key1 := new(MyType1)
|
||||
key2 := new(MyType1)
|
||||
value1 := new(MyOtherType)
|
||||
m := make(MyType1MyOtherTypeMap)
|
||||
|
||||
assert.Equal(t, m, m.Set(key1, value1))
|
||||
assert.True(t, m.Has(key1))
|
||||
assert.False(t, m.Has(key2))
|
||||
assert.Equal(t, value1, m.Get(key1))
|
||||
|
||||
}
|
||||
Generated
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package multipletypes
|
||||
|
||||
type InterfaceIntMap map[interface{}]int
|
||||
|
||||
func (m InterfaceIntMap) Has(key interface{}) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m InterfaceIntMap) Get(key interface{}) int {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m InterfaceIntMap) Set(key interface{}, value int) InterfaceIntMap {
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package multipletypes
|
||||
|
||||
type StringIntMap map[string]int
|
||||
|
||||
func (m StringIntMap) Has(key string) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m StringIntMap) Get(key string) int {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m StringIntMap) Set(key string, value int) StringIntMap {
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
package multipletypesets
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/cheekybits/genny/generic"
|
||||
)
|
||||
|
||||
type KeyType generic.Type
|
||||
type ValueType generic.Type
|
||||
|
||||
type KeyTypeValueTypeMap map[KeyType]ValueType
|
||||
|
||||
func (m KeyTypeValueTypeMap) Has(key KeyType) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m KeyTypeValueTypeMap) Get(key KeyType) ValueType {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m KeyTypeValueTypeMap) Set(key KeyType, value ValueType) KeyTypeValueTypeMap {
|
||||
log.Println(value)
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
Generated
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
package multipletypesets
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSimpleMap(t *testing.T) {
|
||||
|
||||
key1 := new(KeyType)
|
||||
key2 := new(KeyType)
|
||||
value1 := new(ValueType)
|
||||
m := make(KeyTypeValueTypeMap)
|
||||
|
||||
assert.Equal(t, m, m.Set(key1, value1))
|
||||
assert.True(t, m.Has(key1))
|
||||
assert.False(t, m.Has(key2))
|
||||
assert.Equal(t, value1, m.Get(key1))
|
||||
|
||||
}
|
||||
Generated
Vendored
-41
@@ -1,41 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package multipletypesets
|
||||
|
||||
import "log"
|
||||
|
||||
type IntStringMap map[int]string
|
||||
|
||||
func (m IntStringMap) Has(key int) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m IntStringMap) Get(key int) string {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m IntStringMap) Set(key int, value string) IntStringMap {
|
||||
log.Println(value)
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
|
||||
type Float64BoolMap map[float64]bool
|
||||
|
||||
func (m Float64BoolMap) Has(key float64) bool {
|
||||
_, ok := m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m Float64BoolMap) Get(key float64) bool {
|
||||
return m[key]
|
||||
}
|
||||
|
||||
func (m Float64BoolMap) Set(key float64, value bool) Float64BoolMap {
|
||||
log.Println(value)
|
||||
m[key] = value
|
||||
return m
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package numbers
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
type NumberType generic.Number
|
||||
|
||||
func NumberTypeMax(a, b NumberType) NumberType {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package numbers
|
||||
|
||||
func IntMax(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package changed
|
||||
|
||||
// IntQueue is a queue of Ints.
|
||||
type IntQueue struct {
|
||||
items []int
|
||||
}
|
||||
|
||||
func NewIntQueue() *IntQueue {
|
||||
return &IntQueue{items: make([]int, 0)}
|
||||
}
|
||||
func (q *IntQueue) Push(item int) {
|
||||
q.items = append(q.items, item)
|
||||
}
|
||||
func (q *IntQueue) Pop() int {
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return item
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package queue
|
||||
|
||||
// Float32Queue is a queue of Float32s.
|
||||
type Float32Queue struct {
|
||||
items []float32
|
||||
}
|
||||
|
||||
func NewFloat32Queue() *Float32Queue {
|
||||
return &Float32Queue{items: make([]float32, 0)}
|
||||
}
|
||||
func (q *Float32Queue) Push(item float32) {
|
||||
q.items = append(q.items, item)
|
||||
}
|
||||
func (q *Float32Queue) Pop() float32 {
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return item
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package queue
|
||||
|
||||
import "github.com/cheekybits/genny/generic"
|
||||
|
||||
// Something is a type that does something
|
||||
type Something generic.Type
|
||||
|
||||
// SomethingQueue is a queue of Somethings.
|
||||
type SomethingQueue struct {
|
||||
items []Something
|
||||
}
|
||||
|
||||
func NewSomethingQueue() *SomethingQueue {
|
||||
return &SomethingQueue{items: make([]Something, 0)}
|
||||
}
|
||||
func (q *SomethingQueue) Push(item Something) {
|
||||
q.items = append(q.items, item)
|
||||
}
|
||||
func (q *SomethingQueue) Pop() Something {
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return item
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package queue
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSomethingQueue(t *testing.T) {
|
||||
|
||||
var item1 *Something = new(Something)
|
||||
var item2 *Something = new(Something)
|
||||
var item3 *Something = new(Something)
|
||||
|
||||
q := NewSomethingQueue()
|
||||
|
||||
q.Push(item1)
|
||||
if len(q.items) != 1 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
q.Push(item2)
|
||||
if len(q.items) != 2 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
q.Push(item3)
|
||||
if len(q.items) != 3 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
|
||||
if q.Pop() != item1 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 2 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
if q.Pop() != item2 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 1 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
if q.Pop() != item3 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 0 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIntQueue(t *testing.T) {
|
||||
|
||||
var item1 int = 1
|
||||
var item2 int = 2
|
||||
var item3 int = 3
|
||||
|
||||
q := NewIntQueue()
|
||||
|
||||
q.Push(item1)
|
||||
if len(q.items) != 1 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
q.Push(item2)
|
||||
if len(q.items) != 2 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
q.Push(item3)
|
||||
if len(q.items) != 3 {
|
||||
t.Error("Push should add the item")
|
||||
}
|
||||
|
||||
if q.Pop() != item1 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 2 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
if q.Pop() != item2 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 1 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
if q.Pop() != item3 {
|
||||
t.Error("Pop should return items in the order in which they were added")
|
||||
}
|
||||
if len(q.items) != 0 {
|
||||
t.Error("Pop should remove the item")
|
||||
}
|
||||
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package queue
|
||||
|
||||
// IntQueue is a queue of Ints.
|
||||
type IntQueue struct {
|
||||
items []int
|
||||
}
|
||||
|
||||
func NewIntQueue() *IntQueue {
|
||||
return &IntQueue{items: make([]int, 0)}
|
||||
}
|
||||
func (q *IntQueue) Push(item int) {
|
||||
q.items = append(q.items, item)
|
||||
}
|
||||
func (q *IntQueue) Pop() int {
|
||||
item := q.items[0]
|
||||
q.items = q.items[1:]
|
||||
return item
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package slice
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
|
||||
"github.com/cheekybits/genny/generic"
|
||||
)
|
||||
|
||||
type MyType generic.Type
|
||||
|
||||
func EnsureSlice(objectOrSlice interface{}) []MyType {
|
||||
log.Printf("%v", reflect.TypeOf(objectOrSlice))
|
||||
switch obj := objectOrSlice.(type) {
|
||||
case []MyType:
|
||||
log.Println(" returning it untouched")
|
||||
return obj
|
||||
case MyType, *MyType:
|
||||
log.Println(" wrapping in slice")
|
||||
return []MyType{obj}
|
||||
default:
|
||||
panic("ensure slice needs MyType or []MyType")
|
||||
}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package slice
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEnsureSlice(t *testing.T) {
|
||||
|
||||
myType := new(MyType)
|
||||
slice := EnsureSlice(myType)
|
||||
if assert.NotNil(t, slice) {
|
||||
assert.Equal(t, slice[0], myType)
|
||||
}
|
||||
|
||||
slice = EnsureSlice(slice)
|
||||
log.Printf("%#v", slice[0])
|
||||
if assert.NotNil(t, slice) {
|
||||
assert.Equal(t, slice[0], myType)
|
||||
}
|
||||
|
||||
}
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
package unexported
|
||||
|
||||
type myType struct{}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package unexported
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cheekybits/genny/generic"
|
||||
)
|
||||
|
||||
type secret generic.Type
|
||||
|
||||
func secretInspect(s secret) string {
|
||||
return fmt.Sprintf("%#v", s)
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
// This file was automatically generated by genny.
|
||||
// Any changes will be lost if this file is regenerated.
|
||||
// see https://github.com/cheekybits/genny
|
||||
|
||||
package unexported
|
||||
|
||||
import "fmt"
|
||||
|
||||
func myTypeInspect(s *myType) string {
|
||||
return fmt.Sprintf("%#v", s)
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
package parse
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
typeSep = " "
|
||||
keyValueSep = "="
|
||||
valuesSep = ","
|
||||
builtins = "BUILTINS"
|
||||
numbers = "NUMBERS"
|
||||
)
|
||||
|
||||
// TypeSet turns a type string into a []map[string]string
|
||||
// that can be given to parse.Generics for it to do its magic.
|
||||
//
|
||||
// Acceptable args are:
|
||||
//
|
||||
// Person=man
|
||||
// Person=man Animal=dog
|
||||
// Person=man Animal=dog Animal2=cat
|
||||
// Person=man,woman Animal=dog,cat
|
||||
// Person=man,woman,child Animal=dog,cat Place=london,paris
|
||||
func TypeSet(arg string) ([]map[string]string, error) {
|
||||
|
||||
types := make(map[string][]string)
|
||||
var keys []string
|
||||
for _, pair := range strings.Split(arg, typeSep) {
|
||||
segs := strings.Split(pair, keyValueSep)
|
||||
if len(segs) != 2 {
|
||||
return nil, &errBadTypeArgs{Arg: arg, Message: "Generic=Specific expected"}
|
||||
}
|
||||
key := segs[0]
|
||||
keys = append(keys, key)
|
||||
types[key] = make([]string, 0)
|
||||
for _, t := range strings.Split(segs[1], valuesSep) {
|
||||
if t == builtins {
|
||||
types[key] = append(types[key], Builtins...)
|
||||
} else if t == numbers {
|
||||
types[key] = append(types[key], Numbers...)
|
||||
} else {
|
||||
types[key] = append(types[key], t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cursors := make(map[string]int)
|
||||
for _, key := range keys {
|
||||
cursors[key] = 0
|
||||
}
|
||||
|
||||
outChan := make(chan map[string]string)
|
||||
go func() {
|
||||
buildTypeSet(keys, 0, cursors, types, outChan)
|
||||
close(outChan)
|
||||
}()
|
||||
|
||||
var typeSets []map[string]string
|
||||
for typeSet := range outChan {
|
||||
typeSets = append(typeSets, typeSet)
|
||||
}
|
||||
|
||||
return typeSets, nil
|
||||
|
||||
}
|
||||
|
||||
func buildTypeSet(keys []string, keyI int, cursors map[string]int, types map[string][]string, out chan<- map[string]string) {
|
||||
key := keys[keyI]
|
||||
for cursors[key] < len(types[key]) {
|
||||
if keyI < len(keys)-1 {
|
||||
buildTypeSet(keys, keyI+1, copycursors(cursors), types, out)
|
||||
} else {
|
||||
// build the typeset for this combination
|
||||
ts := make(map[string]string)
|
||||
for k, vals := range types {
|
||||
ts[k] = vals[cursors[k]]
|
||||
}
|
||||
out <- ts
|
||||
}
|
||||
cursors[key]++
|
||||
}
|
||||
}
|
||||
|
||||
func copycursors(source map[string]int) map[string]int {
|
||||
copy := make(map[string]int)
|
||||
for k, v := range source {
|
||||
copy[k] = v
|
||||
}
|
||||
return copy
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package parse_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/cheekybits/genny/parse"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestArgsToTypeset(t *testing.T) {
|
||||
|
||||
args := "Person=man,woman Animal=dog,cat Place=london,paris"
|
||||
ts, err := parse.TypeSet(args)
|
||||
|
||||
if assert.NoError(t, err) {
|
||||
if assert.Equal(t, 8, len(ts)) {
|
||||
|
||||
assert.Equal(t, ts[0]["Person"], "man")
|
||||
assert.Equal(t, ts[0]["Animal"], "dog")
|
||||
assert.Equal(t, ts[0]["Place"], "london")
|
||||
|
||||
assert.Equal(t, ts[1]["Person"], "man")
|
||||
assert.Equal(t, ts[1]["Animal"], "dog")
|
||||
assert.Equal(t, ts[1]["Place"], "paris")
|
||||
|
||||
assert.Equal(t, ts[2]["Person"], "man")
|
||||
assert.Equal(t, ts[2]["Animal"], "cat")
|
||||
assert.Equal(t, ts[2]["Place"], "london")
|
||||
|
||||
assert.Equal(t, ts[3]["Person"], "man")
|
||||
assert.Equal(t, ts[3]["Animal"], "cat")
|
||||
assert.Equal(t, ts[3]["Place"], "paris")
|
||||
|
||||
assert.Equal(t, ts[4]["Person"], "woman")
|
||||
assert.Equal(t, ts[4]["Animal"], "dog")
|
||||
assert.Equal(t, ts[4]["Place"], "london")
|
||||
|
||||
assert.Equal(t, ts[5]["Person"], "woman")
|
||||
assert.Equal(t, ts[5]["Animal"], "dog")
|
||||
assert.Equal(t, ts[5]["Place"], "paris")
|
||||
|
||||
assert.Equal(t, ts[6]["Person"], "woman")
|
||||
assert.Equal(t, ts[6]["Animal"], "cat")
|
||||
assert.Equal(t, ts[6]["Place"], "london")
|
||||
|
||||
assert.Equal(t, ts[7]["Person"], "woman")
|
||||
assert.Equal(t, ts[7]["Animal"], "cat")
|
||||
assert.Equal(t, ts[7]["Place"], "paris")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ts, err = parse.TypeSet("Person=man Animal=dog Place=london")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, 1, len(ts))
|
||||
}
|
||||
ts, err = parse.TypeSet("Person=1,2,3,4,5 Animal=1,2,3,4,5 Place=1,2,3,4,5")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, 125, len(ts))
|
||||
}
|
||||
ts, err = parse.TypeSet("Person=1 Animal=1,2,3,4,5 Place=1,2")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, 10, len(ts))
|
||||
}
|
||||
|
||||
ts, err = parse.TypeSet("Person=interface{} Animal=interface{} Place=interface{}")
|
||||
if assert.NoError(t, err) {
|
||||
assert.Equal(t, 1, len(ts))
|
||||
assert.Equal(t, ts[0]["Animal"], "interface{}")
|
||||
assert.Equal(t, ts[0]["Person"], "interface{}")
|
||||
assert.Equal(t, ts[0]["Place"], "interface{}")
|
||||
}
|
||||
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
str1:
|
||||
foo: bar
|
||||
arr1: strval1
|
||||
map1:
|
||||
- abc
|
||||
- def
|
||||
int1: true
|
||||
float1: "strval2"
|
||||
bool1: 123.45
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
cat <<EOM
|
||||
str1: d3str1val1
|
||||
arr1:
|
||||
- d3arr1val1
|
||||
- d3arr1val2
|
||||
map1:
|
||||
key2: d3map1val2
|
||||
key3: d3map1val3
|
||||
int1: 333
|
||||
float1: 3.33
|
||||
bool1: true
|
||||
EOM
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
str1: d3str1val1
|
||||
arr1:
|
||||
- d3arr1val1
|
||||
- d3arr1val2
|
||||
- dupval
|
||||
map1:
|
||||
key2: d3map1val2
|
||||
key3: d3map1val3
|
||||
dup: d3dupval
|
||||
int1: 333
|
||||
float1: 3.33
|
||||
bool1: true
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
str1: d3str1val1
|
||||
arr1:
|
||||
- d3arr1val1
|
||||
- d3arr1val2
|
||||
map1:
|
||||
key2: d3map1val2
|
||||
key3: d3map1val3
|
||||
int1: 333
|
||||
float1: 3.33
|
||||
bool1: true
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
str1: d3str1val1
|
||||
arr1:
|
||||
- d3arr1val1
|
||||
- d3arr1val2
|
||||
map1:
|
||||
key2: d3map1val2
|
||||
key3: d3map1val3
|
||||
int1: 333
|
||||
float1: 3.33
|
||||
bool1: true
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
cat <<EOM
|
||||
str1: d2str1val1
|
||||
arr1:
|
||||
- d2arr1val1
|
||||
- d2arr1val2
|
||||
map1:
|
||||
key1: d2map1val1
|
||||
key2: d2map1val2
|
||||
int1: 222
|
||||
float1: 2.22
|
||||
bool1: false
|
||||
EOM
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
str1: d2str1val1
|
||||
arr1:
|
||||
- d2arr1val1
|
||||
- d2arr1val2
|
||||
- dupval
|
||||
map1:
|
||||
key1: d2map1val1
|
||||
key2: d2map1val2
|
||||
dup: d2dupval
|
||||
int1: 222
|
||||
float1: 2.22
|
||||
bool1: false
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
config:
|
||||
overwrite:
|
||||
- str1
|
||||
- arr1
|
||||
- bool1
|
||||
str1: d2str1val1
|
||||
arr1:
|
||||
- d2arr1val1
|
||||
- d2arr1val2
|
||||
map1:
|
||||
key1: d2map1val1
|
||||
key2: d2map1val2
|
||||
int1: 222
|
||||
float1: 2.22
|
||||
bool1: false
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
config:
|
||||
stop: true
|
||||
str1: d2str1val1
|
||||
arr1:
|
||||
- d2arr1val1
|
||||
- d2arr1val2
|
||||
map1:
|
||||
key1: d2map1val1
|
||||
key2: d2map1val2
|
||||
int1: 222
|
||||
float1: 2.22
|
||||
bool1: false
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
#!/bin/bash
|
||||
cat <<EOM
|
||||
str1: d1str1val1
|
||||
arr1:
|
||||
- d1arr1val1
|
||||
- d1arr1val2
|
||||
map1:
|
||||
key0: d1map1val0
|
||||
key1: d1map1val1
|
||||
int1: 111
|
||||
float1: 1.11
|
||||
bool1: true
|
||||
EOM
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
str1: d1str1val1
|
||||
arr1:
|
||||
- d1arr1val1
|
||||
- d1arr1val2
|
||||
- dupval
|
||||
map1:
|
||||
key0: d1map1val0
|
||||
key1: d1map1val1
|
||||
dup: d1dupval
|
||||
int1: 111
|
||||
float1: 1.11
|
||||
bool1: true
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
config:
|
||||
overwrite:
|
||||
- map1
|
||||
- int1
|
||||
- float1
|
||||
str1: d1str1val1
|
||||
arr1:
|
||||
- d1arr1val1
|
||||
- d1arr1val2
|
||||
map1:
|
||||
key0: d1map1val0
|
||||
key1: d1map1val1
|
||||
int1: 111
|
||||
float1: 1.11
|
||||
bool1: true
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
str1: d1str1val1
|
||||
arr1:
|
||||
- d1arr1val1
|
||||
- d1arr1val2
|
||||
map1:
|
||||
key0: d1map1val0
|
||||
key1: d1map1val1
|
||||
int1: 111
|
||||
float1: 1.11
|
||||
bool1: true
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for _, v := range []string{"method_call", "method_return", "error", "signal"} {
|
||||
call := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"eavesdrop='true',type='"+v+"'")
|
||||
if call.Err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to add match:", call.Err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
c := make(chan *dbus.Message, 10)
|
||||
conn.Eavesdrop(c)
|
||||
fmt.Println("Listening for everything")
|
||||
for v := range c {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"github.com/guelfey/go.dbus/introspect"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
node, err := introspect.Call(conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data, _ := json.MarshalIndent(node, "", " ")
|
||||
os.Stdout.Write(data)
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var s []string
|
||||
err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&s)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to get list of owned names:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Currently owned names on the session bus:")
|
||||
for _, v := range s {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import "github.com/guelfey/go.dbus"
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
obj := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications")
|
||||
call := obj.Call("org.freedesktop.Notifications.Notify", 0, "", uint32(0),
|
||||
"", "Test", "This is a test of the DBus bindings for go.", []string{},
|
||||
map[string]dbus.Variant{}, int32(5000))
|
||||
if call.Err != nil {
|
||||
panic(call.Err)
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"github.com/guelfey/go.dbus/introspect"
|
||||
"github.com/guelfey/go.dbus/prop"
|
||||
"os"
|
||||
)
|
||||
|
||||
type foo string
|
||||
|
||||
func (f foo) Foo() (string, *dbus.Error) {
|
||||
fmt.Println(f)
|
||||
return string(f), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
reply, err := conn.RequestName("com.github.guelfey.Demo",
|
||||
dbus.NameFlagDoNotQueue)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if reply != dbus.RequestNameReplyPrimaryOwner {
|
||||
fmt.Fprintln(os.Stderr, "name already taken")
|
||||
os.Exit(1)
|
||||
}
|
||||
propsSpec := map[string]map[string]*prop.Prop{
|
||||
"com.github.guelfey.Demo": {
|
||||
"SomeInt": {
|
||||
int32(0),
|
||||
true,
|
||||
prop.EmitTrue,
|
||||
func(c *prop.Change) *dbus.Error {
|
||||
fmt.Println(c.Name, "changed to", c.Value)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
f := foo("Bar")
|
||||
conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
|
||||
props := prop.New(conn, "/com/github/guelfey/Demo", propsSpec)
|
||||
n := &introspect.Node{
|
||||
Name: "/com/github/guelfey/Demo",
|
||||
Interfaces: []introspect.Interface{
|
||||
introspect.IntrospectData,
|
||||
prop.IntrospectData,
|
||||
{
|
||||
Name: "com.github.guelfey.Demo",
|
||||
Methods: introspect.Methods(f),
|
||||
Properties: props.Introspection("com.github.guelfey.Demo"),
|
||||
},
|
||||
},
|
||||
}
|
||||
conn.Export(introspect.NewIntrospectable(n), "/com/github/guelfey/Demo",
|
||||
"org.freedesktop.DBus.Introspectable")
|
||||
fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
|
||||
|
||||
c := make(chan *dbus.Signal)
|
||||
conn.Signal(c)
|
||||
for _ = range c {
|
||||
}
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"github.com/guelfey/go.dbus/introspect"
|
||||
"os"
|
||||
)
|
||||
|
||||
const intro = `
|
||||
<node>
|
||||
<interface name="com.github.guelfey.Demo">
|
||||
<method name="Foo">
|
||||
<arg direction="out" type="s"/>
|
||||
</method>
|
||||
</interface>` + introspect.IntrospectDataString + `</node> `
|
||||
|
||||
type foo string
|
||||
|
||||
func (f foo) Foo() (string, *dbus.Error) {
|
||||
fmt.Println(f)
|
||||
return string(f), nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
reply, err := conn.RequestName("com.github.guelfey.Demo",
|
||||
dbus.NameFlagDoNotQueue)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if reply != dbus.RequestNameReplyPrimaryOwner {
|
||||
fmt.Fprintln(os.Stderr, "name already taken")
|
||||
os.Exit(1)
|
||||
}
|
||||
f := foo("Bar!")
|
||||
conn.Export(f, "/com/github/guelfey/Demo", "com.github.guelfey.Demo")
|
||||
conn.Export(introspect.Introspectable(intro), "/com/github/guelfey/Demo",
|
||||
"org.freedesktop.DBus.Introspectable")
|
||||
fmt.Println("Listening on com.github.guelfey.Demo / /com/github/guelfey/Demo ...")
|
||||
select {}
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := dbus.SessionBus()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Failed to connect to session bus:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0,
|
||||
"type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',sender='org.freedesktop.DBus'")
|
||||
|
||||
c := make(chan *dbus.Signal, 10)
|
||||
conn.Signal(c)
|
||||
for v := range c {
|
||||
fmt.Println(v)
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
package introspect
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Call calls org.freedesktop.Introspectable.Introspect on a remote object
|
||||
// and returns the introspection data.
|
||||
func Call(o *dbus.Object) (*Node, error) {
|
||||
var xmldata string
|
||||
var node Node
|
||||
|
||||
err := o.Call("org.freedesktop.DBus.Introspectable.Introspect", 0).Store(&xmldata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = xml.NewDecoder(strings.NewReader(xmldata)).Decode(&node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node.Name == "" {
|
||||
node.Name = string(o.Path())
|
||||
}
|
||||
return &node, nil
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
// Package introspect provides some utilities for dealing with the DBus
|
||||
// introspection format.
|
||||
package introspect
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// The introspection data for the org.freedesktop.DBus.Introspectable interface.
|
||||
var IntrospectData = Interface{
|
||||
Name: "org.freedesktop.DBus.Introspectable",
|
||||
Methods: []Method{
|
||||
{
|
||||
Name: "Introspect",
|
||||
Args: []Arg{
|
||||
{"out", "s", "out"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// The introspection data for the org.freedesktop.DBus.Introspectable interface,
|
||||
// as a string.
|
||||
const IntrospectDataString = `
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="out" direction="out" type="s"/>
|
||||
</method>
|
||||
</interface>
|
||||
`
|
||||
|
||||
// Node is the root element of an introspection.
|
||||
type Node struct {
|
||||
XMLName xml.Name `xml:"node"`
|
||||
Name string `xml:"name,attr,omitempty"`
|
||||
Interfaces []Interface `xml:"interface"`
|
||||
Children []Node `xml:"node,omitempty"`
|
||||
}
|
||||
|
||||
// Interface describes a DBus interface that is available on the message bus.
|
||||
type Interface struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Methods []Method `xml:"method"`
|
||||
Signals []Signal `xml:"signal"`
|
||||
Properties []Property `xml:"property"`
|
||||
Annotations []Annotation `xml:"annotation"`
|
||||
}
|
||||
|
||||
// Method describes a Method on an Interface as retured by an introspection.
|
||||
type Method struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Args []Arg `xml:"arg"`
|
||||
Annotations []Annotation `xml:"annotation"`
|
||||
}
|
||||
|
||||
// Signal describes a Signal emitted on an Interface.
|
||||
type Signal struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Args []Arg `xml:"arg"`
|
||||
Annotations []Annotation `xml:"annotation"`
|
||||
}
|
||||
|
||||
// Property describes a property of an Interface.
|
||||
type Property struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Access string `xml:"access,attr"`
|
||||
Annotations []Annotation `xml:"annotation"`
|
||||
}
|
||||
|
||||
// Arg represents an argument of a method or a signal.
|
||||
type Arg struct {
|
||||
Name string `xml:"name,attr,omitempty"`
|
||||
Type string `xml:"type,attr"`
|
||||
Direction string `xml:"direction,attr,omitempty"`
|
||||
}
|
||||
|
||||
// Annotation is an annotation in the introspection format.
|
||||
type Annotation struct {
|
||||
Name string `xml:"name,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package introspect
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"github.com/guelfey/go.dbus"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Introspectable implements org.freedesktop.Introspectable.
|
||||
//
|
||||
// You can create it by converting the XML-formatted introspection data from a
|
||||
// string to an Introspectable or call NewIntrospectable with a Node. Then,
|
||||
// export it as org.freedesktop.Introspectable on you object.
|
||||
type Introspectable string
|
||||
|
||||
// NewIntrospectable returns an Introspectable that returns the introspection
|
||||
// data that corresponds to the given Node. If n.Interfaces doesn't contain the
|
||||
// data for org.freedesktop.DBus.Introspectable, it is added automatically.
|
||||
func NewIntrospectable(n *Node) Introspectable {
|
||||
found := false
|
||||
for _, v := range n.Interfaces {
|
||||
if v.Name == "org.freedesktop.DBus.Introspectable" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
n.Interfaces = append(n.Interfaces, IntrospectData)
|
||||
}
|
||||
b, err := xml.Marshal(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return Introspectable(b)
|
||||
}
|
||||
|
||||
// Introspect implements org.freedesktop.Introspectable.Introspect.
|
||||
func (i Introspectable) Introspect() (string, *dbus.Error) {
|
||||
return string(i), nil
|
||||
}
|
||||
|
||||
// Methods returns the description of the methods of v. This can be used to
|
||||
// create a Node which can be passed to NewIntrospectable.
|
||||
func Methods(v interface{}) []Method {
|
||||
t := reflect.TypeOf(v)
|
||||
ms := make([]Method, 0, t.NumMethod())
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
if t.Method(i).PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
mt := t.Method(i).Type
|
||||
if mt.NumOut() == 0 ||
|
||||
mt.Out(mt.NumOut()-1) != reflect.TypeOf(&dbus.Error{"", nil}) {
|
||||
|
||||
continue
|
||||
}
|
||||
var m Method
|
||||
m.Name = t.Method(i).Name
|
||||
m.Args = make([]Arg, 0, mt.NumIn()+mt.NumOut()-2)
|
||||
for j := 1; j < mt.NumIn(); j++ {
|
||||
if mt.In(j) != reflect.TypeOf((*dbus.Sender)(nil)).Elem() {
|
||||
arg := Arg{"", dbus.SignatureOfType(mt.In(j)).String(), "in"}
|
||||
m.Args = append(m.Args, arg)
|
||||
}
|
||||
}
|
||||
for j := 0; j < mt.NumOut()-1; j++ {
|
||||
arg := Arg{"", dbus.SignatureOfType(mt.Out(j)).String(), "out"}
|
||||
m.Args = append(m.Args, arg)
|
||||
}
|
||||
m.Annotations = make([]Annotation, 0)
|
||||
ms = append(ms, m)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
-264
@@ -1,264 +0,0 @@
|
||||
// Package prop provides the Properties struct which can be used to implement
|
||||
// org.freedesktop.DBus.Properties.
|
||||
package prop
|
||||
|
||||
import (
|
||||
"github.com/guelfey/go.dbus"
|
||||
"github.com/guelfey/go.dbus/introspect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// EmitType controls how org.freedesktop.DBus.Properties.PropertiesChanged is
|
||||
// emitted for a property. If it is EmitTrue, the signal is emitted. If it is
|
||||
// EmitInvalidates, the signal is also emitted, but the new value of the property
|
||||
// is not disclosed.
|
||||
type EmitType byte
|
||||
|
||||
const (
|
||||
EmitFalse EmitType = iota
|
||||
EmitTrue
|
||||
EmitInvalidates
|
||||
)
|
||||
|
||||
// ErrIfaceNotFound is the error returned to peers who try to access properties
|
||||
// on interfaces that aren't found.
|
||||
var ErrIfaceNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InterfaceNotFound", nil}
|
||||
|
||||
// ErrPropNotFound is the error returned to peers trying to access properties
|
||||
// that aren't found.
|
||||
var ErrPropNotFound = &dbus.Error{"org.freedesktop.DBus.Properties.Error.PropertyNotFound", nil}
|
||||
|
||||
// ErrReadOnly is the error returned to peers trying to set a read-only
|
||||
// property.
|
||||
var ErrReadOnly = &dbus.Error{"org.freedesktop.DBus.Properties.Error.ReadOnly", nil}
|
||||
|
||||
// ErrInvalidArg is returned to peers if the type of the property that is being
|
||||
// changed and the argument don't match.
|
||||
var ErrInvalidArg = &dbus.Error{"org.freedesktop.DBus.Properties.Error.InvalidArg", nil}
|
||||
|
||||
// The introspection data for the org.freedesktop.DBus.Properties interface.
|
||||
var IntrospectData = introspect.Interface{
|
||||
Name: "org.freedesktop.DBus.Properties",
|
||||
Methods: []introspect.Method{
|
||||
{
|
||||
Name: "Get",
|
||||
Args: []introspect.Arg{
|
||||
{"interface", "s", "in"},
|
||||
{"property", "s", "in"},
|
||||
{"value", "v", "out"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "GetAll",
|
||||
Args: []introspect.Arg{
|
||||
{"interface", "s", "in"},
|
||||
{"props", "a{sv}", "out"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Set",
|
||||
Args: []introspect.Arg{
|
||||
{"interface", "s", "in"},
|
||||
{"property", "s", "in"},
|
||||
{"value", "v", "in"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Signals: []introspect.Signal{
|
||||
{
|
||||
Name: "PropertiesChanged",
|
||||
Args: []introspect.Arg{
|
||||
{"interface", "s", "out"},
|
||||
{"changed_properties", "a{sv}", "out"},
|
||||
{"invalidates_properties", "as", "out"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// The introspection data for the org.freedesktop.DBus.Properties interface, as
|
||||
// a string.
|
||||
const IntrospectDataString = `
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Get">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="out" type="v"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="props" direction="out" type="a{sv}"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface" direction="in" type="s"/>
|
||||
<arg name="property" direction="in" type="s"/>
|
||||
<arg name="value" direction="in" type="v"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidates_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
`
|
||||
|
||||
// Prop represents a single property. It is used for creating a Properties
|
||||
// value.
|
||||
type Prop struct {
|
||||
// Initial value. Must be a DBus-representable type.
|
||||
Value interface{}
|
||||
|
||||
// If true, the value can be modified by calls to Set.
|
||||
Writable bool
|
||||
|
||||
// Controls how org.freedesktop.DBus.Properties.PropertiesChanged is
|
||||
// emitted if this property changes.
|
||||
Emit EmitType
|
||||
|
||||
// If not nil, anytime this property is changed by Set, this function is
|
||||
// called with an appropiate Change as its argument. If the returned error
|
||||
// is not nil, it is sent back to the caller of Set and the property is not
|
||||
// changed.
|
||||
Callback func(*Change) *dbus.Error
|
||||
}
|
||||
|
||||
// Change represents a change of a property by a call to Set.
|
||||
type Change struct {
|
||||
Props *Properties
|
||||
Iface string
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// Properties is a set of values that can be made available to the message bus
|
||||
// using the org.freedesktop.DBus.Properties interface. It is safe for
|
||||
// concurrent use by multiple goroutines.
|
||||
type Properties struct {
|
||||
m map[string]map[string]*Prop
|
||||
mut sync.RWMutex
|
||||
conn *dbus.Conn
|
||||
path dbus.ObjectPath
|
||||
}
|
||||
|
||||
// New returns a new Properties structure that manages the given properties.
|
||||
// The key for the first-level map of props is the name of the interface; the
|
||||
// second-level key is the name of the property. The returned structure will be
|
||||
// exported as org.freedesktop.DBus.Properties on path.
|
||||
func New(conn *dbus.Conn, path dbus.ObjectPath, props map[string]map[string]*Prop) *Properties {
|
||||
p := &Properties{m: props, conn: conn, path: path}
|
||||
conn.Export(p, path, "org.freedesktop.DBus.Properties")
|
||||
return p
|
||||
}
|
||||
|
||||
// Get implements org.freedesktop.DBus.Properties.Get.
|
||||
func (p *Properties) Get(iface, property string) (dbus.Variant, *dbus.Error) {
|
||||
p.mut.RLock()
|
||||
defer p.mut.RUnlock()
|
||||
m, ok := p.m[iface]
|
||||
if !ok {
|
||||
return dbus.Variant{}, ErrIfaceNotFound
|
||||
}
|
||||
prop, ok := m[property]
|
||||
if !ok {
|
||||
return dbus.Variant{}, ErrPropNotFound
|
||||
}
|
||||
return dbus.MakeVariant(prop.Value), nil
|
||||
}
|
||||
|
||||
// GetAll implements org.freedesktop.DBus.Properties.GetAll.
|
||||
func (p *Properties) GetAll(iface string) (map[string]dbus.Variant, *dbus.Error) {
|
||||
p.mut.RLock()
|
||||
defer p.mut.RUnlock()
|
||||
m, ok := p.m[iface]
|
||||
if !ok {
|
||||
return nil, ErrIfaceNotFound
|
||||
}
|
||||
rm := make(map[string]dbus.Variant, len(m))
|
||||
for k, v := range m {
|
||||
rm[k] = dbus.MakeVariant(v.Value)
|
||||
}
|
||||
return rm, nil
|
||||
}
|
||||
|
||||
// GetMust returns the value of the given property and panics if either the
|
||||
// interface or the property name are invalid.
|
||||
func (p *Properties) GetMust(iface, property string) interface{} {
|
||||
p.mut.RLock()
|
||||
defer p.mut.RUnlock()
|
||||
return p.m[iface][property].Value
|
||||
}
|
||||
|
||||
// Introspection returns the introspection data that represents the properties
|
||||
// of iface.
|
||||
func (p *Properties) Introspection(iface string) []introspect.Property {
|
||||
p.mut.RLock()
|
||||
defer p.mut.RUnlock()
|
||||
m := p.m[iface]
|
||||
s := make([]introspect.Property, 0, len(m))
|
||||
for k, v := range m {
|
||||
p := introspect.Property{Name: k, Type: dbus.SignatureOf(v.Value).String()}
|
||||
if v.Writable {
|
||||
p.Access = "readwrite"
|
||||
} else {
|
||||
p.Access = "read"
|
||||
}
|
||||
s = append(s, p)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// set sets the given property and emits PropertyChanged if appropiate. p.mut
|
||||
// must already be locked.
|
||||
func (p *Properties) set(iface, property string, v interface{}) {
|
||||
prop := p.m[iface][property]
|
||||
prop.Value = v
|
||||
switch prop.Emit {
|
||||
case EmitFalse:
|
||||
// do nothing
|
||||
case EmitInvalidates:
|
||||
p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
|
||||
iface, map[string]dbus.Variant{}, []string{property})
|
||||
case EmitTrue:
|
||||
p.conn.Emit(p.path, "org.freedesktop.DBus.Properties.PropertiesChanged",
|
||||
iface, map[string]dbus.Variant{property: dbus.MakeVariant(v)},
|
||||
[]string{})
|
||||
default:
|
||||
panic("invalid value for EmitType")
|
||||
}
|
||||
}
|
||||
|
||||
// Set implements org.freedesktop.Properties.Set.
|
||||
func (p *Properties) Set(iface, property string, newv dbus.Variant) *dbus.Error {
|
||||
p.mut.Lock()
|
||||
defer p.mut.Unlock()
|
||||
m, ok := p.m[iface]
|
||||
if !ok {
|
||||
return ErrIfaceNotFound
|
||||
}
|
||||
prop, ok := m[property]
|
||||
if !ok {
|
||||
return ErrPropNotFound
|
||||
}
|
||||
if !prop.Writable {
|
||||
return ErrReadOnly
|
||||
}
|
||||
if newv.Signature() != dbus.SignatureOf(prop.Value) {
|
||||
return ErrInvalidArg
|
||||
}
|
||||
if prop.Callback != nil {
|
||||
err := prop.Callback(&Change{p, iface, property, newv.Value()})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
p.set(iface, property, newv.Value())
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetMust sets the value of the given property and panics if the interface or
|
||||
// the property name are invalid.
|
||||
func (p *Properties) SetMust(iface, property string, v interface{}) {
|
||||
p.mut.Lock()
|
||||
p.set(iface, property, v)
|
||||
p.mut.Unlock()
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
func main() {
|
||||
stdOut := bufio.NewWriter(colorable.NewColorableStdout())
|
||||
|
||||
fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
|
||||
fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
|
||||
stdOut.Flush()
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
|
||||
logrus.SetOutput(colorable.NewColorableStdout())
|
||||
|
||||
logrus.Info("succeeded")
|
||||
logrus.Warn("not correct")
|
||||
logrus.Error("something error")
|
||||
logrus.Fatal("panic")
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
. "github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
func main() {
|
||||
out := NewColorableStdout()
|
||||
fmt.Fprint(out, "\x1B]0;TITLE Changed\007(See title and hit any key)")
|
||||
var c [1]byte
|
||||
os.Stdin.Read(c[:])
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
func main() {
|
||||
io.Copy(colorable.NewColorableStdout(), os.Stdin)
|
||||
}
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mgutz/ansi"
|
||||
)
|
||||
|
||||
func main() {
|
||||
printColors()
|
||||
print256Colors()
|
||||
printConstants()
|
||||
}
|
||||
|
||||
func pad(s string, length int) string {
|
||||
for len(s) < length {
|
||||
s += " "
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func padColor(s string, styles []string) string {
|
||||
buffer := ""
|
||||
for _, style := range styles {
|
||||
buffer += ansi.Color(pad(s+style, 20), s+style)
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
func printPlain() {
|
||||
ansi.DisableColors(true)
|
||||
bgColors := []string{
|
||||
"",
|
||||
":black",
|
||||
":red",
|
||||
":green",
|
||||
":yellow",
|
||||
":blue",
|
||||
":magenta",
|
||||
":cyan",
|
||||
":white",
|
||||
}
|
||||
for fg := range ansi.Colors {
|
||||
for _, bg := range bgColors {
|
||||
println(padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
|
||||
println(padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h"}))
|
||||
println(padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printColors() {
|
||||
ansi.DisableColors(false)
|
||||
stdout := colorable.NewColorableStdout()
|
||||
|
||||
bgColors := []string{
|
||||
"",
|
||||
":black",
|
||||
":red",
|
||||
":green",
|
||||
":yellow",
|
||||
":blue",
|
||||
":magenta",
|
||||
":cyan",
|
||||
":white",
|
||||
}
|
||||
|
||||
keys := []string{}
|
||||
for fg := range ansi.Colors {
|
||||
_, err := strconv.Atoi(fg)
|
||||
if err != nil {
|
||||
keys = append(keys, fg)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, fg := range keys {
|
||||
for _, bg := range bgColors {
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+bh" + bg, "+u" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+uh" + bg, "+B" + bg, "+Bb" + bg /* backgrounds */, "" + bg + "+h", "+s" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+b" + bg + "+h", "+bh" + bg + "+h", "+u" + bg + "+h", "+uh" + bg + "+h"}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func print256Colors() {
|
||||
ansi.DisableColors(false)
|
||||
stdout := colorable.NewColorableStdout()
|
||||
|
||||
bgColors := []string{""}
|
||||
for i := 0; i < 256; i++ {
|
||||
key := fmt.Sprintf(":%d", i)
|
||||
bgColors = append(bgColors, key)
|
||||
}
|
||||
|
||||
keys := []string{}
|
||||
for fg := range ansi.Colors {
|
||||
n, err := strconv.Atoi(fg)
|
||||
if err == nil {
|
||||
keys = append(keys, fmt.Sprintf("%3d", n))
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, fg := range keys {
|
||||
for _, bg := range bgColors {
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"" + bg, "+b" + bg, "+u" + bg}))
|
||||
fmt.Fprintln(stdout, padColor(fg, []string{"+B" + bg, "+Bb" + bg, "+s" + bg}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printConstants() {
|
||||
stdout := colorable.NewColorableStdout()
|
||||
fmt.Fprintln(stdout, ansi.DefaultFG, "ansi.DefaultFG", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Black, "ansi.Black", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Red, "ansi.Red", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Green, "ansi.Green", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Yellow, "ansi.Yellow", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Blue, "ansi.Blue", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Magenta, "ansi.Magenta", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.Cyan, "ansi.Cyan", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.White, "ansi.White", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightBlack, "ansi.LightBlack", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightRed, "ansi.LightRed", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightGreen, "ansi.LightGreen", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightYellow, "ansi.LightYellow", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightBlue, "ansi.LightBlue", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightMagenta, "ansi.LightMagenta", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightCyan, "ansi.LightCyan", ansi.Reset)
|
||||
fmt.Fprintln(stdout, ansi.LightWhite, "ansi.LightWhite", ansi.Reset)
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
// Open is a simple example of the github.com/pkg/browser package.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// # Open a file in a browser window
|
||||
// Open $FILE
|
||||
//
|
||||
// # Open a URL in a browser window
|
||||
// Open $URL
|
||||
//
|
||||
// # Open the contents of stdin in a browser window
|
||||
// cat $SOMEFILE | Open
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "Usage:\n %s [file]\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
func init() {
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func check(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := flag.Args()
|
||||
switch len(args) {
|
||||
case 0:
|
||||
check(browser.OpenReader(os.Stdin))
|
||||
case 1:
|
||||
check(browser.OpenFile(args[0]))
|
||||
default:
|
||||
usage()
|
||||
}
|
||||
}
|
||||
-27
@@ -1,27 +0,0 @@
|
||||
# Timing Tests
|
||||
|
||||
It was noted in [issue #2](github.com/sethgrid/pester/issue/2) that Pester may be slower than the standard library (along with bug that was fixed).
|
||||
|
||||
I put together a quick test to see how Pester fairs against the stand library. Here are the results:
|
||||
|
||||
```
|
||||
$ go test
|
||||
Standard Library Get 675178 ns Avg.
|
||||
Pester, Default 690157 ns Avg.
|
||||
Pester, Retries 1, Conc 1 671322 ns Avg.
|
||||
Pester, Retries 2, Conc 2 764386 ns Avg.
|
||||
Pester, Retries 3, Conc 3 893899 ns Avg.
|
||||
Pester, Retries 0, Conc 1 730407 ns Avg.
|
||||
Pester, Retries 0, Conc 2 1077721 ns Avg.
|
||||
Pester, Retries 0, Conc 3 1889403 ns Avg.
|
||||
Pester, Retries 0, Conc 1 1758464 ns Avg.
|
||||
Pester, Retries 2, Conc 1 1249081 ns Avg.
|
||||
Pester, Retries 3, Conc 1 1824322 ns Avg.
|
||||
PASS
|
||||
```
|
||||
|
||||
Running the test locally multiple times shows some variance, but this is a typical result. In raw time, these average times are not far off from each other (about 1ms from the best to worst case). In comparisons between percents, we see a drift of up to 3x.
|
||||
|
||||
The up to 3x drift between the near identical default Pester implementation and the Standard Library http.Get call compared to the last test case of 'Retries 3, Conc 1' makes little sense in that the default Pester uses 'Retries 3, Conc 1' as its settings.
|
||||
|
||||
I think that it is safe to say that there is no material difference in speed between the Standard Library and Pester.
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
Can't use testing.B Tests because it eats up file descriptors
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sethgrid/pester"
|
||||
)
|
||||
|
||||
type getter func(string) (*http.Response, error)
|
||||
|
||||
func TestWarmup(t *testing.T) {
|
||||
// The first request/test takes more time.
|
||||
// Does not matter if we use http.Get or pester.Get
|
||||
// nor if we use the default client or initialize one.
|
||||
// I don't know why yet.
|
||||
c := pester.New()
|
||||
_ = runner("Warm Up", c.Get)
|
||||
}
|
||||
|
||||
func TestStdLibGet(t *testing.T) {
|
||||
// base case - get a url with std lib
|
||||
fmt.Println(runner("Standard Library Get ", http.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetDefaults(t *testing.T) {
|
||||
fmt.Println(runner("Pester, Default", pester.Get))
|
||||
}
|
||||
|
||||
func TestPesterRetry1Conc1(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 1
|
||||
c.Concurrency = 1
|
||||
|
||||
fmt.Println(runner("Pester, Retries 1, Conc 1", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterRetry2Conc2(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 2
|
||||
c.Concurrency = 2
|
||||
|
||||
fmt.Println(runner("Pester, Retries 2, Conc 2", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterRetry3Conc3(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 3
|
||||
c.Concurrency = 3
|
||||
|
||||
fmt.Println(runner("Pester, Retries 3, Conc 3", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetry0Conc1(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 0
|
||||
c.Concurrency = 1
|
||||
|
||||
fmt.Println(runner("Pester, Retries 0, Conc 1", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetry0Conc2(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 0
|
||||
c.Concurrency = 2
|
||||
|
||||
fmt.Println(runner("Pester, Retries 0, Conc 2", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetry0Conc3(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 0
|
||||
c.Concurrency = 3
|
||||
|
||||
fmt.Println(runner("Pester, Retries 0, Conc 3", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetry1Conc1(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.MaxRetries = 0
|
||||
c.Concurrency = 1
|
||||
|
||||
fmt.Println(runner("Pester, Retries 0, Conc 1", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetries2Conc1(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.Concurrency = 2
|
||||
c.MaxRetries = 1
|
||||
|
||||
fmt.Println(runner("Pester, Retries 2, Conc 1", c.Get))
|
||||
}
|
||||
|
||||
func TestPesterGetRetries3Conc1(t *testing.T) {
|
||||
c := pester.New()
|
||||
c.Concurrency = 3
|
||||
c.MaxRetries = 1
|
||||
|
||||
fmt.Println(runner("Pester, Retries 3, Conc 1", c.Get))
|
||||
}
|
||||
|
||||
func reportTimings(name string, timings []int64) string {
|
||||
var sum int64
|
||||
for _, t := range timings {
|
||||
sum += t
|
||||
}
|
||||
average := sum / int64(len(timings))
|
||||
return fmt.Sprintf(" %-29s %7d ns Avg.", name, average)
|
||||
}
|
||||
|
||||
func runServer() int {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
l, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
log.Fatal("unable to secure listener", err)
|
||||
}
|
||||
go func() {
|
||||
if err := http.Serve(l, mux); err != nil {
|
||||
log.Fatal("stable server error", err)
|
||||
}
|
||||
}()
|
||||
port, err := strconv.Atoi(strings.Replace(l.Addr().String(), "[::]:", "", 1))
|
||||
if err != nil {
|
||||
log.Fatal("unable to determine port", err)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
func runner(name string, Do getter) string {
|
||||
var timings []int64
|
||||
for n := 0; n < 7; n++ {
|
||||
stableServerPort := runServer()
|
||||
|
||||
start := time.Now().UnixNano()
|
||||
r, err := Do(fmt.Sprintf("http://localhost:%d/%d", stableServerPort, time.Now().UnixNano()))
|
||||
if err != nil {
|
||||
log.Fatal("Error came back and it should not have", err)
|
||||
}
|
||||
if r == nil {
|
||||
log.Fatal("No response!")
|
||||
}
|
||||
if r.Body == nil {
|
||||
log.Fatal("No response body!")
|
||||
}
|
||||
r.Body.Close()
|
||||
end := time.Now().UnixNano()
|
||||
|
||||
timings = append(timings, end-start)
|
||||
}
|
||||
return reportTimings(name, timings)
|
||||
}
|
||||
-184
@@ -1,184 +0,0 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
We start up a rando response server that will give different response codes
|
||||
and different response times to simulate poor network / service conditions.
|
||||
|
||||
The main function is cut into blocks to perserve variable scope and examples
|
||||
of each pester function can be seen in action.
|
||||
|
||||
The server logs incoming requests while the main blocks log what they intend
|
||||
to do and what they get back.
|
||||
*/
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sethgrid/pester"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
}
|
||||
|
||||
func main() {
|
||||
// set everything up
|
||||
var port int
|
||||
flag.IntVar(&port, "port", 9000, "set the port for the rando response server")
|
||||
flag.Parse()
|
||||
|
||||
log.Printf("Starting a rando response server on :%d ...\n\n", port)
|
||||
|
||||
go func() {
|
||||
http.HandleFunc("/", randoHandler)
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
||||
}()
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// begin running through each of the pestor methods //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
log.Println("> pester.Get default")
|
||||
{ // drop in replacement for http.Get and other client methods
|
||||
resp, err := pester.Get(fmt.Sprintf("http://localhost:%d", port))
|
||||
if err != nil {
|
||||
log.Fatalf("error GETing default", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("GET :%d %s \n\n", port, resp.Status)
|
||||
}
|
||||
|
||||
log.Println("> pester.Get with set backoff stategy, concurrency and retries increased")
|
||||
{ // control the resiliency
|
||||
client := pester.New()
|
||||
client.Concurrency = 3
|
||||
client.MaxRetries = 5
|
||||
client.Backoff = pester.ExponentialJitterBackoff
|
||||
client.KeepLog = true
|
||||
|
||||
resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port))
|
||||
if err != nil {
|
||||
log.Fatalf("error GETing with all options, %s\n\n", client.LogString())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("Exponential Jitter Backoff :%d %s [request %d, retry %d]\n\n", port, resp.Status, client.SuccessReqNum, client.SuccessRetryNum)
|
||||
}
|
||||
|
||||
log.Println("> pester.Get with custom backoff strategy")
|
||||
{ // set a custom backoff strategy
|
||||
client := pester.New()
|
||||
client.Backoff = func(retry int) time.Duration {
|
||||
return time.Duration(retry*200) * time.Millisecond
|
||||
}
|
||||
client.Timeout = 5 * time.Second
|
||||
client.KeepLog = true
|
||||
|
||||
resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port))
|
||||
if err != nil {
|
||||
log.Fatalf("error GETing custom backoff\n\n", client.LogString())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("Custom backoff :%d %s [request %d, retry %d]\n\n", port, resp.Status, client.SuccessReqNum, client.SuccessRetryNum)
|
||||
}
|
||||
|
||||
log.Println("> pester.Post with defaults")
|
||||
{ // use the pester.Post drop in replacement
|
||||
resp, err := pester.Post(fmt.Sprintf("http://localhost:%d", port), "text/plain", strings.NewReader("data"))
|
||||
if err != nil {
|
||||
log.Fatalf("error POSTing with defaults - %v\n\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("POST :%d %s\n\n", port, resp.Status)
|
||||
}
|
||||
|
||||
log.Println("> pester.Post with retries to non-existant url")
|
||||
{
|
||||
client := pester.New()
|
||||
client.MaxRetries = 3
|
||||
client.KeepLog = true
|
||||
|
||||
_, err := client.Post("http://localhost:9001", "application/json", strings.NewReader(`{"json":true}`))
|
||||
if err == nil {
|
||||
log.Printf("expected to error after max retries of 3")
|
||||
}
|
||||
|
||||
if len(client.ErrLog) != 3 {
|
||||
log.Fatalf("expected 3 error logs, got %d: %v", len(client.ErrLog), client.ErrLog)
|
||||
}
|
||||
log.Printf("POST: %v\n\n", err)
|
||||
}
|
||||
|
||||
log.Println("> pester.Head with defaults")
|
||||
{ // use the pester.Head drop in replacement
|
||||
resp, err := pester.Head(fmt.Sprintf("http://localhost:%d", port))
|
||||
if err != nil {
|
||||
log.Fatalf("error HEADing with defaults - %v\n\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("HEAD :%d %s\n\n", port, resp.Status)
|
||||
}
|
||||
|
||||
log.Println("> pester.PostForm with defaults")
|
||||
{ // use the pester.Head drop in replacement
|
||||
resp, err := pester.PostForm(fmt.Sprintf("http://localhost:%d", port), url.Values{"param1": []string{"val1a", "val1b"}, "param2": []string{"val2"}})
|
||||
if err != nil {
|
||||
log.Fatalf("error POSTing a form with defaults - %v\n\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("POST (form) :%d %s\n\n", port, resp.Status)
|
||||
}
|
||||
|
||||
log.Println("> pester Do with POST")
|
||||
{ // use the pester version of http.Client.Do
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("http://localhost:%d", port), strings.NewReader("data"))
|
||||
if err != nil {
|
||||
log.Fatal("Unable to create a new http request", err)
|
||||
}
|
||||
resp, err := pester.Do(req)
|
||||
if err != nil {
|
||||
log.Fatalf("error POSTing with Do() - %v\n\n", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("Do() POST :%d %s\n\n", port, resp.Status)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// randoHandler will cause random delays and give random status responses
|
||||
func randoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
delay := rand.Intn(5000)
|
||||
var code int
|
||||
switch rand.Intn(10) {
|
||||
case 0:
|
||||
code = 404
|
||||
case 1:
|
||||
code = 400
|
||||
case 2:
|
||||
code = 501
|
||||
case 3:
|
||||
code = 500
|
||||
default:
|
||||
code = 200
|
||||
}
|
||||
|
||||
log.Printf("incoming request on :9000 - will return %d in %d ms", code, delay)
|
||||
|
||||
<-time.Tick(time.Duration(delay) * time.Millisecond)
|
||||
|
||||
w.WriteHeader(code)
|
||||
w.Write([]byte(http.StatusText(code)))
|
||||
}
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
// Shows example use of the keyring package
|
||||
//
|
||||
// May need to be built with a platform-specific build flag to specify a
|
||||
// provider. See keyring documentation for details.
|
||||
//
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/tmc/keyring"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if pw, err := keyring.Get("keyring_example", "jack"); err == nil {
|
||||
fmt.Println("current stored password:", pw)
|
||||
} else if err == keyring.ErrNotFound {
|
||||
fmt.Println("no password stored yet")
|
||||
} else {
|
||||
fmt.Println("got unexpected error:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("enter new password: ")
|
||||
pw, err := terminal.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("setting keyring_example/jack to..", pw)
|
||||
err = keyring.Set("keyring_example", "jack", string(pw))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("fetching keyring_example/jack..")
|
||||
if pw, err := keyring.Get("keyring_example", "jack"); err == nil {
|
||||
fmt.Println("got", pw)
|
||||
} else {
|
||||
fmt.Println("error:", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user