<commit_before>// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Package gorums outputs a gorums client API in Go code.
// It runs as a plugin for the Go protocol buffer compiler plugin.
// It is linked in to protoc-gen-gorums.
package gorums

import (
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"

	pb "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
	"github.com/gogo/protobuf/protoc-gen-gogo/generator"
)

func init() {
	generator.RegisterPlugin(new(gorums))
}

// gorums is an implementation of the Go protocol buffer compiler's
// plugin architecture. It generates bindings for gorums support.
type gorums struct {
	gen       *generator.Generator
	logger    *log.Logger
	templates []tmpl
	pkgData   struct {
		PackageName   string
		Clients       []string
		Services      []serviceMethod
		IgnoreImports bool
	}
}

// Name returns the name of this plugin, "gorums".
func (g *gorums) Name() string {
	return "gorums"
}

// Init initializes the plugin.
func (g *gorums) Init(gen *generator.Generator) {
	g.gen = gen

	g.logger = log.New(os.Stdout, "gorums: ", 0)
	if !logEnabled() {
		g.logger.SetOutput(ioutil.Discard)
	}

	g.templates = make([]tmpl, 0, len(templates))
	for name, devTemplate := range templates {
		t := tmpl{
			name: name,
			t:    template.Must(template.New(name).Parse(devTemplate)),
		}
		g.templates = append(g.templates, t)
	}

	// sort to ensure deterministic output
	sort.Sort(tmplSlice(g.templates))
}

// Given a type name defined in a .proto, return its object.
// Also record that we're using it, to guarantee the associated import.
func (g *gorums) objectNamed(name string) generator.Object {
	g.gen.RecordTypeUse(name)
	return g.gen.ObjectNamed(name)
}

// Given a type name defined in a .proto, return its name as we will print it.
func (g *gorums) typeName(str string) string {
	return g.gen.TypeName(g.objectNamed(str))
}

// P forwards to g.gen.P.
func (g *gorums) P(args ...interface{}) { g.gen.P(args...) }

type tmpl struct {
	name string
	t    *template.Template
}

type tmplSlice []tmpl

func (p tmplSlice) Len() int           { return len(p) }
func (p tmplSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p tmplSlice) Less(i, j int) bool { return p[i].name < p[j].name }

// Generate generates code for the services in the given file.
func (g *gorums) Generate(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}

	g.pkgData.PackageName = file.GetPackage()
	g.pkgData.Clients, g.pkgData.Services = g.generateServiceMethods(file.FileDescriptorProto.Service)

	g.referenceToSuppressErrs()

	g.pkgData.IgnoreImports = true
	if err := g.processTemplates(); err != nil {
		die(err)
	}

	g.pkgData.IgnoreImports = false
	if err := g.generateDevFiles(); err != nil {
		die(err)
	}

	g.embedStaticResources()
}

func (g *gorums) referenceToSuppressErrs() {
	g.P()
	g.P("//  Reference Gorums specific imports to suppress errors if they are not otherwise used.")
	g.P("var _ = codes.OK")
}

func (g *gorums) processTemplates() error {
	for _, tmpl := range g.templates {
		out := new(bytes.Buffer)
		err := tmpl.t.Execute(out, g.pkgData)
		if err != nil {
			return fmt.Errorf("error executing template for %q: %v", tmpl.name, err)
		}
		g.P()
		g.P("/* 'gorums' plugin for protoc-gen-go - generated from: ", tmpl.name, " */")
		g.P()
		g.P(out.String())
	}

	return nil
}

func (g *gorums) generateDevFiles() error {
	if !produceDevFiles() {
		return nil
	}

	for _, tmpl := range g.templates {
		out := new(bytes.Buffer)
		out.WriteString("// DO NOT EDIT. Generated by 'gorums' plugin for protoc-gen-go\n")
		out.WriteString("// Source file to edit is: " + tmpl.name + "\n")

		err := tmpl.t.Execute(out, g.pkgData)
		if err != nil {
			return fmt.Errorf("error executing template for %q: %v", tmpl.name, err)
		}

		dst, err := format.Source(out.Bytes())
		if err != nil {
			return fmt.Errorf("error formating code for %q: %v", tmpl.name, err)
		}

		genfile := filepath.Join(g.pkgData.PackageName, strings.Replace(tmpl.name, "_tmpl", "_gen.go", 1))
		g.logger.Println("writing:", genfile)
		err = ioutil.WriteFile(genfile, dst, 0644)
		if err != nil {
			return fmt.Errorf("error writing file for %q: %v", tmpl.name, err)
		}
	}

	return nil
}

func (g *gorums) embedStaticResources() {
	g.P("/* Static resources */")
	g.P(staticResources)
}

// GenerateImports generates the import declaration for this file.
func (g *gorums) GenerateImports(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}
	if len(staticImports) == 0 {
		return
	}

	sort.Strings(staticImports)
	g.P("import (")
	for _, simport := range staticImports {
		if ignore := ignoreImport[simport]; ignore {
			continue
		}
		g.P("\"", simport, "\"")
	}
	g.P()
	g.P("\"golang.org/x/net/trace\"")
	g.P()
	g.P("\"google.golang.org/grpc/codes\"")
	g.P(")")
}

var ignoreImport = map[string]bool{
	"fmt":                      true,
	"io":                       true,
	"math":                     true,
	"strings":                  true,
	"golang.org/x/net/context": true,
	"golang.org/x/net/trace":   true,
	"google.golang.org/grpc":   true,
}

func die(err error) {
	fmt.Fprintf(os.Stderr, "gorums: %v\n", err)
	os.Exit(2)
}

func produceDevFiles() bool {
	return os.Getenv("GORUMSGENDEV") == "1"
}

func logEnabled() bool {
	return os.Getenv("GORUMSLOG") == "1"
}

func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }

type serviceMethod struct {
	OrigName             string
	MethodName           string
	UnexportedMethodName string
	RPCName              string

	RespName string
	ReqName  string

	TypeName           string
	UnexportedTypeName string

	QuorumCall    bool
	Correctable   bool
	CorrectablePR bool
	Future        bool
	Multicast     bool

	ServName string // Redundant, but keeps it simple.
}

type smSlice []serviceMethod

func (p smSlice) Len() int      { return len(p) }
func (p smSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p smSlice) Less(i, j int) bool {
	if p[i].ServName < p[j].ServName {
		return true
	} else if p[i].ServName > p[j].ServName {
		return false
	} else {
		if p[i].OrigName < p[j].OrigName {
			return true
		} else if p[i].OrigName > p[j].OrigName {
			return false
		} else {
			return false
		}
	}
}

func (g *gorums) generateServiceMethods(services []*pb.ServiceDescriptorProto) ([]string, []serviceMethod) {
	clients := make([]string, len(services))
	smethods := make(map[string][]*serviceMethod)
	for i, service := range services {
		clients[i] = service.GetName() + "Client"
		for _, method := range service.Method {
			sm, err := verifyExtensionsAndCreate(service.GetName(), method)
			if err != nil {
				die(err)
			}
			if sm == nil {
				continue
			}

			sm.OrigName = method.GetName()
			sm.MethodName = generator.CamelCase(sm.OrigName)
			sm.RPCName = sm.MethodName // sm.MethodName may be overwritten if method name conflict
			sm.UnexportedMethodName = unexport(sm.MethodName)
			sm.RespName = g.typeName(method.GetOutputType())
			sm.ReqName = g.typeName(method.GetInputType())
			sm.TypeName = sm.MethodName + "Reply"
			sm.UnexportedTypeName = unexport(sm.TypeName)
			sm.ServName = service.GetName()
			if sm.TypeName == sm.RespName {
				sm.TypeName += "_"
			}

			methodsForName, _ := smethods[sm.MethodName]
			methodsForName = append(methodsForName, sm)
			smethods[sm.MethodName] = methodsForName
		}
	}

	var allRewrittenFlat []serviceMethod

	for _, methodsForName := range smethods {
		switch len(methodsForName) {
		case 0:
			panic("generateServiceMethods: found method name with no data")
		case 1:
			allRewrittenFlat = append(allRewrittenFlat, *methodsForName[0])
			continue
		default:
			for _, sm := range methodsForName {
				sm.OrigName = sm.ServName + sm.OrigName
				sm.MethodName = sm.ServName + sm.MethodName
				sm.UnexportedMethodName = unexport(sm.MethodName)
				sm.TypeName = sm.MethodName + "Reply"
				sm.UnexportedTypeName = unexport(sm.TypeName)
				if sm.TypeName == sm.RespName {
					sm.TypeName += "_"
				}
				allRewrittenFlat = append(allRewrittenFlat, *sm)
			}
		}
	}

	sort.Sort(smSlice(allRewrittenFlat))

	return clients, allRewrittenFlat
}

func verifyExtensionsAndCreate(service string, method *pb.MethodDescriptorProto) (*serviceMethod, error) {
	sm := &serviceMethod{
		QuorumCall:    hasQuorumCallExtension(method),
		Future:        hasFutureExtension(method),
		Correctable:   hasCorrectableExtension(method),
		CorrectablePR: hasCorrectablePRExtension(method),
		Multicast:     hasMulticastExtension(method),
	}

	switch {
	case sm.Future && !sm.QuorumCall:
		return nil, fmt.Errorf(
			"%s.%s: illegal combination combination of options: 'future' but not 'qrpc'",
			service, method.GetName(),
		)
	case !sm.QuorumCall && !sm.Correctable && !sm.CorrectablePR && !sm.Multicast:
		return nil, nil
	case (sm.QuorumCall || sm.Correctable || sm.CorrectablePR) && sm.Multicast:
		return nil, fmt.Errorf(
			"%s.%s: illegal combination combination of options: both 'qrpc/correctable' and 'broadcast'",
			service, method.GetName(),
		)
	case sm.Multicast && !method.GetClientStreaming():
		return nil, fmt.Errorf(
			"%s.%s: 'broadcast' option only vaild for client-server streams methods",
			service, method.GetName(),
		)
	case method.GetServerStreaming() && !sm.CorrectablePR:
		return nil, fmt.Errorf(
			"%s.%s: server-client streams only supported for 'correctable' option",
			service, method.GetName(),
		)
	default:
		return sm, nil
	}
}
<commit_msg>plugins/gorums: check if 'bytes' import should be ignored in generated code<commit_after>// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors.  All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Package gorums outputs a gorums client API in Go code.
// It runs as a plugin for the Go protocol buffer compiler plugin.
// It is linked in to protoc-gen-gorums.
package gorums

