<commit_before>package largedatatests

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"github.com/couchbase/cbauth"
	tc "github.com/couchbase/indexing/secondary/tests/framework/common"
	"github.com/prataprc/goparsec"
	"github.com/prataprc/monster"
	"github.com/prataprc/monster/common"
	"io/ioutil"
	"os"
	"runtime"
	"testing"
)

var seed int
var defaultlimit int64 = 10000000
var kvaddress, indexManagementAddress, indexScanAddress string
var clusterconfig tc.ClusterConfiguration
var proddir, bagdir string

func init() {
	fmt.Println("In init()")
	var configpath string
	seed = 1
	flag.StringVar(&configpath, "cbconfig", "../config/clusterrun_conf.json", "Path of the configuration file with data about Couchbase Cluster")
	flag.Parse()
	clusterconfig = tc.GetClusterConfFromFile(configpath)
	kvaddress = clusterconfig.KVAddress
	indexManagementAddress = clusterconfig.KVAddress
	indexScanAddress = clusterconfig.KVAddress

	// setup cbauth
	if _, err := cbauth.InternalRetryDefaultInit(kvaddress, clusterconfig.Username, clusterconfig.Password); err != nil {
		log.Fatalf("Failed to initialize cbauth: %s", err)
	}

	proddir, bagdir = tc.FetchMonsterToolPath()
}

func FailTestIfError(err error, msg string, t *testing.T) {
	if err != nil {
		t.Fatal("%v: %v\n", msg, err)
	}
}

var options struct {
	bagdir  string
	outfile string
	nonterm string
	seed    int
	count   int
	help    bool
	debug   bool
}

func GenerateJsons(count, seed int, prodfile, bagdir string) tc.KeyValues {
	runtime.GOMAXPROCS(50)
	keyValues := make(tc.KeyValues)
	options.outfile = "./out.txt"
	options.bagdir = bagdir
	options.count = count
	options.seed = seed

	var err error
	outfd := os.Stdout
	if options.outfile != "-" && options.outfile != "" {
		outfd, err = os.Create(options.outfile)
		if err != nil {
			log.Fatal(err)
		}
	}

	// read production-file
	text, err := ioutil.ReadFile(prodfile)
	if err != nil {
		log.Fatal(err)
	}
	// compile
	root := compile(parsec.NewScanner(text))
	scope := root.(common.Scope)
	nterms := scope["_nonterminals"].(common.NTForms)
	scope = monster.BuildContext(scope, uint64(options.seed), options.bagdir)
	scope["_prodfile"] = prodfile

	if options.nonterm != "" {
		for i := 0; i < options.count; i++ {
			val := evaluate("root", scope, nterms[options.nonterm])
			fmt.Println(val)
			outtext := fmt.Sprintf("%v\n", val)
			if _, err := outfd.Write([]byte(outtext)); err != nil {
				log.Fatal(err)
			}
		}

	} else {
		// evaluate
		for i := 0; i < options.count; i++ {
			val := evaluate("root", scope, nterms["s"])
			jsonString := val.(string)
			byt := []byte(jsonString)
			var dat map[string]interface{}
			if err := json.Unmarshal(byt, &dat); err != nil {
				panic(err)
			}
			dockey := dat["docid"].(string)
			keyValues[dockey] = dat
			outtext := fmt.Sprintf("%v\n", val)
			if _, err := outfd.Write([]byte(outtext)); err != nil {
				log.Fatal(err)
			}
		}
	}
	return keyValues
}

func compile(s parsec.Scanner) parsec.ParsecNode {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("%v at %v", r, s.GetCursor())
		}
	}()
	root, _ := monster.Y(s)
	return root
}

func evaluate(name string, scope common.Scope, forms []*common.Form) interface{} {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("%v", r)
		}
	}()
	scope = scope.ApplyGlobalForms()
	return monster.EvalForms(name, scope, forms)
}
<commit_msg>tests: use Errorf instead of Fatal<commit_after>package largedatatests

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/couchbase/cbauth"
	tc "github.com/couchbase/indexing/secondary/tests/framework/common"
	"github.com/prataprc/goparsec"
	"github.com/prataprc/monster"
	"github.com/prataprc/monster/common"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"testing"
)

var seed int
var defaultlimit int64 = 10000000
var kvaddress, indexManagementAddress, indexScanAddress string
var clusterconfig tc.ClusterConfiguration
var proddir, bagdir string

func init() {
	fmt.Println("In init()")
	var configpath string
	seed = 1
	flag.StringVar(&configpath, "cbconfig", "../config/clusterrun_conf.json", "Path of the configuration file with data about Couchbase Cluster")
	flag.Parse()
	clusterconfig = tc.GetClusterConfFromFile(configpath)
	kvaddress = clusterconfig.KVAddress
	indexManagementAddress = clusterconfig.KVAddress
	indexScanAddress = clusterconfig.KVAddress

	// setup cbauth
	if _, err := cbauth.InternalRetryDefaultInit(kvaddress, clusterconfig.Username, clusterconfig.Password); err != nil {
		log.Fatalf("Failed to initialize cbauth: %s", err)
	}

	proddir, bagdir = tc.FetchMonsterToolPath()
}

func FailTestIfError(err error, msg string, t *testing.T) {
	if err != nil {
		t.Errorf("%v: %v\n", msg, err)
	}
}

var options struct {
	bagdir  string
	outfile string
	nonterm string
	seed    int
	count   int
	help    bool
	debug   bool
}

func GenerateJsons(count, seed int, prodfile, bagdir string) tc.KeyValues {
	runtime.GOMAXPROCS(50)
	keyValues := make(tc.KeyValues)
	options.outfile = "./out.txt"
	options.bagdir = bagdir
	options.count = count
	options.seed = seed

	var err error
	outfd := os.Stdout
	if options.outfile != "-" && options.outfile != "" {
		outfd, err = os.Create(options.outfile)
		if err != nil {
			log.Fatal(err)
		}
	}

	// read production-file
	text, err := ioutil.ReadFile(prodfile)
	if err != nil {
		log.Fatal(err)
	}
	// compile
	root := compile(parsec.NewScanner(text))
	scope := root.(common.Scope)
	nterms := scope["_nonterminals"].(common.NTForms)
	scope = monster.BuildContext(scope, uint64(options.seed), options.bagdir)
	scope["_prodfile"] = prodfile

	if options.nonterm != "" {
		for i := 0; i < options.count; i++ {
			val := evaluate("root", scope, nterms[options.nonterm])
			fmt.Println(val)
			outtext := fmt.Sprintf("%v\n", val)
			if _, err := outfd.Write([]byte(outtext)); err != nil {
				log.Fatal(err)
			}
		}

	} else {
		// evaluate
		for i := 0; i < options.count; i++ {
			val := evaluate("root", scope, nterms["s"])
			jsonString := val.(string)
			byt := []byte(jsonString)
			var dat map[string]interface{}
			if err := json.Unmarshal(byt, &dat); err != nil {
				panic(err)
			}
			dockey := dat["docid"].(string)
			keyValues[dockey] = dat
			outtext := fmt.Sprintf("%v\n", val)
			if _, err := outfd.Write([]byte(outtext)); err != nil {
				log.Fatal(err)
			}
		}
	}
	return keyValues
}

func compile(s parsec.Scanner) parsec.ParsecNode {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("%v at %v", r, s.GetCursor())
		}
	}()
	root, _ := monster.Y(s)
	return root
}

func evaluate(name string, scope common.Scope, forms []*common.Form) interface{} {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("%v", r)
		}
	}()
	scope = scope.ApplyGlobalForms()
	return monster.EvalForms(name, scope, forms)
}
<|endoftext|>


<commit_before>package drivers

import (
	"fmt"
)

// ErrNilValue is the "Nil value provided" error
var ErrNilValue = fmt.Errorf("Nil value provided")

// ErrNotImplemented is the "Not implemented" error
var ErrNotImplemented = fmt.Errorf("Not implemented")

// ErrUnknownDriver is the "Unknown driver" error
var ErrUnknownDriver = fmt.Errorf("Unknown driver")
<commit_msg>lxd/storage/drivers/errors: Removes unused error<commit_after>package drivers

import (
	"fmt"
)

// ErrNotImplemented is the "Not implemented" error
var ErrNotImplemented = fmt.Errorf("Not implemented")

// ErrUnknownDriver is the "Unknown driver" error
var ErrUnknownDriver = fmt.Errorf("Unknown driver")
<|endoftext|>


<commit_before>package sessions

import (
	"errors"
	"net/http"
)

// SessionStorer provides methods to retrieve, add and delete session keys
// and their corresponding values.
type SessionStorer interface {
	Get(r *http.Request) (value string, err error)
	Put(r *http.Request, value string) error
	Del(r *http.Request) error

	GetID(id string) (value string, err error)
	PutID(id string, value string) error
	DelID(r *http.Request, id string) error
}

// SessionKey is the key name in the cookie that holds the session id.
const SessionKey = "_SESSION_ID"

// ErrNoSession is returned when a session does not exist.
var ErrNoSession = errors.New("cookie has no session id")
<commit_msg>Adjust interface for sessions<commit_after>package sessions

import (
	"errors"
	"net/http"
)

// SessionStorer provides methods to retrieve, add and delete session keys
// and their corresponding values.
type SessionStorer interface {
	Get(r *http.Request) (value string, err error)
	Put(r *http.Request, value string) error
	Del(r *http.Request) error
}

// SessionKey is the key name in the cookie that holds the session id.
const SessionKey = "_SESSION_ID"

// ErrNoSession is returned when a session does not exist.
var ErrNoSession = errors.New("cookie has no session id")
<|endoftext|>


<commit_before>// Copyright The OpenTelemetry 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 zipkinreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver"

import (
	"compress/gzip"
	"compress/zlib"
	"context"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/component/componenterror"
	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/consumer"
	"go.opentelemetry.io/collector/obsreport"
	"go.opentelemetry.io/collector/pdata/ptrace"

	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv1"
	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv2"
)

const (
	receiverTransportV1Thrift = "http_v1_thrift"
	receiverTransportV1JSON   = "http_v1_json"
	receiverTransportV2JSON   = "http_v2_json"
	receiverTransportV2PROTO  = "http_v2_proto"
)

var errNextConsumerRespBody = []byte(`"Internal Server Error"`)

// zipkinReceiver type is used to handle spans received in the Zipkin format.
type zipkinReceiver struct {
	// addr is the address onto which the HTTP server will be bound
	host         component.Host
	nextConsumer consumer.Traces
	id           config.ComponentID

	shutdownWG sync.WaitGroup
	server     *http.Server
	config     *Config

	v1ThriftUnmarshaler      ptrace.Unmarshaler
	v1JSONUnmarshaler        ptrace.Unmarshaler
	jsonUnmarshaler          ptrace.Unmarshaler
	protobufUnmarshaler      ptrace.Unmarshaler
	protobufDebugUnmarshaler ptrace.Unmarshaler

	settings component.ReceiverCreateSettings
}

var _ http.Handler = (*zipkinReceiver)(nil)

// newReceiver creates a new zipkinreceiver.zipkinReceiver reference.
func newReceiver(config *Config, nextConsumer consumer.Traces, settings component.ReceiverCreateSettings) (*zipkinReceiver, error) {
	if nextConsumer == nil {
		return nil, componenterror.ErrNilNextConsumer
	}

	zr := &zipkinReceiver{
		nextConsumer:             nextConsumer,
		id:                       config.ID(),
		config:                   config,
		v1ThriftUnmarshaler:      zipkinv1.NewThriftTracesUnmarshaler(),
		v1JSONUnmarshaler:        zipkinv1.NewJSONTracesUnmarshaler(config.ParseStringTags),
		jsonUnmarshaler:          zipkinv2.NewJSONTracesUnmarshaler(config.ParseStringTags),
		protobufUnmarshaler:      zipkinv2.NewProtobufTracesUnmarshaler(false, config.ParseStringTags),
		protobufDebugUnmarshaler: zipkinv2.NewProtobufTracesUnmarshaler(true, config.ParseStringTags),
		settings:                 settings,
	}
	return zr, nil
}

