<commit_before>// Copyright 2018 The LUCI 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 main

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"unicode"

	"cloud.google.com/go/bigquery"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"

	"github.com/pmezard/go-difflib/difflib"

	"go.chromium.org/luci/common/data/text/indented"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/proto/google/descutil"
)

// sourceCodeInfoMap maps descriptor proto messages to source code info,
// if available.
// See also descutil.IndexSourceCodeInfo.
type sourceCodeInfoMap map[interface{}]*descriptor.SourceCodeInfo_Location

type schemaConverter struct {
	desc           *descriptor.FileDescriptorSet
	sourceCodeInfo map[*descriptor.FileDescriptorProto]sourceCodeInfoMap
}

// schema constructs a bigquery.Schema from a named message.
func (c *schemaConverter) schema(messageName string) (schema bigquery.Schema, description string, err error) {
	file, obj, _ := descutil.Resolve(c.desc, messageName)
	if obj == nil {
		return nil, "", fmt.Errorf("message %q is not found", messageName)
	}
	msg, isMsg := obj.(*descriptor.DescriptorProto)
	if !isMsg {
		return nil, "", fmt.Errorf("expected %q to be a message, but it is %T", messageName, obj)
	}

	schema = make(bigquery.Schema, 0, len(msg.Field))
	for _, field := range msg.Field {
		switch s, err := c.field(file, field); {
		case err != nil:
			return nil, "", errors.Annotate(err, "failed to derive schema for field %q in message %q", field.Name, msg.Name).Err()
		case s != nil:
			schema = append(schema, s)
		}
	}
	return schema, c.description(file, msg), nil
}

// field constructs bigquery.FieldSchema from proto field descriptor.
func (c *schemaConverter) field(file *descriptor.FileDescriptorProto, field *descriptor.FieldDescriptorProto) (*bigquery.FieldSchema, error) {
	schema := &bigquery.FieldSchema{
		Name:        field.GetName(),
		Description: c.description(file, field),
		Repeated:    descutil.Repeated(field),
		Required:    descutil.Required(field),
	}

	typeName := strings.TrimPrefix(field.GetTypeName(), ".")
	switch field.GetType() {
	case
		descriptor.FieldDescriptorProto_TYPE_DOUBLE,
		descriptor.FieldDescriptorProto_TYPE_FLOAT:

		schema.Type = bigquery.FloatFieldType

	case
		descriptor.FieldDescriptorProto_TYPE_INT64,
		descriptor.FieldDescriptorProto_TYPE_UINT64,
		descriptor.FieldDescriptorProto_TYPE_INT32,
		descriptor.FieldDescriptorProto_TYPE_FIXED64,
		descriptor.FieldDescriptorProto_TYPE_FIXED32,
		descriptor.FieldDescriptorProto_TYPE_UINT32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED64,
		descriptor.FieldDescriptorProto_TYPE_SINT32,
		descriptor.FieldDescriptorProto_TYPE_SINT64:

		schema.Type = bigquery.IntegerFieldType

	case descriptor.FieldDescriptorProto_TYPE_BOOL:
		schema.Type = bigquery.BooleanFieldType

	case descriptor.FieldDescriptorProto_TYPE_STRING:
		schema.Type = bigquery.StringFieldType

	case descriptor.FieldDescriptorProto_TYPE_BYTES:
		schema.Type = bigquery.BytesFieldType

	case descriptor.FieldDescriptorProto_TYPE_ENUM:
		schema.Type = bigquery.StringFieldType

	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
		switch typeName {
		case "google.protobuf.Timestamp":
			schema.Type = bigquery.TimestampFieldType
		case "google.protobuf.Struct":
			// google.protobuf.Struct is persisted as JSONPB string.
			// See also https://bit.ly/chromium-bq-struct
			schema.Type = bigquery.StringFieldType
		default:
			switch s, _, err := c.schema(typeName); {
			case err != nil:
				return nil, err
			case len(s) == 0:
				// BigQuery does not like empty record fields.
				return nil, nil
			default:
				schema.Type = bigquery.RecordFieldType
				schema.Schema = s
			}
		}
	default:
		return nil, fmt.Errorf("not supported field type %q", field.GetType())
	}
	return schema, nil
}

// description returns a string description of the descriptor proto that
// ptr points to.
// If ptr is a field of an enum type, appends
// "\nValid values: <comma-separated enum member names>".
func (c *schemaConverter) description(file *descriptor.FileDescriptorProto, ptr interface{}) string {
	description := c.sourceCodeInfo[file][ptr].GetLeadingComments()

	// Trim leading whitespace.
	lines := strings.Split(description, "\n")
	trimSize := -1
	for _, l := range lines {
		if len(strings.TrimSpace(l)) == 0 {
			// skip empty lines
			continue
		}
		space := 0
		for _, r := range l {
			if unicode.IsSpace(r) {
				space++
			} else {
				break
			}
		}
		if trimSize == -1 || space < trimSize {
			trimSize = space
		}
	}
	if trimSize > 0 {
		for i := range lines {
			if len(lines[i]) >= trimSize {
				lines[i] = lines[i][trimSize:]
			}
		}
		description = strings.Join(lines, "\n")
	}
	description = strings.TrimSpace(description)

	// Append valid enum values.
	if field, ok := ptr.(*descriptor.FieldDescriptorProto); ok && field.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM {
		_, obj, _ := descutil.Resolve(c.desc, strings.TrimPrefix(field.GetTypeName(), "."))
		if enum, ok := obj.(*descriptor.EnumDescriptorProto); ok {
			names := make([]string, len(enum.Value))
			for i, v := range enum.Value {
				names[i] = v.GetName()
			}
			if description != "" {
				description += "\n"
			}
			description += fmt.Sprintf("Valid values: %s.", strings.Join(names, ", "))
		}
	}
	return description
}

func printSchema(w *indented.Writer, s bigquery.Schema) {
	// Field order does not matter.
	// A new field is always added to the end of the field list in a live table.
	// Sort fields by name to make the result deterministic.
	// Schema diffing relies on it.

	s = append(bigquery.Schema(nil), s...)
	sort.Slice(s, func(i, j int) bool {
		return s[i].Name < s[j].Name
	})

	for i, f := range s {
		if i > 0 {
			fmt.Fprintln(w)
		}

		if f.Description != "" {
			for _, line := range strings.Split(f.Description, "\n") {
				fmt.Fprintln(w, "//", line)
			}
		}

		switch {
		case f.Repeated:
			fmt.Fprint(w, "repeated ")
		case f.Required:
			fmt.Fprint(w, "required ")
		}

		fmt.Fprint(w, f.Type, f.Name)

		if f.Type == bigquery.RecordFieldType {
			fmt.Fprintln(w, " {")
			w.Level++
			printSchema(w, f.Schema)
			w.Level--
			fmt.Fprint(w, "}")
		}

		fmt.Fprintln(w)
	}
}

func schemaString(s bigquery.Schema) string {
	var buf bytes.Buffer
	printSchema(&indented.Writer{Writer: &buf}, s)
	return buf.String()
}

// schemaDiff returns unified diff of two schemas.
// Returns "" if there is no difference.
func schemaDiff(before, after bigquery.Schema) string {
	ret, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
		A:        difflib.SplitLines(schemaString(before)),
		B:        difflib.SplitLines(schemaString(after)),
		FromFile: "Current",
		ToFile:   "New",
		Context:  3,
		Eol:      "\n",
	})
	if err != nil {
		// GetUnifiedDiffString returns an error only if it fails
		// to write to a bytes.Buffer, which either cannot happen or we better
		// panic.
		panic(err)
	}
	return ret
}
<commit_msg>[bqschemaupdater] insert spaces between type and name<commit_after>// Copyright 2018 The LUCI 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 main

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"unicode"

	"cloud.google.com/go/bigquery"
	"github.com/golang/protobuf/protoc-gen-go/descriptor"

	"github.com/pmezard/go-difflib/difflib"

	"go.chromium.org/luci/common/data/text/indented"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/proto/google/descutil"
)

// sourceCodeInfoMap maps descriptor proto messages to source code info,
// if available.
// See also descutil.IndexSourceCodeInfo.
type sourceCodeInfoMap map[interface{}]*descriptor.SourceCodeInfo_Location

type schemaConverter struct {
	desc           *descriptor.FileDescriptorSet
	sourceCodeInfo map[*descriptor.FileDescriptorProto]sourceCodeInfoMap
}

// schema constructs a bigquery.Schema from a named message.
func (c *schemaConverter) schema(messageName string) (schema bigquery.Schema, description string, err error) {
	file, obj, _ := descutil.Resolve(c.desc, messageName)
	if obj == nil {
		return nil, "", fmt.Errorf("message %q is not found", messageName)
	}
	msg, isMsg := obj.(*descriptor.DescriptorProto)
	if !isMsg {
		return nil, "", fmt.Errorf("expected %q to be a message, but it is %T", messageName, obj)
	}

	schema = make(bigquery.Schema, 0, len(msg.Field))
	for _, field := range msg.Field {
		switch s, err := c.field(file, field); {
		case err != nil:
			return nil, "", errors.Annotate(err, "failed to derive schema for field %q in message %q", field.Name, msg.Name).Err()
		case s != nil:
			schema = append(schema, s)
		}
	}
	return schema, c.description(file, msg), nil
}

// field constructs bigquery.FieldSchema from proto field descriptor.
func (c *schemaConverter) field(file *descriptor.FileDescriptorProto, field *descriptor.FieldDescriptorProto) (*bigquery.FieldSchema, error) {
	schema := &bigquery.FieldSchema{
		Name:        field.GetName(),
		Description: c.description(file, field),
		Repeated:    descutil.Repeated(field),
		Required:    descutil.Required(field),
	}

	typeName := strings.TrimPrefix(field.GetTypeName(), ".")
	switch field.GetType() {
	case
		descriptor.FieldDescriptorProto_TYPE_DOUBLE,
		descriptor.FieldDescriptorProto_TYPE_FLOAT:

		schema.Type = bigquery.FloatFieldType

	case
		descriptor.FieldDescriptorProto_TYPE_INT64,
		descriptor.FieldDescriptorProto_TYPE_UINT64,
		descriptor.FieldDescriptorProto_TYPE_INT32,
		descriptor.FieldDescriptorProto_TYPE_FIXED64,
		descriptor.FieldDescriptorProto_TYPE_FIXED32,
		descriptor.FieldDescriptorProto_TYPE_UINT32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED32,
		descriptor.FieldDescriptorProto_TYPE_SFIXED64,
		descriptor.FieldDescriptorProto_TYPE_SINT32,
		descriptor.FieldDescriptorProto_TYPE_SINT64:

		schema.Type = bigquery.IntegerFieldType

	case descriptor.FieldDescriptorProto_TYPE_BOOL:
		schema.Type = bigquery.BooleanFieldType

	case descriptor.FieldDescriptorProto_TYPE_STRING:
		schema.Type = bigquery.StringFieldType

	case descriptor.FieldDescriptorProto_TYPE_BYTES:
		schema.Type = bigquery.BytesFieldType

	case descriptor.FieldDescriptorProto_TYPE_ENUM:
		schema.Type = bigquery.StringFieldType

	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
		switch typeName {
		case "google.protobuf.Timestamp":
			schema.Type = bigquery.TimestampFieldType
		case "google.protobuf.Struct":
			// google.protobuf.Struct is persisted as JSONPB string.
			// See also https://bit.ly/chromium-bq-struct
			schema.Type = bigquery.StringFieldType
		default:
			switch s, _, err := c.schema(typeName); {
			case err != nil:
				return nil, err
			case len(s) == 0:
				// BigQuery does not like empty record fields.
				return nil, nil
			default:
				schema.Type = bigquery.RecordFieldType
				schema.Schema = s
			}
		}
	default:
		return nil, fmt.Errorf("not supported field type %q", field.GetType())
	}
	return schema, nil
}