import (
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"text/template"

	pb "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
	"github.com/gogo/protobuf/protoc-gen-gogo/generator"
)

func init() {
	generator.RegisterPlugin(new(gorums))
}

// gorums is an implementation of the Go protocol buffer compiler's
// plugin architecture. It generates bindings for gorums support.
type gorums struct {
	gen       *generator.Generator
	logger    *log.Logger
	templates []tmpl
	pkgData   struct {
		PackageName   string
		Clients       []string
		Services      []serviceMethod
		IgnoreImports bool
	}
}

// Name returns the name of this plugin, "gorums".
func (g *gorums) Name() string {
	return "gorums"
}

// Init initializes the plugin.
func (g *gorums) Init(gen *generator.Generator) {
	g.gen = gen

	g.logger = log.New(os.Stdout, "gorums: ", 0)
	if !logEnabled() {
		g.logger.SetOutput(ioutil.Discard)
	}

	g.templates = make([]tmpl, 0, len(templates))
	for name, devTemplate := range templates {
		t := tmpl{
			name: name,
			t:    template.Must(template.New(name).Parse(devTemplate)),
		}
		g.templates = append(g.templates, t)
	}

	// sort to ensure deterministic output
	sort.Sort(tmplSlice(g.templates))
}

// Given a type name defined in a .proto, return its object.
// Also record that we're using it, to guarantee the associated import.
func (g *gorums) objectNamed(name string) generator.Object {
	g.gen.RecordTypeUse(name)
	return g.gen.ObjectNamed(name)
}

// Given a type name defined in a .proto, return its name as we will print it.
func (g *gorums) typeName(str string) string {
	return g.gen.TypeName(g.objectNamed(str))
}

// P forwards to g.gen.P.
func (g *gorums) P(args ...interface{}) { g.gen.P(args...) }

type tmpl struct {
	name string
	t    *template.Template
}

type tmplSlice []tmpl

func (p tmplSlice) Len() int           { return len(p) }
func (p tmplSlice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p tmplSlice) Less(i, j int) bool { return p[i].name < p[j].name }

// Generate generates code for the services in the given file.
func (g *gorums) Generate(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}

	g.pkgData.PackageName = file.GetPackage()
	g.pkgData.Clients, g.pkgData.Services = g.generateServiceMethods(file.FileDescriptorProto.Service)

	g.referenceToSuppressErrs()

	g.pkgData.IgnoreImports = true
	if err := g.processTemplates(); err != nil {
		die(err)
	}

	g.pkgData.IgnoreImports = false
	if err := g.generateDevFiles(); err != nil {
		die(err)
	}

	g.embedStaticResources()
}

func (g *gorums) referenceToSuppressErrs() {
	g.P()
	g.P("//  Reference Gorums specific imports to suppress errors if they are not otherwise used.")
	g.P("var _ = codes.OK")
}

func (g *gorums) processTemplates() error {
	for _, tmpl := range g.templates {
		out := new(bytes.Buffer)
		err := tmpl.t.Execute(out, g.pkgData)
		if err != nil {
			return fmt.Errorf("error executing template for %q: %v", tmpl.name, err)
		}
		g.P()
		g.P("/* 'gorums' plugin for protoc-gen-go - generated from: ", tmpl.name, " */")
		g.P()
		g.P(out.String())
	}

	return nil
}

func (g *gorums) generateDevFiles() error {
	if !produceDevFiles() {
		return nil
	}

	for _, tmpl := range g.templates {
		out := new(bytes.Buffer)
		out.WriteString("// DO NOT EDIT. Generated by 'gorums' plugin for protoc-gen-go\n")
		out.WriteString("// Source file to edit is: " + tmpl.name + "\n")

		err := tmpl.t.Execute(out, g.pkgData)
		if err != nil {
			return fmt.Errorf("error executing template for %q: %v", tmpl.name, err)
		}

		dst, err := format.Source(out.Bytes())
		if err != nil {
			return fmt.Errorf("error formating code for %q: %v", tmpl.name, err)
		}

		genfile := filepath.Join(g.pkgData.PackageName, strings.Replace(tmpl.name, "_tmpl", "_gen.go", 1))
		g.logger.Println("writing:", genfile)
		err = ioutil.WriteFile(genfile, dst, 0644)
		if err != nil {
			return fmt.Errorf("error writing file for %q: %v", tmpl.name, err)
		}
	}

	return nil
}

func (g *gorums) embedStaticResources() {
	g.P("/* Static resources */")
	g.P(staticResources)
}

// GenerateImports generates the import declaration for this file.
func (g *gorums) GenerateImports(file *generator.FileDescriptor) {
	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}
	if len(staticImports) == 0 {
		return
	}

	if hasMessageWithByteField(file) {
		ignoreImport["bytes"] = true
	}

	sort.Strings(staticImports)
	g.P("import (")
	for _, simport := range staticImports {
		if ignore := ignoreImport[simport]; ignore {
			continue
		}
		g.P("\"", simport, "\"")
	}
	g.P()
	g.P("\"golang.org/x/net/trace\"")
	g.P()
	g.P("\"google.golang.org/grpc/codes\"")
	g.P(")")
}

func hasMessageWithByteField(file *generator.FileDescriptor) bool {
	for _, msg := range file.Messages() {
		for _, field := range msg.Field {
			if field.IsBytes() {
				return true
			}
		}
	}
	return false
}

var ignoreImport = map[string]bool{
	"fmt":                      true,
	"io":                       true,
	"math":                     true,
	"strings":                  true,
	"golang.org/x/net/context": true,
	"golang.org/x/net/trace":   true,
	"google.golang.org/grpc":   true,
}

func die(err error) {
	fmt.Fprintf(os.Stderr, "gorums: %v\n", err)
	os.Exit(2)
}

func produceDevFiles() bool {
	return os.Getenv("GORUMSGENDEV") == "1"
}

func logEnabled() bool {
	return os.Getenv("GORUMSLOG") == "1"
}

func unexport(s string) string { return strings.ToLower(s[:1]) + s[1:] }

type serviceMethod struct {
	OrigName             string
	MethodName           string
	UnexportedMethodName string
	RPCName              string

	RespName string
	ReqName  string

	TypeName           string
	UnexportedTypeName string

	QuorumCall    bool
	Correctable   bool
	CorrectablePR bool
	Future        bool
	Multicast     bool

	ServName string // Redundant, but keeps it simple.
}

type smSlice []serviceMethod

func (p smSlice) Len() int      { return len(p) }
func (p smSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p smSlice) Less(i, j int) bool {
	if p[i].ServName < p[j].ServName {
		return true
	} else if p[i].ServName > p[j].ServName {
		return false
	} else {
		if p[i].OrigName < p[j].OrigName {
			return true
		} else if p[i].OrigName > p[j].OrigName {
			return false
		} else {
			return false
		}
	}
}

func (g *gorums) generateServiceMethods(services []*pb.ServiceDescriptorProto) ([]string, []serviceMethod) {
	clients := make([]string, len(services))
	smethods := make(map[string][]*serviceMethod)
	for i, service := range services {
		clients[i] = service.GetName() + "Client"
		for _, method := range service.Method {
			sm, err := verifyExtensionsAndCreate(service.GetName(), method)
			if err != nil {
				die(err)
			}
			if sm == nil {
				continue
			}

			sm.OrigName = method.GetName()
			sm.MethodName = generator.CamelCase(sm.OrigName)
			sm.RPCName = sm.MethodName // sm.MethodName may be overwritten if method name conflict
			sm.UnexportedMethodName = unexport(sm.MethodName)
			sm.RespName = g.typeName(method.GetOutputType())
			sm.ReqName = g.typeName(method.GetInputType())
			sm.TypeName = sm.MethodName + "Reply"
			sm.UnexportedTypeName = unexport(sm.TypeName)
			sm.ServName = service.GetName()
			if sm.TypeName == sm.RespName {
				sm.TypeName += "_"
			}

			methodsForName, _ := smethods[sm.MethodName]
			methodsForName = append(methodsForName, sm)
			smethods[sm.MethodName] = methodsForName
		}
	}

	var allRewrittenFlat []serviceMethod

	for _, methodsForName := range smethods {
		switch len(methodsForName) {
		case 0:
			panic("generateServiceMethods: found method name with no data")
		case 1:
			allRewrittenFlat = append(allRewrittenFlat, *methodsForName[0])
			continue
		default:
			for _, sm := range methodsForName {
				sm.OrigName = sm.ServName + sm.OrigName
				sm.MethodName = sm.ServName + sm.MethodName
				sm.UnexportedMethodName = unexport(sm.MethodName)
				sm.TypeName = sm.MethodName + "Reply"
				sm.UnexportedTypeName = unexport(sm.TypeName)
				if sm.TypeName == sm.RespName {
					sm.TypeName += "_"
				}
				allRewrittenFlat = append(allRewrittenFlat, *sm)
			}
		}
	}

	sort.Sort(smSlice(allRewrittenFlat))

	return clients, allRewrittenFlat
}

func verifyExtensionsAndCreate(service string, method *pb.MethodDescriptorProto) (*serviceMethod, error) {
	sm := &serviceMethod{
		QuorumCall:    hasQuorumCallExtension(method),
		Future:        hasFutureExtension(method),
		Correctable:   hasCorrectableExtension(method),
		CorrectablePR: hasCorrectablePRExtension(method),
		Multicast:     hasMulticastExtension(method),
	}

	switch {
	case sm.Future && !sm.QuorumCall:
		return nil, fmt.Errorf(
			"%s.%s: illegal combination combination of options: 'future' but not 'qrpc'",
			service, method.GetName(),
		)
	case !sm.QuorumCall && !sm.Correctable && !sm.CorrectablePR && !sm.Multicast:
		return nil, nil
	case (sm.QuorumCall || sm.Correctable || sm.CorrectablePR) && sm.Multicast:
		return nil, fmt.Errorf(
			"%s.%s: illegal combination combination of options: both 'qrpc/correctable' and 'broadcast'",
			service, method.GetName(),
		)
	case sm.Multicast && !method.GetClientStreaming():
		return nil, fmt.Errorf(
			"%s.%s: 'broadcast' option only vaild for client-server streams methods",
			service, method.GetName(),
		)
	case method.GetServerStreaming() && !sm.CorrectablePR:
		return nil, fmt.Errorf(
			"%s.%s: server-client streams only supported for 'correctable' option",
			service, method.GetName(),
		)
	default:
		return sm, nil
	}
}
<|endoftext|>