// Start spins up the receiver's HTTP server and makes the receiver start its processing.
func (zr *zipkinReceiver) Start(_ context.Context, host component.Host) error {
	if host == nil {
		return errors.New("nil host")
	}

	var err error
	zr.host = host
	zr.server, err = zr.config.HTTPServerSettings.ToServer(host, zr.settings.TelemetrySettings, zr)
	if err != nil {
		return err
	}

	var listener net.Listener
	listener, err = zr.config.HTTPServerSettings.ToListener()
	if err != nil {
		return err
	}
	zr.shutdownWG.Add(1)
	go func() {
		defer zr.shutdownWG.Done()

		if errHTTP := zr.server.Serve(listener); !errors.Is(errHTTP, http.ErrServerClosed) && errHTTP != nil {
			host.ReportFatalError(errHTTP)
		}
	}()

	return nil
}

// v1ToTraceSpans parses Zipkin v1 JSON traces and converts them to OpenCensus Proto spans.
func (zr *zipkinReceiver) v1ToTraceSpans(blob []byte, hdr http.Header) (reqs ptrace.Traces, err error) {
	if hdr.Get("Content-Type") == "application/x-thrift" {
		return zr.v1ThriftUnmarshaler.UnmarshalTraces(blob)
	}
	return zr.v1JSONUnmarshaler.UnmarshalTraces(blob)
}

// v2ToTraceSpans parses Zipkin v2 JSON or Protobuf traces and converts them to OpenCensus Proto spans.
func (zr *zipkinReceiver) v2ToTraceSpans(blob []byte, hdr http.Header) (reqs ptrace.Traces, err error) {
	// This flag's reference is from:
	//      https://github.com/openzipkin/zipkin-go/blob/3793c981d4f621c0e3eb1457acffa2c1cc591384/proto/v2/zipkin.proto#L154
	debugWasSet := hdr.Get("X-B3-Flags") == "1"

	// By default, we'll assume using JSON
	unmarshaler := zr.jsonUnmarshaler

	// Zipkin can send protobuf via http
	if hdr.Get("Content-Type") == "application/x-protobuf" {
		// TODO: (@odeke-em) record the unique types of Content-Type uploads
		if debugWasSet {
			unmarshaler = zr.protobufDebugUnmarshaler
		} else {
			unmarshaler = zr.protobufUnmarshaler
		}
	}

	return unmarshaler.UnmarshalTraces(blob)
}

// Shutdown tells the receiver that should stop reception,
// giving it a chance to perform any necessary clean-up and shutting down
// its HTTP server.
func (zr *zipkinReceiver) Shutdown(context.Context) error {
	err := zr.server.Close()
	zr.shutdownWG.Wait()
	return err
}

// processBodyIfNecessary checks the "Content-Encoding" HTTP header and if
// a compression such as "gzip", "deflate", "zlib", is found, the body will
// be uncompressed accordingly or return the body untouched if otherwise.
// Clients such as Zipkin-Java do this behavior e.g.
//    send "Content-Encoding":"gzip" of the JSON content.
func processBodyIfNecessary(req *http.Request) io.Reader {
	switch req.Header.Get("Content-Encoding") {
	default:
		return req.Body

	case "gzip":
		return gunzippedBodyIfPossible(req.Body)

	case "deflate", "zlib":
		return zlibUncompressedbody(req.Body)
	}
}

func gunzippedBodyIfPossible(r io.Reader) io.Reader {
	gzr, err := gzip.NewReader(r)
	if err != nil {
		// Just return the old body as was
		return r
	}
	return gzr
}

func zlibUncompressedbody(r io.Reader) io.Reader {
	zr, err := zlib.NewReader(r)
	if err != nil {
		// Just return the old body as was
		return r
	}
	return zr
}

const (
	zipkinV1TagValue = "zipkinV1"
	zipkinV2TagValue = "zipkinV2"
)

// The zipkinReceiver receives spans from endpoint /api/v2 as JSON,
// unmarshalls them and sends them along to the nextConsumer.
func (zr *zipkinReceiver) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Now deserialize and process the spans.
	asZipkinv1 := r.URL != nil && strings.Contains(r.URL.Path, "api/v1/spans")

	transportTag := transportType(r, asZipkinv1)
	obsrecv := obsreport.NewReceiver(obsreport.ReceiverSettings{
		ReceiverID:             zr.id,
		Transport:              transportTag,
		ReceiverCreateSettings: zr.settings,
	})
	ctx = obsrecv.StartTracesOp(ctx)

	pr := processBodyIfNecessary(r)
	slurp, _ := ioutil.ReadAll(pr)
	if c, ok := pr.(io.Closer); ok {
		_ = c.Close()
	}
	_ = r.Body.Close()

	var td ptrace.Traces
	var err error
	if asZipkinv1 {
		td, err = zr.v1ToTraceSpans(slurp, r.Header)
	} else {
		td, err = zr.v2ToTraceSpans(slurp, r.Header)
	}

	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	consumerErr := zr.nextConsumer.ConsumeTraces(ctx, td)

	receiverTagValue := zipkinV2TagValue
	if asZipkinv1 {
		receiverTagValue = zipkinV1TagValue
	}
	obsrecv.EndTracesOp(ctx, receiverTagValue, td.SpanCount(), consumerErr)

	if consumerErr != nil {
		// Transient error, due to some internal condition.
		w.WriteHeader(http.StatusInternalServerError)
		w.Write(errNextConsumerRespBody) // nolint:errcheck
		return
	}

	// Finally send back the response "Accepted" as
	// required at https://zipkin.io/zipkin-api/#/default/post_spans
	w.WriteHeader(http.StatusAccepted)
}

func transportType(r *http.Request, asZipkinv1 bool) string {
	if asZipkinv1 {
		if r.Header.Get("Content-Type") == "application/x-thrift" {
			return receiverTransportV1Thrift
		}
		return receiverTransportV1JSON
	}
	if r.Header.Get("Content-Type") == "application/x-protobuf" {
		return receiverTransportV2PROTO
	}
	return receiverTransportV2JSON
}
<commit_msg>zipkinreceiver: remove unnecessary internal argument (#9569)<commit_after>// Copyright The OpenTelemetry 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 zipkinreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver"

import (
	"compress/gzip"
	"compress/zlib"
	"context"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"sync"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/component/componenterror"
	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/consumer"
	"go.opentelemetry.io/collector/obsreport"
	"go.opentelemetry.io/collector/pdata/ptrace"

	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv1"
	"github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin/zipkinv2"
)

const (
	receiverTransportV1Thrift = "http_v1_thrift"
	receiverTransportV1JSON   = "http_v1_json"
	receiverTransportV2JSON   = "http_v2_json"
	receiverTransportV2PROTO  = "http_v2_proto"
)

var errNextConsumerRespBody = []byte(`"Internal Server Error"`)

// zipkinReceiver type is used to handle spans received in the Zipkin format.
type zipkinReceiver struct {
	nextConsumer consumer.Traces
	id           config.ComponentID

	shutdownWG sync.WaitGroup
	server     *http.Server
	config     *Config

	v1ThriftUnmarshaler      ptrace.Unmarshaler
	v1JSONUnmarshaler        ptrace.Unmarshaler
	jsonUnmarshaler          ptrace.Unmarshaler
	protobufUnmarshaler      ptrace.Unmarshaler
	protobufDebugUnmarshaler ptrace.Unmarshaler

	settings component.ReceiverCreateSettings
}

var _ http.Handler = (*zipkinReceiver)(nil)

// newReceiver creates a new zipkinReceiver reference.
func newReceiver(config *Config, nextConsumer consumer.Traces, settings component.ReceiverCreateSettings) (*zipkinReceiver, error) {
	if nextConsumer == nil {
		return nil, componenterror.ErrNilNextConsumer
	}

	zr := &zipkinReceiver{
		nextConsumer:             nextConsumer,
		id:                       config.ID(),
		config:                   config,
		v1ThriftUnmarshaler:      zipkinv1.NewThriftTracesUnmarshaler(),
		v1JSONUnmarshaler:        zipkinv1.NewJSONTracesUnmarshaler(config.ParseStringTags),
		jsonUnmarshaler:          zipkinv2.NewJSONTracesUnmarshaler(config.ParseStringTags),
		protobufUnmarshaler:      zipkinv2.NewProtobufTracesUnmarshaler(false, config.ParseStringTags),
		protobufDebugUnmarshaler: zipkinv2.NewProtobufTracesUnmarshaler(true, config.ParseStringTags),
		settings:                 settings,
	}
	return zr, nil
}

// Start spins up the receiver's HTTP server and makes the receiver start its processing.
func (zr *zipkinReceiver) Start(_ context.Context, host component.Host) error {
	if host == nil {
		return errors.New("nil host")
	}

	var err error
	zr.server, err = zr.config.HTTPServerSettings.ToServer(host, zr.settings.TelemetrySettings, zr)
	if err != nil {
		return err
	}

	var listener net.Listener
	listener, err = zr.config.HTTPServerSettings.ToListener()
	if err != nil {
		return err
	}
	zr.shutdownWG.Add(1)
	go func() {
		defer zr.shutdownWG.Done()

		if errHTTP := zr.server.Serve(listener); !errors.Is(errHTTP, http.ErrServerClosed) && errHTTP != nil {
			host.ReportFatalError(errHTTP)
		}
	}()

	return nil
}

// v1ToTraceSpans parses Zipkin v1 JSON traces and converts them to OpenCensus Proto spans.
func (zr *zipkinReceiver) v1ToTraceSpans(blob []byte, hdr http.Header) (reqs ptrace.Traces, err error) {
	if hdr.Get("Content-Type") == "application/x-thrift" {
		return zr.v1ThriftUnmarshaler.UnmarshalTraces(blob)
	}
	return zr.v1JSONUnmarshaler.UnmarshalTraces(blob)
}

// v2ToTraceSpans parses Zipkin v2 JSON or Protobuf traces and converts them to OpenCensus Proto spans.
func (zr *zipkinReceiver) v2ToTraceSpans(blob []byte, hdr http.Header) (reqs ptrace.Traces, err error) {
	// This flag's reference is from:
	//      https://github.com/openzipkin/zipkin-go/blob/3793c981d4f621c0e3eb1457acffa2c1cc591384/proto/v2/zipkin.proto#L154
	debugWasSet := hdr.Get("X-B3-Flags") == "1"

	// By default, we'll assume using JSON
	unmarshaler := zr.jsonUnmarshaler

	// Zipkin can send protobuf via http
	if hdr.Get("Content-Type") == "application/x-protobuf" {
		// TODO: (@odeke-em) record the unique types of Content-Type uploads
		if debugWasSet {
			unmarshaler = zr.protobufDebugUnmarshaler
		} else {
			unmarshaler = zr.protobufUnmarshaler
		}
	}

	return unmarshaler.UnmarshalTraces(blob)
}

// Shutdown tells the receiver that should stop reception,
// giving it a chance to perform any necessary clean-up and shutting down
// its HTTP server.
func (zr *zipkinReceiver) Shutdown(context.Context) error {
	err := zr.server.Close()
	zr.shutdownWG.Wait()
	return err
}

// processBodyIfNecessary checks the "Content-Encoding" HTTP header and if
// a compression such as "gzip", "deflate", "zlib", is found, the body will
// be uncompressed accordingly or return the body untouched if otherwise.
// Clients such as Zipkin-Java do this behavior e.g.
//    send "Content-Encoding":"gzip" of the JSON content.
func processBodyIfNecessary(req *http.Request) io.Reader {
	switch req.Header.Get("Content-Encoding") {
	default:
		return req.Body

	case "gzip":
		return gunzippedBodyIfPossible(req.Body)

	case "deflate", "zlib":
		return zlibUncompressedbody(req.Body)
	}
}

func gunzippedBodyIfPossible(r io.Reader) io.Reader {
	gzr, err := gzip.NewReader(r)
	if err != nil {
		// Just return the old body as was
		return r
	}
	return gzr
}

func zlibUncompressedbody(r io.Reader) io.Reader {
	zr, err := zlib.NewReader(r)
	if err != nil {
		// Just return the old body as was
		return r
	}
	return zr
}

const (
	zipkinV1TagValue = "zipkinV1"
	zipkinV2TagValue = "zipkinV2"
)

// The zipkinReceiver receives spans from endpoint /api/v2 as JSON,
// unmarshalls them and sends them along to the nextConsumer.
func (zr *zipkinReceiver) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()

	// Now deserialize and process the spans.
	asZipkinv1 := r.URL != nil && strings.Contains(r.URL.Path, "api/v1/spans")

	transportTag := transportType(r, asZipkinv1)
	obsrecv := obsreport.NewReceiver(obsreport.ReceiverSettings{
		ReceiverID:             zr.id,
		Transport:              transportTag,
		ReceiverCreateSettings: zr.settings,
	})
	ctx = obsrecv.StartTracesOp(ctx)

	pr := processBodyIfNecessary(r)
	slurp, _ := ioutil.ReadAll(pr)
	if c, ok := pr.(io.Closer); ok {
		_ = c.Close()
	}
	_ = r.Body.Close()

	var td ptrace.Traces
	var err error
	if asZipkinv1 {
		td, err = zr.v1ToTraceSpans(slurp, r.Header)
	} else {
		td, err = zr.v2ToTraceSpans(slurp, r.Header)
	}

	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	consumerErr := zr.nextConsumer.ConsumeTraces(ctx, td)

	receiverTagValue := zipkinV2TagValue
	if asZipkinv1 {
		receiverTagValue = zipkinV1TagValue
	}
	obsrecv.EndTracesOp(ctx, receiverTagValue, td.SpanCount(), consumerErr)

	if consumerErr != nil {
		// Transient error, due to some internal condition.
		w.WriteHeader(http.StatusInternalServerError)
		w.Write(errNextConsumerRespBody) // nolint:errcheck
		return
	}

	// Finally send back the response "Accepted" as
	// required at https://zipkin.io/zipkin-api/#/default/post_spans
	w.WriteHeader(http.StatusAccepted)
}

