<commit_before>package migrator

import (
	"log"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/kinesis"
	"github.com/awslabs/aws-sdk-go/gen/swf"
	. "github.com/sclasen/swfsm/sugar"
	//"github.com/awslabs/aws-sdk-go/gen/dynamodb"
	"fmt"
	"time"
)

// TypesMigrator is composed of a DomainMigrator, a WorkflowTypeMigrator and an ActivityTypeMigrator.
type TypesMigrator struct {
	DomainMigrator       *DomainMigrator
	WorkflowTypeMigrator *WorkflowTypeMigrator
	ActivityTypeMigrator *ActivityTypeMigrator
	StreamMigrator       *StreamMigrator
}

type SWFOps interface {
	DeprecateActivityType(req *swf.DeprecateActivityTypeInput) (err error)
	DeprecateDomain(req *swf.DeprecateDomainInput) (err error)
	DeprecateWorkflowType(req *swf.DeprecateWorkflowTypeInput) (err error)
	DescribeActivityType(req *swf.DescribeActivityTypeInput) (resp *swf.ActivityTypeDetail, err error)
	DescribeDomain(req *swf.DescribeDomainInput) (resp *swf.DomainDetail, err error)
	DescribeWorkflowExecution(req *swf.DescribeWorkflowExecutionInput) (resp *swf.WorkflowExecutionDetail, err error)
	DescribeWorkflowType(req *swf.DescribeWorkflowTypeInput) (resp *swf.WorkflowTypeDetail, err error)
	RegisterActivityType(req *swf.RegisterActivityTypeInput) (err error)
	RegisterDomain(req *swf.RegisterDomainInput) (err error)
	RegisterWorkflowType(req *swf.RegisterWorkflowTypeInput) (err error)
}

type KinesisOps interface {
	CreateStream(req *kinesis.CreateStreamInput) (err error)
	DescribeStream(req *kinesis.DescribeStreamInput) (resp *kinesis.DescribeStreamOutput, err error)
}

// Migrate runs Migrate on the underlying DomainMigrator, a WorkflowTypeMigrator and ActivityTypeMigrator.
func (t *TypesMigrator) Migrate() {
	if t.ActivityTypeMigrator == nil {
		t.ActivityTypeMigrator = new(ActivityTypeMigrator)
	}
	if t.DomainMigrator == nil {
		t.DomainMigrator = new(DomainMigrator)
	}
	if t.WorkflowTypeMigrator == nil {
		t.WorkflowTypeMigrator = new(WorkflowTypeMigrator)
	}
	if t.StreamMigrator == nil {
		t.StreamMigrator = new(StreamMigrator)
	}
	t.DomainMigrator.Migrate()
	t.WorkflowTypeMigrator.Migrate()
	t.ActivityTypeMigrator.Migrate()
	t.StreamMigrator.Migrate()
}

// DomainMigrator will register or deprecate the configured domains as required.
type DomainMigrator struct {
	RegisteredDomains []swf.RegisterDomainInput
	DeprecatedDomains []swf.DeprecateDomainInput
	Client            SWFOps
}

// Migrate asserts that DeprecatedDomains are deprecated or deprecates them, then asserts that RegisteredDomains are registered or registers them.
func (d *DomainMigrator) Migrate() {
	for _, dd := range d.DeprecatedDomains {
		if d.isDeprecated(dd.Name) {
			log.Printf("action=migrate at=deprecate-domain domain=%s status=previously-deprecated", LS(dd.Name))
		} else {
			d.deprecate(dd)
			log.Printf("action=migrate at=deprecate-domain domain=%s status=deprecated", LS(dd.Name))
		}
	}
	for _, r := range d.RegisteredDomains {
		if d.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-domain domain=%s status=previously-registered", LS(r.Name))
		} else {
			d.register(r)
			log.Printf("action=migrate at=register-domain domain=%s status=registered", LS(r.Name))
		}
	}
}

func (d *DomainMigrator) isRegisteredNotDeprecated(rd swf.RegisterDomainInput) bool {
	desc, err := d.describe(rd.Name)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.DomainInfo.Status == swf.RegistrationStatusRegistered
}

func (d *DomainMigrator) register(rd swf.RegisterDomainInput) {
	err := d.Client.RegisterDomain(&rd)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeDomainAlreadyExistsFault {
			return
		}

		panicWithError(err)

	}
}

func (d *DomainMigrator) isDeprecated(domain aws.StringValue) bool {
	desc, err := d.describe(domain)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s error=%s", LS(domain), err.Error())
		return false
	}

	return *desc.DomainInfo.Status == swf.RegistrationStatusDeprecated
}