<commit_before>package awsecs

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/report"
)

type taskInfo struct {
	containerIDs []string
	family       string
}

// return map from cluster to map of task arns to task infos
func getLabelInfo(rpt report.Report) map[string]map[string]*taskInfo {
	results := make(map[string]map[string]*taskInfo)
	log.Debug("scanning for ECS containers")
	for nodeID, node := range rpt.Container.Nodes {

		taskArn, taskArnOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.task-arn")
		cluster, clusterOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.cluster")
		family, familyOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.task-definition-family")

		if taskArnOk && clusterOk && familyOk {
			taskMap, ok := results[cluster]
			if !ok {
				taskMap = make(map[string]*taskInfo)
				results[cluster] = taskMap
			}

			task, ok := taskMap[taskArn]
			if !ok {
				task = &taskInfo{containerIDs: make([]string, 0), family: family}
				taskMap[taskArn] = task
			}

			task.containerIDs = append(task.containerIDs, nodeID)
		}
	}
	log.Debug("Got ECS container info: %v", results)
	return results
}

// implements Tagger
type Reporter struct {
}

// Tag needed for Tagger
func (r Reporter) Tag(rpt report.Report) (report.Report, error) {
	rpt = rpt.Copy()

	clusterMap := getLabelInfo(rpt)

	for cluster, taskMap := range clusterMap {
		log.Debugf("Fetching ECS info for cluster %v with %v tasks", cluster, len(taskMap))

		client, err := newClient(cluster)
		if err != nil {
			return rpt, err
		}

		taskArns := make([]string, 0, len(taskMap))
		for taskArn := range taskMap {
			taskArns = append(taskArns, taskArn)
		}

		taskServices, err := client.getTaskServices(taskArns)
		if err != nil {
			return rpt, err
		}

		// Create all the services first
		unique := make(map[string]bool)
		for _, serviceName := range taskServices {
			if !unique[serviceName] {
				rpt.ECSService = rpt.ECSService.AddNode(report.MakeNode(serviceNodeID(serviceName)))
				unique[serviceName] = true
			}
		}
		log.Debugf("Created %v ECS service nodes", len(taskServices))

		for taskArn, info := range taskMap {

			// new task node
			node := report.MakeNodeWith(taskNodeID(taskArn), map[string]string{"family": info.family})

			rpt.ECSTask = rpt.ECSTask.AddNode(node)

			for _, containerID := range info.containerIDs {
				// TODO set task node as parent of container
				log.Debugf("task %v has container %v", taskArn, containerID)
			}

			if serviceName, ok := taskServices[taskArn]; ok {
				// TODO set service node as parent of task node
				log.Debugf("service %v has task %v", serviceName, taskArn)
			}
		}

	}

	return rpt, nil
}

// Name needed for Tagger
func (r Reporter) Name() string {
	return "awsecs"
}

func serviceNodeID(id string) string {
	return fmt.Sprintf("%s;ECSService", id)
}

func taskNodeID(id string) string {
	return fmt.Sprintf("%s;ECSTask", id)
}
<commit_msg>ecs reporter: Associate containers with ECS tasks and services as parents<commit_after>package awsecs

import (
	"fmt"

	log "github.com/Sirupsen/logrus"
	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/report"
)

type taskInfo struct {
	containerIDs []string
	family       string
}

// return map from cluster to map of task arns to task infos
func getLabelInfo(rpt report.Report) map[string]map[string]*taskInfo {
	results := make(map[string]map[string]*taskInfo)
	log.Debug("scanning for ECS containers")
	for nodeID, node := range rpt.Container.Nodes {

		taskArn, taskArnOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.task-arn")
		cluster, clusterOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.cluster")
		family, familyOk := node.Latest.Lookup(docker.LabelPrefix + "com.amazonaws.ecs.task-definition-family")

		if taskArnOk && clusterOk && familyOk {
			taskMap, ok := results[cluster]
			if !ok {
				taskMap = make(map[string]*taskInfo)
				results[cluster] = taskMap
			}

			task, ok := taskMap[taskArn]
			if !ok {
				task = &taskInfo{containerIDs: make([]string, 0), family: family}
				taskMap[taskArn] = task
			}

			task.containerIDs = append(task.containerIDs, nodeID)
		}
	}
	log.Debug("Got ECS container info: %v", results)
	return results
}

// implements Tagger
type Reporter struct {
}

// Tag needed for Tagger
func (r Reporter) Tag(rpt report.Report) (report.Report, error) {
	rpt = rpt.Copy()

	clusterMap := getLabelInfo(rpt)

	for cluster, taskMap := range clusterMap {
		log.Debugf("Fetching ECS info for cluster %v with %v tasks", cluster, len(taskMap))

		client, err := newClient(cluster)
		if err != nil {
			return rpt, err
		}

		taskArns := make([]string, 0, len(taskMap))
		for taskArn := range taskMap {
			taskArns = append(taskArns, taskArn)
		}

		taskServices, err := client.getTaskServices(taskArns)
		if err != nil {
			return rpt, err
		}

		// Create all the services first
		unique := make(map[string]bool)
		for _, serviceName := range taskServices {
			if !unique[serviceName] {
				rpt.ECSService = rpt.ECSService.AddNode(report.MakeNode(serviceNodeID(serviceName)))
				unique[serviceName] = true
			}
		}
		log.Debugf("Created %v ECS service nodes", len(taskServices))

		for taskArn, info := range taskMap {

			// new task node
			node := report.MakeNodeWith(taskNodeID(taskArn), map[string]string{"family": info.family})
			rpt.ECSTask = rpt.ECSTask.AddNode(node)

			// parents sets to merge into all matching container nodes
			parentsSets := report.MakeSets()
			parentsSets.Add(report.ECSTask, report.MakeStringSet(taskNodeID(taskArn)))
			if serviceName, ok := taskServices[taskArn]; ok {
				parentsSets.Add(report.ECSService, report.MakeStringSet(serviceNodeID(serviceName)))
			}

			for _, containerID := range info.containerIDs {
				if containerNode, ok := rpt.Container.Nodes[containerID]; ok {
					rpt.Container.Nodes[containerID] = containerNode.WithParents(parentsSets)
				} else {
					log.Warnf("Got task info for non-existent container %v, this shouldn't be able to happen", containerID)
				}
			}

		}

	}

	return rpt, nil
}

// Name needed for Tagger
func (r Reporter) Name() string {
	return "awsecs"
}

func serviceNodeID(id string) string {
	return fmt.Sprintf("%s;ECSService", id)
}

func taskNodeID(id string) string {
	return fmt.Sprintf("%s;ECSTask", id)
}
<|endoftext|>


<commit_before>package provisioning

import "testing"
import "github.com/wingedpig/loom"

type Config struct {
	loom.Config
}

func TestRun(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Run("ls -la")
	if err != nil {
		t.Errorf("Run cmd error, %s", err)
	}
}

func TestSudo(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Sudo("ls -la"); if err != nil {
		t.Errorf("Run sudo error, %s", err)
	}
}

func TestPutString(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	err := c.PutString("TestPutString\nTestPutString", "~/testputstring"); if err != nil {
		t.Errorf("Run putstring error, %s", err)
	} else {
		c.Run("cat ~/testputstring")
	}
}

func TestPut(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	err := c.Put("./remote.iml", "~/remote.iml"); if err != nil {
		t.Errorf("Run put error, %s", err)
	} else {
		c.Run("cat ~/remote.iml")
	}
}

// Local support linux only
func TestLocal(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Local("echo testlocal"); if err != nil {
		t.Errorf("Run local error, %s", err)
	}
}

func TestGet(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"10.32.151.68",
		DisplayOutput:true, AbortOnError:true}}
	err := c.Get("~/remote.iml", "./remote.iml1"); if err != nil {
		t.Errorf("Run get error, %s", err)
	}
}

func TestDeploy(t *testing.T) {
	c, err := MakeConfig("ubuntu", "10.32.151.68", true, true); if err != nil {
		t.Errorf("Make config error, %s", err)
	}
	cmd := Cmd{AptCache: true, UseSudo:true, CmdLine: "ls -la"}

	var i Provisioning
	i = c
	i.Execute(cmd)
}<commit_msg>Add TESTSERVER to Host<commit_after>package provisioning

import "testing"
import "github.com/wingedpig/loom"

type Config struct {
	loom.Config
}

func TestRun(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Run("ls -la")
	if err != nil {
		t.Errorf("Run cmd error, %s", err)
	}
}

func TestSudo(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Sudo("ls -la"); if err != nil {
		t.Errorf("Run sudo error, %s", err)
	}
}

func TestPutString(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	err := c.PutString("TestPutString\nTestPutString", "~/testputstring"); if err != nil {
		t.Errorf("Run putstring error, %s", err)
	} else {
		c.Run("cat ~/testputstring")
	}
}

func TestPut(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	err := c.Put("./remote.iml", "~/remote.iml"); if err != nil {
		t.Errorf("Run put error, %s", err)
	} else {
		c.Run("cat ~/remote.iml")
	}
}

// Local support linux only
func TestLocal(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	_, err := c.Local("echo testlocal"); if err != nil {
		t.Errorf("Run local error, %s", err)
	}
}

func TestGet(t *testing.T) {
	c := &Config{loom.Config{User:"ubuntu",Host:"TESTSERVER",
		DisplayOutput:true, AbortOnError:true}}
	err := c.Get("~/remote.iml", "./remote.iml1"); if err != nil {
		t.Errorf("Run get error, %s", err)
	}
}

func TestDeploy(t *testing.T) {
	c, err := MakeConfig("ubuntu", "TESTSERVER", true, true); if err != nil {
		t.Errorf("Make config error, %s", err)
	}
	cmd := Cmd{AptCache: true, UseSudo:true, CmdLine: "ls -la"}

	var i Provisioning
	i = c
	i.Execute(cmd)
}<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"testing"
)