func transportType(r *http.Request, asZipkinv1 bool) string {
	if asZipkinv1 {
		if r.Header.Get("Content-Type") == "application/x-thrift" {
			return receiverTransportV1Thrift
		}
		return receiverTransportV1JSON
	}
	if r.Header.Get("Content-Type") == "application/x-protobuf" {
		return receiverTransportV2PROTO
	}
	return receiverTransportV2JSON
}
<|endoftext|>


<commit_before>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// Cross-compiles gh for all supported platforms.
//
// Cross-compiles gh for all supported platforms. The build artifacts
// will be in target/VERSION. This only works on darwin with Vagrant setup.
func TaskCrossCompileAll(t *tasking.T) {
	t.Log("Removing build target...")
	err := os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	// for current
	t.Logf("Compiling for %s...\n", runtime.GOOS)
	TaskCrossCompile(t)
	if t.Failed() {
		return
	}

	// for linux
	t.Log("Compiling for linux...")
	err = t.Exec("vagrant ssh -c 'cd ~/src/github.com/jingweno/gh && git pull origin master && gotask cross-compile'")
	if err != nil {
		t.Errorf("Can't compile on linux: %s\n", err)
		return
	}
}

// Cross-compiles gh for current operating system.
//
// Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	// TODO: use a dependency manager that has versioning
	if runtime.GOOS != "windows" {
		t.Log("Updating dependencies...")
		err = t.Exec("go get -u ./...")
		if err != nil {
			t.Errorf("Can't update goxc: %s\n", err)
			return
		}
	}

	t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS)
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<commit_msg>Update to latest gotask comments man page<commit_after>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// NAME
//    cross-compile-all - cross-compiles gh for all supported platforms.
//
// DESCRIPTION
//    Cross-compiles gh for all supported platforms. Build artifacts will be in target/VERSION.
//    This only works on darwin with Vagrant setup.
func TaskCrossCompileAll(t *tasking.T) {
	t.Log("Removing build target...")
	err := os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	// for current
	t.Logf("Compiling for %s...\n", runtime.GOOS)
	TaskCrossCompile(t)
	if t.Failed() {
		return
	}

	// for linux
	t.Log("Compiling for linux...")
	err = t.Exec("vagrant ssh -c 'cd ~/src/github.com/jingweno/gh && git pull origin master && gotask cross-compile'")
	if err != nil {
		t.Errorf("Can't compile on linux: %s\n", err)
		return
	}
}

// NAME
//    cross-compile - cross-compiles gh for current platform.
//
// DESCRIPTION
//    Cross-compiles gh for current platform. Build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	// TODO: use a dependency manager that has versioning
	if runtime.GOOS != "windows" {
		t.Log("Updating dependencies...")
		err = t.Exec("go get -u ./...")
		if err != nil {
			t.Errorf("Can't update goxc: %s\n", err)
			return
		}
	}

	t.Logf("Cross-compiling gh for %s...\n", runtime.GOOS)
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<|endoftext|>


<commit_before>package formatter

import (
	"github.com/BluePecker/JwtAuth/dialog/client/formatter/context"
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/jwt/response"
	"bytes"
	"strconv"
)

const (
	AddrHeader   = "CLIENT ADDR"
	TLLHeader    = "TLL"
	DeviceHeader = "DEVICE"
	TokenHeader  = "TOKEN"

	QuietFormat    = "{{.Token}}"
	JwtTableFormat = "table {{.Addr}}\t{{.Tll}}\t{{.Device}}\t{{.Token}}"
)

type (
	JsonWebToken struct {
		context.BaseSubjectContext
		truncate bool
		jwt      response.JsonWebToken
	}

	JsonWebTokenContext struct {
		context.Context
		JsonWebTokens []response.JsonWebToken
	}
)

func (ctx JsonWebTokenContext) Write() {
	switch ctx.Template {
	case context.RawKey:
		if ctx.Quiet {
			ctx.Template = `Singed: {{.Singed}}`
		} else {
			ctx.Template = `Client Addr: {{.Addr}}\nTTL: {{.Tll}}\nDevice: {{.Device}}\nToken: {{.Token}}\n`
		}
	case context.TableKey:
		if ctx.Quiet {
			ctx.Template = QuietFormat
		} else {
			ctx.Template = JwtTableFormat
		}
	}

	ctx.Buffer = bytes.NewBufferString("")
	ctx.PreFormat()

	tpl, err := ctx.Parser()
	if err != nil {
		return
	}

	for _, jwt := range ctx.JsonWebTokens {
		jwtCtx := &JsonWebToken{
			truncate: ctx.Truncate,
			jwt:      jwt,
		}
		err = ctx.ContextFormat(tpl, jwtCtx)
		if err != nil {
			return
		}
	}

	ctx.FormFormat(tpl, &JsonWebToken{})
}

func (j *JsonWebToken) Addr() string {
	j.AddHeader(AddrHeader)
	return j.jwt.Addr
}

func (j *JsonWebToken) Tll() string {
	j.AddHeader(TLLHeader)
	return strconv.FormatFloat(j.jwt.TTL, 'f', -1, 64)
}

func (j *JsonWebToken) Device() string {
	j.AddHeader(DeviceHeader)
	return j.jwt.Device
}

func (j *JsonWebToken) Token() string {
	j.AddHeader(TokenHeader)
	return j.jwt.Singed
}
<commit_msg>rename<commit_after>package formatter

import (
	"github.com/BluePecker/JwtAuth/dialog/client/formatter/context"
	"github.com/BluePecker/JwtAuth/dialog/server/parameter/jwt/response"
	"bytes"
	"strconv"
)

const (
	AddrHeader   = "CLIENT ADDR"
	TLLHeader    = "TOKEN TLL"
	DeviceHeader = "DEVICE"
	TokenHeader  = "TOKEN"

	QuietFormat    = "{{.Token}}"
	JwtTableFormat = "table {{.Addr}}\t{{.Tll}}\t{{.Device}}\t{{.Token}}"
)

type (
	JsonWebToken struct {
		context.BaseSubjectContext
		truncate bool
		jwt      response.JsonWebToken
	}

	JsonWebTokenContext struct {
		context.Context
		JsonWebTokens []response.JsonWebToken
	}
)

func (ctx JsonWebTokenContext) Write() {
	switch ctx.Template {
	case context.RawKey:
		if ctx.Quiet {
			ctx.Template = `Singed: {{.Singed}}`
		} else {
			ctx.Template = `Client Addr: {{.Addr}}\nToken TTL: {{.Tll}}\nDevice: {{.Device}}\nToken: {{.Token}}\n`
		}
	case context.TableKey:
		if ctx.Quiet {
			ctx.Template = QuietFormat
		} else {
			ctx.Template = JwtTableFormat
		}
	}

	ctx.Buffer = bytes.NewBufferString("")
	ctx.PreFormat()

	tpl, err := ctx.Parser()
	if err != nil {
		return
	}

	for _, jwt := range ctx.JsonWebTokens {
		jwtCtx := &JsonWebToken{
			truncate: ctx.Truncate,
			jwt:      jwt,
		}
		err = ctx.ContextFormat(tpl, jwtCtx)
		if err != nil {
			return
		}
	}

	ctx.FormFormat(tpl, &JsonWebToken{})
}

func (j *JsonWebToken) Addr() string {
	j.AddHeader(AddrHeader)
	return j.jwt.Addr
}

func (j *JsonWebToken) Tll() string {
	j.AddHeader(TLLHeader)
	return strconv.FormatFloat(j.jwt.TTL, 'f', -1, 64)
}

func (j *JsonWebToken) Device() string {
	j.AddHeader(DeviceHeader)
	return j.jwt.Device
}