// description returns a string description of the descriptor proto that
// ptr points to.
// If ptr is a field of an enum type, appends
// "\nValid values: <comma-separated enum member names>".
func (c *schemaConverter) description(file *descriptor.FileDescriptorProto, ptr interface{}) string {
	description := c.sourceCodeInfo[file][ptr].GetLeadingComments()

	// Trim leading whitespace.
	lines := strings.Split(description, "\n")
	trimSize := -1
	for _, l := range lines {
		if len(strings.TrimSpace(l)) == 0 {
			// skip empty lines
			continue
		}
		space := 0
		for _, r := range l {
			if unicode.IsSpace(r) {
				space++
			} else {
				break
			}
		}
		if trimSize == -1 || space < trimSize {
			trimSize = space
		}
	}
	if trimSize > 0 {
		for i := range lines {
			if len(lines[i]) >= trimSize {
				lines[i] = lines[i][trimSize:]
			}
		}
		description = strings.Join(lines, "\n")
	}
	description = strings.TrimSpace(description)

	// Append valid enum values.
	if field, ok := ptr.(*descriptor.FieldDescriptorProto); ok && field.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM {
		_, obj, _ := descutil.Resolve(c.desc, strings.TrimPrefix(field.GetTypeName(), "."))
		if enum, ok := obj.(*descriptor.EnumDescriptorProto); ok {
			names := make([]string, len(enum.Value))
			for i, v := range enum.Value {
				names[i] = v.GetName()
			}
			if description != "" {
				description += "\n"
			}
			description += fmt.Sprintf("Valid values: %s.", strings.Join(names, ", "))
		}
	}
	return description
}

func printSchema(w *indented.Writer, s bigquery.Schema) {
	// Field order does not matter.
	// A new field is always added to the end of the field list in a live table.
	// Sort fields by name to make the result deterministic.
	// Schema diffing relies on it.

	s = append(bigquery.Schema(nil), s...)
	sort.Slice(s, func(i, j int) bool {
		return s[i].Name < s[j].Name
	})

	for i, f := range s {
		if i > 0 {
			fmt.Fprintln(w)
		}

		if f.Description != "" {
			for _, line := range strings.Split(f.Description, "\n") {
				fmt.Fprintln(w, "//", line)
			}
		}

		switch {
		case f.Repeated:
			fmt.Fprint(w, "repeated ")
		case f.Required:
			fmt.Fprint(w, "required ")
		}

		fmt.Fprintf(w, "%s %s", f.Type, f.Name)

		if f.Type == bigquery.RecordFieldType {
			fmt.Fprintln(w, " {")
			w.Level++
			printSchema(w, f.Schema)
			w.Level--
			fmt.Fprint(w, "}")
		}

		fmt.Fprintln(w)
	}
}

func schemaString(s bigquery.Schema) string {
	var buf bytes.Buffer
	printSchema(&indented.Writer{Writer: &buf}, s)
	return buf.String()
}

// schemaDiff returns unified diff of two schemas.
// Returns "" if there is no difference.
func schemaDiff(before, after bigquery.Schema) string {
	ret, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
		A:        difflib.SplitLines(schemaString(before)),
		B:        difflib.SplitLines(schemaString(after)),
		FromFile: "Current",
		ToFile:   "New",
		Context:  3,
		Eol:      "\n",
	})
	if err != nil {
		// GetUnifiedDiffString returns an error only if it fails
		// to write to a bytes.Buffer, which either cannot happen or we better
		// panic.
		panic(err)
	}
	return ret
}
<|endoftext|>


<commit_before>package pubsub

type server struct{}
<commit_msg>add first pubsub<commit_after>package pubsub

import (
	ppubsub "github.com/real-nil/grpc-pubsub/proto/pubsub"
	"golang.org/x/net/context"
	"google.golang.org/grpc/grpclog"
	"sync"
)

type Sender interface {
	Send(*ppubsub.Data) error
}

type server struct {
	lockForPubsuber *sync.RWMutex
	pubsubClinet    map[string][]Sender
}

func New() *server {
	return &server{
		lockForPubsuber: &sync.RWMutex{},
		pubsubClinet:    make(map[string][]Sender, 0),
	}
}

/*
        Subscribe(*Topic, PubSub_SubscribeServer) error
	Publish(context.Context, *Data) (*Answer, error)
*/

func (s *server) Subscribe(top *ppubsub.Topic, stream ppubsub.PubSub_SubscribeServer) error {
	grpclog.Printf("start subscribe for topic %s", top.Name)
	//c := stream.Context()
	s.lockForPubsuber.Lock()
	s.pubsubClinet[top.Name] = append(s.pubsubClinet[top.Name], stream)
	s.lockForPubsuber.Unlock()
	// check context, return error if Done
	//stream, err := client.New(context.Background())
	//if err := nil{
	//	grpclog.Printf("incorrect create stream %s", stream)
	//	return errors.New("ololo")
	//}

	return nil
}

func (s *server) Publish(ctx *context.Context, data *ppubsub.Data) (*ppubsub.Answer, error) {
	var (
		senders []Sender
		ok      bool
	)
	s.lockForPubsuber.RLock()
	senders, ok = s.pubsubClinet[data.Topic]
	s.lockForPubsuber.RUnlock()

	if !ok {
		// OR send error return nil, errors.New()
		return &ppubsub.Answer{Subsriptions: 0}, nil
	}

	var c int32
	c = int32(len(senders))

	for _, stream := range senders {
		err := stream.Send(data)
		if err != nil {
			grpclog.Printf("incorrect streamt")
			c--
		}
	}

	return &ppubsub.Answer{Subsriptions: c}, nil
}
<|endoftext|>


<commit_before>package influxdb

import (
	"sync"
	"time"

	"github.com/funkygao/gafka/cmd/kguard/monitor"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/go-metrics"
	log "github.com/funkygao/log4go"
	"github.com/influxdata/influxdb/client/v2"
)

func init() {
	monitor.RegisterWatcher("influxdb.server", func() monitor.Watcher {
		return &WatchInfluxServer{
			Tick: time.Minute,
		}
	})
}

// WatchInfluxServer continuously pings influxdb server.
type WatchInfluxServer struct {
	Zkzone *zk.ZkZone
	Stop   <-chan struct{}
	Tick   time.Duration
	Wg     *sync.WaitGroup

	addr string
	cli  client.Client
}

func (this *WatchInfluxServer) Init(ctx monitor.Context) {
	this.Zkzone = ctx.ZkZone()
	this.Stop = ctx.StopChan()
	this.Wg = ctx.Inflight()
	this.addr = ctx.InfluxAddr()
}

func (this *WatchInfluxServer) Run() {
	defer this.Wg.Done()

	if this.addr == "" {
		log.Warn("empty influxdb server addr, quit...")
		return
	}

	ticker := time.NewTicker(this.Tick)
	defer ticker.Stop()

	var (
		err                 error
		influxdbServerAlive = metrics.NewRegisteredGauge("influxdb.alive", nil)
	)

	for {
		select {
		case <-this.Stop:
			log.Info("influx.server stopped")
			return

		case <-ticker.C:
			if this.cli == nil {
				this.cli, err = client.NewHTTPClient(client.HTTPConfig{
					Addr:     this.addr,
					Username: "",
					Password: "",
				})
				if err != nil {
					log.Error("influxdb.server: %v", err)
					influxdbServerAlive.Update(0)
					continue
				}
				if this.cli == nil {
					log.Error("influxdb.server connected got nil cli")
					influxdbServerAlive.Update(0)
					continue
				}
			}

			_, _, err = this.cli.Ping(time.Second * 4)
			if err != nil {
				log.Error("influxdb.server: %v", err)
				influxdbServerAlive.Update(0)
			} else {
				influxdbServerAlive.Update(1)
			}

		}
	}
}
<commit_msg>warmup<commit_after>package influxdb

import (
	"sync"
	"time"

	"github.com/funkygao/gafka/cmd/kguard/monitor"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/go-metrics"
	log "github.com/funkygao/log4go"
	"github.com/influxdata/influxdb/client/v2"
)

func init() {
	monitor.RegisterWatcher("influxdb.server", func() monitor.Watcher {
		return &WatchInfluxServer{
			Tick: time.Minute,
		}
	})
}

// WatchInfluxServer continuously pings influxdb server.
type WatchInfluxServer struct {
	Zkzone *zk.ZkZone
	Stop   <-chan struct{}
	Tick   time.Duration
	Wg     *sync.WaitGroup

	addr string
	cli  client.Client

	influxdbServerAlive metrics.Gauge
}

func (this *WatchInfluxServer) Init(ctx monitor.Context) {
	this.Zkzone = ctx.ZkZone()
	this.Stop = ctx.StopChan()
	this.Wg = ctx.Inflight()
	this.addr = ctx.InfluxAddr()

	// warmup
	if this.addr != "" {
		this.influxdbServerAlive = metrics.NewRegisteredGauge("influxdb.alive", nil)
		this.influxdbServerAlive.Update(int64(this.aliveInstances()))
	}

}

func (this *WatchInfluxServer) Run() {
	defer this.Wg.Done()

	if this.addr == "" {
		log.Warn("empty influxdb server addr, quit...")
		return
	}

	ticker := time.NewTicker(this.Tick)
	defer ticker.Stop()

	for {
		select {
		case <-this.Stop:
			log.Info("influx.server stopped")
			return

		case <-ticker.C:
			this.influxdbServerAlive.Update(int64(this.aliveInstances()))

		}
	}
}

func (this *WatchInfluxServer) aliveInstances() int {
	var err error
	if this.cli == nil {
		this.cli, err = client.NewHTTPClient(client.HTTPConfig{
			Addr:     this.addr,
			Username: "",
			Password: "",
		})
		if err != nil {
			log.Error("influxdb.server: %v", err)
			return 0
		}
		if this.cli == nil {
			log.Error("influxdb.server connected got nil cli")
			return 0
		}
	}

	_, _, err = this.cli.Ping(time.Second * 4)
	if err != nil {
		log.Error("influxdb.server: %v", err)
		return 0
	}

	return 1 // TODO what if multiple influxdb instances?
}
<|endoftext|>


<commit_before>package lib_test

import (
	"os"
	"testing"

	"github.com/masutaka/github-nippou/lib"
)

func TestInit(t *testing.T) {
	t.Skip("This test is pending.")
}

func TestGetUser(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_USER", "taro")

	actual, _ := lib.GetUser()
	const expected = "taro"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}

	os.Setenv("GITHUB_NIPPOU_USER", "")
}