const testThis = "@k8s-bot test this"

type JSONJob struct {
	Scenario string   `json:"scenario"`
	Args     []string `json:"args"`
}

// Consistent but meaningless order.
func flattenJobs(jobs []Presubmit) []Presubmit {
	ret := jobs
	for _, job := range jobs {
		if len(job.RunAfterSuccess) > 0 {
			ret = append(ret, flattenJobs(job.RunAfterSuccess)...)
		}
	}
	return ret
}

func TestPresubmits(t *testing.T) {
	c, err := Load("../config.yaml")
	if err != nil {
		t.Fatalf("Could not load config: %v", err)
	}
	if len(c.Presubmits) == 0 {
		t.Fatalf("No jobs found in presubmit.yaml.")
	}
	b, err := ioutil.ReadFile("../../jobs/config.json")
	if err != nil {
		t.Fatalf("Could not load jobs/config.json: %v", err)
	}
	var bootstrapConfig map[string]JSONJob
	json.Unmarshal(b, &bootstrapConfig)
	for _, rootJobs := range c.Presubmits {
		jobs := flattenJobs(rootJobs)
		for i, job := range jobs {
			if job.Name == "" {
				t.Errorf("Job %v needs a name.", job)
				continue
			}
			if job.Context == "" {
				t.Errorf("Job %s needs a context.", job.Name)
			}
			if job.RerunCommand == "" || job.Trigger == "" {
				t.Errorf("Job %s needs a trigger and a rerun command.", job.Name)
				continue
			}
			// Check that the merge bot will run AlwaysRun jobs, otherwise it
			// will attempt to rerun forever.
			if job.AlwaysRun && !job.re.MatchString(testThis) {
				t.Errorf("AlwaysRun job %s: \"%s\" does not match regex \"%v\".", job.Name, testThis, job.Trigger)
			}
			// Check that the rerun command actually runs the job.
			if !job.re.MatchString(job.RerunCommand) {
				t.Errorf("For job %s: RerunCommand \"%s\" does not match regex \"%v\".", job.Name, job.RerunCommand, job.Trigger)
			}
			// Next check that the rerun command doesn't run any other jobs.
			for j, job2 := range jobs {
				if i == j {
					continue
				}
				if job.Name == job2.Name && i > j {
					t.Errorf("Two jobs have the same name: %s", job.Name)
				}
				if job.Context == job2.Context && i > j {
					t.Errorf("Jobs %s and %s have the same context: %s", job.Name, job2.Name, job.Context)
				}
				if job2.re.MatchString(job.RerunCommand) {
					t.Errorf("RerunCommand \"%s\" from job %s matches \"%v\" from job %s but shouldn't.", job.RerunCommand, job.Name, job2.Trigger, job2.Name)
				}
			}
			var scenario string
			job.Name = strings.Replace(job.Name, "pull-security-kubernetes", "pull-kubernetes", 1)
			if j, present := bootstrapConfig[job.Name]; present {
				scenario = fmt.Sprintf("scenarios/%s.py", j.Scenario)
			} else {
				scenario = fmt.Sprintf("jobs/%s.sh", job.Name)
			}

			// Ensure that jobs have a shell script of the same name.
			if s, err := os.Stat(fmt.Sprintf("../../%s", scenario)); err != nil {
				t.Errorf("Cannot find test-infra/%s for %s", scenario, job.Name)
			} else {
				if s.Mode()&0111 == 0 {
					t.Errorf("Not executable: test-infra/%s (%o)", scenario, s.Mode()&0777)
				}
				if s.Mode()&0444 == 0 {
					t.Errorf("Not readable: test-infra/%s (%o)", scenario, s.Mode()&0777)
				}
			}
		}
	}
}