func (j *JsonWebToken) Token() string {
	j.AddHeader(TokenHeader)
	return j.jwt.Singed
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

type Option struct {
	Name     string
	Question string
	Default  string
}

type Config struct {
	Prod  string
	Other []string
}

func LoadConfig_(getOption func(string) (string, error)) (*Config, error) {
	config := Config{}

	cfg := map[string]string{}

	for _, opt := range options {
		s, err := getOption(opt.Name)
		if err != nil {
			return nil, err
		}
		cfg[opt.Name] = s
	}
	config.Prod = cfg["prod"]
	config.Other = strings.Split(cfg["other"], " ")

	return &config, nil
}

func LoadConfig() (*Config, error) {
	return LoadConfig_(getOption)
}

func getOption(opt string) (string, error) {
	stdout, err := exec.Command("git", "config", "env-branch."+opt).Output()
	if err != nil {
		return "", errors.New("This repo isn't git env enabled. Run 'git env init' first.")
	}
	return string(stdout)[:len(stdout)-1], nil
}

func (c Config) IsEnv(branch string) bool {
	if branch == c.Prod {
		return true
	}
	for _, b := range c.Other {
		if branch == b {
			return true
		}
	}
	return false
}

func (c Config) ProdRemote() string {
	stdout, err := exec.Command("git", "config", "branch."+c.Prod+".remote").Output()
	if err != nil {
		log.Fatalf("Failed to get remote of %s branch.", c.Prod)
	}
	return string(stdout)[:len(stdout)-1]
}

var (
	config  *Config
	options = []Option{
		{
			Name:     "prod",
			Question: "What is your production environment branch?",
			Default:  "master",
		},
		{
			Name:     "other",
			Question: "What other environment branches do you have?",
			Default:  "stage dev",
		},
	}
)

func main() {
	if len(os.Args) > 1 && os.Args[1] == "init" {
		cmdInit()
		return
	}

	var err error
	config, err = LoadConfig()
	if err != nil {
		log.Fatalln(err)
	}

	if len(os.Args) < 2 {
		help("")
	} else {

		switch os.Args[1] {
		case "start":
			cmdStart(os.Args[2:])
		case "deploy":
			cmdDeploy(os.Args[2:])
		case "help":
			if len(os.Args) > 2 {
				help(os.Args[2])
			} else {
				help("")
			}
		default:
			help("")
		}
	}
}

// Commands

func cmdInit() {
	values := map[string]string{}
	reader := bufio.NewReader(os.Stdin)

	for _, opt := range options {
		fmt.Printf("%s [%s] ", opt.Question, opt.Default)
		value, err := reader.ReadString('\n')
		if err != nil {
			panic(err)
		}
		if value == "\n" {
			values[opt.Name] = opt.Default
		} else {
			values[opt.Name] = value[:len(value)-1]
		}
	}

	for k, v := range values {
		err := exec.Command("git", "config", "--local", "--replace-all", "env-branch."+k, v).Run()
		if err != nil {
			panic(err)
		}
	}

	fmt.Println("You're ready to go.")
}

func cmdStart(args []string) {
	if len(args) < 1 {
		help("start")
	}

	newBranch := args[0]

	gitCommand("checkout", config.Prod)
	gitCommand("pull", "--rebase", config.ProdRemote(), config.Prod)
	gitCommand("checkout", "-b", newBranch)
}

func cmdDeploy(args []string) {
	if len(args) < 1 {
		help("deploy")
	}

	deployEnv := args[0]
	var feature string
	var err error

	if len(args) > 1 {
		feature = args[1]
	} else {
		feature, err = getCurrentBranch()
		if err != nil {
			panic(err)
		}
	}

	if !config.IsEnv(deployEnv) {
		log.Fatalf("Branch %s is not an env branch. Can't merge a feature into it.", deployEnv)
	}

	if config.IsEnv(feature) {
		log.Fatalf("Branch %s is an env branch. Can't merge an env branch into another env branch.", feature)
	}

	gitCommand("checkout", feature)
	gitCommand("pull", "--rebase", config.ProdRemote(), config.Prod)
	gitCommand("checkout", deployEnv)
	gitCommand("pull", "--rebase", config.ProdRemote(), deployEnv)
	gitCommand("merge", feature)
	// Let's not push anything - leave that up to the developer
	// gitCommand("push", config.ProdRemote(), deployEnv)
}

// Everything else

func help(arg string) {
	switch arg {
	//TODO: add in-depth documentation for each command
	// case "init":
	// case "start":
	// case "deploy":
	default:
		fmt.Println("Commands:")
		fmt.Println("  git env help [COMMAND]                     - show help")
		fmt.Println("  git env init                               - configure which ENV branches are being used")
		fmt.Println("  git env start BRANCH_NAME                  - start a new feature branch")
		fmt.Println("  git env deploy ENV_BRANCH [FEATURE_BRANCH] - deploy a feature branch to an ENV branch (FEATURE_BRANCH defaults to current branch)")
	}
}

func gitCommand(args ...string) {
	fmt.Printf("+ git %s\n", strings.Join(args, " "))
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin

	err := cmd.Run()

	if err != nil {
		log.Fatalf("Failed executing command: git %s", strings.Join(args, " "))
	}
}

func gitBranch() (string, error) {
	stdout, err := exec.Command("git", "branch").Output()
	return string(stdout), err
}

func getCurrentBranch_(gitBranch func() (string, error)) (string, error) {
	stdout, err := gitBranch()
	if err != nil {
		return "", err
	}

	lines := strings.Split(stdout, "\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "* ") {
			items := strings.Split(line, " ")

			return items[1], nil
		}
	}

	return "", errors.New("could not detect current branch")
}

func getCurrentBranch() (string, error) {
	return getCurrentBranch_(gitBranch)
}
<commit_msg>Remove [COMMAND] from help's own documentation<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
)

type Option struct {
	Name     string
	Question string
	Default  string
}

type Config struct {
	Prod  string
	Other []string
}

func LoadConfig_(getOption func(string) (string, error)) (*Config, error) {
	config := Config{}

	cfg := map[string]string{}

	for _, opt := range options {
		s, err := getOption(opt.Name)
		if err != nil {
			return nil, err
		}
		cfg[opt.Name] = s
	}
	config.Prod = cfg["prod"]
	config.Other = strings.Split(cfg["other"], " ")

	return &config, nil
}

func LoadConfig() (*Config, error) {
	return LoadConfig_(getOption)
}

func getOption(opt string) (string, error) {
	stdout, err := exec.Command("git", "config", "env-branch."+opt).Output()
	if err != nil {
		return "", errors.New("This repo isn't git env enabled. Run 'git env init' first.")
	}
	return string(stdout)[:len(stdout)-1], nil
}

func (c Config) IsEnv(branch string) bool {
	if branch == c.Prod {
		return true
	}
	for _, b := range c.Other {
		if branch == b {
			return true
		}
	}
	return false
}

func (c Config) ProdRemote() string {
	stdout, err := exec.Command("git", "config", "branch."+c.Prod+".remote").Output()
	if err != nil {
		log.Fatalf("Failed to get remote of %s branch.", c.Prod)
	}
	return string(stdout)[:len(stdout)-1]
}

var (
	config  *Config
	options = []Option{
		{
			Name:     "prod",
			Question: "What is your production environment branch?",
			Default:  "master",
		},
		{
			Name:     "other",
			Question: "What other environment branches do you have?",
			Default:  "stage dev",
		},
	}
)

func main() {
	if len(os.Args) > 1 && os.Args[1] == "init" {
		cmdInit()
		return
	}

	var err error
	config, err = LoadConfig()
	if err != nil {
		log.Fatalln(err)
	}

	if len(os.Args) < 2 {
		help("")
	} else {

		switch os.Args[1] {
		case "start":
			cmdStart(os.Args[2:])
		case "deploy":
			cmdDeploy(os.Args[2:])
		case "help":
			if len(os.Args) > 2 {
				help(os.Args[2])
			} else {
				help("")
			}
		default:
			help("")
		}
	}
}

// Commands

func cmdInit() {
	values := map[string]string{}
	reader := bufio.NewReader(os.Stdin)

	for _, opt := range options {
		fmt.Printf("%s [%s] ", opt.Question, opt.Default)
		value, err := reader.ReadString('\n')
		if err != nil {
			panic(err)
		}
		if value == "\n" {
			values[opt.Name] = opt.Default
		} else {
			values[opt.Name] = value[:len(value)-1]
		}
	}

	for k, v := range values {
		err := exec.Command("git", "config", "--local", "--replace-all", "env-branch."+k, v).Run()
		if err != nil {
			panic(err)
		}
	}

	fmt.Println("You're ready to go.")
}

func cmdStart(args []string) {
	if len(args) < 1 {
		help("start")
	}

	newBranch := args[0]

	gitCommand("checkout", config.Prod)
	gitCommand("pull", "--rebase", config.ProdRemote(), config.Prod)
	gitCommand("checkout", "-b", newBranch)
}

func cmdDeploy(args []string) {
	if len(args) < 1 {
		help("deploy")
	}

	deployEnv := args[0]
	var feature string
	var err error

	if len(args) > 1 {
		feature = args[1]
	} else {
		feature, err = getCurrentBranch()
		if err != nil {
			panic(err)
		}
	}

	if !config.IsEnv(deployEnv) {
		log.Fatalf("Branch %s is not an env branch. Can't merge a feature into it.", deployEnv)
	}

	if config.IsEnv(feature) {
		log.Fatalf("Branch %s is an env branch. Can't merge an env branch into another env branch.", feature)
	}

	gitCommand("checkout", feature)
	gitCommand("pull", "--rebase", config.ProdRemote(), config.Prod)
	gitCommand("checkout", deployEnv)
	gitCommand("pull", "--rebase", config.ProdRemote(), deployEnv)
	gitCommand("merge", feature)
	// Let's not push anything - leave that up to the developer
	// gitCommand("push", config.ProdRemote(), deployEnv)
}

// Everything else

func help(arg string) {
	switch arg {
	//TODO: add in-depth documentation for each command
	// case "init":
	// case "start":
	// case "deploy":
	default:
		fmt.Println("Commands:")
		fmt.Println("  git env help                               - show this help")
		fmt.Println("  git env init                               - configure which ENV branches are being used")
		fmt.Println("  git env start BRANCH_NAME                  - start a new feature branch")
		fmt.Println("  git env deploy ENV_BRANCH [FEATURE_BRANCH] - deploy a feature branch to an ENV branch (FEATURE_BRANCH defaults to current branch)")
	}
}