func TestGetAccessToken(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_ACCESS_TOKEN", "1234abcd")

	actual, _ := lib.GetAccessToken()
	const expected = "1234abcd"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}

	os.Setenv("GITHUB_NIPPOU_ACCESS_TOKEN", "")
}

func TestGetGistID(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_SETTINGS_GIST_ID", "0123456789")

	actual := lib.GetGistID()
	const expected = "0123456789"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}

	os.Setenv("GITHUB_NIPPOU_SETTINGS_GIST_ID", "")
}

func TestGetParallelNum(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_THREAD_NUM", "10")

	actual, _ := lib.GetParallelNum()
	const expected = 10
	if actual != expected {
		t.Errorf("expected %d but got %d", expected, actual)
	}

	os.Setenv("GITHUB_NIPPOU_THREAD_NUM", "")
}

func TestGetDefaultSettingsURL(t *testing.T) {
	actual := lib.GetDefaultSettingsURL()
	const expected = "https://github.com/masutaka/github-nippou/blob/v" + lib.Version + "/config/settings.yml"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}
}

func TestGetDefaultSettingsYml(t *testing.T) {
	t.Skip("This test is pending.")
}
<commit_msg>Refactor test<commit_after>package lib_test

import (
	"os"
	"testing"

	"github.com/masutaka/github-nippou/lib"
)

func TestInit(t *testing.T) {
	t.Skip("This test is pending.")
}

func TestGetUser(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_USER", "taro")
	defer os.Unsetenv("GITHUB_NIPPOU_USER")

	actual, _ := lib.GetUser()
	const expected = "taro"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}
}

func TestGetAccessToken(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_ACCESS_TOKEN", "1234abcd")
	defer os.Unsetenv("GITHUB_NIPPOU_ACCESS_TOKEN")

	actual, _ := lib.GetAccessToken()
	const expected = "1234abcd"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}
}

func TestGetGistID(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_SETTINGS_GIST_ID", "0123456789")
	defer os.Unsetenv("GITHUB_NIPPOU_SETTINGS_GIST_ID")

	actual := lib.GetGistID()
	const expected = "0123456789"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}
}

func TestGetParallelNum(t *testing.T) {
	os.Setenv("GITHUB_NIPPOU_THREAD_NUM", "10")
	defer os.Unsetenv("GITHUB_NIPPOU_THREAD_NUM")

	actual, _ := lib.GetParallelNum()
	const expected = 10
	if actual != expected {
		t.Errorf("expected %d but got %d", expected, actual)
	}
}

func TestGetDefaultSettingsURL(t *testing.T) {
	actual := lib.GetDefaultSettingsURL()
	const expected = "https://github.com/masutaka/github-nippou/blob/v" + lib.Version + "/config/settings.yml"
	if actual != expected {
		t.Errorf("expected %s but got %s", expected, actual)
	}
}

func TestGetDefaultSettingsYml(t *testing.T) {
	t.Skip("This test is pending.")
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2017 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 main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"

	"github.com/hyperledger/fabric/bccsp/factory"
	"github.com/hyperledger/fabric/common/config"
	mspconfig "github.com/hyperledger/fabric/common/config/msp"
	"github.com/hyperledger/fabric/common/configtx"
	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
	"github.com/hyperledger/fabric/common/flogging"
	cb "github.com/hyperledger/fabric/protos/common"
	pb "github.com/hyperledger/fabric/protos/peer"
	"github.com/hyperledger/fabric/protos/utils"

	"github.com/golang/protobuf/proto"
	mmsp "github.com/hyperledger/fabric/common/mocks/msp"
	logging "github.com/op/go-logging"
)

var logger = flogging.MustGetLogger("common/configtx/tool")

func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error {
	pgen := provisional.New(config)
	logger.Info("Generating genesis block")
	if config.Orderer == nil {
		return fmt.Errorf("config does not contain an Orderers section, necessary for all config blocks, aborting")
	}
	if config.Consortiums == nil {
		logger.Warning("Genesis block does not contain a consortiums group definition.  This block cannot be used for orderer bootstrap.")
	}
	genesisBlock := pgen.GenesisBlockForChannel(channelID)
	logger.Info("Writing genesis block")
	err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644)
	if err != nil {
		return fmt.Errorf("Error writing genesis block: %s", err)
	}
	return nil
}

func doOutputChannelCreateTx(conf *genesisconfig.Profile, channelID string, outputChannelCreateTx string) error {
	logger.Info("Generating new channel configtx")
	// TODO, use actual MSP eventually
	signer, err := mmsp.NewNoopMsp().GetDefaultSigningIdentity()
	if err != nil {
		return fmt.Errorf("Error getting signing identity: %s", err)
	}

	if conf.Application == nil {
		return fmt.Errorf("Cannot define a new channel with no Application section")
	}

	if conf.Consortium == "" {
		return fmt.Errorf("Cannot define a new channel with no Consortium section")
	}

	// XXX we ignore the non-application org names here, once the tool supports configuration updates
	// we should come up with a cleaner way to handle this, but leaving as is for the moment to not break
	// backwards compatibility
	var orgNames []string
	for _, org := range conf.Application.Organizations {
		orgNames = append(orgNames, org.Name)
	}
	configtx, err := configtx.MakeChainCreationTransaction(channelID, conf.Consortium, signer, orgNames...)
	if err != nil {
		return fmt.Errorf("Error generating configtx: %s", err)
	}
	logger.Info("Writing new channel tx")
	err = ioutil.WriteFile(outputChannelCreateTx, utils.MarshalOrPanic(configtx), 0644)
	if err != nil {
		return fmt.Errorf("Error writing channel create tx: %s", err)
	}
	return nil
}

func doOutputAnchorPeersUpdate(conf *genesisconfig.Profile, channelID string, outputAnchorPeersUpdate string, asOrg string) error {
	logger.Info("Generating anchor peer update")
	if asOrg == "" {
		return fmt.Errorf("Must specify an organization to update the anchor peer for")
	}

	if conf.Application == nil {
		return fmt.Errorf("Cannot update anchor peers without an application section")
	}

	var org *genesisconfig.Organization
	for _, iorg := range conf.Application.Organizations {
		if iorg.Name == asOrg {
			org = iorg
		}
	}

	if org == nil {
		return fmt.Errorf("No org matching: %s", asOrg)
	}

	anchorPeers := make([]*pb.AnchorPeer, len(org.AnchorPeers))
	for i, anchorPeer := range org.AnchorPeers {
		anchorPeers[i] = &pb.AnchorPeer{
			Host: anchorPeer.Host,
			Port: int32(anchorPeer.Port),
		}
	}

	configGroup := config.TemplateAnchorPeers(org.Name, anchorPeers)
	configUpdate := &cb.ConfigUpdate{
		ChannelId: channelID,
		WriteSet:  configGroup,
		ReadSet:   cb.NewConfigGroup(),
	}

	// Add all the existing config to the readset
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup()
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Version = 1
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name] = cb.NewConfigGroup()
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}

	// Add all the existing at the same versions to the writeset
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version = 1
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Version = 1
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}

	configUpdateEnvelope := &cb.ConfigUpdateEnvelope{
		ConfigUpdate: utils.MarshalOrPanic(configUpdate),
	}

	update := &cb.Envelope{
		Payload: utils.MarshalOrPanic(&cb.Payload{
			Header: &cb.Header{
				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
					ChannelId: channelID,
					Type:      int32(cb.HeaderType_CONFIG_UPDATE),
				}),
			},
			Data: utils.MarshalOrPanic(configUpdateEnvelope),
		}),
	}

	logger.Info("Writing anchor peer update")
	err := ioutil.WriteFile(outputAnchorPeersUpdate, utils.MarshalOrPanic(update), 0644)
	if err != nil {
		return fmt.Errorf("Error writing channel anchor peer update: %s", err)
	}
	return nil
}

func doInspectBlock(inspectBlock string) error {
	logger.Info("Inspecting block")
	data, err := ioutil.ReadFile(inspectBlock)
	logger.Info("Parsing genesis block")
	block := &cb.Block{}
	err = proto.Unmarshal(data, block)
	if err != nil {
		return fmt.Errorf("Error unmarshaling block: %s", err)
	}

	ctx, err := utils.ExtractEnvelope(block, 0)
	if err != nil {
		return fmt.Errorf("Error retrieving configtx from block: %s", err)
	}

	payload, err := utils.UnmarshalPayload(ctx.Payload)
	if err != nil {
		return fmt.Errorf("Error extracting configtx payload: %s", err)
	}

	if payload.Header == nil {
		return fmt.Errorf("Config block did not contain header")
	}

	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return fmt.Errorf("Error unmarshaling channel header: %s", err)
	}

	if header.Type != int32(cb.HeaderType_CONFIG) {
		return fmt.Errorf("Bad header type: %d", header.Type)
	}

	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
	if err != nil {
		return fmt.Errorf("Bad configuration envelope")
	}

	if configEnvelope.Config == nil {
		return fmt.Errorf("ConfigEnvelope contained no config")
	}

	configAsJSON, err := configGroupAsJSON(configEnvelope.Config.ChannelGroup)
	if err != nil {
		return err
	}

	fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
	fmt.Println(configAsJSON)

	return nil
}

func configGroupAsJSON(group *cb.ConfigGroup) (string, error) {
	configResult, err := configtx.NewConfigResult(group, configtx.NewInitializer())
	if err != nil {
		return "", fmt.Errorf("Error parsing config: %s", err)
	}

	buffer := &bytes.Buffer{}
	err = json.Indent(buffer, []byte(configResult.JSON()), "", "    ")
	if err != nil {
		return "", fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
	}
	return buffer.String(), nil
}

func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
	logger.Info("Inspecting transaction")
	data, err := ioutil.ReadFile(inspectChannelCreateTx)
	logger.Info("Parsing transaction")
	env, err := utils.UnmarshalEnvelope(data)
	if err != nil {
		return fmt.Errorf("Error unmarshaling envelope: %s", err)
	}

	payload, err := utils.UnmarshalPayload(env.Payload)
	if err != nil {
		return fmt.Errorf("Error extracting configtx payload: %s", err)
	}

	if payload.Header == nil {
		return fmt.Errorf("Config block did not contain header")
	}

	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return fmt.Errorf("Error unmarshaling channel header: %s", err)
	}

	if header.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
		return fmt.Errorf("Bad header type: %d", header.Type)
	}

	configUpdateEnvelope, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
	if err != nil {
		return fmt.Errorf("Bad ConfigUpdateEnvelope")
	}

	configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnvelope.ConfigUpdate)
	if err != nil {
		return fmt.Errorf("ConfigUpdateEnvelope contained no config")
	}

	if configUpdate.ChannelId != header.ChannelId {
		return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId)
	}

	fmt.Printf("\nChannel creation for channel: %s\n", header.ChannelId)
	fmt.Println()

	if configUpdate.ReadSet == nil {
		fmt.Println("Read Set: empty")
	} else {
		fmt.Println("Read Set:")
		readSetAsJSON, err := configGroupAsJSON(configUpdate.ReadSet)
		if err != nil {
			return err
		}
		fmt.Println(readSetAsJSON)
	}
	fmt.Println()

	if configUpdate.WriteSet == nil {
		return fmt.Errorf("Empty WriteSet")
	}

	fmt.Println("Write Set:")
	writeSetAsJSON, err := configGroupAsJSON(configUpdate.WriteSet)
	if err != nil {
		return err
	}
	fmt.Println(writeSetAsJSON)
	fmt.Println()

	readSetMap, err := configtx.MapConfig(configUpdate.ReadSet)
	if err != nil {
		return fmt.Errorf("Error mapping read set: %s", err)
	}
	writeSetMap, err := configtx.MapConfig(configUpdate.WriteSet)
	if err != nil {
		return fmt.Errorf("Error mapping write set: %s", err)
	}

	fmt.Println("Delta Set:")
	deltaSet := configtx.ComputeDeltaSet(readSetMap, writeSetMap)
	for key := range deltaSet {
		fmt.Println(key)
	}
	fmt.Println()

	return nil
}