func TestCommentBodyMatches(t *testing.T) {
	var testcases = []struct {
		repo         string
		body         string
		expectedJobs []string
	}{
		{
			"org/repo",
			"this is a random comment",
			[]string{},
		},
		{
			"org/repo",
			"ok to test",
			[]string{"gce", "unit"},
		},
		{
			"org/repo",
			"@k8s-bot test this",
			[]string{"gce", "unit", "gke"},
		},
		{
			"org/repo",
			"@k8s-bot unit test this",
			[]string{"unit"},
		},
		{
			"org/repo",
			"@k8s-bot federation test this",
			[]string{"federation"},
		},
		{
			"org/repo2",
			"@k8s-bot test this",
			[]string{"cadveapster"},
		},
		{
			"org/repo3",
			"@k8s-bot test this",
			[]string{},
		},
	}
	c := &Config{
		Presubmits: map[string][]Presubmit{
			"org/repo": {
				{
					Name:      "gce",
					re:        regexp.MustCompile(`@k8s-bot (gce )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "unit",
					re:        regexp.MustCompile(`@k8s-bot (unit )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "gke",
					re:        regexp.MustCompile(`@k8s-bot (gke )?test this`),
					AlwaysRun: false,
				},
				{
					Name:      "federation",
					re:        regexp.MustCompile(`@k8s-bot federation test this`),
					AlwaysRun: false,
				},
			},
			"org/repo2": {
				{
					Name:      "cadveapster",
					re:        regexp.MustCompile(`@k8s-bot test this`),
					AlwaysRun: true,
				},
			},
		},
	}
	for _, tc := range testcases {
		actualJobs := c.MatchingPresubmits(tc.repo, tc.body, regexp.MustCompile(`ok to test`))
		match := true
		if len(actualJobs) != len(tc.expectedJobs) {
			match = false
		} else {
			for _, actualJob := range actualJobs {
				found := false
				for _, expectedJob := range tc.expectedJobs {
					if expectedJob == actualJob.Name {
						found = true
						break
					}
				}
				if !found {
					match = false
					break
				}
			}
		}
		if !match {
			t.Errorf("Wrong jobs for body %s. Got %v, expected %v.", tc.body, actualJobs, tc.expectedJobs)
		}
	}
}

func TestConditionalPresubmits(t *testing.T) {
	presubmits := []Presubmit{
		{
			Name:         "cross build",
			RunIfChanged: `(Makefile|\.sh|_(windows|linux|osx|unknown)(_test)?\.go)$`,
		},
	}
	setRegexes(presubmits)
	ps := presubmits[0]
	var testcases = []struct {
		changes  []string
		expected bool
	}{
		{[]string{"some random file"}, false},
		{[]string{"./pkg/util/rlimit/rlimit_linux.go"}, true},
		{[]string{"./pkg/util/rlimit/rlimit_unknown_test.go"}, true},
		{[]string{"build.sh"}, true},
		{[]string{"build.shoo"}, false},
		{[]string{"Makefile"}, true},
	}
	for _, tc := range testcases {
		actual := ps.RunsAgainstChanges(tc.changes)
		if actual != tc.expected {
			t.Errorf("wrong RunsAgainstChanges(%#v) result. Got %v, expected %v", tc.changes, actual, tc.expected)
		}
	}
}

func TestGetPresubmits(t *testing.T) {
	pres := []Presubmit{
		{
			Name: "a",
			RunAfterSuccess: []Presubmit{
				{Name: "aa"},
				{Name: "ab"},
			},
		},
		{Name: "b"},
	}
	if p := getPresubmit(pres, "b"); p == nil {
		t.Error("Missed root level presubmit.")
	}
	if p := getPresubmit(pres, "ab"); p == nil {
		t.Error("Missed child presubmit.")
	}
	if p := getPresubmit(pres, "c"); p != nil {
		t.Error("Whaa!? Found a presubmit that shouldn't exist.")
	}
}

func TestListJobNames(t *testing.T) {
	c := &Config{
		Presubmits: map[string][]Presubmit{
			"r1": {
				{
					Name: "a",
					RunAfterSuccess: []Presubmit{
						{Name: "aa"},
						{Name: "ab"},
					},
				},
				{Name: "b"},
			},
		},
		Postsubmits: map[string][]Postsubmit{
			"r1": {
				{
					Name: "c",
					RunAfterSuccess: []Postsubmit{
						{Name: "ca"},
						{Name: "cb"},
					},
				},
				{Name: "d"},
			},
			"r2": {{Name: "e"}},
		},
	}
	expected := []string{"a", "aa", "ab", "b", "c", "ca", "cb", "d", "e"}
	actual := c.AllJobNames()
	if len(actual) != len(expected) {
		t.Fatalf("Wrong number of jobs. Got %v, expected %v", actual, expected)
	}
	for _, j1 := range expected {
		found := false
		for _, j2 := range actual {
			if j1 == j2 {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Did not find job %s in output", j1)
		}
	}
}

func TestRunAgainstBranch(t *testing.T) {
	jobs := []Presubmit{
		{
			Name:     "a",
			Brancher: Brancher{SkipBranches: []string{"s"}},
		},
		{
			Name:     "b",
			Brancher: Brancher{Branches: []string{"r"}},
		},
		{
			Name: "c",
			Brancher: Brancher{
				SkipBranches: []string{"s"},
				Branches:     []string{"r"},
			},
		},
		{
			Name: "d",
			Brancher: Brancher{
				SkipBranches: []string{"s"},
				Branches:     []string{"s", "r"},
			},
		},
		{
			Name: "default",
		},
	}

	for _, job := range jobs {
		if job.Name == "default" {
			if !job.RunsAgainstBranch("s") {
				t.Errorf("Job %s should run branch s", job.Name)
			}
		} else if job.RunsAgainstBranch("s") {
			t.Errorf("Job %s should not run branch s", job.Name)
		}

		if !job.RunsAgainstBranch("r") {
			t.Errorf("Job %s should run branch r", job.Name)
		}
	}
}
<commit_msg>Job names must be valid pod names.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package config

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"regexp"
	"strings"
	"testing"
)

var podRe = regexp.MustCompile(`[a-z0-9]([-a-z0-9]*[a-z0-9])?`)

const testThis = "@k8s-bot test this"

type JSONJob struct {
	Scenario string   `json:"scenario"`
	Args     []string `json:"args"`
}

// Consistent but meaningless order.
func flattenJobs(jobs []Presubmit) []Presubmit {
	ret := jobs
	for _, job := range jobs {
		if len(job.RunAfterSuccess) > 0 {
			ret = append(ret, flattenJobs(job.RunAfterSuccess)...)
		}
	}
	return ret
}

func TestPresubmits(t *testing.T) {
	c, err := Load("../config.yaml")
	if err != nil {
		t.Fatalf("Could not load config: %v", err)
	}
	if len(c.Presubmits) == 0 {
		t.Fatalf("No jobs found in presubmit.yaml.")
	}
	b, err := ioutil.ReadFile("../../jobs/config.json")
	if err != nil {
		t.Fatalf("Could not load jobs/config.json: %v", err)
	}
	var bootstrapConfig map[string]JSONJob
	json.Unmarshal(b, &bootstrapConfig)
	for _, rootJobs := range c.Presubmits {
		jobs := flattenJobs(rootJobs)
		for i, job := range jobs {
			if job.Name == "" {
				t.Errorf("Job %v needs a name.", job)
				continue
			}
			if job.Context == "" {
				t.Errorf("Job %s needs a context.", job.Name)
			}
			if job.RerunCommand == "" || job.Trigger == "" {
				t.Errorf("Job %s needs a trigger and a rerun command.", job.Name)
				continue
			}
			// Check that the merge bot will run AlwaysRun jobs, otherwise it
			// will attempt to rerun forever.
			if job.AlwaysRun && !job.re.MatchString(testThis) {
				t.Errorf("AlwaysRun job %s: \"%s\" does not match regex \"%v\".", job.Name, testThis, job.Trigger)
			}
			// Check that the rerun command actually runs the job.
			if !job.re.MatchString(job.RerunCommand) {
				t.Errorf("For job %s: RerunCommand \"%s\" does not match regex \"%v\".", job.Name, job.RerunCommand, job.Trigger)
			}
			// Next check that the rerun command doesn't run any other jobs.
			for j, job2 := range jobs {
				if i == j {
					continue
				}
				if job.Name == job2.Name && i > j {
					t.Errorf("Two jobs have the same name: %s", job.Name)
				}
				if job.Context == job2.Context && i > j {
					t.Errorf("Jobs %s and %s have the same context: %s", job.Name, job2.Name, job.Context)
				}
				if job2.re.MatchString(job.RerunCommand) {
					t.Errorf("RerunCommand \"%s\" from job %s matches \"%v\" from job %s but shouldn't.", job.RerunCommand, job.Name, job2.Trigger, job2.Name)
				}
			}
			var scenario string
			job.Name = strings.Replace(job.Name, "pull-security-kubernetes", "pull-kubernetes", 1)
			if j, present := bootstrapConfig[job.Name]; present {
				scenario = fmt.Sprintf("scenarios/%s.py", j.Scenario)
			} else {
				scenario = fmt.Sprintf("jobs/%s.sh", job.Name)
			}

			// Ensure that jobs have a shell script of the same name.
			if s, err := os.Stat(fmt.Sprintf("../../%s", scenario)); err != nil {
				t.Errorf("Cannot find test-infra/%s for %s", scenario, job.Name)
			} else {
				if s.Mode()&0111 == 0 {
					t.Errorf("Not executable: test-infra/%s (%o)", scenario, s.Mode()&0777)
				}
				if s.Mode()&0444 == 0 {
					t.Errorf("Not readable: test-infra/%s (%o)", scenario, s.Mode()&0777)
				}
			}
		}
	}
}

func TestCommentBodyMatches(t *testing.T) {
	var testcases = []struct {
		repo         string
		body         string
		expectedJobs []string
	}{
		{
			"org/repo",
			"this is a random comment",
			[]string{},
		},
		{
			"org/repo",
			"ok to test",
			[]string{"gce", "unit"},
		},
		{
			"org/repo",
			"@k8s-bot test this",
			[]string{"gce", "unit", "gke"},
		},
		{
			"org/repo",
			"@k8s-bot unit test this",
			[]string{"unit"},
		},
		{
			"org/repo",
			"@k8s-bot federation test this",
			[]string{"federation"},
		},
		{
			"org/repo2",
			"@k8s-bot test this",
			[]string{"cadveapster"},
		},
		{
			"org/repo3",
			"@k8s-bot test this",
			[]string{},
		},
	}
	c := &Config{
		Presubmits: map[string][]Presubmit{
			"org/repo": {
				{
					Name:      "gce",
					re:        regexp.MustCompile(`@k8s-bot (gce )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "unit",
					re:        regexp.MustCompile(`@k8s-bot (unit )?test this`),
					AlwaysRun: true,
				},
				{
					Name:      "gke",
					re:        regexp.MustCompile(`@k8s-bot (gke )?test this`),
					AlwaysRun: false,
				},
				{
					Name:      "federation",
					re:        regexp.MustCompile(`@k8s-bot federation test this`),
					AlwaysRun: false,
				},
			},
			"org/repo2": {
				{
					Name:      "cadveapster",
					re:        regexp.MustCompile(`@k8s-bot test this`),
					AlwaysRun: true,
				},
			},
		},
	}
	for _, tc := range testcases {
		actualJobs := c.MatchingPresubmits(tc.repo, tc.body, regexp.MustCompile(`ok to test`))
		match := true
		if len(actualJobs) != len(tc.expectedJobs) {
			match = false
		} else {
			for _, actualJob := range actualJobs {
				found := false
				for _, expectedJob := range tc.expectedJobs {
					if expectedJob == actualJob.Name {
						found = true
						break
					}
				}
				if !found {
					match = false
					break
				}
			}
		}
		if !match {
			t.Errorf("Wrong jobs for body %s. Got %v, expected %v.", tc.body, actualJobs, tc.expectedJobs)
		}
	}
}

func TestConditionalPresubmits(t *testing.T) {
	presubmits := []Presubmit{
		{
			Name:         "cross build",
			RunIfChanged: `(Makefile|\.sh|_(windows|linux|osx|unknown)(_test)?\.go)$`,
		},
	}
	setRegexes(presubmits)
	ps := presubmits[0]
	var testcases = []struct {
		changes  []string
		expected bool
	}{
		{[]string{"some random file"}, false},
		{[]string{"./pkg/util/rlimit/rlimit_linux.go"}, true},
		{[]string{"./pkg/util/rlimit/rlimit_unknown_test.go"}, true},
		{[]string{"build.sh"}, true},
		{[]string{"build.shoo"}, false},
		{[]string{"Makefile"}, true},
	}
	for _, tc := range testcases {
		actual := ps.RunsAgainstChanges(tc.changes)
		if actual != tc.expected {
			t.Errorf("wrong RunsAgainstChanges(%#v) result. Got %v, expected %v", tc.changes, actual, tc.expected)
		}
	}
}

func TestGetPresubmits(t *testing.T) {
	pres := []Presubmit{
		{
			Name: "a",
			RunAfterSuccess: []Presubmit{
				{Name: "aa"},
				{Name: "ab"},
			},
		},
		{Name: "b"},
	}
	if p := getPresubmit(pres, "b"); p == nil {
		t.Error("Missed root level presubmit.")
	}
	if p := getPresubmit(pres, "ab"); p == nil {
		t.Error("Missed child presubmit.")
	}
	if p := getPresubmit(pres, "c"); p != nil {
		t.Error("Whaa!? Found a presubmit that shouldn't exist.")
	}
}

func TestListJobNames(t *testing.T) {
	c := &Config{
		Presubmits: map[string][]Presubmit{
			"r1": {
				{
					Name: "a",
					RunAfterSuccess: []Presubmit{
						{Name: "aa"},
						{Name: "ab"},
					},
				},
				{Name: "b"},
			},
		},
		Postsubmits: map[string][]Postsubmit{
			"r1": {
				{
					Name: "c",
					RunAfterSuccess: []Postsubmit{
						{Name: "ca"},
						{Name: "cb"},
					},
				},
				{Name: "d"},
			},
			"r2": {{Name: "e"}},
		},
	}
	expected := []string{"a", "aa", "ab", "b", "c", "ca", "cb", "d", "e"}
	actual := c.AllJobNames()
	if len(actual) != len(expected) {
		t.Fatalf("Wrong number of jobs. Got %v, expected %v", actual, expected)
	}
	for _, j1 := range expected {
		found := false
		for _, j2 := range actual {
			if j1 == j2 {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Did not find job %s in output", j1)
		}
	}
}

func TestRunAgainstBranch(t *testing.T) {
	jobs := []Presubmit{
		{
			Name:     "a",
			Brancher: Brancher{SkipBranches: []string{"s"}},
		},
		{
			Name:     "b",
			Brancher: Brancher{Branches: []string{"r"}},
		},
		{
			Name: "c",
			Brancher: Brancher{
				SkipBranches: []string{"s"},
				Branches:     []string{"r"},
			},
		},
		{
			Name: "d",
			Brancher: Brancher{
				SkipBranches: []string{"s"},
				Branches:     []string{"s", "r"},
			},
		},
		{
			Name: "default",
		},
	}

	for _, job := range jobs {
		if job.Name == "default" {
			if !job.RunsAgainstBranch("s") {
				t.Errorf("Job %s should run branch s", job.Name)
			}
		} else if job.RunsAgainstBranch("s") {
			t.Errorf("Job %s should not run branch s", job.Name)
		}

		if !job.RunsAgainstBranch("r") {
			t.Errorf("Job %s should run branch r", job.Name)
		}
	}
}

func TestValidPodNames(t *testing.T) {
	c, err := Load("../config.yaml")
	if err != nil {
		t.Fatalf("Could not load config: %v", err)
	}
	for _, j := range c.AllJobNames() {
		if !podRe.MatchString(j) {
			t.Errorf("Job \"%s\" must match regex \"%s\".", j, podRe.String())
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Rook Authors. All rights reserved.

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

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

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

package config

import (
	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/clusterd"
	"github.com/rook/rook/pkg/daemon/ceph/client"
)

// MonStore provides methods for setting Ceph configurations in the centralized mon
// configuration database.
type MonStore struct {
	context   *clusterd.Context
	namespace string
}

// GetMonStore returns a new MonStore for the cluster.
func GetMonStore(context *clusterd.Context, namespace string) *MonStore {
	return &MonStore{
		context:   context,
		namespace: namespace,
	}
}

// Option defines the pieces of information relevant to Ceph configuration options.
type Option struct {
	// Who is the entity(-ies) the option should apply to.
	Who string

	// Option is the option key
	Option string

	// Value is the value for the option
	Value string
}

// Set sets a config in the centralized mon configuration database.
// https://docs.ceph.com/docs/master/rados/configuration/ceph-conf/#monitor-configuration-database
func (m *MonStore) Set(who, option, value string) error {
	args := []string{"config", "set", who, normalizeKey(option), value}
	cephCmd := client.NewCephCommand(m.context, m.namespace, args)
	out, err := cephCmd.Run()
	if err != nil {
		return errors.Wrapf(err, "failed to set ceph config in the centralized mon configuration database; "+
			"you may need to use the rook-config-override ConfigMap. output: %s", string(out))
	}
	return nil
}

// Get retrieves a config in the centralized mon configuration database.
// https://docs.ceph.com/docs/master/rados/configuration/ceph-conf/#monitor-configuration-database
func (m *MonStore) Get(who, option string) (string, error) {
	args := []string{"config", "get", who, normalizeKey(option)}
	cephCmd := client.NewCephCommand(m.context, m.namespace, args)
	out, err := cephCmd.Run()
	if err != nil {
		return "", errors.Wrapf(err, "failed to get config setting %q for user %q", option, who)
	}
	return string(out), nil
}

// SetAll sets all configs from the overrides in the centralized mon configuration database.
// See MonStore.Set for more.
func (m *MonStore) SetAll(options ...Option) error {
	var errs []error
	for _, override := range options {
		err := m.Set(override.Who, override.Option, override.Value)
		if err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		retErr := errors.New("failed to set one or more Ceph configs")
		for _, err := range errs {
			retErr = errors.Wrapf(err, "%v", retErr)
		}
		return retErr
	}
	return nil
}
<commit_msg>ceph: remove leading and trailing space from get config<commit_after>/*
Copyright 2019 The Rook Authors. All rights reserved.

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

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

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

package config

import (
	"github.com/pkg/errors"
	"github.com/rook/rook/pkg/clusterd"
	"github.com/rook/rook/pkg/daemon/ceph/client"
	"strings"
)

// MonStore provides methods for setting Ceph configurations in the centralized mon
// configuration database.
type MonStore struct {
	context   *clusterd.Context
	namespace string
}

// GetMonStore returns a new MonStore for the cluster.
func GetMonStore(context *clusterd.Context, namespace string) *MonStore {
	return &MonStore{
		context:   context,
		namespace: namespace,
	}
}

// Option defines the pieces of information relevant to Ceph configuration options.
type Option struct {
	// Who is the entity(-ies) the option should apply to.
	Who string

	// Option is the option key
	Option string

	// Value is the value for the option
	Value string
}

// Set sets a config in the centralized mon configuration database.
// https://docs.ceph.com/docs/master/rados/configuration/ceph-conf/#monitor-configuration-database
func (m *MonStore) Set(who, option, value string) error {
	args := []string{"config", "set", who, normalizeKey(option), value}
	cephCmd := client.NewCephCommand(m.context, m.namespace, args)
	out, err := cephCmd.Run()
	if err != nil {
		return errors.Wrapf(err, "failed to set ceph config in the centralized mon configuration database; "+
			"you may need to use the rook-config-override ConfigMap. output: %s", string(out))
	}
	return nil
}

// Get retrieves a config in the centralized mon configuration database.
// https://docs.ceph.com/docs/master/rados/configuration/ceph-conf/#monitor-configuration-database
func (m *MonStore) Get(who, option string) (string, error) {
	args := []string{"config", "get", who, normalizeKey(option)}
	cephCmd := client.NewCephCommand(m.context, m.namespace, args)
	out, err := cephCmd.Run()
	if err != nil {
		return "", errors.Wrapf(err, "failed to get config setting %q for user %q", option, who)
	}
	return strings.TrimSpace(string(out)), nil
}

// SetAll sets all configs from the overrides in the centralized mon configuration database.
// See MonStore.Set for more.
func (m *MonStore) SetAll(options ...Option) error {
	var errs []error
	for _, override := range options {
		err := m.Set(override.Who, override.Option, override.Value)
		if err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		retErr := errors.New("failed to set one or more Ceph configs")
		for _, err := range errs {
			retErr = errors.Wrapf(err, "%v", retErr)
		}
		return retErr
	}
	return nil
}
<|endoftext|>


<commit_before>package gumble_ffmpeg

import (
	"encoding/binary"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"github.com/layeh/gumble/gumble"
)

const (
	DefaultCommand = "ffmpeg"
)

type Stream struct {
	Done    func()
	Command string

	client *gumble.Client
	cmd    *exec.Cmd
	pipe   io.ReadCloser
	volume float32

	stop          chan bool
	stopWaitGroup sync.WaitGroup
}

func New(client *gumble.Client) (*Stream, error) {
	stream := &Stream{
		client: client,
		volume: 1.0,
		stop:   make(chan bool),
	}
	return stream, nil
}

func (s *Stream) Play(file string) error {
	if s.IsPlaying() {
		return errors.New("already playing")
	}
	command := s.Command
	if command == "" {
		command = DefaultCommand
	}
	cmd := exec.Command(command, "-i", file, "-ac", "1", "-ar", strconv.Itoa(gumble.AudioSampleRate), "-f", "s16le", "-")
	if pipe, err := cmd.StdoutPipe(); err != nil {
		return err
	} else {
		s.pipe = pipe
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	s.stopWaitGroup.Add(1)
	s.cmd = cmd
	go s.sourceRoutine()
	return nil
}

func (s *Stream) IsPlaying() bool {
	return s.cmd != nil
}

func (s *Stream) Stop() error {
	if !s.IsPlaying() {
		return errors.New("nothing playing")
	}

	s.stop <- true
	s.stopWaitGroup.Wait()
	return nil
}

func (s *Stream) Volume() float32 {
	return s.volume
}

func (s *Stream) SetVolume(volume float32) {
	s.volume = volume
}

func (s *Stream) sourceRoutine() {
	interval := s.client.Config().GetAudioInterval()
	frameSize := s.client.Config().GetAudioFrameSize()

	ticker := time.NewTicker(interval)

	defer func() {
		ticker.Stop()
		s.cmd.Process.Kill()
		s.cmd.Wait()
		s.cmd = nil
		s.stopWaitGroup.Done()
		if done := s.Done; done != nil {
			done()
		}
	}()

	int16Buffer := make([]int16, frameSize)
	byteBuffer := make([]byte, frameSize*2)

	for {
		select {
		case <-s.stop:
			return
		case <-ticker.C:
			if _, err := io.ReadFull(s.pipe, byteBuffer); err != nil {
				return
			}
			for i := range int16Buffer {
				float := float32(int16(binary.LittleEndian.Uint16(byteBuffer[i*2 : (i+1)*2])))
				int16Buffer[i] = int16(s.volume * float)
			}
			s.client.Send(gumble.AudioBuffer(int16Buffer))
		}
	}
}
<commit_msg>gumble_ffmpeg: add lock to Play<commit_after>package gumble_ffmpeg

import (
	"encoding/binary"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"sync"
	"time"

	"github.com/layeh/gumble/gumble"
)

const (
	DefaultCommand = "ffmpeg"
)

type Stream struct {
	Done    func()
	Command string

	playLock sync.Mutex

	client *gumble.Client
	cmd    *exec.Cmd
	pipe   io.ReadCloser
	volume float32

	stop          chan bool
	stopWaitGroup sync.WaitGroup
}

func New(client *gumble.Client) (*Stream, error) {
	stream := &Stream{
		client: client,
		volume: 1.0,
		stop:   make(chan bool),
	}
	return stream, nil
}

func (s *Stream) Play(file string) error {
	s.playLock.Lock()
	defer s.playLock.Unlock()

	if s.IsPlaying() {
		return errors.New("already playing")
	}
	command := s.Command
	if command == "" {
		command = DefaultCommand
	}
	cmd := exec.Command(command, "-i", file, "-ac", "1", "-ar", strconv.Itoa(gumble.AudioSampleRate), "-f", "s16le", "-")
	if pipe, err := cmd.StdoutPipe(); err != nil {
		return err
	} else {
		s.pipe = pipe
	}
	if err := cmd.Start(); err != nil {
		return err
	}
	s.stopWaitGroup.Add(1)
	s.cmd = cmd
	go s.sourceRoutine()
	return nil
}

func (s *Stream) IsPlaying() bool {
	return s.cmd != nil
}

func (s *Stream) Stop() error {
	if !s.IsPlaying() {
		return errors.New("nothing playing")
	}

	s.stop <- true
	s.stopWaitGroup.Wait()
	return nil
}

func (s *Stream) Volume() float32 {
	return s.volume
}

func (s *Stream) SetVolume(volume float32) {
	s.volume = volume
}

func (s *Stream) sourceRoutine() {
	interval := s.client.Config().GetAudioInterval()
	frameSize := s.client.Config().GetAudioFrameSize()

	ticker := time.NewTicker(interval)

	defer func() {
		ticker.Stop()
		s.cmd.Process.Kill()
		s.cmd.Wait()
		s.cmd = nil
		s.stopWaitGroup.Done()
		if done := s.Done; done != nil {
			done()
		}
	}()

	int16Buffer := make([]int16, frameSize)
	byteBuffer := make([]byte, frameSize*2)

	for {
		select {
		case <-s.stop:
			return
		case <-ticker.C:
			if _, err := io.ReadFull(s.pipe, byteBuffer); err != nil {
				return
			}
			for i := range int16Buffer {
				float := float32(int16(binary.LittleEndian.Uint16(byteBuffer[i*2 : (i+1)*2])))
				int16Buffer[i] = int16(s.volume * float)
			}
			s.client.Send(gumble.AudioBuffer(int16Buffer))
		}
	}
}
<|endoftext|>


<commit_before>package oauth2

import (
	"strings"
	"time"

	jwtx "github.com/dgrijalva/jwt-go"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/token/jwt"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// RS256JWTStrategy is a JWT RS256 strategy.
type RS256JWTStrategy struct {
	*jwt.RS256JWTStrategy
	Issuer string
}

func (h RS256JWTStrategy) signature(token string) string {
	split := strings.Split(token, ".")
	if len(split) != 3 {
		return ""
	}

	return split[2]
}

func (h RS256JWTStrategy) AccessTokenSignature(token string) string {
	return h.signature(token)
}

func (h RS256JWTStrategy) RefreshTokenSignature(token string) string {
	return h.signature(token)
}

func (h RS256JWTStrategy) AuthorizeCodeSignature(token string) string {
	return h.signature(token)
}

func (h *RS256JWTStrategy) ValidateJWT(tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) {
	t, err := h.validate(token)
	if err != nil {
		return nil, err
	}

	claims := jwt.JWTClaims{}
	claims.FromMapClaims(t.Claims.(jwtx.MapClaims))

	requester = &fosite.Request{
		Client:      &fosite.DefaultClient{},
		RequestedAt: claims.IssuedAt,
		Session: &JWTSession{
			JWTClaims: &claims,
			JWTHeader: &jwt.Headers{
				Extra: make(map[string]interface{}),
			},
			ExpiresAt: map[fosite.TokenType]time.Time{
				tokenType: claims.ExpiresAt,
			},
			Subject: claims.Subject,
		},
		Scopes:        claims.Scope,
		GrantedScopes: claims.Scope,
	}

	return
}

func (h *RS256JWTStrategy) GenerateAccessToken(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.AccessToken, requester)
}

func (h *RS256JWTStrategy) ValidateAccessToken(_ context.Context, _ fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) GenerateRefreshToken(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.RefreshToken, requester)
}

func (h *RS256JWTStrategy) ValidateRefreshToken(_ context.Context, _ fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) GenerateAuthorizeCode(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.AuthorizeCode, requester)
}

func (h *RS256JWTStrategy) ValidateAuthorizeCode(_ context.Context, requester fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) validate(token string) (t *jwtx.Token, err error) {
	t, err = h.RS256JWTStrategy.Decode(token)

	if err == nil {
		err = t.Claims.Valid()
	}

	if err != nil {
		if e, ok := errors.Cause(err).(*jwtx.ValidationError); ok {
			switch e.Errors {
			case jwtx.ValidationErrorMalformed:
				err = errors.Wrap(fosite.ErrInvalidTokenFormat, err.Error())
			case jwtx.ValidationErrorUnverifiable:
				err = errors.Wrap(fosite.ErrTokenSignatureMismatch, err.Error())
			case jwtx.ValidationErrorSignatureInvalid:
				err = errors.Wrap(fosite.ErrTokenSignatureMismatch, err.Error())
			case jwtx.ValidationErrorAudience:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorExpired:
				err = errors.Wrap(fosite.ErrTokenExpired, err.Error())
			case jwtx.ValidationErrorIssuedAt:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorIssuer:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorNotValidYet:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorId:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorClaimsInvalid:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			default:
				err = errors.Wrap(fosite.ErrRequestUnauthorized, err.Error())
			}
		}
	}

	return
}

func (h *RS256JWTStrategy) generate(tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) {
	if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok {
		return "", "", errors.New("Session must be of type JWTSessionContainer")
	} else if jwtSession.GetJWTClaims() == nil {
		return "", "", errors.New("GetTokenClaims() must not be nil")
	} else {
		claims := jwtSession.GetJWTClaims()

		if claims.ExpiresAt.IsZero() {
			claims.ExpiresAt = jwtSession.GetExpiresAt(tokenType)
		}

		if claims.IssuedAt.IsZero() {
			claims.IssuedAt = time.Now()
		}

		if claims.Issuer == "" {
			claims.Issuer = h.Issuer
		}

		claims.Scope = requester.GetGrantedScopes()

		return h.RS256JWTStrategy.Generate(claims.ToMapClaims(), jwtSession.GetJWTHeader())
	}
}
<commit_msg>revert unintentional change<commit_after>package oauth2

import (
	"strings"
	"time"

	jwtx "github.com/dgrijalva/jwt-go"
	"github.com/ory-am/fosite"
	"github.com/ory-am/fosite/token/jwt"
	"github.com/pkg/errors"
	"golang.org/x/net/context"
)

// RS256JWTStrategy is a JWT RS256 strategy.
type RS256JWTStrategy struct {
	*jwt.RS256JWTStrategy
	Issuer string
}

func (h RS256JWTStrategy) signature(token string) string {
	split := strings.Split(token, ".")
	if len(split) != 3 {
		return ""
	}

	return split[2]
}

func (h RS256JWTStrategy) AccessTokenSignature(token string) string {
	return h.signature(token)
}

func (h RS256JWTStrategy) RefreshTokenSignature(token string) string {
	return h.signature(token)
}

func (h RS256JWTStrategy) AuthorizeCodeSignature(token string) string {
	return h.signature(token)
}

func (h *RS256JWTStrategy) ValidateJWT(tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) {
	t, err := h.validate(token)
	if err != nil {
		return nil, err
	}

	claims := jwt.JWTClaims{}
	claims.FromMapClaims(t.Claims.(jwtx.MapClaims))

	requester = &fosite.Request{
		Client:      &fosite.DefaultClient{},
		RequestedAt: claims.IssuedAt,
		Session: &JWTSession{
			JWTClaims: &claims,
			JWTHeader: &jwt.Headers{
				Extra: make(map[string]interface{}),
			},
			ExpiresAt: map[fosite.TokenType]time.Time{
				tokenType: claims.ExpiresAt,
			},
			Subject: claims.Subject,
		},
		Scopes:        claims.Scope,
		GrantedScopes: claims.Scope,
	}

	return
}

func (h *RS256JWTStrategy) GenerateAccessToken(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.AccessToken, requester)
}

func (h *RS256JWTStrategy) ValidateAccessToken(_ context.Context, _ fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) GenerateRefreshToken(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.RefreshToken, requester)
}

func (h *RS256JWTStrategy) ValidateRefreshToken(_ context.Context, _ fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) GenerateAuthorizeCode(_ context.Context, requester fosite.Requester) (token string, signature string, err error) {
	return h.generate(fosite.AuthorizeCode, requester)
}

func (h *RS256JWTStrategy) ValidateAuthorizeCode(_ context.Context, requester fosite.Requester, token string) error {
	_, err := h.validate(token)
	return err
}

func (h *RS256JWTStrategy) validate(token string) (t *jwtx.Token, err error) {
	t, err = h.RS256JWTStrategy.Decode(token)

	if err == nil {
		err = t.Claims.Valid()
	}

	if err != nil {
		if e, ok := errors.Cause(err).(*jwtx.ValidationError); ok {
			switch e.Errors {
			case jwtx.ValidationErrorMalformed:
				err = errors.Wrap(fosite.ErrInvalidTokenFormat, err.Error())
			case jwtx.ValidationErrorUnverifiable:
				err = errors.Wrap(fosite.ErrTokenSignatureMismatch, err.Error())
			case jwtx.ValidationErrorSignatureInvalid:
				err = errors.Wrap(fosite.ErrTokenSignatureMismatch, err.Error())
			case jwtx.ValidationErrorAudience:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorExpired:
				err = errors.Wrap(fosite.ErrTokenExpired, err.Error())
			case jwtx.ValidationErrorIssuedAt:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorIssuer:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorNotValidYet:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorId:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			case jwtx.ValidationErrorClaimsInvalid:
				err = errors.Wrap(fosite.ErrTokenClaim, err.Error())
			default:
				err = errors.Wrap(fosite.ErrRequestUnauthorized, err.Error())
			}
		}
	}

	return
}

func (h *RS256JWTStrategy) generate(tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) {
	if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok {
		return "", "", errors.New("Session must be of type JWTSessionContainer")
	} else if jwtSession.GetJWTClaims() == nil {
		return "", "", errors.New("GetTokenClaims() must not be nil")
	} else {
		claims := jwtSession.GetJWTClaims()
		claims.ExpiresAt = jwtSession.GetExpiresAt(tokenType)

		if claims.IssuedAt.IsZero() {
			claims.IssuedAt = time.Now()
		}

		if claims.Issuer == "" {
			claims.Issuer = h.Issuer
		}

		claims.Scope = requester.GetGrantedScopes()

		return h.RS256JWTStrategy.Generate(claims.ToMapClaims(), jwtSession.GetJWTHeader())
	}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"context"
	"crypto/sha1"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"

	"cloud.google.com/go/datastore"
	"google.golang.org/appengine/log"
)

const salt = "[replace this with something unique]"

type Snippet struct {
	Body []byte
}

func (s *Snippet) Id() string {
	h := sha1.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	return string(b)[:10]
}

func init() {
	http.HandleFunc("/share", share)
}

func share(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}
	ctx := context.Background()

	var body bytes.Buffer
	_, err := body.ReadFrom(r.Body)
	if err != nil {
		log.Errorf(ctx, "reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	r.Body.Close()
	snip := &Snippet{Body: body.Bytes()}
	id := snip.Id()
	key := datastore.NameKey("Snippet", id, nil)
	_, err = datastoreClient.Put(ctx, key, snip)
	if err != nil {
		log.Errorf(ctx, "putting Snippet: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}
<commit_msg>reviewed share function<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/base64"
	"fmt"
	"io"
	"net/http"

	"cloud.google.com/go/datastore"
	"google.golang.org/appengine/log"
)

const (
	salt           = "Go playground salt\n"
	maxSnippetSize = 64 * 1024
)

type Snippet struct {
	Body []byte `datastore:",noindex"`
}

func (s *Snippet) Id() string {
	h := sha256.New()
	io.WriteString(h, salt)
	h.Write(s.Body)
	sum := h.Sum(nil)
	b := make([]byte, base64.URLEncoding.EncodedLen(len(sum)))
	base64.URLEncoding.Encode(b, sum)
	// Web sites don’t always linkify a trailing underscore, making it seem like
	// the link is broken. If there is an underscore at the end of the substring,
	// extend it until there is not.
	hashLen := 11
	for hashLen <= len(b) && b[hashLen-1] == '_' {
		hashLen++
	}
	return string(b)[:hashLen]
}

func init() {
	http.HandleFunc("/share", share)
}

func share(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}

	var body bytes.Buffer
	_, err := io.Copy(&body, io.LimitReader(r.Body, maxSnippetSize+1))
	if err != nil {
		log.Errorf(r.Context(), "reading Body: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}
	r.Body.Close()
	snip := &Snippet{Body: body.Bytes()}
	id := snip.Id()
	key := datastore.NameKey("Snippet", id, nil)
	_, err = datastoreClient.Put(r.Context(), key, snip)
	if err != nil {
		log.Errorf(r.Context(), "putting Snippet: %v", err)
		http.Error(w, "Server Error", http.StatusInternalServerError)
		return
	}

	fmt.Fprint(w, id)
}
<|endoftext|>


<commit_before>package shell

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

var (
	Shell = "/bin/sh"
	Panic = true
	Trace = false

	exit = os.Exit
)

var Tee io.Writer

func assert(err error) {
	if err != nil {
		panic(err)
	}
}

func Path(parts ...string) string {
	return filepath.Join(parts...)
}

func PathTemplate(parts ...string) func(...interface{}) string {
	return func(values ...interface{}) string {
		return fmt.Sprintf(Path(parts...), values...)
	}
}

func Quote(arg string) string {
	return fmt.Sprintf("'%s'", strings.Replace(arg, "'", "'\\''", -1))
}

func ErrExit() {
	if p, ok := recover().(*Process); p != nil {
		if !ok {
			fmt.Fprintf(os.Stderr, "Unexpected panic: %v\n", p)
			exit(1)
		}
		fmt.Fprintf(os.Stderr, "%s\n", p.Error())
		exit(p.ExitStatus)
	}
}

type Command struct {
	args []string
	in   *Command
}

func (c *Command) ProcFn() func(...interface{}) *Process {
	return func(args ...interface{}) *Process {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		return cmd.Run()
	}
}

func (c *Command) OutputFn() func(...interface{}) (string, error) {
	return func(args ...interface{}) (out string, err error) {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		defer func() {
			if p, ok := recover().(*Process); p != nil {
				if ok {
					err = p.Error()
				} else {
					err = fmt.Errorf("panic: %v", p)
				}
			}
		}()
		out = cmd.Run().String()
		return
	}
}

func (c *Command) ErrFn() func(...interface{}) error {
	return func(args ...interface{}) (err error) {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		defer func() {
			if p, ok := recover().(*Process); p != nil {
				if ok {
					err = p.Error()
				} else {
					err = fmt.Errorf("panic: %v", p)
				}
			}
		}()
		cmd.Run()
		return
	}
}

func (c *Command) Pipe(cmd ...interface{}) *Command {
	return Cmd(append(cmd, c)...)
}

func (c *Command) addArgs(args ...interface{}) {
	var strArgs []string
	for i, arg := range args {
		switch v := arg.(type) {
		case string:
			strArgs = append(strArgs, v)
		case fmt.Stringer:
			strArgs = append(strArgs, v.String())
		default:
			cmd, ok := arg.(*Command)
			if i+1 == len(args) && ok {
				c.in = cmd
				continue
			}
			panic("invalid type for argument")
		}
	}
	c.args = append(c.args, strArgs...)
}

func (c *Command) shellCmd(quote bool) string {
	if !quote {
		return strings.Join(c.args, " ")
	}
	var quoted []string
	for i := range c.args {
		quoted = append(quoted, Quote(c.args[i]))
	}
	return strings.Join(quoted, " ")
}

func (c *Command) Run() *Process {
	if Trace {
		fmt.Fprintln(os.Stderr, "+", c.shellCmd(false))
	}
	cmd := exec.Command(Shell, "-c", c.shellCmd(false))
	p := new(Process)
	if c.in != nil {
		cmd.Stdin = c.in.Run()
	} else {
		stdin, err := cmd.StdinPipe()
		assert(err)
		p.Stdin = stdin
	}
	var stdout bytes.Buffer
	if Tee != nil {
		cmd.Stdout = io.MultiWriter(&stdout, Tee)
	} else {
		cmd.Stdout = &stdout
	}
	p.Stdout = &stdout
	var stderr bytes.Buffer
	if Tee != nil {
		cmd.Stderr = io.MultiWriter(&stderr, Tee)
	} else {
		cmd.Stderr = &stderr
	}
	p.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			if stat, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				p.ExitStatus = int(stat.ExitStatus())
				if Panic {
					panic(p)
				}
			}
		} else {
			assert(err)
		}
	}
	return p
}

func Cmd(cmd ...interface{}) *Command {
	c := new(Command)
	c.addArgs(cmd...)
	return c
}

type Process struct {
	Stdout     *bytes.Buffer
	Stderr     *bytes.Buffer
	Stdin      io.WriteCloser
	ExitStatus int
}

func (p *Process) String() string {
	return strings.Trim(p.Stdout.String(), "\n")
}

func (p *Process) Bytes() []byte {
	return p.Stdout.Bytes()
}

func (p *Process) Error() error {
	return fmt.Errorf("%s (%v)", strings.Trim(p.Stderr.String(), "\n"), p.ExitStatus)
}

func (p *Process) Read(b []byte) (int, error) {
	return p.Stdout.Read(b)
}

func (p *Process) Write(b []byte) (int, error) {
	return p.Stdin.Write(b)
}

func Run(cmd ...interface{}) *Process {
	return Cmd(cmd...).Run()
}
<commit_msg>trace prefix and shell as an array<commit_after>package shell

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
)

var (
	Shell       = []string{"/bin/sh", "-c"}
	Panic       = true
	Trace       = false
	TracePrefix = "+"

	exit = os.Exit
)

var Tee io.Writer

func assert(err error) {
	if err != nil {
		panic(err)
	}
}

func Path(parts ...string) string {
	return filepath.Join(parts...)
}

func PathTemplate(parts ...string) func(...interface{}) string {
	return func(values ...interface{}) string {
		return fmt.Sprintf(Path(parts...), values...)
	}
}

func Quote(arg string) string {
	return fmt.Sprintf("'%s'", strings.Replace(arg, "'", "'\\''", -1))
}

func ErrExit() {
	if p, ok := recover().(*Process); p != nil {
		if !ok {
			fmt.Fprintf(os.Stderr, "Unexpected panic: %v\n", p)
			exit(1)
		}
		fmt.Fprintf(os.Stderr, "%s\n", p.Error())
		exit(p.ExitStatus)
	}
}

type Command struct {
	args []string
	in   *Command
}

func (c *Command) ProcFn() func(...interface{}) *Process {
	return func(args ...interface{}) *Process {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		return cmd.Run()
	}
}

func (c *Command) OutputFn() func(...interface{}) (string, error) {
	return func(args ...interface{}) (out string, err error) {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		defer func() {
			if p, ok := recover().(*Process); p != nil {
				if ok {
					err = p.Error()
				} else {
					err = fmt.Errorf("panic: %v", p)
				}
			}
		}()
		out = cmd.Run().String()
		return
	}
}

func (c *Command) ErrFn() func(...interface{}) error {
	return func(args ...interface{}) (err error) {
		cmd := &Command{c.args, c.in}
		cmd.addArgs(args...)
		defer func() {
			if p, ok := recover().(*Process); p != nil {
				if ok {
					err = p.Error()
				} else {
					err = fmt.Errorf("panic: %v", p)
				}
			}
		}()
		cmd.Run()
		return
	}
}

func (c *Command) Pipe(cmd ...interface{}) *Command {
	return Cmd(append(cmd, c)...)
}

func (c *Command) addArgs(args ...interface{}) {
	var strArgs []string
	for i, arg := range args {
		switch v := arg.(type) {
		case string:
			strArgs = append(strArgs, v)
		case fmt.Stringer:
			strArgs = append(strArgs, v.String())
		default:
			cmd, ok := arg.(*Command)
			if i+1 == len(args) && ok {
				c.in = cmd
				continue
			}
			panic("invalid type for argument")
		}
	}
	c.args = append(c.args, strArgs...)
}

func (c *Command) shellCmd(quote bool) string {
	if !quote {
		return strings.Join(c.args, " ")
	}
	var quoted []string
	for i := range c.args {
		quoted = append(quoted, Quote(c.args[i]))
	}
	return strings.Join(quoted, " ")
}

func (c *Command) Run() *Process {
	if Trace {
		fmt.Fprintln(os.Stderr, TracePrefix, c.shellCmd(false))
	}
	cmd := exec.Command(Shell[0], append(Shell[1:], c.shellCmd(false))...)
	p := new(Process)
	if c.in != nil {
		cmd.Stdin = c.in.Run()
	} else {
		stdin, err := cmd.StdinPipe()
		assert(err)
		p.Stdin = stdin
	}
	var stdout bytes.Buffer
	if Tee != nil {
		cmd.Stdout = io.MultiWriter(&stdout, Tee)
	} else {
		cmd.Stdout = &stdout
	}
	p.Stdout = &stdout
	var stderr bytes.Buffer
	if Tee != nil {
		cmd.Stderr = io.MultiWriter(&stderr, Tee)
	} else {
		cmd.Stderr = &stderr
	}
	p.Stderr = &stderr
	err := cmd.Run()
	if err != nil {
		if exiterr, ok := err.(*exec.ExitError); ok {
			if stat, ok := exiterr.Sys().(syscall.WaitStatus); ok {
				p.ExitStatus = int(stat.ExitStatus())
				if Panic {
					panic(p)
				}
			}
		} else {
			assert(err)
		}
	}
	return p
}

func Cmd(cmd ...interface{}) *Command {
	c := new(Command)
	c.addArgs(cmd...)
	return c
}

type Process struct {
	Stdout     *bytes.Buffer
	Stderr     *bytes.Buffer
	Stdin      io.WriteCloser
	ExitStatus int
}

func (p *Process) String() string {
	return strings.Trim(p.Stdout.String(), "\n")
}

func (p *Process) Bytes() []byte {
	return p.Stdout.Bytes()
}

func (p *Process) Error() error {
	return fmt.Errorf("%s (%v)", strings.Trim(p.Stderr.String(), "\n"), p.ExitStatus)
}

func (p *Process) Read(b []byte) (int, error) {
	return p.Stdout.Read(b)
}

func (p *Process) Write(b []byte) (int, error) {
	return p.Stdin.Write(b)
}

func Run(cmd ...interface{}) *Process {
	return Cmd(cmd...).Run()
}
<|endoftext|>