func gitCommand(args ...string) {
	fmt.Printf("+ git %s\n", strings.Join(args, " "))
	cmd := exec.Command("git", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Stdin = os.Stdin

	err := cmd.Run()

	if err != nil {
		log.Fatalf("Failed executing command: git %s", strings.Join(args, " "))
	}
}

func gitBranch() (string, error) {
	stdout, err := exec.Command("git", "branch").Output()
	return string(stdout), err
}

func getCurrentBranch_(gitBranch func() (string, error)) (string, error) {
	stdout, err := gitBranch()
	if err != nil {
		return "", err
	}

	lines := strings.Split(stdout, "\n")
	for _, line := range lines {
		if strings.HasPrefix(line, "* ") {
			items := strings.Split(line, " ")

			return items[1], nil
		}
	}

	return "", errors.New("could not detect current branch")
}

func getCurrentBranch() (string, error) {
	return getCurrentBranch_(gitBranch)
}
<|endoftext|>


<commit_before>package mongodb

import (
	"fmt"
	"koding/tools/config"
	"os"
	"sync"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type MongoDB struct {
	Session *mgo.Session
	URL     string
}

var (
	Mongo *MongoDB
	mu    sync.Mutex
)

func init() {
	Mongo = NewMongoDB(config.Current.Mongo)
}

func NewMongoDB(url string) *MongoDB {
	m := &MongoDB{
		URL: url,
	}

	m.CreateSession(m.URL)
	return m
}

func (m *MongoDB) CreateSession(url string) {
	var err error
	m.Session, err = mgo.Dial(url)
	if err != nil {
		fmt.Printf("mongodb connection error: %s\n", err)
		os.Exit(1)
		return
	}

	m.Session.SetSafe(&mgo.Safe{})
}

func (m *MongoDB) Close() {
	m.Session.Close()
}

func (m *MongoDB) Refresh() {
	m.Session.Refresh()
}

func (m *MongoDB) Copy() *mgo.Session {
	return m.Session.Copy()
}

func (m *MongoDB) GetSession() *mgo.Session {
	if m.Session == nil {
		m.CreateSession(m.URL)
	}
	return m.Copy()
}

func (m *MongoDB) Run(collection string, s func(*mgo.Collection) error) error {
	session := m.GetSession()
	defer session.Close()
	c := session.DB("").C(collection)
	return s(c)
}

func (m *MongoDB) RunOnDatabase(database, collection string, s func(*mgo.Collection) error) error {
	session := m.GetSession()
	defer session.Close()
	c := session.DB(database).C(collection)
	return s(c)
}

// RunOnDatabase runs command on given database, instead of current database
// this is needed for kite datastores currently, since it uses another database
// on the same connection. mongodb has database level write lock, which locks
// the entire database while flushing data, if kites tend to send too many
// set/get/delete commands this wont lock our koding database - hopefully
func RunOnDatabase(database, collection string, s func(*mgo.Collection) error) error {
	session := Mongo.GetSession()
	defer session.Close()
	c := session.DB(database).C(collection)
	return s(c)
}

func Run(collection string, s func(*mgo.Collection) error) error {
	session := Mongo.GetSession()
	defer session.Close()
	c := session.DB("").C(collection)
	return s(c)
}

func One(collection, id string, result interface{}) error {
	session := Mongo.GetSession()
	defer session.Close()
	return session.DB("").C(collection).FindId(bson.ObjectIdHex(id)).One(result)
}
<commit_msg>go/mongodb: enable monotonic consistency and enable stats<commit_after>package mongodb

import (
	"fmt"
	"koding/tools/config"
	"os"
	"sync"

	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
)

type MongoDB struct {
	Session *mgo.Session
	URL     string
}

var (
	Mongo *MongoDB
	mu    sync.Mutex
)

func init() {
	Mongo = NewMongoDB(config.Current.Mongo)
	mgo.SetStats(true)
}

func NewMongoDB(url string) *MongoDB {
	m := &MongoDB{
		URL: url,
	}

	m.CreateSession(m.URL)
	return m
}

func (m *MongoDB) CreateSession(url string) {
	var err error
	m.Session, err = mgo.Dial(url)
	if err != nil {
		fmt.Printf("mongodb connection error: %s\n", err)
		os.Exit(1)
		return
	}

	m.Session.SetSafe(&mgo.Safe{})
	m.Session.SetMode(mgo.Monotonic, true)
}

func (m *MongoDB) Close() {
	m.Session.Close()
}

func (m *MongoDB) Refresh() {
	m.Session.Refresh()
}

func (m *MongoDB) Copy() *mgo.Session {
	return m.Session.Copy()
}

func (m *MongoDB) Clone() *mgo.Session {
	return m.Session.Clone()
}

func (m *MongoDB) GetSession() *mgo.Session {
	if m.Session == nil {
		m.CreateSession(m.URL)
	}

	return m.Copy()
}

func (m *MongoDB) Run(collection string, s func(*mgo.Collection) error) error {
	session := m.GetSession()
	defer session.Close()
	c := session.DB("").C(collection)
	return s(c)
}

func (m *MongoDB) RunOnDatabase(database, collection string, s func(*mgo.Collection) error) error {
	session := m.GetSession()
	defer session.Close()
	c := session.DB(database).C(collection)
	return s(c)
}

// RunOnDatabase runs command on given database, instead of current database
// this is needed for kite datastores currently, since it uses another database
// on the same connection. mongodb has database level write lock, which locks
// the entire database while flushing data, if kites tend to send too many
// set/get/delete commands this wont lock our koding database - hopefully
func RunOnDatabase(database, collection string, s func(*mgo.Collection) error) error {
	session := Mongo.GetSession()
	defer session.Close()
	c := session.DB(database).C(collection)
	return s(c)
}

func Run(collection string, s func(*mgo.Collection) error) error {
	session := Mongo.GetSession()
	defer session.Close()
	c := session.DB("").C(collection)
	return s(c)
}

func One(collection, id string, result interface{}) error {
	session := Mongo.GetSession()
	defer session.Close()
	return session.DB("").C(collection).FindId(bson.ObjectIdHex(id)).One(result)
}
<|endoftext|>


<commit_before>package git

import (
	"fmt"
	tlog "github.com/heysquirrel/tribe/log"
	"github.com/heysquirrel/tribe/shell"
	"log"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Contributor struct {
	Name         string
	Count        int
	RelativeDate string
	UnixTime     int
}

type RelatedFile struct {
	Name         string
	Count        int
	RelativeDate string
	UnixTime     int
}

type byRelevance []*RelatedFile

func (a byRelevance) Len() int      { return len(a) }
func (a byRelevance) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byRelevance) Less(i, j int) bool {
	if a[i].UnixTime == a[j].UnixTime {
		return a[i].Count < a[j].Count
	}

	return a[i].UnixTime < a[j].UnixTime
}

type Repo struct {
	shell  *shell.Shell
	logger *tlog.Log
}

func (repo *Repo) git(args ...string) (string, error) {
	return repo.shell.Exec("git", args...)
}

func (repo *Repo) log(args ...string) (string, error) {
	sixMonthsAgo := time.Now().AddDate(0, -6, 0)
	after := fmt.Sprintf("--after=%s", sixMonthsAgo.Format("2012/01/30"))

	logCommand := make([]string, 0)
	logCommand = append(logCommand, "log", "--no-merges", after)
	logCommand = append(logCommand, args...)

	results, err := repo.git(logCommand...)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(results), nil
}

func New(dir string, logger *tlog.Log) (*Repo, error) {
	temp := shell.New(dir, logger)
	out, err := temp.Exec("git", "rev-parse", "--show-toplevel")
	if err != nil {
		return nil, err
	}

	repo := new(Repo)
	repo.shell = shell.New(strings.TrimSpace(out), logger)
	repo.logger = logger

	return repo, err
}

func (repo *Repo) Changes() []string {
	var results = make([]string, 1)

	cmdOut, err := repo.git("status", "--porcelain")
	if err != nil {
		repo.logger.Add(err.Error())
		return results
	}

	output := strings.Split(cmdOut, "\n")
	for _, change := range output {
		if len(change) > 0 {
			results = append(results, change[3:len(change)])
		}
	}

	return results
}

func (repo *Repo) Related(filename string) ([]*RelatedFile, []string, []*Contributor) {
	return repo.relatedFiles(filename), repo.relatedWorkItems(filename), repo.relatedContributors(filename)
}

func (repo *Repo) relatedFiles(filename string) []*RelatedFile {
	files := make([]*RelatedFile, 0)
	namedFiles := make(map[string]*RelatedFile)

	if len(filename) == 0 {
		return files
	}

	out, err := repo.log("--pretty=format:%H", "--follow", filename)
	if err != nil {
		repo.logger.Add(err.Error())
	}

	output := strings.Split(out, "\n")

	for _, sha := range output {
		if len(sha) == 0 {
			continue
		}

		out, err = repo.git("show", "--pretty=format:%ar%m%at", "--name-only", sha)
		if err != nil {
			repo.logger.Add(err.Error())
		}
		lines := strings.Split(out, "\n")
		dateData := strings.Split(lines[0], ">")

		for _, file := range lines[1:] {
			if len(strings.TrimSpace(file)) == 0 || file == filename {
				continue
			}

			relatedFile, ok := namedFiles[file]
			if ok {
				relatedFile.Count += 1
			} else {
				relatedFile := new(RelatedFile)
				relatedFile.Name = file
				relatedFile.Count = 1
				relatedFile.RelativeDate = dateData[0]
				relatedFile.UnixTime, err = strconv.Atoi(dateData[1])
				if err != nil {
					repo.logger.Add(err.Error())
				}

				namedFiles[file] = relatedFile
				files = append(files, relatedFile)
			}
		}
	}

	sort.Sort(sort.Reverse(byRelevance(files)))
	return files
}

func (repo *Repo) relatedWorkItems(filename string) []string {
	workItems := make([]string, 0)

	if len(filename) == 0 {
		return workItems
	}

	out, err := repo.log("--pretty=format:%s", "--follow", filename)
	if err != nil {
		repo.logger.Add(err.Error())
	}

	subjects := strings.Split(out, "\n")
	re := regexp.MustCompile("(S|DE)[0-9][0-9]+")

	for _, subjects := range subjects {
		found := re.FindString(subjects)
		if len(found) > 0 {
			workItems = append(workItems, found)
		}
	}

	return workItems
}

func (repo *Repo) relatedContributors(filename string) []*Contributor {
	contributors := make([]*Contributor, 0)
	namedContributors := make(map[string]*Contributor)

	if len(filename) == 0 {
		return contributors
	}

	out, err := repo.log("--pretty=format:%aN%m%ar%m%at", "--follow", filename)
	if err != nil {
		repo.logger.Add(err.Error())
	}

	output := strings.Split(out, "\n")
	for _, line := range output {
		if len(line) > 0 {
			contributorData := strings.Split(line, ">")
			name := strings.TrimSpace(contributorData[0])

			contributor, ok := namedContributors[name]
			if ok {
				contributor.Count += 1
			} else {
				contributor := new(Contributor)
				contributor.Name = name
				contributor.Count = 1
				contributor.RelativeDate = contributorData[1]
				contributor.UnixTime, err = strconv.Atoi(contributorData[2])
				if err != nil {
					log.Panicln(err)
				}

				namedContributors[name] = contributor
				contributors = append(contributors, contributor)
			}
		}
	}

	return contributors
}
<commit_msg>Only execute one log query per file change<commit_after>package git

import (
	"fmt"
	tlog "github.com/heysquirrel/tribe/log"
	"github.com/heysquirrel/tribe/shell"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Contributor struct {
	Name         string
	Count        int
	RelativeDate string
	UnixTime     int
}

type RelatedFile struct {
	Name         string
	Count        int
	RelativeDate string
	UnixTime     int
}

type byRelevance []*RelatedFile

func (a byRelevance) Len() int      { return len(a) }
func (a byRelevance) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byRelevance) Less(i, j int) bool {
	if a[i].UnixTime == a[j].UnixTime {
		return a[i].Count < a[j].Count
	}

	return a[i].UnixTime < a[j].UnixTime
}

type Repo struct {
	shell  *shell.Shell
	logger *tlog.Log
}

func (repo *Repo) git(args ...string) (string, error) {
	return repo.shell.Exec("git", args...)
}

func (repo *Repo) log(args ...string) (string, error) {
	sixMonthsAgo := time.Now().AddDate(0, -6, 0)
	after := fmt.Sprintf("--after=%s", sixMonthsAgo.Format("2012/01/30"))

	logCommand := make([]string, 0)
	logCommand = append(logCommand, "log", "--no-merges", after)
	logCommand = append(logCommand, args...)

	results, err := repo.git(logCommand...)
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(results), nil
}

func New(dir string, logger *tlog.Log) (*Repo, error) {
	temp := shell.New(dir, logger)
	out, err := temp.Exec("git", "rev-parse", "--show-toplevel")
	if err != nil {
		return nil, err
	}

	repo := new(Repo)
	repo.shell = shell.New(strings.TrimSpace(out), logger)
	repo.logger = logger

	return repo, err
}

func (repo *Repo) Changes() []string {
	var results = make([]string, 1)

	cmdOut, err := repo.git("status", "--porcelain")
	if err != nil {
		repo.logger.Add(err.Error())
		return results
	}

	output := strings.Split(cmdOut, "\n")
	for _, change := range output {
		if len(change) > 0 {
			results = append(results, change[3:len(change)])
		}
	}

	return results
}

type LogEntry struct {
	Sha          string
	Subject      string
	Author       string
	RelativeDate string
	UnixTime     int
}

func (repo *Repo) Related(filename string) ([]*RelatedFile, []string, []*Contributor) {
	logEntries := make([]*LogEntry, 0)
	out, err := repo.log("--pretty=format:%H%m%s%m%aN%m%ar%m%at", "--follow", filename)
	if err != nil {
		repo.logger.Add(err.Error())
	}

	logs := strings.Split(out, "\n")
	for _, log := range logs {
		if len(log) == 0 {
			continue
		}

		parts := strings.Split(log, ">")
		entry := new(LogEntry)
		entry.Sha = parts[0]
		entry.Subject = parts[1]
		entry.Author = strings.TrimSpace(parts[2])
		entry.RelativeDate = parts[3]
		entry.UnixTime, err = strconv.Atoi(parts[4])
		if err != nil {
			repo.logger.Add(err.Error())
		}

		logEntries = append(logEntries, entry)
	}

	return repo.relatedFiles(logEntries, filename),
		repo.relatedWorkItems(logEntries),
		repo.relatedContributors(logEntries)
}

func (repo *Repo) relatedFiles(entries []*LogEntry, filename string) []*RelatedFile {
	files := make([]*RelatedFile, 0)
	namedFiles := make(map[string]*RelatedFile)

	for _, entry := range entries {
		out, err := repo.git("show", "--pretty=format:%ar%m%at", "--name-only", entry.Sha)
		if err != nil {
			repo.logger.Add(err.Error())
		}
		lines := strings.Split(out, "\n")
		dateData := strings.Split(lines[0], ">")

		for _, file := range lines[1:] {
			if len(strings.TrimSpace(file)) == 0 || file == filename {
				continue
			}

			relatedFile, ok := namedFiles[file]
			if ok {
				relatedFile.Count += 1
			} else {
				relatedFile := new(RelatedFile)
				relatedFile.Name = file
				relatedFile.Count = 1
				relatedFile.RelativeDate = dateData[0]
				relatedFile.UnixTime, err = strconv.Atoi(dateData[1])
				if err != nil {
					repo.logger.Add(err.Error())
				}

				namedFiles[file] = relatedFile
				files = append(files, relatedFile)
			}
		}
	}

	sort.Sort(sort.Reverse(byRelevance(files)))
	return files
}

func (repo *Repo) relatedWorkItems(entries []*LogEntry) []string {
	workItems := make([]string, 0)

	re := regexp.MustCompile("(S|DE)[0-9][0-9]+")

	for _, entry := range entries {
		found := re.FindString(entry.Subject)
		if len(found) > 0 {
			workItems = append(workItems, found)
		}
	}

	return workItems
}

func (repo *Repo) relatedContributors(entries []*LogEntry) []*Contributor {
	contributors := make([]*Contributor, 0)
	namedContributors := make(map[string]*Contributor)

	for _, entry := range entries {
		name := entry.Author

		contributor, ok := namedContributors[name]
		if ok {
			contributor.Count += 1
		} else {
			contributor := new(Contributor)
			contributor.Name = name
			contributor.Count = 1
			contributor.RelativeDate = entry.RelativeDate
			contributor.UnixTime = entry.UnixTime

			namedContributors[name] = contributor
			contributors = append(contributors, contributor)
		}
	}

	return contributors
}
<|endoftext|>


<commit_before>package gitmock

//go:generate go run _tools/gen.go
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/Masterminds/semver"
	"github.com/pkg/errors"
)

// New creates a new git mock repository.
// If gitPath is the empty string, `git` is used.
func New(gitPath string) (*GitMock, error) {
	return (&GitMock{gitPath: gitPath}).Initialize()
}

// GitMock is git mock repository
type GitMock struct {
	repoPath string
	gitPath  string
	user     string
	email    string
}

// Initialize the GitMock
func (gm *GitMock) Initialize() (*GitMock, error) {
	if gm.gitPath == "" {
		gm.gitPath = "git"
	}

	cmd := exec.Command(gm.gitPath, "version")
	cmd.Env = append(os.Environ(), "LANG=C")
	var b bytes.Buffer
	cmd.Stdout = &b
	err := cmd.Run()
	if err != nil {
		return nil, errors.Wrap(err, "failed to create new GitMock")
	}
	gitVer := b.String()
	arr := strings.Fields(gitVer)
	if len(arr) != 3 || arr[0] != "git" || arr[1] != "version" {
		return nil, fmt.Errorf("output of `git version` looks strange: %s", gitVer)
	}
	verArr := strings.Split(arr[2], ".")
	if len(verArr) < 3 {
		return nil, fmt.Errorf("git version [%s] looks strange", arr[2])
	}
	semv := strings.Join(verArr[:3], ".")
	ver, err := semver.NewVersion(semv)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("git version [%s] looks strange", arr[2]))
	}
	c, _ := semver.NewConstraint(">= 1.8.5")
	if !c.Check(ver) {
		return nil, fmt.Errorf("git 1.8.5 or later required")
	}

	err = exec.Command(gm.gitPath, "config", "user.name").Run()
	if err != nil {
		gm.user = "gitmock"
	}
	err = exec.Command(gm.gitPath, "config", "user.email").Run()
	if err != nil {
		gm.email = "gitmock@example.com"
	}

	return gm, nil
}