func (d *DomainMigrator) deprecate(dd swf.DeprecateDomainInput) {
	err := d.Client.DeprecateDomain(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (d *DomainMigrator) describe(domain aws.StringValue) (*swf.DomainDetail, error) {
	resp, err := d.Client.DescribeDomain(&swf.DescribeDomainInput{Name: domain})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// WorkflowTypeMigrator will register or deprecate the configured workflow types as required.
type WorkflowTypeMigrator struct {
	RegisteredWorkflowTypes []swf.RegisterWorkflowTypeInput
	DeprecatedWorkflowTypes []swf.DeprecateWorkflowTypeInput
	Client                  SWFOps
}

// Migrate asserts that DeprecatedWorkflowTypes are deprecated or deprecates them, then asserts that RegisteredWorkflowTypes are registered or registers them.
func (w *WorkflowTypeMigrator) Migrate() {
	for _, dd := range w.DeprecatedWorkflowTypes {
		if w.isDeprecated(dd.Domain, dd.WorkflowType.Name, dd.WorkflowType.Version) {
			log.Printf("action=migrate at=deprecate-workflow domain=%s workflow=%s version=%s status=previously-deprecated", LS(dd.Domain), LS(dd.WorkflowType.Name), LS(dd.WorkflowType.Version))
		} else {
			w.deprecate(dd)
			log.Printf("action=migrate at=deprecate-workflow domain=%s  workflow=%s version=%s status=deprecate", LS(dd.Domain), LS(dd.WorkflowType.Name), LS(dd.WorkflowType.Version))
		}
	}
	for _, r := range w.RegisteredWorkflowTypes {
		if w.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-workflow domain=%s workflow=%s version=%s status=previously-registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		} else {
			w.register(r)
			log.Printf("action=migrate at=register-workflow domain=%s  workflow=%s version=%s status=registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		}
	}
}

func (w *WorkflowTypeMigrator) isRegisteredNotDeprecated(rd swf.RegisterWorkflowTypeInput) bool {
	desc, err := w.describe(rd.Domain, rd.Name, rd.Version)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusRegistered
}

func (w *WorkflowTypeMigrator) register(rd swf.RegisterWorkflowTypeInput) {
	err := w.Client.RegisterWorkflowType(&rd)
    if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeAlreadyExistsFault {
        return
    }

    panicWithError(err)
}

func (w *WorkflowTypeMigrator) isDeprecated(domain aws.StringValue, name aws.StringValue, version aws.StringValue) bool {
	desc, err := w.describe(domain, name, version)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s workflow=%s version=%s error=%s", LS(domain), LS(name), LS(version), err.Error())
		return false
	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusDeprecated
}

func (w *WorkflowTypeMigrator) deprecate(dd swf.DeprecateWorkflowTypeInput) {
	err := w.Client.DeprecateWorkflowType(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (w *WorkflowTypeMigrator) describe(domain aws.StringValue, name aws.StringValue, version aws.StringValue) (*swf.WorkflowTypeDetail, error) {
	resp, err := w.Client.DescribeWorkflowType(&swf.DescribeWorkflowTypeInput{Domain: domain, WorkflowType: &swf.WorkflowType{Name: name, Version: version}})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// ActivityTypeMigrator will register or deprecate the configured activity types as required.
type ActivityTypeMigrator struct {
	RegisteredActivityTypes []swf.RegisterActivityTypeInput
	DeprecatedActivityTypes []swf.DeprecateActivityTypeInput
	Client                  SWFOps
}

// Migrate asserts that DeprecatedActivityTypes are deprecated or deprecates them, then asserts that RegisteredActivityTypes are registered or registers them.
func (a *ActivityTypeMigrator) Migrate() {
	for _, d := range a.DeprecatedActivityTypes {
		if a.isDeprecated(d.Domain, d.ActivityType.Name, d.ActivityType.Version) {
			log.Printf("action=migrate at=deprecate-activity domain=%s activity=%s version=%s status=previously-deprecated", LS(d.Domain), LS(d.ActivityType.Name), LS(d.ActivityType.Version))
		} else {
			a.deprecate(d)
			log.Printf("action=migrate at=depreacate-activity domain=%s activity=%s version=%s status=deprecated", LS(d.Domain), LS(d.ActivityType.Name), LS(d.ActivityType.Version))
		}
	}
	for _, r := range a.RegisteredActivityTypes {
		if a.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-activity domain=%s activity=%s version=%s status=previously-registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		} else {
			a.register(r)
			log.Printf("action=migrate at=register-activity domain=%s activity=%s version=%s status=registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		}
	}
}

func (a *ActivityTypeMigrator) isRegisteredNotDeprecated(rd swf.RegisterActivityTypeInput) bool {
	desc, err := a.describe(rd.Domain, rd.Name, rd.Version)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusRegistered
}

func (a *ActivityTypeMigrator) register(rd swf.RegisterActivityTypeInput) {
	err := a.Client.RegisterActivityType(&rd)
	if err != nil {
		panicWithError(err)
	}
}

func (a *ActivityTypeMigrator) isDeprecated(domain aws.StringValue, name aws.StringValue, version aws.StringValue) bool {
	desc, err := a.describe(domain, name, version)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s activity=%s version=%s error=%s", LS(domain), LS(name), LS(version), err.Error())
		return false
	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusDeprecated
}

func (a *ActivityTypeMigrator) deprecate(dd swf.DeprecateActivityTypeInput) {
	err := a.Client.DeprecateActivityType(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (a *ActivityTypeMigrator) describe(domain aws.StringValue, name aws.StringValue, version aws.StringValue) (*swf.ActivityTypeDetail, error) {
	resp, err := a.Client.DescribeActivityType(&swf.DescribeActivityTypeInput{Domain: domain, ActivityType: &swf.ActivityType{Name: name, Version: version}})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// StreamMigrator will create any Kinesis Streams required.
type StreamMigrator struct {
	Streams []kinesis.CreateStreamInput
	Client  KinesisOps
}

// Migrate checks that the desired streams have been created and if they have not, creates them.s
func (s *StreamMigrator) Migrate() {
	for _, st := range s.Streams {
		if s.isCreated(st) {
			log.Printf("action=migrate at=create-stream stream=%s status=previously-created", LS(st.StreamName))
		} else {
			s.create(st)
			log.Printf("action=migrate at=create-stream stream=%s status=created", LS(st.StreamName))
		}
		s.awaitActive(st.StreamName, 30)
	}
}

func (s *StreamMigrator) isCreated(st kinesis.CreateStreamInput) bool {
	_, err := s.describe(st)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeStreamNotFound {
			return false
		}
		panicWithError(err)

	}

	return true
}

func (s *StreamMigrator) create(st kinesis.CreateStreamInput) {
	err := s.Client.CreateStream(&st)
	if err != nil {
		panicWithError(err)
	}
}

func (s *StreamMigrator) describe(st kinesis.CreateStreamInput) (*kinesis.DescribeStreamOutput, error) {
	req := kinesis.DescribeStreamInput{
		StreamName: st.StreamName,
	}
	resp, err := s.Client.DescribeStream(&req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *StreamMigrator) awaitActive(stream aws.StringValue, atMostSeconds int) {

	waited := 0
	status := kinesis.StreamStatusCreating
	for status != kinesis.StreamStatusActive {
		desc, err := s.Client.DescribeStream(&kinesis.DescribeStreamInput{
			StreamName: stream,
		})
		if err != nil {
			log.Printf("component=kinesis-migrator fn=awaitActive at=describe-error error=%s", err)
			panicWithError(err)
		}
		log.Printf("component=kinesis-migrator fn=awaitActive stream=%s at=describe status=%s", *stream, *desc.StreamDescription.StreamStatus)
		status = *desc.StreamDescription.StreamStatus
		time.Sleep(1 * time.Second)
		waited++
		if waited >= atMostSeconds {
			log.Printf("component=kinesis-migrator fn=awaitActive streal=%s  at=error error=exeeeded-max-wait", *stream)
			panic("waited too long")
		}
	}
}

func panicWithError(err error) {
	if ae, ok := err.(aws.APIError); ok {
		panic(fmt.Sprintf("aws error while migrating type=%s message=%s code=%s request-id=%s", ae.Type, ae.Message, ae.Code, ae.RequestID))
	}

	panic(err)
}
<commit_msg>fmtffs<commit_after>package migrator

import (
	"log"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/kinesis"
	"github.com/awslabs/aws-sdk-go/gen/swf"
	. "github.com/sclasen/swfsm/sugar"
	//"github.com/awslabs/aws-sdk-go/gen/dynamodb"
	"fmt"
	"time"
)

// TypesMigrator is composed of a DomainMigrator, a WorkflowTypeMigrator and an ActivityTypeMigrator.
type TypesMigrator struct {
	DomainMigrator       *DomainMigrator
	WorkflowTypeMigrator *WorkflowTypeMigrator
	ActivityTypeMigrator *ActivityTypeMigrator
	StreamMigrator       *StreamMigrator
}

type SWFOps interface {
	DeprecateActivityType(req *swf.DeprecateActivityTypeInput) (err error)
	DeprecateDomain(req *swf.DeprecateDomainInput) (err error)
	DeprecateWorkflowType(req *swf.DeprecateWorkflowTypeInput) (err error)
	DescribeActivityType(req *swf.DescribeActivityTypeInput) (resp *swf.ActivityTypeDetail, err error)
	DescribeDomain(req *swf.DescribeDomainInput) (resp *swf.DomainDetail, err error)
	DescribeWorkflowExecution(req *swf.DescribeWorkflowExecutionInput) (resp *swf.WorkflowExecutionDetail, err error)
	DescribeWorkflowType(req *swf.DescribeWorkflowTypeInput) (resp *swf.WorkflowTypeDetail, err error)
	RegisterActivityType(req *swf.RegisterActivityTypeInput) (err error)
	RegisterDomain(req *swf.RegisterDomainInput) (err error)
	RegisterWorkflowType(req *swf.RegisterWorkflowTypeInput) (err error)
}

type KinesisOps interface {
	CreateStream(req *kinesis.CreateStreamInput) (err error)
	DescribeStream(req *kinesis.DescribeStreamInput) (resp *kinesis.DescribeStreamOutput, err error)
}

// Migrate runs Migrate on the underlying DomainMigrator, a WorkflowTypeMigrator and ActivityTypeMigrator.
func (t *TypesMigrator) Migrate() {
	if t.ActivityTypeMigrator == nil {
		t.ActivityTypeMigrator = new(ActivityTypeMigrator)
	}
	if t.DomainMigrator == nil {
		t.DomainMigrator = new(DomainMigrator)
	}
	if t.WorkflowTypeMigrator == nil {
		t.WorkflowTypeMigrator = new(WorkflowTypeMigrator)
	}
	if t.StreamMigrator == nil {
		t.StreamMigrator = new(StreamMigrator)
	}
	t.DomainMigrator.Migrate()
	t.WorkflowTypeMigrator.Migrate()
	t.ActivityTypeMigrator.Migrate()
	t.StreamMigrator.Migrate()
}

// DomainMigrator will register or deprecate the configured domains as required.
type DomainMigrator struct {
	RegisteredDomains []swf.RegisterDomainInput
	DeprecatedDomains []swf.DeprecateDomainInput
	Client            SWFOps
}

// Migrate asserts that DeprecatedDomains are deprecated or deprecates them, then asserts that RegisteredDomains are registered or registers them.
func (d *DomainMigrator) Migrate() {
	for _, dd := range d.DeprecatedDomains {
		if d.isDeprecated(dd.Name) {
			log.Printf("action=migrate at=deprecate-domain domain=%s status=previously-deprecated", LS(dd.Name))
		} else {
			d.deprecate(dd)
			log.Printf("action=migrate at=deprecate-domain domain=%s status=deprecated", LS(dd.Name))
		}
	}
	for _, r := range d.RegisteredDomains {
		if d.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-domain domain=%s status=previously-registered", LS(r.Name))
		} else {
			d.register(r)
			log.Printf("action=migrate at=register-domain domain=%s status=registered", LS(r.Name))
		}
	}
}

func (d *DomainMigrator) isRegisteredNotDeprecated(rd swf.RegisterDomainInput) bool {
	desc, err := d.describe(rd.Name)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.DomainInfo.Status == swf.RegistrationStatusRegistered
}

func (d *DomainMigrator) register(rd swf.RegisterDomainInput) {
	err := d.Client.RegisterDomain(&rd)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeDomainAlreadyExistsFault {
			return
		}

		panicWithError(err)

	}
}

func (d *DomainMigrator) isDeprecated(domain aws.StringValue) bool {
	desc, err := d.describe(domain)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s error=%s", LS(domain), err.Error())
		return false
	}

	return *desc.DomainInfo.Status == swf.RegistrationStatusDeprecated
}

func (d *DomainMigrator) deprecate(dd swf.DeprecateDomainInput) {
	err := d.Client.DeprecateDomain(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (d *DomainMigrator) describe(domain aws.StringValue) (*swf.DomainDetail, error) {
	resp, err := d.Client.DescribeDomain(&swf.DescribeDomainInput{Name: domain})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// WorkflowTypeMigrator will register or deprecate the configured workflow types as required.
type WorkflowTypeMigrator struct {
	RegisteredWorkflowTypes []swf.RegisterWorkflowTypeInput
	DeprecatedWorkflowTypes []swf.DeprecateWorkflowTypeInput
	Client                  SWFOps
}

// Migrate asserts that DeprecatedWorkflowTypes are deprecated or deprecates them, then asserts that RegisteredWorkflowTypes are registered or registers them.
func (w *WorkflowTypeMigrator) Migrate() {
	for _, dd := range w.DeprecatedWorkflowTypes {
		if w.isDeprecated(dd.Domain, dd.WorkflowType.Name, dd.WorkflowType.Version) {
			log.Printf("action=migrate at=deprecate-workflow domain=%s workflow=%s version=%s status=previously-deprecated", LS(dd.Domain), LS(dd.WorkflowType.Name), LS(dd.WorkflowType.Version))
		} else {
			w.deprecate(dd)
			log.Printf("action=migrate at=deprecate-workflow domain=%s  workflow=%s version=%s status=deprecate", LS(dd.Domain), LS(dd.WorkflowType.Name), LS(dd.WorkflowType.Version))
		}
	}
	for _, r := range w.RegisteredWorkflowTypes {
		if w.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-workflow domain=%s workflow=%s version=%s status=previously-registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		} else {
			w.register(r)
			log.Printf("action=migrate at=register-workflow domain=%s  workflow=%s version=%s status=registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		}
	}
}

func (w *WorkflowTypeMigrator) isRegisteredNotDeprecated(rd swf.RegisterWorkflowTypeInput) bool {
	desc, err := w.describe(rd.Domain, rd.Name, rd.Version)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusRegistered
}

func (w *WorkflowTypeMigrator) register(rd swf.RegisterWorkflowTypeInput) {
	err := w.Client.RegisterWorkflowType(&rd)
	if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeAlreadyExistsFault {
		return
	}

	panicWithError(err)
}

func (w *WorkflowTypeMigrator) isDeprecated(domain aws.StringValue, name aws.StringValue, version aws.StringValue) bool {
	desc, err := w.describe(domain, name, version)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s workflow=%s version=%s error=%s", LS(domain), LS(name), LS(version), err.Error())
		return false
	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusDeprecated
}

func (w *WorkflowTypeMigrator) deprecate(dd swf.DeprecateWorkflowTypeInput) {
	err := w.Client.DeprecateWorkflowType(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (w *WorkflowTypeMigrator) describe(domain aws.StringValue, name aws.StringValue, version aws.StringValue) (*swf.WorkflowTypeDetail, error) {
	resp, err := w.Client.DescribeWorkflowType(&swf.DescribeWorkflowTypeInput{Domain: domain, WorkflowType: &swf.WorkflowType{Name: name, Version: version}})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// ActivityTypeMigrator will register or deprecate the configured activity types as required.
type ActivityTypeMigrator struct {
	RegisteredActivityTypes []swf.RegisterActivityTypeInput
	DeprecatedActivityTypes []swf.DeprecateActivityTypeInput
	Client                  SWFOps
}

// Migrate asserts that DeprecatedActivityTypes are deprecated or deprecates them, then asserts that RegisteredActivityTypes are registered or registers them.
func (a *ActivityTypeMigrator) Migrate() {
	for _, d := range a.DeprecatedActivityTypes {
		if a.isDeprecated(d.Domain, d.ActivityType.Name, d.ActivityType.Version) {
			log.Printf("action=migrate at=deprecate-activity domain=%s activity=%s version=%s status=previously-deprecated", LS(d.Domain), LS(d.ActivityType.Name), LS(d.ActivityType.Version))
		} else {
			a.deprecate(d)
			log.Printf("action=migrate at=depreacate-activity domain=%s activity=%s version=%s status=deprecated", LS(d.Domain), LS(d.ActivityType.Name), LS(d.ActivityType.Version))
		}
	}
	for _, r := range a.RegisteredActivityTypes {
		if a.isRegisteredNotDeprecated(r) {
			log.Printf("action=migrate at=register-activity domain=%s activity=%s version=%s status=previously-registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		} else {
			a.register(r)
			log.Printf("action=migrate at=register-activity domain=%s activity=%s version=%s status=registered", LS(r.Domain), LS(r.Name), LS(r.Version))
		}
	}
}

func (a *ActivityTypeMigrator) isRegisteredNotDeprecated(rd swf.RegisterActivityTypeInput) bool {
	desc, err := a.describe(rd.Domain, rd.Name, rd.Version)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeUnknownResourceFault {
			return false
		}

		panicWithError(err)

	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusRegistered
}

func (a *ActivityTypeMigrator) register(rd swf.RegisterActivityTypeInput) {
	err := a.Client.RegisterActivityType(&rd)
	if err != nil {
		panicWithError(err)
	}
}

func (a *ActivityTypeMigrator) isDeprecated(domain aws.StringValue, name aws.StringValue, version aws.StringValue) bool {
	desc, err := a.describe(domain, name, version)
	if err != nil {
		log.Printf("action=migrate at=is-dep domain=%s activity=%s version=%s error=%s", LS(domain), LS(name), LS(version), err.Error())
		return false
	}

	return *desc.TypeInfo.Status == swf.RegistrationStatusDeprecated
}

func (a *ActivityTypeMigrator) deprecate(dd swf.DeprecateActivityTypeInput) {
	err := a.Client.DeprecateActivityType(&dd)
	if err != nil {
		panicWithError(err)
	}
}

func (a *ActivityTypeMigrator) describe(domain aws.StringValue, name aws.StringValue, version aws.StringValue) (*swf.ActivityTypeDetail, error) {
	resp, err := a.Client.DescribeActivityType(&swf.DescribeActivityTypeInput{Domain: domain, ActivityType: &swf.ActivityType{Name: name, Version: version}})
	if err != nil {
		return nil, err
	}
	return resp, nil
}

// StreamMigrator will create any Kinesis Streams required.
type StreamMigrator struct {
	Streams []kinesis.CreateStreamInput
	Client  KinesisOps
}

// Migrate checks that the desired streams have been created and if they have not, creates them.s
func (s *StreamMigrator) Migrate() {
	for _, st := range s.Streams {
		if s.isCreated(st) {
			log.Printf("action=migrate at=create-stream stream=%s status=previously-created", LS(st.StreamName))
		} else {
			s.create(st)
			log.Printf("action=migrate at=create-stream stream=%s status=created", LS(st.StreamName))
		}
		s.awaitActive(st.StreamName, 30)
	}
}

func (s *StreamMigrator) isCreated(st kinesis.CreateStreamInput) bool {
	_, err := s.describe(st)
	if err != nil {
		if ae, ok := err.(aws.APIError); ok && ae.Type == ErrorTypeStreamNotFound {
			return false
		}
		panicWithError(err)

	}

	return true
}

func (s *StreamMigrator) create(st kinesis.CreateStreamInput) {
	err := s.Client.CreateStream(&st)
	if err != nil {
		panicWithError(err)
	}
}

func (s *StreamMigrator) describe(st kinesis.CreateStreamInput) (*kinesis.DescribeStreamOutput, error) {
	req := kinesis.DescribeStreamInput{
		StreamName: st.StreamName,
	}
	resp, err := s.Client.DescribeStream(&req)
	if err != nil {
		return nil, err
	}
	return resp, nil
}

func (s *StreamMigrator) awaitActive(stream aws.StringValue, atMostSeconds int) {

	waited := 0
	status := kinesis.StreamStatusCreating
	for status != kinesis.StreamStatusActive {
		desc, err := s.Client.DescribeStream(&kinesis.DescribeStreamInput{
			StreamName: stream,
		})
		if err != nil {
			log.Printf("component=kinesis-migrator fn=awaitActive at=describe-error error=%s", err)
			panicWithError(err)
		}
		log.Printf("component=kinesis-migrator fn=awaitActive stream=%s at=describe status=%s", *stream, *desc.StreamDescription.StreamStatus)
		status = *desc.StreamDescription.StreamStatus
		time.Sleep(1 * time.Second)
		waited++
		if waited >= atMostSeconds {
			log.Printf("component=kinesis-migrator fn=awaitActive streal=%s  at=error error=exeeeded-max-wait", *stream)
			panic("waited too long")
		}
	}
}

func panicWithError(err error) {
	if ae, ok := err.(aws.APIError); ok {
		panic(fmt.Sprintf("aws error while migrating type=%s message=%s code=%s request-id=%s", ae.Type, ae.Message, ae.Code, ae.RequestID))
	}

	panic(err)
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/lang"
	"github.com/zclconf/go-cty/cty"
)

// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
// its module path expanded.
type nodeExpandModuleVariable struct {
	Addr   addrs.InputVariable
	Module addrs.Module
	Config *configs.Variable
	Expr   hcl.Expression
}

var (
	_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceOutside  = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceable     = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferencer        = (*nodeExpandModuleVariable)(nil)
	_ graphNodeTemporaryValue    = (*nodeExpandModuleVariable)(nil)
	_ RemovableIfNotTargeted     = (*nodeExpandModuleVariable)(nil)
	_ graphNodeExpandsInstances  = (*nodeExpandModuleVariable)(nil)
)

func (n *nodeExpandModuleVariable) expandsInstances() {}

func (n *nodeExpandModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
	var g Graph
	expander := ctx.InstanceExpander()
	for _, module := range expander.ExpandModule(n.Module) {
		o := &nodeModuleVariable{
			Addr:           n.Addr.Absolute(module),
			Config:         n.Config,
			Expr:           n.Expr,
			ModuleInstance: module,
		}
		g.Add(o)
	}
	return &g, nil
}

func (n *nodeExpandModuleVariable) Name() string {
	return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
}

// GraphNodeModulePath
func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
	return n.Module
}

// GraphNodeReferencer
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {

	// If we have no value expression, we cannot depend on anything.
	if n.Expr == nil {
		return nil
	}

	// Variables in the root don't depend on anything, because their values
	// are gathered prior to the graph walk and recorded in the context.
	if len(n.Module) == 0 {
		return nil
	}

	// Otherwise, we depend on anything referenced by our value expression.
	// We ignore diagnostics here under the assumption that we'll re-eval
	// all these things later and catch them then; for our purposes here,
	// we only care about valid references.
	//
	// Due to our GraphNodeReferenceOutside implementation, the addresses
	// returned by this function are interpreted in the _parent_ module from
	// where our associated variable was declared, which is correct because
	// our value expression is assigned within a "module" block in the parent
	// module.
	refs, _ := lang.ReferencesInExpr(n.Expr)
	return refs
}

// GraphNodeReferenceOutside implementation
func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
	return n.Module, n.Module.Parent()
}

// GraphNodeReferenceable
func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
	// FIXME: References for module variables probably need to be thought out a bit more
	// Otherwise, we can reference the output via the address itself, or the
	// module call
	_, call := n.Module.Call()
	return []addrs.Referenceable{n.Addr, call}
}

// RemovableIfNotTargeted
func (n *nodeExpandModuleVariable) RemoveIfNotTargeted() bool {
	return true
}

// GraphNodeTargetDownstream
func (n *nodeExpandModuleVariable) TargetDownstream(targetedDeps, untargetedDeps dag.Set) bool {
	return true
}

// nodeModuleVariable represents a module variable input during
// the apply step.
type nodeModuleVariable struct {
	Addr   addrs.AbsInputVariableInstance
	Config *configs.Variable // Config is the var in the config
	Expr   hcl.Expression    // Expr is the value expression given in the call
	// ModuleInstance in order to create the appropriate context for evaluating
	// ModuleCallArguments, ex. so count.index and each.key can resolve
	ModuleInstance addrs.ModuleInstance
}

// Ensure that we are implementing all of the interfaces we think we are
// implementing.
var (
	_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
	_ RemovableIfNotTargeted  = (*nodeModuleVariable)(nil)
	_ GraphNodeEvalable       = (*nodeModuleVariable)(nil)
	_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
	_ dag.GraphNodeDotter     = (*nodeModuleVariable)(nil)
)

func (n *nodeModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeModuleVariable) Name() string {
	return n.Addr.String()
}

// GraphNodeModuleInstance
func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
	// We execute in the parent scope (above our own module) because
	// expressions in our value are resolved in that context.
	return n.Addr.Module.Parent()
}

// GraphNodeModulePath
func (n *nodeModuleVariable) ModulePath() addrs.Module {
	return n.Addr.Module.Parent().Module()
}

// RemovableIfNotTargeted
func (n *nodeModuleVariable) RemoveIfNotTargeted() bool {
	// We need to add this so that this node will be removed if
	// it isn't targeted or a dependency of a target.
	return true
}

// GraphNodeEvalable
func (n *nodeModuleVariable) EvalTree() EvalNode {
	// If we have no value, do nothing
	if n.Expr == nil {
		return &EvalNoop{}
	}

	// Otherwise, interpolate the value of this variable and set it
	// within the variables mapping.
	vals := make(map[string]cty.Value)

	_, call := n.Addr.Module.CallInstance()

	return &EvalSequence{
		Nodes: []EvalNode{
			&EvalOpFilter{
				Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
					walkDestroy},
				Node: &EvalModuleCallArgument{
					Addr:           n.Addr.Variable,
					Config:         n.Config,
					Expr:           n.Expr,
					ModuleInstance: n.ModuleInstance,
					Values:         vals,
				},
			},

			&EvalOpFilter{
				Ops: []walkOperation{walkValidate},
				Node: &EvalModuleCallArgument{
					Addr:           n.Addr.Variable,
					Config:         n.Config,
					Expr:           n.Expr,
					ModuleInstance: n.ModuleInstance,
					Values:         vals,
					validateOnly:   true,
				},
			},

			&EvalSetModuleCallArguments{
				Module: call,
				Values: vals,
			},

			&evalVariableValidations{
				Addr:   n.Addr,
				Config: n.Config,
				Expr:   n.Expr,
			},
		},
	}
}

// dag.GraphNodeDotter impl.
func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
	return &dag.DotNode{
		Name: name,
		Attrs: map[string]string{
			"label": n.Name(),
			"shape": "note",
		},
	}
}
<commit_msg>variable ModulePath must return configured path<commit_after>package terraform

import (
	"fmt"

	"github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/terraform/addrs"
	"github.com/hashicorp/terraform/configs"
	"github.com/hashicorp/terraform/dag"
	"github.com/hashicorp/terraform/lang"
	"github.com/zclconf/go-cty/cty"
)

// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
// its module path expanded.
type nodeExpandModuleVariable struct {
	Addr   addrs.InputVariable
	Module addrs.Module
	Config *configs.Variable
	Expr   hcl.Expression
}

var (
	_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceOutside  = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferenceable     = (*nodeExpandModuleVariable)(nil)
	_ GraphNodeReferencer        = (*nodeExpandModuleVariable)(nil)
	_ graphNodeTemporaryValue    = (*nodeExpandModuleVariable)(nil)
	_ RemovableIfNotTargeted     = (*nodeExpandModuleVariable)(nil)
	_ graphNodeExpandsInstances  = (*nodeExpandModuleVariable)(nil)
)

func (n *nodeExpandModuleVariable) expandsInstances() {}

func (n *nodeExpandModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
	var g Graph
	expander := ctx.InstanceExpander()
	for _, module := range expander.ExpandModule(n.Module) {
		o := &nodeModuleVariable{
			Addr:           n.Addr.Absolute(module),
			Config:         n.Config,
			Expr:           n.Expr,
			ModuleInstance: module,
		}
		g.Add(o)
	}
	return &g, nil
}

func (n *nodeExpandModuleVariable) Name() string {
	return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
}

// GraphNodeModulePath
func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
	return n.Module
}

// GraphNodeReferencer
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {

	// If we have no value expression, we cannot depend on anything.
	if n.Expr == nil {
		return nil
	}

	// Variables in the root don't depend on anything, because their values
	// are gathered prior to the graph walk and recorded in the context.
	if len(n.Module) == 0 {
		return nil
	}

	// Otherwise, we depend on anything referenced by our value expression.
	// We ignore diagnostics here under the assumption that we'll re-eval
	// all these things later and catch them then; for our purposes here,
	// we only care about valid references.
	//
	// Due to our GraphNodeReferenceOutside implementation, the addresses
	// returned by this function are interpreted in the _parent_ module from
	// where our associated variable was declared, which is correct because
	// our value expression is assigned within a "module" block in the parent
	// module.
	refs, _ := lang.ReferencesInExpr(n.Expr)
	return refs
}

// GraphNodeReferenceOutside implementation
func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
	return n.Module, n.Module.Parent()
}

// GraphNodeReferenceable
func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
	// FIXME: References for module variables probably need to be thought out a bit more
	// Otherwise, we can reference the output via the address itself, or the
	// module call
	_, call := n.Module.Call()
	return []addrs.Referenceable{n.Addr, call}
}

// RemovableIfNotTargeted
func (n *nodeExpandModuleVariable) RemoveIfNotTargeted() bool {
	return true
}

// GraphNodeTargetDownstream
func (n *nodeExpandModuleVariable) TargetDownstream(targetedDeps, untargetedDeps dag.Set) bool {
	return true
}

// nodeModuleVariable represents a module variable input during
// the apply step.
type nodeModuleVariable struct {
	Addr   addrs.AbsInputVariableInstance
	Config *configs.Variable // Config is the var in the config
	Expr   hcl.Expression    // Expr is the value expression given in the call
	// ModuleInstance in order to create the appropriate context for evaluating
	// ModuleCallArguments, ex. so count.index and each.key can resolve
	ModuleInstance addrs.ModuleInstance
}

// Ensure that we are implementing all of the interfaces we think we are
// implementing.
var (
	_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
	_ RemovableIfNotTargeted  = (*nodeModuleVariable)(nil)
	_ GraphNodeEvalable       = (*nodeModuleVariable)(nil)
	_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
	_ dag.GraphNodeDotter     = (*nodeModuleVariable)(nil)
)

func (n *nodeModuleVariable) temporaryValue() bool {
	return true
}

func (n *nodeModuleVariable) Name() string {
	return n.Addr.String()
}

// GraphNodeModuleInstance
func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
	// We execute in the parent scope (above our own module) because
	// expressions in our value are resolved in that context.
	return n.Addr.Module.Parent()
}

// GraphNodeModulePath
func (n *nodeModuleVariable) ModulePath() addrs.Module {
	return n.Addr.Module.Module()
}

// RemovableIfNotTargeted
func (n *nodeModuleVariable) RemoveIfNotTargeted() bool {
	// We need to add this so that this node will be removed if
	// it isn't targeted or a dependency of a target.
	return true
}

// GraphNodeEvalable
func (n *nodeModuleVariable) EvalTree() EvalNode {
	// If we have no value, do nothing
	if n.Expr == nil {
		return &EvalNoop{}
	}

	// Otherwise, interpolate the value of this variable and set it
	// within the variables mapping.
	vals := make(map[string]cty.Value)

	_, call := n.Addr.Module.CallInstance()

	return &EvalSequence{
		Nodes: []EvalNode{
			&EvalOpFilter{
				Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
					walkDestroy},
				Node: &EvalModuleCallArgument{
					Addr:           n.Addr.Variable,
					Config:         n.Config,
					Expr:           n.Expr,
					ModuleInstance: n.ModuleInstance,
					Values:         vals,
				},
			},

			&EvalOpFilter{
				Ops: []walkOperation{walkValidate},
				Node: &EvalModuleCallArgument{
					Addr:           n.Addr.Variable,
					Config:         n.Config,
					Expr:           n.Expr,
					ModuleInstance: n.ModuleInstance,
					Values:         vals,
					validateOnly:   true,
				},
			},

			&EvalSetModuleCallArguments{
				Module: call,
				Values: vals,
			},

			&evalVariableValidations{
				Addr:   n.Addr,
				Config: n.Config,
				Expr:   n.Expr,
			},
		},
	}
}

// dag.GraphNodeDotter impl.
func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
	return &dag.DotNode{
		Name: name,
		Attrs: map[string]string{
			"label": n.Name(),
			"shape": "note",
		},
	}
}
<|endoftext|>


<commit_before>package openapi

import (
	"net/http"
	"net/url"
)

var defaultBaseURL = "https://api.bearychat.com/v1/"

// Client interacts with BearyChat's API.
type Client struct {
	// HTTP client for calling the API.
	// Use http.DefaultClient by default.
	httpClient *http.Client

	// Base URL for API requests. Defaults to BearyChat's OpenAPI host.
	// BaseURL should always be specified with a trailing slash.
	BaseURL *url.URL

	// Access token for the client.
	Token string

	// Shared services holder to reduce real service allocating.
	base service
}

type service struct {
	client *Client
}

type clientOpt func(c *Client)

// NewClientWithBaseURL binds BaseURL to client.
func NewClientWithBaseURL(u *url.URL) clientOpt {
	return func(c *Client) {
		c.BaseURL = u
	}
}

// NewClientWithHTTPClient binds http client to client.
func NewClientWithHTTPClient(httpClient *http.Client) clientOpt {
	return func(c *Client) {
		c.httpClient = httpClient
	}
}

// NewClient constructs a client with given access token.
// Other settings can set via clientOpt functions.
func NewClient(token string, opts ...clientOpt) *Client {
	c := &Client{
		Token: token,
	}

	for _, o := range opts {
		o(c)
	}

	if c.httpClient == nil {
		c.httpClient = http.DefaultClient
	}

	if c.BaseURL == nil {
		baseURL, _ := url.Parse(defaultBaseURL)
		c.BaseURL = baseURL
	}

	c.base.client = c

	return c
}
<commit_msg>feat(openapi.client): implement api client<commit_after>package openapi

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

var defaultBaseURL = "https://api.bearychat.com/v1/"

// Client interacts with BearyChat's API.
type Client struct {
	// HTTP client for calling the API.
	// Use http.DefaultClient by default.
	httpClient *http.Client

	// Base URL for API requests. Defaults to BearyChat's OpenAPI host.
	// BaseURL should always be specified with a trailing slash.
	BaseURL *url.URL

	// Access token for the client.
	Token string

	// Shared services holder to reduce real service allocating.
	base service
}

type service struct {
	client *Client
}

type clientOpt func(c *Client)

// NewClientWithBaseURL binds BaseURL to client.
func NewClientWithBaseURL(u *url.URL) clientOpt {
	return func(c *Client) {
		c.BaseURL = u
	}
}

// NewClientWithHTTPClient binds http client to client.
func NewClientWithHTTPClient(httpClient *http.Client) clientOpt {
	return func(c *Client) {
		c.httpClient = httpClient
	}
}

// NewClient constructs a client with given access token.
// Other settings can set via clientOpt functions.
func NewClient(token string, opts ...clientOpt) *Client {
	c := &Client{
		Token: token,
	}

	for _, o := range opts {
		o(c)
	}

	if c.httpClient == nil {
		c.httpClient = http.DefaultClient
	}

	if c.BaseURL == nil {
		baseURL, _ := url.Parse(defaultBaseURL)
		c.BaseURL = baseURL
	}

	c.base.client = c
	c.Team = (*TeamService)(&c.base)

	return c
}

// newRequest creates an API request. API method should specified without a leading slash.
// If specified, the value pointed to body is JSON encoded and included as the request body.
func (c *Client) newRequest(requestMethod, apiMethod string, body interface{}) (*http.Request, error) {
	m, err := url.Parse(apiMethod)
	if err != nil {
		return nil, err
	}

	u := c.BaseURL.ResolveReference(m)
	q := u.Query()
	q.Set("token", c.Token)
	u.RawQuery = q.Encode()

	var buf io.ReadWriter
	if body != nil {
		buf = &bytes.Buffer{}
		err := json.NewEncoder(buf).Encode(body)
		if err != nil {
			return nil, err
		}
	}

	req, err := http.NewRequest(requestMethod, u.String(), buf)
	if err != nil {
		return nil, err
	}

	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}

	return req, nil
}

// do sends an API request and returns the API response. The API response is JSON decoded and
// stored in the value pointed to v. If v implements the io.Writer interface, the raw response body
// will be written to v, without attempting to first decode it.
//
// The provided ctx must be non-nil. If it is canceled or times out, ctx.Err() will be returned.
func (c *Client) do(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) {
	req = req.WithContext(ctx)

	resp, err := c.httpClient.Do(req)
	if err != nil {
		// try to use context's error
		select {
		case <-ctx.Done():
			return nil, ctx.Err()
		default:
		}

		return nil, err
	}

	defer resp.Body.Close()

	err = CheckResponse(resp)
	if err != nil {
		return resp, err
	}

	if v != nil {
		if w, ok := v.(io.Writer); ok {
			io.Copy(w, resp.Body)
		} else {
			err = json.NewDecoder(resp.Body).Decode(v)
		}
	}

	return resp, err
}

// ErrorResponse represents errors caused by an API request.
type ErrorResponse struct {
	// HTTP response that caused this error
	Response    *http.Response
	ErrorCode   int    `json:"code"`
	ErrorReason string `json:"error"`
}

func (r ErrorResponse) Error() string {
	return fmt.Sprintf(
		"%v %v: %d %d %s",
		r.Response.Request.Method,
		r.Response.Request.URL,
		r.Response.StatusCode,
		r.ErrorCode,
		r.ErrorReason,
	)
}

// CheckResponse checks the API response for errors, and returns them if present.
func CheckResponse(r *http.Response) error {
	if c := r.StatusCode; 200 <= c && c <= 299 {
		return nil
	}

	errResponse := &ErrorResponse{Response: r}
	data, err := ioutil.ReadAll(r.Body)
	if err == nil && data != nil {
		json.Unmarshal(data, errResponse)
	}

	// TODO(hbc): handle ratelimit error

	return errResponse
}

const timeLayout = "2006-01-02T15:04:05-0700"

// Time with custom JSON format.
type Time struct {
	time.Time
}

func (t Time) UnmarshalJSON(b []byte) (err error) {
	s := strings.Trim(string(b), "\"")
	t.Time, err = time.Parse(timeLayout, s)
	return
}

func (t Time) MarshalJSON() ([]byte, error) {
	return []byte(fmt.Sprintf("\"%s\"", t.Time.Format(timeLayout))), nil
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 builder

import (
	"fmt"
	"path/filepath"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/toolchain"
	"mynewt.apache.org/newt/util"
)

// Indicates whether a package's API dependency has been another package.
type reqApiStatus int

const (
	REQ_API_STATUS_UNSATISFIED reqApiStatus = iota
	REQ_API_STATUS_SATISFIED
)

type BuildPackage struct {
	*pkg.LocalPackage

	ci *toolchain.CompilerInfo

	// Keeps track of API requirements and whether they are satisfied.
	reqApiMap map[string]reqApiStatus

	depsResolved  bool
	apisSatisfied bool
}

// Recursively iterates through an pkg's dependencies, adding each pkg
// encountered to the supplied set.
func (bpkg *BuildPackage) collectDepsAux(b *Builder,
	set *map[*BuildPackage]bool) error {

	if (*set)[bpkg] {
		return nil
	}

	(*set)[bpkg] = true

	for _, dep := range bpkg.Deps() {
		if dep.Name == "" {
			break
		}

		// Get pkg structure
		dpkg := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
		if dpkg == nil {
			return util.NewNewtError("Cannot resolve dependency " + dep.String())
		}

		dbpkg := b.Packages[dpkg]
		if dbpkg == nil {
			return util.NewNewtError(fmt.Sprintf("Package not found (%s)",
				dpkg.Name()))
		}

		if err := dbpkg.collectDepsAux(b, set); err != nil {
			return err
		}
	}

	return nil
}

// Recursively iterates through an pkg's dependencies.  The resulting array
// contains a pointer to each encountered pkg.
func (bpkg *BuildPackage) collectDeps(b *Builder) ([]*BuildPackage, error) {
	set := map[*BuildPackage]bool{}

	err := bpkg.collectDepsAux(b, &set)
	if err != nil {
		return nil, err
	}

	arr := []*BuildPackage{}
	for p, _ := range set {
		arr = append(arr, p)
	}

	return arr, nil
}

// Calculates the include paths exported by the specified pkg and all of
// its recursive dependencies.
func (bpkg *BuildPackage) recursiveIncludePaths(b *Builder) ([]string, error) {
	deps, err := bpkg.collectDeps(b)
	if err != nil {
		return nil, err
	}

	incls := []string{}
	for _, p := range deps {
		incls = append(incls, p.publicIncludeDirs(b)...)
	}

	return incls, nil
}

func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, error) {
	if !bpkg.depsResolved || !bpkg.apisSatisfied {
		return nil, util.NewNewtError("Package must be resolved before " +
			"compiler info is fetched; package=" + bpkg.Name())
	}

	// If this package's compiler info has already been generated, returned the
	// cached copy.
	if bpkg.ci != nil {
		return bpkg.ci, nil
	}

	ci := toolchain.NewCompilerInfo()
	ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.cflags")
	ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.lflags")
	ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.aflags")

	includePaths, err := bpkg.recursiveIncludePaths(b)
	if err != nil {
		return nil, err
	}
	ci.Includes = append(bpkg.privateIncludeDirs(b), includePaths...)
	bpkg.ci = ci

	return bpkg.ci, nil
}

func (bpkg *BuildPackage) loadFeatures(b *Builder) (map[string]bool, bool) {
	features := b.Features()

	foundNewFeature := false

	newFeatures := newtutil.GetStringSliceFeatures(bpkg.Viper, features,
		"pkg.features")
	for _, nfeature := range newFeatures {
		_, ok := features[nfeature]
		if !ok {
			b.AddFeature(nfeature)
			foundNewFeature = true
		}
	}

	return b.Features(), foundNewFeature
}

// Searches for a package which can satisfy bpkg's API requirement.  If such a
// package is found, bpkg's API requirement is marked as satisfied, and the
// package is added to bpkg's dependency list.
func (bpkg *BuildPackage) satisfyReqApi(b *Builder, reqApi string) bool {
	depBpkg := b.apis[reqApi]
	if depBpkg == nil {
		return false
	}

	dep := &pkg.Dependency{
		Name: depBpkg.Name(),
		Repo: depBpkg.Repo().Name(),
	}
	bpkg.AddDep(dep)
	bpkg.reqApiMap[reqApi] = REQ_API_STATUS_SATISFIED

	// This package now has a new unresolved dependency.
	bpkg.depsResolved = false

	util.StatusMessage(util.VERBOSITY_VERBOSE, "API requirement satisfied; "+
		"pkg=%s API=(%s, %s)\n", bpkg.Name(), reqApi, dep.String())

	return true
}

// @return bool                 True if this this function changed the builder
//                                  state; another full iteration is required
//                                  in this case.
//         error                non-nil on failure.
func (bpkg *BuildPackage) loadDeps(b *Builder,
	features map[string]bool) (bool, error) {

	proj := project.GetProject()

	changed := false

	newDeps := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.deps")
	for _, newDepStr := range newDeps {
		newDep, err := pkg.NewDependency(bpkg.Repo(), newDepStr)
		if err != nil {
			return false, err
		}

		pkg := proj.ResolveDependency(newDep).(*pkg.LocalPackage)
		if pkg == nil {
			return false, util.NewNewtError("Cannot resolve dependency: " +
				newDep.String())
		}

		if pkg == nil {
			return false,
				util.NewNewtError("Could not resolve package dependency " +
					newDep.String())
		}

		if b.Packages[pkg] == nil {
			changed = true
			b.AddPackage(pkg)
		}

		if !bpkg.HasDep(newDep) {
			changed = true
			bpkg.AddDep(newDep)
		}
	}

	// Determine if this package supports any APIs that we haven't seen
	// yet.  If so, another full iteration is required.
	apis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.apis")
	for _, api := range apis {
		newApi := b.AddApi(api, bpkg)
		if newApi {
			changed = true
		}
	}

	return changed, nil
}

func (bpkg *BuildPackage) satisfyApis(b *Builder) {
	// Assume all this package's APIs are satisfied.
	bpkg.apisSatisfied = true

	// Determine if any of the package's API requirements can now be satisfied.
	// If so, another full iteration is required.
	reqApis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.req_apis")
	for _, reqApi := range reqApis {
		reqStatus, ok := bpkg.reqApiMap[reqApi]
		if !ok {
			reqStatus = REQ_API_STATUS_UNSATISFIED
			bpkg.reqApiMap[reqApi] = reqStatus
		}

		if reqStatus == REQ_API_STATUS_UNSATISFIED {
			apiSatisfied := bpkg.satisfyReqApi(b, reqApi)
			if !apiSatisfied {
				bpkg.apisSatisfied = false
			}
		}
	}
}

func (bpkg *BuildPackage) publicIncludeDirs(b *Builder) []string {
	pkgBase := filepath.Base(bpkg.Name())

	return []string{
		bpkg.BasePath() + "/include",
		bpkg.BasePath() + "/include/" + pkgBase + "/arch/" + b.target.Arch,
	}
}

func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string {
	srcDir := bpkg.BasePath() + "/src/"

	incls := []string{}
	incls = append(incls, srcDir)
	incls = append(incls, srcDir+"/arch/"+b.target.Arch)

	if b.Features()["test"] {
		testSrcDir := srcDir + "/test"
		incls = append(incls, testSrcDir)
		incls = append(incls, testSrcDir+"/arch/"+b.target.Arch)
	}

	return incls
}

// Attempts to resolve all of a build package's dependencies, identities, APIs,
// and required APIs.  This function should be called repeatedly until the
// package is fully resolved.
//
// @return bool                 true if the package is fully resolved;
//                              false if another call is required.
func (bpkg *BuildPackage) Resolve(b *Builder) (bool, error) {
	if !bpkg.depsResolved {
		features, newFeatures := bpkg.loadFeatures(b)
		newDeps, err := bpkg.loadDeps(b, features)
		if err != nil {
			return false, err
		}

		bpkg.depsResolved = !newFeatures && !newDeps
	}

	if !bpkg.apisSatisfied {
		bpkg.satisfyApis(b)
	}

	return bpkg.depsResolved && bpkg.apisSatisfied, nil
}

func (bp *BuildPackage) Init(pkg *pkg.LocalPackage) {
	bp.LocalPackage = pkg
	bp.reqApiMap = map[string]reqApiStatus{}
}

func NewBuildPackage(pkg *pkg.LocalPackage) *BuildPackage {
	bpkg := &BuildPackage{}
	bpkg.Init(pkg)

	return bpkg
}
<commit_msg>Don't crash on unresolvable dependency.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 builder

import (
	"fmt"
	"path/filepath"

	"mynewt.apache.org/newt/newt/newtutil"
	"mynewt.apache.org/newt/newt/pkg"
	"mynewt.apache.org/newt/newt/project"
	"mynewt.apache.org/newt/newt/toolchain"
	"mynewt.apache.org/newt/util"
)

// Indicates whether a package's API dependency has been another package.
type reqApiStatus int

const (
	REQ_API_STATUS_UNSATISFIED reqApiStatus = iota
	REQ_API_STATUS_SATISFIED
)

type BuildPackage struct {
	*pkg.LocalPackage

	ci *toolchain.CompilerInfo

	// Keeps track of API requirements and whether they are satisfied.
	reqApiMap map[string]reqApiStatus

	depsResolved  bool
	apisSatisfied bool
}

// Recursively iterates through an pkg's dependencies, adding each pkg
// encountered to the supplied set.
func (bpkg *BuildPackage) collectDepsAux(b *Builder,
	set *map[*BuildPackage]bool) error {

	if (*set)[bpkg] {
		return nil
	}

	(*set)[bpkg] = true

	for _, dep := range bpkg.Deps() {
		if dep.Name == "" {
			break
		}

		// Get pkg structure
		dpkg := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
		if dpkg == nil {
			return util.NewNewtError("Cannot resolve dependency " + dep.String())
		}

		dbpkg := b.Packages[dpkg]
		if dbpkg == nil {
			return util.NewNewtError(fmt.Sprintf("Package not found (%s)",
				dpkg.Name()))
		}

		if err := dbpkg.collectDepsAux(b, set); err != nil {
			return err
		}
	}

	return nil
}

// Recursively iterates through an pkg's dependencies.  The resulting array
// contains a pointer to each encountered pkg.
func (bpkg *BuildPackage) collectDeps(b *Builder) ([]*BuildPackage, error) {
	set := map[*BuildPackage]bool{}

	err := bpkg.collectDepsAux(b, &set)
	if err != nil {
		return nil, err
	}

	arr := []*BuildPackage{}
	for p, _ := range set {
		arr = append(arr, p)
	}

	return arr, nil
}

// Calculates the include paths exported by the specified pkg and all of
// its recursive dependencies.
func (bpkg *BuildPackage) recursiveIncludePaths(b *Builder) ([]string, error) {
	deps, err := bpkg.collectDeps(b)
	if err != nil {
		return nil, err
	}

	incls := []string{}
	for _, p := range deps {
		incls = append(incls, p.publicIncludeDirs(b)...)
	}

	return incls, nil
}

func (bpkg *BuildPackage) CompilerInfo(b *Builder) (*toolchain.CompilerInfo, error) {
	if !bpkg.depsResolved || !bpkg.apisSatisfied {
		return nil, util.NewNewtError("Package must be resolved before " +
			"compiler info is fetched; package=" + bpkg.Name())
	}

	// If this package's compiler info has already been generated, returned the
	// cached copy.
	if bpkg.ci != nil {
		return bpkg.ci, nil
	}

	ci := toolchain.NewCompilerInfo()
	ci.Cflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.cflags")
	ci.Lflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.lflags")
	ci.Aflags = newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.aflags")

	includePaths, err := bpkg.recursiveIncludePaths(b)
	if err != nil {
		return nil, err
	}
	ci.Includes = append(bpkg.privateIncludeDirs(b), includePaths...)
	bpkg.ci = ci

	return bpkg.ci, nil
}

func (bpkg *BuildPackage) loadFeatures(b *Builder) (map[string]bool, bool) {
	features := b.Features()

	foundNewFeature := false

	newFeatures := newtutil.GetStringSliceFeatures(bpkg.Viper, features,
		"pkg.features")
	for _, nfeature := range newFeatures {
		_, ok := features[nfeature]
		if !ok {
			b.AddFeature(nfeature)
			foundNewFeature = true
		}
	}

	return b.Features(), foundNewFeature
}

// Searches for a package which can satisfy bpkg's API requirement.  If such a
// package is found, bpkg's API requirement is marked as satisfied, and the
// package is added to bpkg's dependency list.
func (bpkg *BuildPackage) satisfyReqApi(b *Builder, reqApi string) bool {
	depBpkg := b.apis[reqApi]
	if depBpkg == nil {
		return false
	}

	dep := &pkg.Dependency{
		Name: depBpkg.Name(),
		Repo: depBpkg.Repo().Name(),
	}
	bpkg.AddDep(dep)
	bpkg.reqApiMap[reqApi] = REQ_API_STATUS_SATISFIED

	// This package now has a new unresolved dependency.
	bpkg.depsResolved = false

	util.StatusMessage(util.VERBOSITY_VERBOSE, "API requirement satisfied; "+
		"pkg=%s API=(%s, %s)\n", bpkg.Name(), reqApi, dep.String())

	return true
}

// @return bool                 True if this this function changed the builder
//                                  state; another full iteration is required
//                                  in this case.
//         error                non-nil on failure.
func (bpkg *BuildPackage) loadDeps(b *Builder,
	features map[string]bool) (bool, error) {

	proj := project.GetProject()

	changed := false

	newDeps := newtutil.GetStringSliceFeatures(bpkg.Viper, features, "pkg.deps")
	for _, newDepStr := range newDeps {
		newDep, err := pkg.NewDependency(bpkg.Repo(), newDepStr)
		if err != nil {
			return false, err
		}

		pkg, ok := proj.ResolveDependency(newDep).(*pkg.LocalPackage)
		if !ok {
			return false,
				util.NewNewtError("Could not resolve package dependency " +
					newDep.String())
		}

		if b.Packages[pkg] == nil {
			changed = true
			b.AddPackage(pkg)
		}

		if !bpkg.HasDep(newDep) {
			changed = true
			bpkg.AddDep(newDep)
		}
	}

	// Determine if this package supports any APIs that we haven't seen
	// yet.  If so, another full iteration is required.
	apis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.apis")
	for _, api := range apis {
		newApi := b.AddApi(api, bpkg)
		if newApi {
			changed = true
		}
	}

	return changed, nil
}

func (bpkg *BuildPackage) satisfyApis(b *Builder) {
	// Assume all this package's APIs are satisfied.
	bpkg.apisSatisfied = true

	// Determine if any of the package's API requirements can now be satisfied.
	// If so, another full iteration is required.
	reqApis := newtutil.GetStringSliceFeatures(bpkg.Viper, b.Features(),
		"pkg.req_apis")
	for _, reqApi := range reqApis {
		reqStatus, ok := bpkg.reqApiMap[reqApi]
		if !ok {
			reqStatus = REQ_API_STATUS_UNSATISFIED
			bpkg.reqApiMap[reqApi] = reqStatus
		}

		if reqStatus == REQ_API_STATUS_UNSATISFIED {
			apiSatisfied := bpkg.satisfyReqApi(b, reqApi)
			if !apiSatisfied {
				bpkg.apisSatisfied = false
			}
		}
	}
}

func (bpkg *BuildPackage) publicIncludeDirs(b *Builder) []string {
	pkgBase := filepath.Base(bpkg.Name())

	return []string{
		bpkg.BasePath() + "/include",
		bpkg.BasePath() + "/include/" + pkgBase + "/arch/" + b.target.Arch,
	}
}

func (bpkg *BuildPackage) privateIncludeDirs(b *Builder) []string {
	srcDir := bpkg.BasePath() + "/src/"

	incls := []string{}
	incls = append(incls, srcDir)
	incls = append(incls, srcDir+"/arch/"+b.target.Arch)

	if b.Features()["test"] {
		testSrcDir := srcDir + "/test"
		incls = append(incls, testSrcDir)
		incls = append(incls, testSrcDir+"/arch/"+b.target.Arch)
	}

	return incls
}

// Attempts to resolve all of a build package's dependencies, identities, APIs,
// and required APIs.  This function should be called repeatedly until the
// package is fully resolved.
//
// @return bool                 true if the package is fully resolved;
//                              false if another call is required.
func (bpkg *BuildPackage) Resolve(b *Builder) (bool, error) {
	if !bpkg.depsResolved {
		features, newFeatures := bpkg.loadFeatures(b)
		newDeps, err := bpkg.loadDeps(b, features)
		if err != nil {
			return false, err
		}

		bpkg.depsResolved = !newFeatures && !newDeps
	}

	if !bpkg.apisSatisfied {
		bpkg.satisfyApis(b)
	}

	return bpkg.depsResolved && bpkg.apisSatisfied, nil
}

func (bp *BuildPackage) Init(pkg *pkg.LocalPackage) {
	bp.LocalPackage = pkg
	bp.reqApiMap = map[string]reqApiStatus{}
}

func NewBuildPackage(pkg *pkg.LocalPackage) *BuildPackage {
	bpkg := &BuildPackage{}
	bpkg.Init(pkg)

	return bpkg
}
<|endoftext|>


<commit_before>package models

import (
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/mgo.v2/bson"
)

// UserChallengeEffort struct handles the MongoDB schema for each users challenge effort
type UserChallengeEffort struct {
	ID               int     `json:"id"`
	Name             string  `json:"name"`
	Photo            string  `json:"photo"`
	Time             int     `json:"time"`
	Completed        bool    `json:"completed"`
	AverageCadence   float32 `json:"averageCadence"`
	AverageWatts     float32 `json:"averageWatts"`
	AverageHeartRate float32 `json:"averageHeartRate"`
	MaxHeartRate     int     `json:"maxHeartRate"`
}

// Challenge struct handles the MongoDB schema for a challenge
type Challenge struct {
	ID         bson.ObjectId       `bson:"_id,omitempty" json:"_id"`
	Segment    Segment             `json:"segment"`
	Challenger UserChallengeEffort `json:"challenger"`
	Challengee UserChallengeEffort `json:"challengee"`
	Status     string              `json:"status"`
	Created    time.Time           `json:"created"`
	Expires    time.Time           `json:"expires"`
	Completed  time.Time           `json:"completed"`
	Expired    bool                `json:"expired"`
	WinnerID   int                 `json:"winnerId"`
	WinnerName string              `json:"winnerName"`
	LoserID    int                 `json:"loserId"`
	LoserName  string              `json:"loserName"`
}

// GetChallengeByID gets a single stored challenge from MongoDB
func GetChallengeByID(id bson.ObjectId) (*Challenge, error) {
	var c Challenge

	if err := session.DB("heroku_zgxbr4j2").C("challenges").Find(bson.M{"_id": id}).One(&c); err != nil {
		log.WithField("ID", id).Error("Unable to find challenge with id in database")
		return nil, err
	}

	return &c, nil
}

// CreateChallenge creates a new challenge
func CreateChallenge(c Challenge) error {
	if err := session.DB("heroku_zgxbr4j2").C("challenges").Insert(c); err != nil {
		log.Errorf("Unable to create a new challenge:\n %v", err)
		return err
	}
	log.Printf("Challenge successfully created")
	return nil
}

// RemoveChallenge removes a challenge
func RemoveChallenge(id bson.ObjectId) error {
	if err := session.DB("heroku_zgxbr4j2").C("challenges").Remove(bson.M{"_id": id}); err != nil {
		log.WithField("ID", id).Error("Unable to find challenge with id in database")
		return err
	}
	log.Printf("Challenge successfully removed: %v", id)
	return nil
}
<commit_msg>comments<commit_after>package models

import (
	"time"

	log "github.com/Sirupsen/logrus"
	"gopkg.in/mgo.v2/bson"
)

// UserChallengeEffort struct handles the MongoDB schema for each users challenge effort
type UserChallengeEffort struct {
	ID               int     `json:"id"`
	Name             string  `json:"name"`
	Photo            string  `json:"photo"`
	Time             int     `json:"time"`
	Completed        bool    `json:"completed"`
	AverageCadence   float32 `json:"averageCadence"`
	AverageWatts     float32 `json:"averageWatts"`
	AverageHeartRate float32 `json:"averageHeartRate"`
	MaxHeartRate     int     `json:"maxHeartRate"`
}

// Challenge struct handles the MongoDB schema for a challenge
type Challenge struct {
	ID         bson.ObjectId       `bson:"_id,omitempty" json:"_id"`
	Segment    Segment             `json:"segment"`
	Challenger UserChallengeEffort `json:"challenger"`
	Challengee UserChallengeEffort `json:"challengee"`
	Status     string              `json:"status"`
	Created    time.Time           `json:"created"`
	Expires    time.Time           `json:"expires"`
	Completed  time.Time           `json:"completed"`
	Expired    bool                `json:"expired"`
	WinnerID   int                 `json:"winnerId"`
	WinnerName string              `json:"winnerName"`
	LoserID    int                 `json:"loserId"`
	LoserName  string              `json:"loserName"`
}

// GetChallengeByID gets a single stored challenge from MongoDB
func GetChallengeByID(id bson.ObjectId) (*Challenge, error) {
	var c Challenge

	if err := session.DB("heroku_zgxbr4j2").C("challenges").Find(bson.M{"_id": id}).One(&c); err != nil {
		log.WithField("ID", id).Error("Unable to find challenge with id in database")
		return nil, err
	}

	return &c, nil
}

// CreateChallenge creates a new challenge in MongoDB
func CreateChallenge(c Challenge) error {
	if err := session.DB("heroku_zgxbr4j2").C("challenges").Insert(c); err != nil {
		log.Errorf("Unable to create a new challenge:\n %v", err)
		return err
	}
	log.Printf("Challenge successfully created")
	return nil
}

// RemoveChallenge removes a challenge from MongoDB
func RemoveChallenge(id bson.ObjectId) error {
	if err := session.DB("heroku_zgxbr4j2").C("challenges").Remove(bson.M{"_id": id}); err != nil {
		log.WithField("ID", id).Error("Unable to find challenge with id in database")
		return err
	}
	log.Printf("Challenge successfully removed: %v", id)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2022 Brian J. Downs
//
// 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 openweathermap

import (
	"errors"
	"net/http"
	"strings"
)

var errUnitUnavailable = errors.New("unit unavailable")
var errLangUnavailable = errors.New("language unavailable")
var errInvalidKey = errors.New("invalid api key")
var errInvalidOption = errors.New("invalid option")
var errInvalidHttpClient = errors.New("invalid http client")
var errForecastUnavailable = errors.New("forecast unavailable")
var errExcludesUnavailable = errors.New("onecall excludes unavailable")

// DataUnits represents the character chosen to represent the temperature notation
var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"}
var (
	baseURL        = "https://api.openweathermap.org/data/2.5/weather?%s"
	onecallURL     = "https://api.openweathermap.org/data/2.5/onecall?%s"
	iconURL        = "https://openweathermap.org/img/w/%s"
	stationURL     = "https://api.openweathermap.org/data/2.5/station?id=%d"
	forecast5Base  = "https://api.openweathermap.org/data/2.5/forecast?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
	forecast16Base = "https://api.openweathermap.org/data/2.5/forecast/daily?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
	historyURL     = "https://api.openweathermap.org/data/2.5/history/%s"
	pollutionURL   = "https://api.openweathermap.org/pollution/v1/co/"
	uvURL          = "https://api.openweathermap.org/data/2.5/"
	dataPostURL    = "https://openweathermap.org/data/post"
)

// LangCodes holds all supported languages to be used
// inspried and sourced from @bambocher (github.com/bambocher)
var LangCodes = map[string]string{
	"EN":    "English",
	"RU":    "Russian",
	"IT":    "Italian",
	"ES":    "Spanish",
	"SP":    "Spanish",
	"UK":    "Ukrainian",
	"UA":    "Ukrainian",
	"DE":    "German",
	"PT":    "Portuguese",
	"RO":    "Romanian",
	"PL":    "Polish",
	"FI":    "Finnish",
	"NL":    "Dutch",
	"FR":    "French",
	"BG":    "Bulgarian",
	"SV":    "Swedish",
	"SE":    "Swedish",
	"TR":    "Turkish",
	"HR":    "Croatian",
	"CA":    "Catalan",
	"ZH_TW": "Chinese Traditional",
	"ZH":    "Chinese Simplified",
	"ZH_CN": "Chinese Simplified",
}

// Exclude holds all supported excludes option to be used
const (
	ExcludeCurrent  = "current"
	ExcludeMinutely = "minutely"
	ExcludeHourly   = "hourly"
	ExcludeDaily    = "daily"
	ExcludeAlerts   = "alerts"
)

var Excludes []string = []string{ExcludeCurrent, ExcludeMinutely, ExcludeHourly, ExcludeDaily, ExcludeAlerts}

// Config will hold default settings to be passed into the
// "NewCurrent, NewForecast, etc}" functions.
type Config struct {
	Mode     string // user choice of JSON or XML
	Unit     string // measurement for results to be displayed.  F, C, or K
	Lang     string // should reference a key in the LangCodes map
	APIKey   string // API Key for connecting to the OWM
	Username string // Username for posting data
	Password string // Pasword for posting data
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data in returned
// JSON or as parameter data for requests using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request
// and the surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	ID      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   float64 `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	ID          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the temperates, humidity, pressure for the request.
type Main struct {
	Temp      float64 `json:"temp"`
	TempMin   float64 `json:"temp_min"`
	TempMax   float64 `json:"temp_max"`
	FeelsLike float64 `json:"feels_like"`
	Pressure  float64 `json:"pressure"`
	SeaLevel  float64 `json:"sea_level"`
	GrndLevel float64 `json:"grnd_level"`
	Humidity  int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}

// 	return key
// }
func setKey(key string) (string, error) {
	if err := ValidAPIKey(key); err != nil {
		return "", err
	}
	return key, nil
}

// ValidDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
func ValidDataUnit(u string) bool {
	for d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidLangCode makes sure the string passed in is an
// acceptable lang code.
func ValidLangCode(c string) bool {
	for d := range LangCodes {
		if c == d {
			return true
		}
	}
	return false
}

// ValidDataUnitSymbol makes sure the string passed in is an
// acceptable data unit symbol.
func ValidDataUnitSymbol(u string) bool {
	for _, d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidExcludes makes sure the string passed in is an
// acceptable excludes options.
func ValidExcludes(e []string) (string, error) {
	list := make([]string, 0)
	for _, v := range e {
		vl := strings.ToLower(v)
		notFound := true

		for _, d := range Excludes {
			if d == vl {
				list = append(list, v)
				notFound = false
				break
			}
		}

		if notFound {
			return "", errExcludesUnavailable
		}
	}
	return strings.Join(list, ","), nil
}

// ValidAPIKey makes sure that the key given is a valid one
func ValidAPIKey(key string) error {
	if len(key) != 32 {
		return errors.New("invalid key")
	}
	return nil
}

// CheckAPIKeyExists will see if an API key has been set.
func (c *Config) CheckAPIKeyExists() bool { return len(c.APIKey) > 1 }

// Settings holds the client settings
type Settings struct {
	client *http.Client
}

// NewSettings returns a new Setting pointer with default http client.
func NewSettings() *Settings {
	return &Settings{
		client: http.DefaultClient,
	}
}

// Optional client settings
type Option func(s *Settings) error

// WithHttpClient sets custom http client when creating a new Client.
func WithHttpClient(c *http.Client) Option {
	return func(s *Settings) error {
		if c == nil {
			return errInvalidHttpClient
		}
		s.client = c
		return nil
	}
}

// setOptions sets Optional client settings to the Settings pointer
func setOptions(settings *Settings, options []Option) error {
	for _, option := range options {
		if option == nil {
			return errInvalidOption
		}
		err := option(settings)
		if err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>update key size<commit_after>// Copyright 2022 Brian J. Downs
//
// 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 openweathermap

import (
	"errors"
	"net/http"
	"strings"
)

var errUnitUnavailable = errors.New("unit unavailable")
var errLangUnavailable = errors.New("language unavailable")
var errInvalidKey = errors.New("invalid api key")
var errInvalidOption = errors.New("invalid option")
var errInvalidHttpClient = errors.New("invalid http client")
var errForecastUnavailable = errors.New("forecast unavailable")
var errExcludesUnavailable = errors.New("onecall excludes unavailable")

// DataUnits represents the character chosen to represent the temperature notation
var DataUnits = map[string]string{"C": "metric", "F": "imperial", "K": "internal"}
var (
	baseURL        = "https://api.openweathermap.org/data/2.5/weather?%s"
	onecallURL     = "https://api.openweathermap.org/data/2.5/onecall?%s"
	iconURL        = "https://openweathermap.org/img/w/%s"
	stationURL     = "https://api.openweathermap.org/data/2.5/station?id=%d"
	forecast5Base  = "https://api.openweathermap.org/data/2.5/forecast?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
	forecast16Base = "https://api.openweathermap.org/data/2.5/forecast/daily?appid=%s&%s&mode=json&units=%s&lang=%s&cnt=%d"
	historyURL     = "https://api.openweathermap.org/data/2.5/history/%s"
	pollutionURL   = "https://api.openweathermap.org/pollution/v1/co/"
	uvURL          = "https://api.openweathermap.org/data/2.5/"
	dataPostURL    = "https://openweathermap.org/data/post"
)

// LangCodes holds all supported languages to be used
// inspried and sourced from @bambocher (github.com/bambocher)
var LangCodes = map[string]string{
	"EN":    "English",
	"RU":    "Russian",
	"IT":    "Italian",
	"ES":    "Spanish",
	"SP":    "Spanish",
	"UK":    "Ukrainian",
	"UA":    "Ukrainian",
	"DE":    "German",
	"PT":    "Portuguese",
	"RO":    "Romanian",
	"PL":    "Polish",
	"FI":    "Finnish",
	"NL":    "Dutch",
	"FR":    "French",
	"BG":    "Bulgarian",
	"SV":    "Swedish",
	"SE":    "Swedish",
	"TR":    "Turkish",
	"HR":    "Croatian",
	"CA":    "Catalan",
	"ZH_TW": "Chinese Traditional",
	"ZH":    "Chinese Simplified",
	"ZH_CN": "Chinese Simplified",
}

// Exclude holds all supported excludes option to be used
const (
	ExcludeCurrent  = "current"
	ExcludeMinutely = "minutely"
	ExcludeHourly   = "hourly"
	ExcludeDaily    = "daily"
	ExcludeAlerts   = "alerts"
)

var Excludes []string = []string{ExcludeCurrent, ExcludeMinutely, ExcludeHourly, ExcludeDaily, ExcludeAlerts}

// Config will hold default settings to be passed into the
// "NewCurrent, NewForecast, etc}" functions.
type Config struct {
	Mode     string // user choice of JSON or XML
	Unit     string // measurement for results to be displayed.  F, C, or K
	Lang     string // should reference a key in the LangCodes map
	APIKey   string // API Key for connecting to the OWM
	Username string // Username for posting data
	Password string // Pasword for posting data
}

// APIError returned on failed API calls.
type APIError struct {
	Message string `json:"message"`
	COD     string `json:"cod"`
}

// Coordinates struct holds longitude and latitude data in returned
// JSON or as parameter data for requests using longitude and latitude.
type Coordinates struct {
	Longitude float64 `json:"lon"`
	Latitude  float64 `json:"lat"`
}

// Sys struct contains general information about the request
// and the surrounding area for where the request was made.
type Sys struct {
	Type    int     `json:"type"`
	ID      int     `json:"id"`
	Message float64 `json:"message"`
	Country string  `json:"country"`
	Sunrise int     `json:"sunrise"`
	Sunset  int     `json:"sunset"`
}

// Wind struct contains the speed and degree of the wind.
type Wind struct {
	Speed float64 `json:"speed"`
	Deg   float64 `json:"deg"`
}

// Weather struct holds high-level, basic info on the returned
// data.
type Weather struct {
	ID          int    `json:"id"`
	Main        string `json:"main"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
}

// Main struct contains the temperates, humidity, pressure for the request.
type Main struct {
	Temp      float64 `json:"temp"`
	TempMin   float64 `json:"temp_min"`
	TempMax   float64 `json:"temp_max"`
	FeelsLike float64 `json:"feels_like"`
	Pressure  float64 `json:"pressure"`
	SeaLevel  float64 `json:"sea_level"`
	GrndLevel float64 `json:"grnd_level"`
	Humidity  int     `json:"humidity"`
}

// Clouds struct holds data regarding cloud cover.
type Clouds struct {
	All int `json:"all"`
}

// 	return key
// }
func setKey(key string) (string, error) {
	if err := ValidAPIKey(key); err != nil {
		return "", err
	}
	return key, nil
}

// ValidDataUnit makes sure the string passed in is an accepted
// unit of measure to be used for the return data.
func ValidDataUnit(u string) bool {
	for d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidLangCode makes sure the string passed in is an
// acceptable lang code.
func ValidLangCode(c string) bool {
	for d := range LangCodes {
		if c == d {
			return true
		}
	}
	return false
}

// ValidDataUnitSymbol makes sure the string passed in is an
// acceptable data unit symbol.
func ValidDataUnitSymbol(u string) bool {
	for _, d := range DataUnits {
		if u == d {
			return true
		}
	}
	return false
}

// ValidExcludes makes sure the string passed in is an
// acceptable excludes options.
func ValidExcludes(e []string) (string, error) {
	list := make([]string, 0)
	for _, v := range e {
		vl := strings.ToLower(v)
		notFound := true

		for _, d := range Excludes {
			if d == vl {
				list = append(list, v)
				notFound = false
				break
			}
		}

		if notFound {
			return "", errExcludesUnavailable
		}
	}
	return strings.Join(list, ","), nil
}

// ValidAPIKey makes sure that the key given is a valid one
func ValidAPIKey(key string) error {
	if len(key) != 64 {
		return errors.New("invalid key")
	}
	return nil
}

// CheckAPIKeyExists will see if an API key has been set.
func (c *Config) CheckAPIKeyExists() bool { return len(c.APIKey) > 1 }

// Settings holds the client settings
type Settings struct {
	client *http.Client
}

// NewSettings returns a new Setting pointer with default http client.
func NewSettings() *Settings {
	return &Settings{
		client: http.DefaultClient,
	}
}

// Optional client settings
type Option func(s *Settings) error

// WithHttpClient sets custom http client when creating a new Client.
func WithHttpClient(c *http.Client) Option {
	return func(s *Settings) error {
		if c == nil {
			return errInvalidHttpClient
		}
		s.client = c
		return nil
	}
}

// setOptions sets Optional client settings to the Settings pointer
func setOptions(settings *Settings, options []Option) error {
	for _, option := range options {
		if option == nil {
			return errInvalidOption
		}
		err := option(settings)
		if err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before><commit_msg>use directory from configfilepath for listing config files<commit_after><|endoftext|>


<commit_before>// +build linux darwin
package prefer

import (
	"os"
	"path/filepath"
)

func getSystemPaths() []string {
	return []string{
		filepath.Join(os.Getenv("HOME"), ".config"),
		os.Getenv("HOME"),
		"/usr/local",
		"/usr",
		"/",
	}
}
<commit_msg>Use windows tag<commit_after>// +build !windows
package prefer

import (
	"os"
	"path/filepath"
)

func getSystemPaths() []string {
	return []string{
		filepath.Join(os.Getenv("HOME"), ".config"),
		os.Getenv("HOME"),
		"/usr/local",
		"/usr",
		"/",
	}
}
<|endoftext|>