func main() {
	var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg string

	flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)")
	flag.StringVar(&channelID, "channelID", provisional.TestChainID, "The channel ID to use in the configtx")
	flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)")
	flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureProfile, "The profile from configtx.yaml to use for generation.")
	flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path")
	flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path")
	flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "Creates an config update to update an anchor peer (works only with the default channel creation, and only for the first update)")
	flag.StringVar(&asOrg, "asOrg", "", "Performs the config generation as a particular organization, only including values in the write set that org (likely) has privilege to set")

	flag.Parse()

	logging.SetLevel(logging.INFO, "")

	logger.Info("Loading configuration")
	factory.InitFactories(nil)
	config := genesisconfig.Load(profile)

	if outputBlock != "" {
		if err := doOutputBlock(config, channelID, outputBlock); err != nil {
			logger.Fatalf("Error on outputBlock: %s", err)
		}
	}

	if outputChannelCreateTx != "" {
		if err := doOutputChannelCreateTx(config, channelID, outputChannelCreateTx); err != nil {
			logger.Fatalf("Error on outputChannelCreateTx: %s", err)
		}
	}

	if inspectBlock != "" {
		if err := doInspectBlock(inspectBlock); err != nil {
			logger.Fatalf("Error on inspectBlock: %s", err)
		}
	}

	if inspectChannelCreateTx != "" {
		if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil {
			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
		}
	}

	if outputAnchorPeersUpdate != "" {
		if err := doOutputAnchorPeersUpdate(config, channelID, outputAnchorPeersUpdate, asOrg); err != nil {
			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
		}
	}
}
<commit_msg>[FAB-4424] Clarify configtx flag and error<commit_after>/*
Copyright IBM Corp. 2017 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 main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"

	"github.com/hyperledger/fabric/bccsp/factory"
	"github.com/hyperledger/fabric/common/config"
	mspconfig "github.com/hyperledger/fabric/common/config/msp"
	"github.com/hyperledger/fabric/common/configtx"
	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
	"github.com/hyperledger/fabric/common/flogging"
	cb "github.com/hyperledger/fabric/protos/common"
	pb "github.com/hyperledger/fabric/protos/peer"
	"github.com/hyperledger/fabric/protos/utils"

	"github.com/golang/protobuf/proto"
	mmsp "github.com/hyperledger/fabric/common/mocks/msp"
	logging "github.com/op/go-logging"
)

var logger = flogging.MustGetLogger("common/configtx/tool")

func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error {
	pgen := provisional.New(config)
	logger.Info("Generating genesis block")
	if config.Orderer == nil {
		return fmt.Errorf("config does not contain an Orderers section, necessary for all config blocks, aborting")
	}
	if config.Consortiums == nil {
		logger.Warning("Genesis block does not contain a consortiums group definition.  This block cannot be used for orderer bootstrap.")
	}
	genesisBlock := pgen.GenesisBlockForChannel(channelID)
	logger.Info("Writing genesis block")
	err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644)
	if err != nil {
		return fmt.Errorf("Error writing genesis block: %s", err)
	}
	return nil
}

func doOutputChannelCreateTx(conf *genesisconfig.Profile, channelID string, outputChannelCreateTx string) error {
	logger.Info("Generating new channel configtx")
	// TODO, use actual MSP eventually
	signer, err := mmsp.NewNoopMsp().GetDefaultSigningIdentity()
	if err != nil {
		return fmt.Errorf("Error getting signing identity: %s", err)
	}

	if conf.Application == nil {
		return fmt.Errorf("Cannot define a new channel with no Application section")
	}

	if conf.Consortium == "" {
		return fmt.Errorf("Cannot define a new channel with no Consortium section")
	}

	// XXX we ignore the non-application org names here, once the tool supports configuration updates
	// we should come up with a cleaner way to handle this, but leaving as is for the moment to not break
	// backwards compatibility
	var orgNames []string
	for _, org := range conf.Application.Organizations {
		orgNames = append(orgNames, org.Name)
	}
	configtx, err := configtx.MakeChainCreationTransaction(channelID, conf.Consortium, signer, orgNames...)
	if err != nil {
		return fmt.Errorf("Error generating configtx: %s", err)
	}
	logger.Info("Writing new channel tx")
	err = ioutil.WriteFile(outputChannelCreateTx, utils.MarshalOrPanic(configtx), 0644)
	if err != nil {
		return fmt.Errorf("Error writing channel create tx: %s", err)
	}
	return nil
}

func doOutputAnchorPeersUpdate(conf *genesisconfig.Profile, channelID string, outputAnchorPeersUpdate string, asOrg string) error {
	logger.Info("Generating anchor peer update")
	if asOrg == "" {
		return fmt.Errorf("Must specify an organization to update the anchor peer for")
	}

	if conf.Application == nil {
		return fmt.Errorf("Cannot update anchor peers without an application section")
	}

	var org *genesisconfig.Organization
	for _, iorg := range conf.Application.Organizations {
		if iorg.Name == asOrg {
			org = iorg
		}
	}

	if org == nil {
		return fmt.Errorf("No organization name matching: %s", asOrg)
	}

	anchorPeers := make([]*pb.AnchorPeer, len(org.AnchorPeers))
	for i, anchorPeer := range org.AnchorPeers {
		anchorPeers[i] = &pb.AnchorPeer{
			Host: anchorPeer.Host,
			Port: int32(anchorPeer.Port),
		}
	}

	configGroup := config.TemplateAnchorPeers(org.Name, anchorPeers)
	configUpdate := &cb.ConfigUpdate{
		ChannelId: channelID,
		WriteSet:  configGroup,
		ReadSet:   cb.NewConfigGroup(),
	}

	// Add all the existing config to the readset
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey] = cb.NewConfigGroup()
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Version = 1
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name] = cb.NewConfigGroup()
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.ReadSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}

	// Add all the existing at the same versions to the writeset
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Version = 1
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Version = 1
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Values[config.MSPKey] = &cb.ConfigValue{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.ReadersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.WritersPolicyKey] = &cb.ConfigPolicy{}
	configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups[org.Name].Policies[mspconfig.AdminsPolicyKey] = &cb.ConfigPolicy{}

	configUpdateEnvelope := &cb.ConfigUpdateEnvelope{
		ConfigUpdate: utils.MarshalOrPanic(configUpdate),
	}

	update := &cb.Envelope{
		Payload: utils.MarshalOrPanic(&cb.Payload{
			Header: &cb.Header{
				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
					ChannelId: channelID,
					Type:      int32(cb.HeaderType_CONFIG_UPDATE),
				}),
			},
			Data: utils.MarshalOrPanic(configUpdateEnvelope),
		}),
	}

	logger.Info("Writing anchor peer update")
	err := ioutil.WriteFile(outputAnchorPeersUpdate, utils.MarshalOrPanic(update), 0644)
	if err != nil {
		return fmt.Errorf("Error writing channel anchor peer update: %s", err)
	}
	return nil
}

func doInspectBlock(inspectBlock string) error {
	logger.Info("Inspecting block")
	data, err := ioutil.ReadFile(inspectBlock)
	logger.Info("Parsing genesis block")
	block := &cb.Block{}
	err = proto.Unmarshal(data, block)
	if err != nil {
		return fmt.Errorf("Error unmarshaling block: %s", err)
	}

	ctx, err := utils.ExtractEnvelope(block, 0)
	if err != nil {
		return fmt.Errorf("Error retrieving configtx from block: %s", err)
	}

	payload, err := utils.UnmarshalPayload(ctx.Payload)
	if err != nil {
		return fmt.Errorf("Error extracting configtx payload: %s", err)
	}

	if payload.Header == nil {
		return fmt.Errorf("Config block did not contain header")
	}

	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return fmt.Errorf("Error unmarshaling channel header: %s", err)
	}

	if header.Type != int32(cb.HeaderType_CONFIG) {
		return fmt.Errorf("Bad header type: %d", header.Type)
	}

	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
	if err != nil {
		return fmt.Errorf("Bad configuration envelope")
	}

	if configEnvelope.Config == nil {
		return fmt.Errorf("ConfigEnvelope contained no config")
	}

	configAsJSON, err := configGroupAsJSON(configEnvelope.Config.ChannelGroup)
	if err != nil {
		return err
	}

	fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
	fmt.Println(configAsJSON)

	return nil
}

func configGroupAsJSON(group *cb.ConfigGroup) (string, error) {
	configResult, err := configtx.NewConfigResult(group, configtx.NewInitializer())
	if err != nil {
		return "", fmt.Errorf("Error parsing config: %s", err)
	}

	buffer := &bytes.Buffer{}
	err = json.Indent(buffer, []byte(configResult.JSON()), "", "    ")
	if err != nil {
		return "", fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
	}
	return buffer.String(), nil
}

func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
	logger.Info("Inspecting transaction")
	data, err := ioutil.ReadFile(inspectChannelCreateTx)
	logger.Info("Parsing transaction")
	env, err := utils.UnmarshalEnvelope(data)
	if err != nil {
		return fmt.Errorf("Error unmarshaling envelope: %s", err)
	}

	payload, err := utils.UnmarshalPayload(env.Payload)
	if err != nil {
		return fmt.Errorf("Error extracting configtx payload: %s", err)
	}

	if payload.Header == nil {
		return fmt.Errorf("Config block did not contain header")
	}

	header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return fmt.Errorf("Error unmarshaling channel header: %s", err)
	}

	if header.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
		return fmt.Errorf("Bad header type: %d", header.Type)
	}

	configUpdateEnvelope, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
	if err != nil {
		return fmt.Errorf("Bad ConfigUpdateEnvelope")
	}

	configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnvelope.ConfigUpdate)
	if err != nil {
		return fmt.Errorf("ConfigUpdateEnvelope contained no config")
	}

	if configUpdate.ChannelId != header.ChannelId {
		return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId)
	}

	fmt.Printf("\nChannel creation for channel: %s\n", header.ChannelId)
	fmt.Println()

	if configUpdate.ReadSet == nil {
		fmt.Println("Read Set: empty")
	} else {
		fmt.Println("Read Set:")
		readSetAsJSON, err := configGroupAsJSON(configUpdate.ReadSet)
		if err != nil {
			return err
		}
		fmt.Println(readSetAsJSON)
	}
	fmt.Println()

	if configUpdate.WriteSet == nil {
		return fmt.Errorf("Empty WriteSet")
	}

	fmt.Println("Write Set:")
	writeSetAsJSON, err := configGroupAsJSON(configUpdate.WriteSet)
	if err != nil {
		return err
	}
	fmt.Println(writeSetAsJSON)
	fmt.Println()

	readSetMap, err := configtx.MapConfig(configUpdate.ReadSet)
	if err != nil {
		return fmt.Errorf("Error mapping read set: %s", err)
	}
	writeSetMap, err := configtx.MapConfig(configUpdate.WriteSet)
	if err != nil {
		return fmt.Errorf("Error mapping write set: %s", err)
	}

	fmt.Println("Delta Set:")
	deltaSet := configtx.ComputeDeltaSet(readSetMap, writeSetMap)
	for key := range deltaSet {
		fmt.Println(key)
	}
	fmt.Println()

	return nil
}

func main() {
	var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg string

	flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)")
	flag.StringVar(&channelID, "channelID", provisional.TestChainID, "The channel ID to use in the configtx")
	flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)")
	flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureProfile, "The profile from configtx.yaml to use for generation.")
	flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path")
	flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path")
	flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "Creates an config update to update an anchor peer (works only with the default channel creation, and only for the first update)")
	flag.StringVar(&asOrg, "asOrg", "", "Performs the config generation as a particular organization (by name), only including values in the write set that org (likely) has privilege to set")

	flag.Parse()

	logging.SetLevel(logging.INFO, "")

	logger.Info("Loading configuration")
	factory.InitFactories(nil)
	config := genesisconfig.Load(profile)

	if outputBlock != "" {
		if err := doOutputBlock(config, channelID, outputBlock); err != nil {
			logger.Fatalf("Error on outputBlock: %s", err)
		}
	}

	if outputChannelCreateTx != "" {
		if err := doOutputChannelCreateTx(config, channelID, outputChannelCreateTx); err != nil {
			logger.Fatalf("Error on outputChannelCreateTx: %s", err)
		}
	}

	if inspectBlock != "" {
		if err := doInspectBlock(inspectBlock); err != nil {
			logger.Fatalf("Error on inspectBlock: %s", err)
		}
	}

	if inspectChannelCreateTx != "" {
		if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil {
			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
		}
	}

	if outputAnchorPeersUpdate != "" {
		if err := doOutputAnchorPeersUpdate(config, channelID, outputAnchorPeersUpdate, asOrg); err != nil {
			logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "bytes"
import "io"
import "io/ioutil"
import "strings"
import "errors"
import "encoding/json"
import "github.com/tj/go-debug"
import "net/http"

var noMfaError = errors.New("MFA required to use this tool")

var debugOkta = debug.Debug("oktad:okta")

// begins the login process by authenticating
// with okta
func login(cfg OktaConfig, user, pass, destArn string) error {
	debugOkta("let the login dance begin")

	pr, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf(
			// TODO: run some checks on this URL
			"%sapi/v1/authn",
			cfg.BaseURL,
		),
		getOktaLoginBody(cfg, user, pass),
	)

	if err != nil {
		debugOkta("caught an error building the first request to okta")
		return err
	}

	ajs := "application/json"
	pr.Header.Set("Content-Type", ajs)
	pr.Header.Set("Accept", ajs)

	res, err := http.DefaultClient.Do(pr)
	if err != nil {
		debugOkta("caught error on first request to okta")
		return err
	}

	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	debugOkta("login response body %s", string(b))

	bod := map[string]interface{}{}
	err = json.Unmarshal(b, &bod)
	if err != nil {
		return err
	}

	if pluckStr(bod, "status") != "MFA_REQUIRED" {
		return noMfaError
	}

	err = doMfa(bod)
	if err != nil {
		return err
	}

	return nil
}

// convenience function to get the request body for the okta request
// just need a buffer, man.
// or, really, an io.Reader
func getOktaLoginBody(cfg OktaConfig, user, pass string) io.Reader {
	return bytes.NewBuffer(
		[]byte(
			fmt.Sprintf(
				`
					{
						"username": "%s",
						"password": "%s",
						"options": {
							"multiOptionalFactorEnroll": false,
							"warnBeforePasswordExpired": false
						}
					}
				`,
				user,
				pass,
			),
		),
	)
}

// do that mfa stuff
func doMfa(oktaLoginResult map[string]interface{}) error {
	factors := pluckIntSlice(oktaLoginResult, "_embedded.factors")
	if len(factors) == 0 {
		return errors.New("MFA required but no configured factors.")
	}

	var tokenFactor map[string]interface{}
	for _, factor := range factors {
		// need to assert that this is a map
		// since I don't know the structure enough
		// to make a struct for it
		if factor, ok := factor.(map[string]interface{}); ok {
			factorType := pluckStr(factor, "factorType")
			if factorType == "token:software:totp" {
				tokenFactor = factor
			}
		}
	}

	fmt.Println(tokenFactor)
	return nil

}

// like pluck, but only gives you strings
// you'll get an empty string if not found
func pluckStr(o map[string]interface{}, path string) string {
	r := pluck(o, path)
	if r, ok := r.(string); ok {
		return r
	} else {
		return ""
	}
}

// like pluck, but only gives you empty interface slices
// you'll get nil if not found
func pluckIntSlice(o map[string]interface{}, path string) []interface{} {
	r := pluck(o, path)
	if r, ok := r.([]interface{}); ok {
		return r
	} else {
		return nil
	}
}

// given a map, pull a property from it at some deeply nested depth
// this reimplements (most of) JS `pluck` in go: https://github.com/gjohnson/pluck
func pluck(o map[string]interface{}, path string) interface{} {
	// support dots for now ebcause thats all we need
	parts := strings.Split(path, ".")

	if len(parts) == 1 && o[parts[0]] != nil {
		// if there is only one part, just return that property value
		return o[parts[0]]
	} else if len(parts) > 1 && o[parts[0]] != nil {
		var prev map[string]interface{}
		var ok bool
		if prev, ok = o[parts[0]].(map[string]interface{}); !ok {
			// not an object type! ...or a map, yeah, that.
			return nil
		}

		for i := 1; i < len(parts)-1; i += 1 {
			// we need to check the existence of another
			// map[string]interface for every property along the way
			cp := parts[i]

			if prev[cp] == nil {
				// didn't find the property, it's missing
				return nil
			}
			var ok bool
			if prev, ok = prev[cp].(map[string]interface{}); !ok {
				return nil
			}
		}

		if prev[parts[len(parts)-1]] != nil {
			return prev[parts[len(parts)-1]]
		} else {
			return nil
		}
	}

	return nil
}
<commit_msg>add request and response model; use request model to make the request to okta; also handle auth failures<commit_after>package main

import "fmt"
import "bytes"
import "io"
import "io/ioutil"
import "strings"
import "errors"
import "encoding/json"
import "github.com/tj/go-debug"
import "net/http"

var noMfaError = errors.New("MFA required to use this tool")
var loginFailedError = errors.New("login failed")

var debugOkta = debug.Debug("oktad:okta")

type OktaLoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
	Options  map[string]interface{}
}

type OktaLoginResponse struct {
	Status   string
	Embedded struct {
		Factors []OktaMfaFactor
	} `json:"_embedded"`
}

type OktaMfaFactor struct {
	Id         string
	FactorType string
	Provider   string
	Status     string
	Links      map[string]HalLink
}

type HalLink struct {
	Href string
}

func newLoginRequest(user, pass string) OktaLoginRequest {
	return OktaLoginRequest{
		user,
		pass,
		map[string]interface{}{
			"multiOptionalFactorEnroll": false,
			"warnBeforePasswordExpired": false,
		},
	}
}

// begins the login process by authenticating
// with okta
func login(cfg OktaConfig, user, pass, destArn string) error {
	debugOkta("let the login dance begin")

	pr, err := http.NewRequest(
		http.MethodPost,
		fmt.Sprintf(
			// TODO: run some checks on this URL
			"%sapi/v1/authn",
			cfg.BaseURL,
		),
		getOktaLoginBody(cfg, user, pass),
	)

	if err != nil {
		debugOkta("caught an error building the first request to okta")
		return err
	}

	ajs := "application/json"
	pr.Header.Set("Content-Type", ajs)
	pr.Header.Set("Accept", ajs)

	res, err := http.DefaultClient.Do(pr)
	if err != nil {
		debugOkta("caught error on first request to okta")
		return err
	}

	if res.StatusCode != http.StatusOK {
		return loginFailedError
	}

	b, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	debugOkta("login response body %s", string(b))

	bod := map[string]interface{}{}
	err = json.Unmarshal(b, &bod)
	if err != nil {
		return err
	}

	if pluckStr(bod, "status") != "MFA_REQUIRED" {
		return noMfaError
	}

	err = doMfa(bod)
	if err != nil {
		return err
	}

	return nil
}

// convenience function to get the request body for the okta request
// just need a buffer, man.
// or, really, an io.Reader
func getOktaLoginBody(cfg OktaConfig, user, pass string) io.Reader {
	var b bytes.Buffer
	enc := json.NewEncoder(&b)
	err := enc.Encode(newLoginRequest(user, pass))
	if err != nil {
		debugOkta("Error encoding login json! %s", err)
	}
	return &b
}

// do that mfa stuff
func doMfa(oktaLoginResult map[string]interface{}) error {
	factors := pluckIntSlice(oktaLoginResult, "_embedded.factors")
	if len(factors) == 0 {
		return errors.New("MFA required but no configured factors.")
	}

	var tokenFactor map[string]interface{}
	for _, factor := range factors {
		// need to assert that this is a map
		// since I don't know the structure enough
		// to make a struct for it
		if factor, ok := factor.(map[string]interface{}); ok {
			factorType := pluckStr(factor, "factorType")
			if factorType == "token:software:totp" {
				tokenFactor = factor
			}
		}
	}

	fmt.Println(tokenFactor)
	return nil

}

// like pluck, but only gives you strings
// you'll get an empty string if not found
func pluckStr(o map[string]interface{}, path string) string {
	r := pluck(o, path)
	if r, ok := r.(string); ok {
		return r
	} else {
		return ""
	}
}

// like pluck, but only gives you empty interface slices
// you'll get nil if not found
func pluckIntSlice(o map[string]interface{}, path string) []interface{} {
	r := pluck(o, path)
	if r, ok := r.([]interface{}); ok {
		return r
	} else {
		return nil
	}
}

// given a map, pull a property from it at some deeply nested depth
// this reimplements (most of) JS `pluck` in go: https://github.com/gjohnson/pluck
func pluck(o map[string]interface{}, path string) interface{} {
	// support dots for now ebcause thats all we need
	parts := strings.Split(path, ".")

	if len(parts) == 1 && o[parts[0]] != nil {
		// if there is only one part, just return that property value
		return o[parts[0]]
	} else if len(parts) > 1 && o[parts[0]] != nil {
		var prev map[string]interface{}
		var ok bool
		if prev, ok = o[parts[0]].(map[string]interface{}); !ok {
			// not an object type! ...or a map, yeah, that.
			return nil
		}

		for i := 1; i < len(parts)-1; i += 1 {
			// we need to check the existence of another
			// map[string]interface for every property along the way
			cp := parts[i]

			if prev[cp] == nil {
				// didn't find the property, it's missing
				return nil
			}
			var ok bool
			if prev, ok = prev[cp].(map[string]interface{}); !ok {
				return nil
			}
		}

		if prev[parts[len(parts)-1]] != nil {
			return prev[parts[len(parts)-1]]
		} else {
			return nil
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package rational

import "math/big"

// Simplify simplifies the rational number by dividing it's numerator and
// denominator by the GCD.
func (ev *Rational) Simplify() {
	currentNumerator := ev.numerator
	currentDenominator := ev.denominator

	if currentNumerator < 0 && currentDenominator > 0 {
		currentNumerator *= -1
	} else if currentDenominator < 0 && currentNumerator >= 0 {
		currentDenominator *= -1
	}

	n := big.NewInt(currentNumerator)
	d := big.NewInt(currentDenominator)

	gcd := new(big.Int).GCD(nil, nil, n, d).Int64()

	if gcd > 1 {
		ev.numerator /= gcd
		ev.denominator /= gcd
	}
}

// Float64 returns the float64 representation of a rational number.
func (ev Rational) Float64() float64 {
	return float64(ev.numerator) / float64(ev.denominator)
}

// Get returns a value.
func (ev Rational) Get() (numerator, denominator int64) {
	return ev.numerator, ev.denominator
}

// IsNull determines whether the value is zero.
func (ev Rational) IsNull() (n bool) {
	if ev.numerator == 0 && ev.denominator == 0 {
		n = true
	}
	return
}

// RationalsAreNull determines whether the slice of Rationals contains only zero values.
func RationalsAreNull(l []Rational) (isNull bool) {
	isNull = true
	for _, v := range l {
		if !v.IsNull() {
			isNull = false
		}
	}
	return
}

func solveNegatives(n, d *int64) {
	if *n < 0 && *d < 0 {
		*n *= -1
		*d *= -1
	}
}
<commit_msg>added numerator and denominator getters<commit_after>package rational

import "math/big"

// Simplify simplifies the rational number by dividing it's numerator and
// denominator by the GCD.
func (ev *Rational) Simplify() {
	currentNumerator := ev.numerator
	currentDenominator := ev.denominator

	if currentNumerator < 0 && currentDenominator > 0 {
		currentNumerator *= -1
	} else if currentDenominator < 0 && currentNumerator >= 0 {
		currentDenominator *= -1
	}

	n := big.NewInt(currentNumerator)
	d := big.NewInt(currentDenominator)

	gcd := new(big.Int).GCD(nil, nil, n, d).Int64()

	if gcd > 1 {
		ev.numerator /= gcd
		ev.denominator /= gcd
	}
}

// Float64 returns the float64 representation of a rational number.
func (ev Rational) Float64() float64 {
	return float64(ev.numerator) / float64(ev.denominator)
}

// Get returns a value.
func (ev Rational) Get() (numerator, denominator int64) {
	return ev.numerator, ev.denominator
}

// GetNumerator returns a numerator.
func (ev Rational) GetNumerator() int64 {
	return ev.numerator
}

// GetDenominator returns a denominator.
func (ev Rational) GetDenominator() int64 {
	return ev.denominator
}

// IsNull determines whether the value is zero.
func (ev Rational) IsNull() (n bool) {
	if ev.numerator == 0 && ev.denominator == 0 {
		n = true
	}
	return
}

// RationalsAreNull determines whether the slice of Rationals contains only zero values.
func RationalsAreNull(l []Rational) (isNull bool) {
	isNull = true
	for _, v := range l {
		if !v.IsNull() {
			isNull = false
		}
	}
	return
}

func solveNegatives(n, d *int64) {
	if *n < 0 && *d < 0 {
		*n *= -1
		*d *= -1
	}
}
<|endoftext|>


<commit_before>package raven

import (
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/yext/glog"
	"github.com/yext/glog-contrib/stacktrace"
)

var (
	projectName string
	hostname    string
	re          *regexp.Regexp
)

func init() {
	hostname, _ = os.Hostname()
	if short := strings.Index(hostname, "."); short != -1 {
		hostname = hostname[:short]
	}
	re = regexp.MustCompile("[0-9]{2,}")
}

// CaptureErrors sets the name of the project so that when events are
// sent to sentry they are tagged as coming from the given
// project. It then sets up the connection to sentry and begins
// to send any errors recieved over comm to sentry.
// It panics if a client could not be initialized.
func CaptureErrors(project, dsn string, comm <-chan glog.Event) {
	projectName = project
	client, err := NewClient(dsn)
	if err != nil {
		panic(err)
	}

	for glogEve := range comm {
		if glogEve.Severity == "ERROR" {
			client.CaptureGlogEvent(glogEve)
		}
	}
}

// CaptureErrorsAltDsn allows you to have errors sent to one of multiple dsn targes.
// It sets up a connection to sentry for each of the given dsn URIs.
//
// To tag an event with a dsn:
//     glog.Error("bad thing happened", raven.AltDsn(YOUR_DSN))
//
// If the dsn of an event is not specificed or is not equal to any of the
// dsns arg, the dsn target will be assumed to be the first dsn in the dsns list.
func CaptureErrorsAltDsn(project string, dsns []string, comm <-chan glog.Event) {
	if len(dsns) == 0 {
		panic("must specify at least one dsn")
	}
	projectName = project

	var primaryClient *Client
	dsnClients := make(map[string]*Client)
	for _, dsn := range dsns {
		client, err := NewClient(dsn)
		if err != nil {
			panic(err)
		}
		if primaryClient == nil {
			primaryClient = client
		}
		dsnClients[dsn] = client
	}

	for glogEve := range comm {
		if glogEve.Severity == "ERROR" {
			e := fromGlogEvent(glogEve)
			eventDsnTarget := e.TargetDsn
			if client, ok := dsnClients[eventDsnTarget]; ok {
				client.Capture(e)
			} else {
				primaryClient.Capture(e)
			}
		}
	}
}

func separateMessageAndIds(message string) (string, string) {
	msg := re.ReplaceAllString(message, "[ID]")
	numbers := re.FindAllString(message, -1)
	ids := strings.Join(numbers, " ")
	return msg, ids
}

// fromGlogEvent converts a glog.Event to the format expected by Sentry.
func fromGlogEvent(e glog.Event) *Event {
	message := string(e.Message)
	if square := strings.Index(message, "]"); square != -1 {
		message = message[square+1:]
	}

	fullMessage := message
	if line := strings.Index(message, "\n"); line != -1 {
		message = message[:line]
	}

	msg, ids := separateMessageAndIds(message)

	eve := &Event{
		Project:    projectName,
		Level:      e.Severity,
		Message:    msg,
		ServerName: hostname,
		Extra:      map[string]interface{}{"FullMessage": fullMessage},
		StackTrace: stacktrace.Build(e.StackTrace),
		Logger:     os.Args[0],
	}

	data := map[string]interface{}{}
	for _, d := range e.Data {
		switch t := d.(type) {
		case altDsn:
			eve.TargetDsn = d.(string)
		case *http.Request:
			eve.Http = NewHttp(t)
		case map[string]interface{}:
			for k, v := range t {
				data[k] = v
			}
		default:
			//TODO(ltacon): ignore for now...
		}
	}

	eve.Extra["Data"] = data
	eve.Extra["Source"] = sourceFromStack(eve.StackTrace)
	if ids != "" {
		eve.Extra["IDs"] = ids
	}

	return eve
}

// sourceFromStack retrieves the function and line where the
// event was logged from in the format "file.Function:118".
func sourceFromStack(s stacktrace.StackTrace) string {
	if len(s.Frames) == 0 {
		return ""
	}

	f := s.Frames[0]
	return f.Function + ":" + f.LineNo
}
<commit_msg>Fix level param and multi dsn usage comment<commit_after>package raven

import (
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/yext/glog"
	"github.com/yext/glog-contrib/stacktrace"
)

var (
	projectName string
	hostname    string
	re          *regexp.Regexp
)

func init() {
	hostname, _ = os.Hostname()
	if short := strings.Index(hostname, "."); short != -1 {
		hostname = hostname[:short]
	}
	re = regexp.MustCompile("[0-9]{2,}")
}

// CaptureErrors sets the name of the project so that when events are
// sent to sentry they are tagged as coming from the given
// project. It then sets up the connection to sentry and begins
// to send any errors recieved over comm to sentry.
// It panics if a client could not be initialized.
func CaptureErrors(project, dsn string, comm <-chan glog.Event) {
	projectName = project
	client, err := NewClient(dsn)
	if err != nil {
		panic(err)
	}

	for glogEve := range comm {
		if glogEve.Severity == "ERROR" {
			client.CaptureGlogEvent(glogEve)
		}
	}
}

// CaptureErrorsAltDsn allows you to have errors sent to one of multiple dsn targes.
// It sets up a connection to sentry for each of the given dsn URIs.
//
// To tag an event with a dsn:
//     glog.Error("bad thing happened", glog.Data(raven.AltDsn(YOUR_DSN)))
//
// If the dsn of an event is not specified or is not equal to any of the
// dsns arg, the dsn target will be assumed to be the first dsn in the dsns list.
func CaptureErrorsAltDsn(project string, dsns []string, comm <-chan glog.Event) {
	if len(dsns) == 0 {
		panic("must specify at least one dsn")
	}
	projectName = project

	var primaryClient *Client
	dsnClients := make(map[string]*Client)
	for _, dsn := range dsns {
		client, err := NewClient(dsn)
		if err != nil {
			panic(err)
		}
		if primaryClient == nil {
			primaryClient = client
		}
		dsnClients[dsn] = client
	}

	for glogEve := range comm {
		if glogEve.Severity == "ERROR" {
			e := fromGlogEvent(glogEve)
			eventDsnTarget := e.TargetDsn
			if client, ok := dsnClients[eventDsnTarget]; ok {
				client.Capture(e)
			} else {
				primaryClient.Capture(e)
			}
		}
	}
}

func separateMessageAndIds(message string) (string, string) {
	msg := re.ReplaceAllString(message, "[ID]")
	numbers := re.FindAllString(message, -1)
	ids := strings.Join(numbers, " ")
	return msg, ids
}

// fromGlogEvent converts a glog.Event to the format expected by Sentry.
func fromGlogEvent(e glog.Event) *Event {
	message := string(e.Message)
	if square := strings.Index(message, "]"); square != -1 {
		message = message[square+1:]
	}

	fullMessage := message
	if line := strings.Index(message, "\n"); line != -1 {
		message = message[:line]
	}

	msg, ids := separateMessageAndIds(message)

	eve := &Event{
		Project:    projectName,
		Level:      strings.ToLower(e.Severity),
		Message:    msg,
		ServerName: hostname,
		Extra:      map[string]interface{}{"FullMessage": fullMessage},
		StackTrace: stacktrace.Build(e.StackTrace),
		Logger:     os.Args[0],
	}

	data := map[string]interface{}{}
	for _, d := range e.Data {
		switch t := d.(type) {
		case altDsn:
			eve.TargetDsn = d.(string)
		case *http.Request:
			eve.Http = NewHttp(t)
		case map[string]interface{}:
			for k, v := range t {
				data[k] = v
			}
		default:
			//TODO(ltacon): ignore for now...
		}
	}

	eve.Extra["Data"] = data
	eve.Extra["Source"] = sourceFromStack(eve.StackTrace)
	if ids != "" {
		eve.Extra["IDs"] = ids
	}

	return eve
}

// sourceFromStack retrieves the function and line where the
// event was logged from in the format "file.Function:118".
func sourceFromStack(s stacktrace.StackTrace) string {
	if len(s.Frames) == 0 {
		return ""
	}

	f := s.Frames[0]
	return f.Function + ":" + f.LineNo
}
<|endoftext|>


<commit_before>package figtree

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"unicode"

	"github.com/fatih/camelcase"
	"github.com/pkg/errors"

	yaml "gopkg.in/coryb/yaml.v2"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("figtree")

type FigTree struct {
	Defaults  interface{}
	EnvPrefix string
	stop      bool
}

func NewFigTree() *FigTree {
	return &FigTree{
		EnvPrefix: "FIGTREE",
	}
}

func LoadAllConfigs(configFile string, options interface{}) error {
	return NewFigTree().LoadAllConfigs(configFile, options)
}

func LoadConfig(configFile string, options interface{}) error {
	return NewFigTree().LoadConfig(configFile, options)
}

func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error {
	// reset from any previous config parsing runs
	f.stop = false
	// assert options is a pointer

	paths := FindParentPaths(configFile)
	paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...)

	// iterate paths in reverse
	for i := len(paths) - 1; i >= 0; i-- {
		file := paths[i]
		err := f.LoadConfig(file, options)
		if err != nil {
			return err
		}
		if f.stop {
			break
		}
	}

	// apply defaults at the end to set any undefined fields
	if f.Defaults != nil {
		m := &merger{sourceFile: "defaults"}
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(f.Defaults),
		)
	}
	return nil
}

func (f *FigTree) LoadConfig(file string, options interface{}) (err error) {
	f.populateEnv(options)
	basePath, err := os.Getwd()
	if err != nil {
		return err
	}

	rel, err := filepath.Rel(basePath, file)
	if err != nil {
		rel = file
	}
	m := &merger{sourceFile: rel}
	type tmpOpts struct {
		Config ConfigOptions
	}

	if stat, err := os.Stat(file); err == nil {
		tmp := reflect.New(reflect.ValueOf(options).Elem().Type()).Interface()
		if stat.Mode()&0111 == 0 {
			log.Debugf("Loading config %s", file)
			// first parse out any config processing option
			if data, err := ioutil.ReadFile(file); err == nil {
				err := yaml.Unmarshal(data, m)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}

				err = yaml.Unmarshal(data, tmp)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}
				// if reflect.ValueOf(tmp).Kind() == reflect.Map {
				// 	tmp, _ = util.YamlFixup(tmp)
				// }
			}
		} else {
			log.Debugf("Found Executable Config file: %s", file)
			// it is executable, so run it and try to parse the output
			cmd := exec.Command(file)
			stdout := bytes.NewBufferString("")
			cmd.Stdout = stdout
			cmd.Stderr = bytes.NewBufferString("")
			if err := cmd.Run(); err != nil {
				return errors.Wrap(err, fmt.Sprintf("%s is exectuable, but it failed to execute:\n%s", file, cmd.Stderr))
			}
			// first parse out any config processing option
			err := yaml.Unmarshal(stdout.Bytes(), m)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
			}
			err = yaml.Unmarshal(stdout.Bytes(), tmp)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Failed to parse STDOUT from executable config file %s", file))
			}
		}
		m.setSource(reflect.ValueOf(tmp))
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(tmp),
		)
		if m.Config.Stop {
			f.stop = true
			return nil
		}
		f.populateEnv(options)
	}
	return nil
}

type ConfigOptions struct {
	Overwrite []string `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Stop      bool     `json:"stop,omitempty" yaml:"stop,omitempty"`
	// Merge     bool     `json:"merge,omitempty" yaml:"merge,omitempty"`
}

type merger struct {
	sourceFile string
	Config     ConfigOptions `json:"config,omitempty" yaml:"config,omitempty"`
}

func yamlFieldName(sf reflect.StructField) string {
	if tag, ok := sf.Tag.Lookup("yaml"); ok {
		// with yaml:"foobar,omitempty"
		// we just want to the "foobar" part
		parts := strings.Split(tag, ",")
		return parts[0]
	}
	return sf.Name
}

func (m *merger) mustOverwrite(name string) bool {
	for _, prop := range m.Config.Overwrite {
		if name == prop {
			return true
		}
	}
	return false
}

func (m *merger) isEmpty(v reflect.Value) bool {
	return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func (m *merger) isSame(v1, v2 reflect.Value) bool {
	return reflect.DeepEqual(v1.Interface(), v2.Interface())
}

// recursively set the Source attribute of the Options
func (m *merger) setSource(v reflect.Value) {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		for _, key := range v.MapKeys() {
			keyval := v.MapIndex(key)
			if keyval.Kind() == reflect.Struct && keyval.FieldByName("Source").IsValid() {
				// map values are immutable, so we need to copy the value
				// update the value, then re-insert the value to the map
				newval := reflect.New(keyval.Type())
				newval.Elem().Set(keyval)
				m.setSource(newval)
				v.SetMapIndex(key, newval.Elem())
			}
		}
	case reflect.Struct:
		if v.CanAddr() {
			if option, ok := v.Addr().Interface().(Option); ok {
				if option.IsDefined() {
					option.SetSource(m.sourceFile)
				}
				return
			}
		}
		for i := 0; i < v.NumField(); i++ {
			m.setSource(v.Field(i))
		}
	case reflect.Array:
		fallthrough
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			m.setSource(v.Index(i))
		}
	}
}

func (m *merger) mergeStructs(ov, nv reflect.Value) {
	if ov.Kind() == reflect.Ptr {
		ov = ov.Elem()
	}
	if nv.Kind() == reflect.Ptr {
		nv = nv.Elem()
	}
	if ov.Kind() == reflect.Map && nv.Kind() == reflect.Map {
		m.mergeMaps(ov, nv)
		return
	}
	if !ov.IsValid() || !nv.IsValid() {
		return
	}
	for i := 0; i < nv.NumField(); i++ {
		fieldName := yamlFieldName(ov.Type().Field(i))

		if (m.isEmpty(ov.Field(i)) || m.mustOverwrite(fieldName)) && !m.isSame(ov.Field(i), nv.Field(i)) {
			log.Debugf("Setting %s to %#v", nv.Type().Field(i).Name, nv.Field(i).Interface())
			ov.Field(i).Set(nv.Field(i))
		} else {
			switch ov.Field(i).Kind() {
			case reflect.Map:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeMaps(ov.Field(i), nv.Field(i))
				}
			case reflect.Slice:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					if ov.Field(i).CanSet() {
						if ov.Field(i).Len() == 0 {
							ov.Field(i).Set(nv.Field(i))
						} else {
							log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
							ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
						}
					}

				}
			case reflect.Array:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
				}
			}
		}
	}
}

func (m *merger) mergeMaps(ov, nv reflect.Value) {
	for _, key := range nv.MapKeys() {
		if !ov.MapIndex(key).IsValid() {
			log.Debugf("Setting %v to %#v", key.Interface(), nv.MapIndex(key).Interface())
			ov.SetMapIndex(key, nv.MapIndex(key))
		} else {
			ovi := reflect.ValueOf(ov.MapIndex(key).Interface())
			nvi := reflect.ValueOf(nv.MapIndex(key).Interface())
			switch ovi.Kind() {
			case reflect.Map:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				m.mergeMaps(ovi, nvi)
			case reflect.Slice:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			case reflect.Array:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			}
		}
	}
}

func (m *merger) mergeArrays(ov, nv reflect.Value) reflect.Value {
Outer:
	for ni := 0; ni < nv.Len(); ni++ {
		niv := nv.Index(ni)
		for oi := 0; oi < ov.Len(); oi++ {
			oiv := ov.Index(oi)
			if reflect.DeepEqual(niv.Interface(), oiv.Interface()) {
				continue Outer
			}
		}
		log.Debugf("Appending %v to %v", niv.Interface(), ov)
		ov = reflect.Append(ov, niv)
	}
	return ov
}

func (f *FigTree) populateEnv(data interface{}) {
	options := reflect.ValueOf(data)
	if options.Kind() == reflect.Ptr {
		options = reflect.ValueOf(options.Elem().Interface())
	}
	if options.Kind() == reflect.Struct {
		for i := 0; i < options.NumField(); i++ {
			name := strings.Join(camelcase.Split(options.Type().Field(i).Name), "_")
			envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))

			envName = strings.Map(func(r rune) rune {
				if unicode.IsDigit(r) || unicode.IsLetter(r) {
					return r
				}
				return '_'
			}, envName)
			var val string
			switch t := options.Field(i).Interface().(type) {
			case string:
				val = t
			case int, int8, int16, int32, int64:
				val = fmt.Sprintf("%d", t)
			case float32, float64:
				val = fmt.Sprintf("%f", t)
			case bool:
				val = fmt.Sprintf("%t", t)
			default:
				if b, err := json.Marshal(t); err == nil {
					val = strings.TrimSpace(string(b))
					if val == "null" {
						val = ""
					}
				}
			}
			os.Setenv(envName, val)
		}
	}
}
<commit_msg>recursively merge structs<commit_after>package figtree

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"reflect"
	"strings"
	"unicode"

	"github.com/fatih/camelcase"
	"github.com/pkg/errors"

	yaml "gopkg.in/coryb/yaml.v2"
	logging "gopkg.in/op/go-logging.v1"
)

var log = logging.MustGetLogger("figtree")

type FigTree struct {
	Defaults  interface{}
	EnvPrefix string
	stop      bool
}

func NewFigTree() *FigTree {
	return &FigTree{
		EnvPrefix: "FIGTREE",
	}
}

func LoadAllConfigs(configFile string, options interface{}) error {
	return NewFigTree().LoadAllConfigs(configFile, options)
}

func LoadConfig(configFile string, options interface{}) error {
	return NewFigTree().LoadConfig(configFile, options)
}

func (f *FigTree) LoadAllConfigs(configFile string, options interface{}) error {
	// reset from any previous config parsing runs
	f.stop = false
	// assert options is a pointer

	paths := FindParentPaths(configFile)
	paths = append([]string{fmt.Sprintf("/etc/%s", configFile)}, paths...)

	// iterate paths in reverse
	for i := len(paths) - 1; i >= 0; i-- {
		file := paths[i]
		err := f.LoadConfig(file, options)
		if err != nil {
			return err
		}
		if f.stop {
			break
		}
	}

	// apply defaults at the end to set any undefined fields
	if f.Defaults != nil {
		m := &merger{sourceFile: "defaults"}
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(f.Defaults),
		)
	}
	return nil
}

func (f *FigTree) LoadConfig(file string, options interface{}) (err error) {
	f.populateEnv(options)
	basePath, err := os.Getwd()
	if err != nil {
		return err
	}

	rel, err := filepath.Rel(basePath, file)
	if err != nil {
		rel = file
	}
	m := &merger{sourceFile: rel}
	type tmpOpts struct {
		Config ConfigOptions
	}

	if stat, err := os.Stat(file); err == nil {
		tmp := reflect.New(reflect.ValueOf(options).Elem().Type()).Interface()
		if stat.Mode()&0111 == 0 {
			log.Debugf("Loading config %s", file)
			// first parse out any config processing option
			if data, err := ioutil.ReadFile(file); err == nil {
				err := yaml.Unmarshal(data, m)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}

				err = yaml.Unmarshal(data, tmp)
				if err != nil {
					return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
				}
				// if reflect.ValueOf(tmp).Kind() == reflect.Map {
				// 	tmp, _ = util.YamlFixup(tmp)
				// }
			}
		} else {
			log.Debugf("Found Executable Config file: %s", file)
			// it is executable, so run it and try to parse the output
			cmd := exec.Command(file)
			stdout := bytes.NewBufferString("")
			cmd.Stdout = stdout
			cmd.Stderr = bytes.NewBufferString("")
			if err := cmd.Run(); err != nil {
				return errors.Wrap(err, fmt.Sprintf("%s is exectuable, but it failed to execute:\n%s", file, cmd.Stderr))
			}
			// first parse out any config processing option
			err := yaml.Unmarshal(stdout.Bytes(), m)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Unable to parse %s", file))
			}
			err = yaml.Unmarshal(stdout.Bytes(), tmp)
			if err != nil {
				return errors.Wrap(err, fmt.Sprintf("Failed to parse STDOUT from executable config file %s", file))
			}
		}
		m.setSource(reflect.ValueOf(tmp))
		m.mergeStructs(
			reflect.ValueOf(options),
			reflect.ValueOf(tmp),
		)
		if m.Config.Stop {
			f.stop = true
			return nil
		}
		f.populateEnv(options)
	}
	return nil
}

type ConfigOptions struct {
	Overwrite []string `json:"overwrite,omitempty" yaml:"overwrite,omitempty"`
	Stop      bool     `json:"stop,omitempty" yaml:"stop,omitempty"`
	// Merge     bool     `json:"merge,omitempty" yaml:"merge,omitempty"`
}

type merger struct {
	sourceFile string
	Config     ConfigOptions `json:"config,omitempty" yaml:"config,omitempty"`
}

func yamlFieldName(sf reflect.StructField) string {
	if tag, ok := sf.Tag.Lookup("yaml"); ok {
		// with yaml:"foobar,omitempty"
		// we just want to the "foobar" part
		parts := strings.Split(tag, ",")
		return parts[0]
	}
	return sf.Name
}

func (m *merger) mustOverwrite(name string) bool {
	for _, prop := range m.Config.Overwrite {
		if name == prop {
			return true
		}
	}
	return false
}

func (m *merger) isEmpty(v reflect.Value) bool {
	return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}

func (m *merger) isSame(v1, v2 reflect.Value) bool {
	return reflect.DeepEqual(v1.Interface(), v2.Interface())
}

// recursively set the Source attribute of the Options
func (m *merger) setSource(v reflect.Value) {
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	switch v.Kind() {
	case reflect.Map:
		for _, key := range v.MapKeys() {
			keyval := v.MapIndex(key)
			if keyval.Kind() == reflect.Struct && keyval.FieldByName("Source").IsValid() {
				// map values are immutable, so we need to copy the value
				// update the value, then re-insert the value to the map
				newval := reflect.New(keyval.Type())
				newval.Elem().Set(keyval)
				m.setSource(newval)
				v.SetMapIndex(key, newval.Elem())
			}
		}
	case reflect.Struct:
		if v.CanAddr() {
			if option, ok := v.Addr().Interface().(Option); ok {
				if option.IsDefined() {
					option.SetSource(m.sourceFile)
				}
				return
			}
		}
		for i := 0; i < v.NumField(); i++ {
			m.setSource(v.Field(i))
		}
	case reflect.Array:
		fallthrough
	case reflect.Slice:
		for i := 0; i < v.Len(); i++ {
			m.setSource(v.Index(i))
		}
	}
}

func (m *merger) mergeStructs(ov, nv reflect.Value) {
	if ov.Kind() == reflect.Ptr {
		ov = ov.Elem()
	}
	if nv.Kind() == reflect.Ptr {
		nv = nv.Elem()
	}
	if ov.Kind() == reflect.Map && nv.Kind() == reflect.Map {
		m.mergeMaps(ov, nv)
		return
	}
	if !ov.IsValid() || !nv.IsValid() {
		return
	}
	for i := 0; i < nv.NumField(); i++ {
		fieldName := yamlFieldName(ov.Type().Field(i))

		if (m.isEmpty(ov.Field(i)) || m.mustOverwrite(fieldName)) && !m.isSame(ov.Field(i), nv.Field(i)) {
			log.Debugf("Setting %s to %#v", nv.Type().Field(i).Name, nv.Field(i).Interface())
			ov.Field(i).Set(nv.Field(i))
		} else {
			switch ov.Field(i).Kind() {
			case reflect.Map:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeMaps(ov.Field(i), nv.Field(i))
				}
			case reflect.Slice:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					if ov.Field(i).CanSet() {
						if ov.Field(i).Len() == 0 {
							ov.Field(i).Set(nv.Field(i))
						} else {
							log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
							ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
						}
					}

				}
			case reflect.Array:
				if nv.Field(i).Len() > 0 {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					ov.Field(i).Set(m.mergeArrays(ov.Field(i), nv.Field(i)))
				}
			case reflect.Struct:
				// only merge structs if they are not an Option type:
				if _, ok := ov.Field(i).Addr().Interface().(Option); !ok {
					log.Debugf("Merging: %v with %v", ov.Field(i), nv.Field(i))
					m.mergeStructs(ov.Field(i), nv.Field(i))
				}
			}
		}
	}
}

func (m *merger) mergeMaps(ov, nv reflect.Value) {
	for _, key := range nv.MapKeys() {
		if !ov.MapIndex(key).IsValid() {
			log.Debugf("Setting %v to %#v", key.Interface(), nv.MapIndex(key).Interface())
			ov.SetMapIndex(key, nv.MapIndex(key))
		} else {
			ovi := reflect.ValueOf(ov.MapIndex(key).Interface())
			nvi := reflect.ValueOf(nv.MapIndex(key).Interface())
			switch ovi.Kind() {
			case reflect.Map:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				m.mergeMaps(ovi, nvi)
			case reflect.Slice:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			case reflect.Array:
				log.Debugf("Merging: %v with %v", ovi.Interface(), nvi.Interface())
				ov.SetMapIndex(key, m.mergeArrays(ovi, nvi))
			}
		}
	}
}

func (m *merger) mergeArrays(ov, nv reflect.Value) reflect.Value {
Outer:
	for ni := 0; ni < nv.Len(); ni++ {
		niv := nv.Index(ni)
		for oi := 0; oi < ov.Len(); oi++ {
			oiv := ov.Index(oi)
			if reflect.DeepEqual(niv.Interface(), oiv.Interface()) {
				continue Outer
			}
		}
		log.Debugf("Appending %v to %v", niv.Interface(), ov)
		ov = reflect.Append(ov, niv)
	}
	return ov
}

func (f *FigTree) populateEnv(data interface{}) {
	options := reflect.ValueOf(data)
	if options.Kind() == reflect.Ptr {
		options = reflect.ValueOf(options.Elem().Interface())
	}
	if options.Kind() == reflect.Struct {
		for i := 0; i < options.NumField(); i++ {
			name := strings.Join(camelcase.Split(options.Type().Field(i).Name), "_")
			envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))

			envName = strings.Map(func(r rune) rune {
				if unicode.IsDigit(r) || unicode.IsLetter(r) {
					return r
				}
				return '_'
			}, envName)
			var val string
			switch t := options.Field(i).Interface().(type) {
			case string:
				val = t
			case int, int8, int16, int32, int64:
				val = fmt.Sprintf("%d", t)
			case float32, float64:
				val = fmt.Sprintf("%f", t)
			case bool:
				val = fmt.Sprintf("%t", t)
			default:
				if b, err := json.Marshal(t); err == nil {
					val = strings.TrimSpace(string(b))
					if val == "null" {
						val = ""
					}
				}
			}
			os.Setenv(envName, val)
		}
	}
}
<|endoftext|>


<commit_before>// Package flagenv provides the ability to populate flags from
// environment variables.
package flagenv

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
)

// If set to true, the corresponding environment variable name for a flag will be uppercased.
// ie: For a flag named "foobar", the corresponding environment variable will be "FOOBAR"
var UseUpperCaseFlagNames = false

func contains(list []*flag.Flag, f *flag.Flag) bool {
	for _, i := range list {
		if i == f {
			return true
		}
	}
	return false
}

func parse() (err error) {
	explicit := make([]*flag.Flag, 0)
	all := make([]*flag.Flag, 0)
	flag.Visit(func(f *flag.Flag) {
		explicit = append(explicit, f)
	})

	defer func() {
		if e := recover(); e != nil {
			err = e.(error)
		}
	}()

	flag.VisitAll(func(f *flag.Flag) {
		all = append(all, f)
		if !contains(explicit, f) {
			name := strings.Replace(f.Name, ".", "_", -1)
			name = strings.Replace(name, "-", "_", -1)
			if UseUpperCaseFlagNames {
				name = strings.ToUpper(name)
			}
			val := os.Getenv(name)
			if val != "" {
				err := f.Value.Set(val)
				if err != nil {
					panic(fmt.Errorf("Failed to set flag %s with value %s", f.Name, val))
				}
			}
		}
	})

	return nil
}

// For each declared flag, Parse() will get the value of the corresponding
// environment variable and will set it. If dots or dash are presents in the
// flag name, they will be converted to underscores. If you want flag names to
// be converted to uppercase, you can set `UseUpperCaseFlagNames` to `true`.
//
// If Parse fails, a fatal error is issued.
func Parse() {
	if err := parse(); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>Make package documentation more concise<commit_after>// Package flagenv populates flags from environment variables.
package flagenv

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
)

// If set to true, the corresponding environment variable name for a flag will be uppercased.
// ie: For a flag named "foobar", the corresponding environment variable will be "FOOBAR"
var UseUpperCaseFlagNames = false

func contains(list []*flag.Flag, f *flag.Flag) bool {
	for _, i := range list {
		if i == f {
			return true
		}
	}
	return false
}

func parse() (err error) {
	explicit := make([]*flag.Flag, 0)
	all := make([]*flag.Flag, 0)
	flag.Visit(func(f *flag.Flag) {
		explicit = append(explicit, f)
	})

	defer func() {
		if e := recover(); e != nil {
			err = e.(error)
		}
	}()

	flag.VisitAll(func(f *flag.Flag) {
		all = append(all, f)
		if !contains(explicit, f) {
			name := strings.Replace(f.Name, ".", "_", -1)
			name = strings.Replace(name, "-", "_", -1)
			if UseUpperCaseFlagNames {
				name = strings.ToUpper(name)
			}
			val := os.Getenv(name)
			if val != "" {
				err := f.Value.Set(val)
				if err != nil {
					panic(fmt.Errorf("Failed to set flag %s with value %s", f.Name, val))
				}
			}
		}
	})

	return nil
}

// For each declared flag, Parse() will get the value of the corresponding
// environment variable and will set it. If dots or dash are presents in the
// flag name, they will be converted to underscores. If you want flag names to
// be converted to uppercase, you can set `UseUpperCaseFlagNames` to `true`.
//
// If Parse fails, a fatal error is issued.
func Parse() {
	if err := parse(); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>