// RepoPath returns repository path
func (gm *GitMock) RepoPath() string {
	if gm.repoPath == "" {
		dir, err := ioutil.TempDir("", "gitmock-")
		if err != nil {
			log.Fatal(err.Error())
		}
		gm.repoPath = dir
	}
	return gm.repoPath
}

func (gm *GitMock) gitProg() string {
	if gm.gitPath != "" {
		return gm.gitPath
	}
	return "git"
}

func (gm *GitMock) env() (ret []string) {
	if gm.user != "" {
		envs := []string{"GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME"}
		for _, v := range envs {
			if env := os.Getenv(v); env == "" {
				ret = append(ret, fmt.Sprintf("%s=%s", v, gm.user))
			}
		}
	}
	if gm.email != "" {
		envs := []string{"GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL"}
		for _, v := range envs {
			if env := os.Getenv(v); env == "" {
				ret = append(ret, fmt.Sprintf("%s=%s", v, gm.email))
			}
		}
	}
	return ret
}

// Do the git command
func (gm *GitMock) Do(args ...string) (string, string, error) {
	arg := append([]string{"-C", gm.RepoPath()}, args...)
	cmd := exec.Command(gm.gitProg(), arg...)
	cmd.Env = append(os.Environ(), "LANG=C")
	cmd.Env = append(cmd.Env, gm.env()...)

	var bout, berr bytes.Buffer
	cmd.Stdout = &bout
	cmd.Stderr = &berr
	err := cmd.Run()
	return bout.String(), berr.String(), err
}

// PutFile put a file to repo
func (gm *GitMock) PutFile(file, content string) error {
	repo := gm.RepoPath()
	fpath := filepath.Join(repo, file)
	err := os.MkdirAll(filepath.Dir(fpath), 0755)
	if err != nil {
		return err
	}
	c := []byte(content)
	return ioutil.WriteFile(fpath, c, 0644)
}
<commit_msg>add comment<commit_after>// Package gitmock provides utilities for creating mock git repository
package gitmock

//go:generate go run _tools/gen.go
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/Masterminds/semver"
	"github.com/pkg/errors"
)

// New creates a new git mock repository.
// If gitPath is the empty string, `git` is used.
func New(gitPath string) (*GitMock, error) {
	return (&GitMock{gitPath: gitPath}).Initialize()
}

// GitMock is git mock repository
type GitMock struct {
	repoPath string
	gitPath  string
	user     string
	email    string
}

// Initialize the GitMock
func (gm *GitMock) Initialize() (*GitMock, error) {
	if gm.gitPath == "" {
		gm.gitPath = "git"
	}

	cmd := exec.Command(gm.gitPath, "version")
	cmd.Env = append(os.Environ(), "LANG=C")
	var b bytes.Buffer
	cmd.Stdout = &b
	err := cmd.Run()
	if err != nil {
		return nil, errors.Wrap(err, "failed to create new GitMock")
	}
	gitVer := b.String()
	arr := strings.Fields(gitVer)
	if len(arr) != 3 || arr[0] != "git" || arr[1] != "version" {
		return nil, fmt.Errorf("output of `git version` looks strange: %s", gitVer)
	}
	verArr := strings.Split(arr[2], ".")
	if len(verArr) < 3 {
		return nil, fmt.Errorf("git version [%s] looks strange", arr[2])
	}
	semv := strings.Join(verArr[:3], ".")
	ver, err := semver.NewVersion(semv)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("git version [%s] looks strange", arr[2]))
	}
	c, _ := semver.NewConstraint(">= 1.8.5")
	if !c.Check(ver) {
		return nil, fmt.Errorf("git 1.8.5 or later required")
	}

	err = exec.Command(gm.gitPath, "config", "user.name").Run()
	if err != nil {
		gm.user = "gitmock"
	}
	err = exec.Command(gm.gitPath, "config", "user.email").Run()
	if err != nil {
		gm.email = "gitmock@example.com"
	}

	return gm, nil
}

// RepoPath returns repository path
func (gm *GitMock) RepoPath() string {
	if gm.repoPath == "" {
		dir, err := ioutil.TempDir("", "gitmock-")
		if err != nil {
			log.Fatal(err.Error())
		}
		gm.repoPath = dir
	}
	return gm.repoPath
}

func (gm *GitMock) gitProg() string {
	if gm.gitPath != "" {
		return gm.gitPath
	}
	return "git"
}

func (gm *GitMock) env() (ret []string) {
	if gm.user != "" {
		envs := []string{"GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME"}
		for _, v := range envs {
			if env := os.Getenv(v); env == "" {
				ret = append(ret, fmt.Sprintf("%s=%s", v, gm.user))
			}
		}
	}
	if gm.email != "" {
		envs := []string{"GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL"}
		for _, v := range envs {
			if env := os.Getenv(v); env == "" {
				ret = append(ret, fmt.Sprintf("%s=%s", v, gm.email))
			}
		}
	}
	return ret
}

// Do the git command
func (gm *GitMock) Do(args ...string) (string, string, error) {
	arg := append([]string{"-C", gm.RepoPath()}, args...)
	cmd := exec.Command(gm.gitProg(), arg...)
	cmd.Env = append(os.Environ(), "LANG=C")
	cmd.Env = append(cmd.Env, gm.env()...)

	var bout, berr bytes.Buffer
	cmd.Stdout = &bout
	cmd.Stderr = &berr
	err := cmd.Run()
	return bout.String(), berr.String(), err
}

// PutFile put a file to repo
func (gm *GitMock) PutFile(file, content string) error {
	repo := gm.RepoPath()
	fpath := filepath.Join(repo, file)
	err := os.MkdirAll(filepath.Dir(fpath), 0755)
	if err != nil {
		return err
	}
	c := []byte(content)
	return ioutil.WriteFile(fpath, c, 0644)
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

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

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

Unless required by applicable law or agreedto 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 vtgate

import (
	"flag"
	"fmt"
	"net"
	"os"
	"sync"
	"syscall"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/mysql"
	"github.com/youtube/vitess/go/sqltypes"
	"github.com/youtube/vitess/go/vt/callerid"
	"github.com/youtube/vitess/go/vt/servenv"
	"github.com/youtube/vitess/go/vt/vttls"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
	vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)

var (
	mysqlServerPort               = flag.Int("mysql_server_port", -1, "If set, also listen for MySQL binary protocol connections on this port.")
	mysqlServerBindAddress        = flag.String("mysql_server_bind_address", "", "Binds on this address when listening to MySQL binary protocol. Useful to restrict listening to 'localhost' only for instance.")
	mysqlServerSocketPath         = flag.String("mysql_server_socket_path", "", "This option specifies the Unix socket file to use when listening for local connections. By default it will be empty and it won't listen to a unix socket")
	mysqlAuthServerImpl           = flag.String("mysql_auth_server_impl", "static", "Which auth server implementation to use.")
	mysqlAllowClearTextWithoutTLS = flag.Bool("mysql_allow_clear_text_without_tls", false, "If set, the server will allow the use of a clear text password over non-SSL connections.")

	mysqlSslCert = flag.String("mysql_server_ssl_cert", "", "Path to the ssl cert for mysql server plugin SSL")
	mysqlSslKey  = flag.String("mysql_server_ssl_key", "", "Path to ssl key for mysql server plugin SSL")
	mysqlSslCa   = flag.String("mysql_server_ssl_ca", "", "Path to ssl CA for mysql server plugin SSL. If specified, server will require and validate client certs.")

	mysqlSlowConnectWarnThreshold = flag.Duration("mysql_slow_connect_warn_threshold", 0, "Warn if it takes more than the given threshold for a mysql connection to establish")
)

// vtgateHandler implements the Listener interface.
// It stores the Session in the ClientData of a Connection, if a transaction
// is in progress.
type vtgateHandler struct {
	vtg *VTGate
}

func newVtgateHandler(vtg *VTGate) *vtgateHandler {
	return &vtgateHandler{
		vtg: vtg,
	}
}

func (vh *vtgateHandler) NewConnection(c *mysql.Conn) {
}

func (vh *vtgateHandler) ConnectionClosed(c *mysql.Conn) {
	// Rollback if there is an ongoing transaction. Ignore error.
	ctx := context.Background()
	session, _ := c.ClientData.(*vtgatepb.Session)
	if session != nil {
		_, _, _ = vh.vtg.Execute(ctx, session, "rollback", make(map[string]*querypb.BindVariable))
	}
}

func (vh *vtgateHandler) SafeToClose(c *mysql.Conn) bool {
	session, _ := c.ClientData.(*vtgatepb.Session)
	return session == nil
}

func (vh *vtgateHandler) ComQuery(c *mysql.Conn, query string, callback func(*sqltypes.Result) error) error {
	// FIXME(alainjobart): Add some kind of timeout to the context.
	ctx := context.Background()

	// Fill in the ImmediateCallerID with the UserData returned by
	// the AuthServer plugin for that user. If nothing was
	// returned, use the User. This lets the plugin map a MySQL
	// user used for authentication to a Vitess User used for
	// Table ACLs and Vitess authentication in general.
	im := c.UserData.Get()
	ef := callerid.NewEffectiveCallerID(
		c.User,                  /* principal: who */
		c.RemoteAddr().String(), /* component: running client process */
		"VTGate MySQL Connector" /* subcomponent: part of the client */)
	ctx = callerid.NewContext(ctx, ef, im)

	session, _ := c.ClientData.(*vtgatepb.Session)
	if session == nil {
		session = &vtgatepb.Session{
			Options: &querypb.ExecuteOptions{
				IncludedFields: querypb.ExecuteOptions_ALL,
			},
			Autocommit: true,
		}
		if c.Capabilities&mysql.CapabilityClientFoundRows != 0 {
			session.Options.ClientFoundRows = true
		}
	}
	if c.SchemaName != "" {
		session.TargetString = c.SchemaName
	}
	if session.Options.Workload == querypb.ExecuteOptions_OLAP {
		err := vh.vtg.StreamExecute(ctx, session, query, make(map[string]*querypb.BindVariable), callback)
		return mysql.NewSQLErrorFromError(err)
	}
	session, result, err := vh.vtg.Execute(ctx, session, query, make(map[string]*querypb.BindVariable))
	c.ClientData = session
	err = mysql.NewSQLErrorFromError(err)
	if err != nil {
		return err
	}
	return callback(result)
}

var mysqlListener *mysql.Listener
var mysqlUnixListener *mysql.Listener

// initiMySQLProtocol starts the mysql protocol.
// It should be called only once in a process.
func initMySQLProtocol() {
	// Flag is not set, just return.
	if *mysqlServerPort < 0 && *mysqlServerSocketPath == "" {
		return
	}

	// If no VTGate was created, just return.
	if rpcVTGate == nil {
		return
	}

	// Initialize registered AuthServer implementations (or other plugins)
	for _, initFn := range pluginInitializers {
		initFn()
	}
	authServer := mysql.GetAuthServer(*mysqlAuthServerImpl)

	// Create a Listener.
	var err error
	vh := newVtgateHandler(rpcVTGate)
	if *mysqlServerPort >= 0 {
		mysqlListener, err = mysql.NewListener("tcp", net.JoinHostPort(*mysqlServerBindAddress, fmt.Sprintf("%v", *mysqlServerPort)), authServer, vh)
		if err != nil {
			log.Exitf("mysql.NewListener failed: %v", err)
		}
		if *mysqlSslCert != "" && *mysqlSslKey != "" {
			mysqlListener.TLSConfig, err = vttls.ServerConfig(*mysqlSslCert, *mysqlSslKey, *mysqlSslCa)
			if err != nil {
				log.Exitf("grpcutils.TLSServerConfig failed: %v", err)
				return
			}
		}
		mysqlListener.AllowClearTextWithoutTLS = *mysqlAllowClearTextWithoutTLS

		// Check for the connection threshold
		if *mysqlSlowConnectWarnThreshold != 0 {
			log.Infof("setting mysql slow connection threshold to %v", mysqlSlowConnectWarnThreshold)
			mysqlListener.SlowConnectWarnThreshold = *mysqlSlowConnectWarnThreshold
		}
		// Start listening for tcp
		go mysqlListener.Accept()
	}

	if *mysqlServerSocketPath != "" {
		// Let's create this unix socket with permissions to all users. In this way,
		// clients can connect to vtgate mysql server without being vtgate user
		oldMask := syscall.Umask(000)
		mysqlUnixListener, err = newMysqlUnixSocket(*mysqlServerSocketPath, authServer, vh)
		_ = syscall.Umask(oldMask)
		if err != nil {
			log.Exitf("mysql.NewListener failed: %v", err)
			return
		}
		// Listen for unix socket
		go mysqlUnixListener.Accept()
	}
}

// newMysqlUnixSocket creates a new unix socket mysql listener. If a socket file already exists, attempts
// to clean it up.
func newMysqlUnixSocket(address string, authServer mysql.AuthServer, handler mysql.Handler) (*mysql.Listener, error) {
	listener, err := mysql.NewListener("unix", address, authServer, handler)
	switch err := err.(type) {
	case nil:
		return listener, nil
	case *net.OpError:
		log.Warningf("Found existent socket when trying to create new unix mysql listener: %s, attempting to clean up", address)
		// err.Op should never be different from listen, just being extra careful
		// in case in the future other errors are returned here
		if err.Op != "listen" {
			return nil, err
		}
		_, dialErr := net.Dial("unix", address)
		if dialErr == nil {
			log.Errorf("Existent socket '%s' is still accepting connections, aborting", address)
			return nil, err
		}
		removeFileErr := os.Remove(address)
		if removeFileErr != nil {
			log.Errorf("Couldn't remove existent socket file: %s", address)
			return nil, err
		}
		listener, listenerErr := mysql.NewListener("unix", address, authServer, handler)
		return listener, listenerErr
	default:
		return nil, err
	}
}

func init() {
	servenv.OnRun(initMySQLProtocol)

	servenv.OnTermSync(func() {
		wg := &sync.WaitGroup{}
		if mysqlListener != nil {
			drainListener(mysqlListener, wg)
		}
		if mysqlUnixListener != nil {
			drainListener(mysqlUnixListener, wg)
		}
		log.Info("Waiting for mysql connections to drain...")
		wg.Wait()
		log.Info("All mysql connections drained successfully!")
	})
}

func drainListener(l *mysql.Listener, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		l.Shutdown()
		l.WaitForConnections()
		l.Close()
		l = nil
		wg.Done()
	}()
}

var pluginInitializers []func()

// RegisterPluginInitializer lets plugins register themselves to be init'ed at servenv.OnRun-time
func RegisterPluginInitializer(initializer func()) {
	pluginInitializers = append(pluginInitializers, initializer)
}
<commit_msg>fix logic<commit_after>/*
Copyright 2017 Google Inc.

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

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

Unless required by applicable law or agreedto 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 vtgate

import (
	"flag"
	"fmt"
	"net"
	"os"
	"sync"
	"syscall"

	log "github.com/golang/glog"
	"golang.org/x/net/context"

	"github.com/youtube/vitess/go/mysql"
	"github.com/youtube/vitess/go/sqltypes"
	"github.com/youtube/vitess/go/vt/callerid"
	"github.com/youtube/vitess/go/vt/servenv"
	"github.com/youtube/vitess/go/vt/vttls"

	querypb "github.com/youtube/vitess/go/vt/proto/query"
	vtgatepb "github.com/youtube/vitess/go/vt/proto/vtgate"
)

var (
	mysqlServerPort               = flag.Int("mysql_server_port", -1, "If set, also listen for MySQL binary protocol connections on this port.")
	mysqlServerBindAddress        = flag.String("mysql_server_bind_address", "", "Binds on this address when listening to MySQL binary protocol. Useful to restrict listening to 'localhost' only for instance.")
	mysqlServerSocketPath         = flag.String("mysql_server_socket_path", "", "This option specifies the Unix socket file to use when listening for local connections. By default it will be empty and it won't listen to a unix socket")
	mysqlAuthServerImpl           = flag.String("mysql_auth_server_impl", "static", "Which auth server implementation to use.")
	mysqlAllowClearTextWithoutTLS = flag.Bool("mysql_allow_clear_text_without_tls", false, "If set, the server will allow the use of a clear text password over non-SSL connections.")

	mysqlSslCert = flag.String("mysql_server_ssl_cert", "", "Path to the ssl cert for mysql server plugin SSL")
	mysqlSslKey  = flag.String("mysql_server_ssl_key", "", "Path to ssl key for mysql server plugin SSL")
	mysqlSslCa   = flag.String("mysql_server_ssl_ca", "", "Path to ssl CA for mysql server plugin SSL. If specified, server will require and validate client certs.")

	mysqlSlowConnectWarnThreshold = flag.Duration("mysql_slow_connect_warn_threshold", 0, "Warn if it takes more than the given threshold for a mysql connection to establish")
)

// vtgateHandler implements the Listener interface.
// It stores the Session in the ClientData of a Connection, if a transaction
// is in progress.
type vtgateHandler struct {
	vtg *VTGate
}

func newVtgateHandler(vtg *VTGate) *vtgateHandler {
	return &vtgateHandler{
		vtg: vtg,
	}
}

func (vh *vtgateHandler) NewConnection(c *mysql.Conn) {
}

func (vh *vtgateHandler) ConnectionClosed(c *mysql.Conn) {
	// Rollback if there is an ongoing transaction. Ignore error.
	ctx := context.Background()
	session, _ := c.ClientData.(*vtgatepb.Session)
	if session != nil {
		_, _, _ = vh.vtg.Execute(ctx, session, "rollback", make(map[string]*querypb.BindVariable))
	}
}

func (vh *vtgateHandler) SafeToClose(c *mysql.Conn) bool {
	session, _ := c.ClientData.(*vtgatepb.Session)
	if session == nil {
		return true
	}
	return !session.InTransaction
}

func (vh *vtgateHandler) ComQuery(c *mysql.Conn, query string, callback func(*sqltypes.Result) error) error {
	// FIXME(alainjobart): Add some kind of timeout to the context.
	ctx := context.Background()

	// Fill in the ImmediateCallerID with the UserData returned by
	// the AuthServer plugin for that user. If nothing was
	// returned, use the User. This lets the plugin map a MySQL
	// user used for authentication to a Vitess User used for
	// Table ACLs and Vitess authentication in general.
	im := c.UserData.Get()
	ef := callerid.NewEffectiveCallerID(
		c.User,                  /* principal: who */
		c.RemoteAddr().String(), /* component: running client process */
		"VTGate MySQL Connector" /* subcomponent: part of the client */)
	ctx = callerid.NewContext(ctx, ef, im)

	session, _ := c.ClientData.(*vtgatepb.Session)
	if session == nil {
		session = &vtgatepb.Session{
			Options: &querypb.ExecuteOptions{
				IncludedFields: querypb.ExecuteOptions_ALL,
			},
			Autocommit: true,
		}
		if c.Capabilities&mysql.CapabilityClientFoundRows != 0 {
			session.Options.ClientFoundRows = true
		}
	}
	if c.SchemaName != "" {
		session.TargetString = c.SchemaName
	}
	if session.Options.Workload == querypb.ExecuteOptions_OLAP {
		err := vh.vtg.StreamExecute(ctx, session, query, make(map[string]*querypb.BindVariable), callback)
		return mysql.NewSQLErrorFromError(err)
	}
	session, result, err := vh.vtg.Execute(ctx, session, query, make(map[string]*querypb.BindVariable))
	c.ClientData = session
	err = mysql.NewSQLErrorFromError(err)
	if err != nil {
		return err
	}
	return callback(result)
}

var mysqlListener *mysql.Listener
var mysqlUnixListener *mysql.Listener

// initiMySQLProtocol starts the mysql protocol.
// It should be called only once in a process.
func initMySQLProtocol() {
	// Flag is not set, just return.
	if *mysqlServerPort < 0 && *mysqlServerSocketPath == "" {
		return
	}

	// If no VTGate was created, just return.
	if rpcVTGate == nil {
		return
	}

	// Initialize registered AuthServer implementations (or other plugins)
	for _, initFn := range pluginInitializers {
		initFn()
	}
	authServer := mysql.GetAuthServer(*mysqlAuthServerImpl)

	// Create a Listener.
	var err error
	vh := newVtgateHandler(rpcVTGate)
	if *mysqlServerPort >= 0 {
		mysqlListener, err = mysql.NewListener("tcp", net.JoinHostPort(*mysqlServerBindAddress, fmt.Sprintf("%v", *mysqlServerPort)), authServer, vh)
		if err != nil {
			log.Exitf("mysql.NewListener failed: %v", err)
		}
		if *mysqlSslCert != "" && *mysqlSslKey != "" {
			mysqlListener.TLSConfig, err = vttls.ServerConfig(*mysqlSslCert, *mysqlSslKey, *mysqlSslCa)
			if err != nil {
				log.Exitf("grpcutils.TLSServerConfig failed: %v", err)
				return
			}
		}
		mysqlListener.AllowClearTextWithoutTLS = *mysqlAllowClearTextWithoutTLS

		// Check for the connection threshold
		if *mysqlSlowConnectWarnThreshold != 0 {
			log.Infof("setting mysql slow connection threshold to %v", mysqlSlowConnectWarnThreshold)
			mysqlListener.SlowConnectWarnThreshold = *mysqlSlowConnectWarnThreshold
		}
		// Start listening for tcp
		go mysqlListener.Accept()
	}

	if *mysqlServerSocketPath != "" {
		// Let's create this unix socket with permissions to all users. In this way,
		// clients can connect to vtgate mysql server without being vtgate user
		oldMask := syscall.Umask(000)
		mysqlUnixListener, err = newMysqlUnixSocket(*mysqlServerSocketPath, authServer, vh)
		_ = syscall.Umask(oldMask)
		if err != nil {
			log.Exitf("mysql.NewListener failed: %v", err)
			return
		}
		// Listen for unix socket
		go mysqlUnixListener.Accept()
	}
}

// newMysqlUnixSocket creates a new unix socket mysql listener. If a socket file already exists, attempts
// to clean it up.
func newMysqlUnixSocket(address string, authServer mysql.AuthServer, handler mysql.Handler) (*mysql.Listener, error) {
	listener, err := mysql.NewListener("unix", address, authServer, handler)
	switch err := err.(type) {
	case nil:
		return listener, nil
	case *net.OpError:
		log.Warningf("Found existent socket when trying to create new unix mysql listener: %s, attempting to clean up", address)
		// err.Op should never be different from listen, just being extra careful
		// in case in the future other errors are returned here
		if err.Op != "listen" {
			return nil, err
		}
		_, dialErr := net.Dial("unix", address)
		if dialErr == nil {
			log.Errorf("Existent socket '%s' is still accepting connections, aborting", address)
			return nil, err
		}
		removeFileErr := os.Remove(address)
		if removeFileErr != nil {
			log.Errorf("Couldn't remove existent socket file: %s", address)
			return nil, err
		}
		listener, listenerErr := mysql.NewListener("unix", address, authServer, handler)
		return listener, listenerErr
	default:
		return nil, err
	}
}

func init() {
	servenv.OnRun(initMySQLProtocol)

	servenv.OnTermSync(func() {
		wg := &sync.WaitGroup{}
		if mysqlListener != nil {
			drainListener(mysqlListener, wg)
		}
		if mysqlUnixListener != nil {
			drainListener(mysqlUnixListener, wg)
		}
		log.Info("Waiting for mysql connections to drain...")
		wg.Wait()
		log.Info("All mysql connections drained successfully!")
	})
}

func drainListener(l *mysql.Listener, wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		l.Shutdown()
		l.WaitForConnections()
		l.Close()
		l = nil
		wg.Done()
	}()
}

var pluginInitializers []func()

// RegisterPluginInitializer lets plugins register themselves to be init'ed at servenv.OnRun-time
func RegisterPluginInitializer(initializer func()) {
	pluginInitializers = append(pluginInitializers, initializer)
}
<|endoftext|>


<commit_before>package slack

import (
	"fmt"
	"log"

	slack_webhook "github.com/ashwanthkumar/slack-go-webhook"
	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

type Slack struct {
}

func init() {
	agent.RegisterPlugin("slack", func() agent.Plugin {
		return &Slack{}
	})
}

func (x *Slack) Description() string {
	return "Send slack events to subscribed plugins"
}

func (x *Slack) SampleConfig() string {
	return ` `
}

func (x *Slack) slack() error {
	return nil
}

func (x *Slack) Start(e chan agent.Event) error {
	go x.slack()
	log.Println("Started Slack")

	return nil
}

func (x *Slack) Stop() {
	log.Println("Stopping Slack")
}

func (x *Slack) Subscribe() []string {
	return []string{
		"plugins.DockerBuild",
		"plugins.DockerDeploy",
		"plugins.Project",
		"plugins.Release",
	}
}

func (x *Slack) Process(e agent.Event) error {
	webhookUrl := viper.GetString("plugins.slack.webhook_url")

	switch e.Name {
	case "plugins.DockerDeploy:create":
		payload := e.Payload.(plugins.DockerDeploy)

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash
			message := payload.Release.HeadFeature.Message

			repository := payload.Project.Repository
			tail := payload.Release.TailFeature.Hash
			head := payload.Release.HeadFeature.Hash

			diffUrl := fmt.Sprintf("https://github.com/%s/compare/%s...%s", repository, tail, head)

			attachment1 := slack_webhook.Attachment{}
			attachment1.AddField(slack_webhook.Field{Title: "Commit", Value: message}).AddField(slack_webhook.Field{Title: "Link", Value: diffUrl})

			slackPayload := slack_webhook.Payload{
				Text:        fmt.Sprintf("Deploying %s for %s", release, project),
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	case "plugins.DockerDeploy:status":
		payload := e.Payload.(plugins.DockerDeploy)

		if payload.State != plugins.Complete && payload.State != plugins.Failed {
			return nil
		}

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash

			msg := fmt.Sprintf("Deploy %s for %s", release, project)
			color := "#008000"

			if payload.State == plugins.Failed {
				color = "#FF0000"
				msg = fmt.Sprintf("Deploy %s for %s", release, project)
			}

			attachment1 := slack_webhook.Attachment{Color: &color}
			attachment1.AddField(slack_webhook.Field{Title: "Status", Value: string(payload.State)})

			slackPayload := slack_webhook.Payload{
				Text:        msg,
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	}

	return nil
}
<commit_msg>Change Slack messages format<commit_after>package slack

import (
	"fmt"
	"log"

	slack_webhook "github.com/ashwanthkumar/slack-go-webhook"
	"github.com/checkr/codeflow/server/agent"
	"github.com/checkr/codeflow/server/plugins"
	"github.com/spf13/viper"
)

type Slack struct {
}

func init() {
	agent.RegisterPlugin("slack", func() agent.Plugin {
		return &Slack{}
	})
}

func (x *Slack) Description() string {
	return "Send slack events to subscribed plugins"
}

func (x *Slack) SampleConfig() string {
	return ` `
}

func (x *Slack) slack() error {
	return nil
}

func (x *Slack) Start(e chan agent.Event) error {
	go x.slack()
	log.Println("Started Slack")

	return nil
}

func (x *Slack) Stop() {
	log.Println("Stopping Slack")
}

func (x *Slack) Subscribe() []string {
	return []string{
		"plugins.DockerBuild",
		"plugins.DockerDeploy",
		"plugins.Project",
		"plugins.Release",
	}
}

func (x *Slack) Process(e agent.Event) error {
	webhookUrl := viper.GetString("plugins.slack.webhook_url")

	switch e.Name {
	case "plugins.DockerDeploy:create":
		payload := e.Payload.(plugins.DockerDeploy)

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash
			message := payload.Release.HeadFeature.Message
			author  := payload.Release.HeadFeature.User

			repository := payload.Project.Repository
			tail := payload.Release.TailFeature.Hash
			head := payload.Release.HeadFeature.Hash

			msg := fmt.Sprintf(
				"%s: [%s](https://github.com/%s) is deploying [%s](https://github.com/%s/compare/%s...%s)",
				project, author, author,
				message, repository, tail, head,
			)

			slackPayload := slack_webhook.Payload{
				Text:        msg,
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	case "plugins.DockerDeploy:status":
		payload := e.Payload.(plugins.DockerDeploy)

		if payload.State != plugins.Complete && payload.State != plugins.Failed {
			return nil
		}

		for _, channel := range payload.Project.NotifyChannels {
			project := payload.Project.Slug
			release := payload.Release.HeadFeature.Hash

			var msg, color string

			if payload.State == plugins.Failed {
				color = "#FF0000"
				msg = fmt.Sprintf("Deploying %s:%s failed", project, release)
			} else {
				msg = fmt.Sprintf("%s:%s went live", project, release)
				color = "#008000"
			}

			attachment1 := slack_webhook.Attachment{Color: &color, Text: &msg}

			slackPayload := slack_webhook.Payload{
				Username:    "codeflow-bot",
				Channel:     channel,
				IconEmoji:   ":rocket:",
				Attachments: []slack_webhook.Attachment{attachment1},
			}
			err := slack_webhook.Send(webhookUrl, "", slackPayload)
			if len(err) > 0 {
				log.Println("error: %s\n", err)
			}
		}
	}

	return nil
}
<|endoftext|>