<commit_before>package release

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/blang/semver"
	pivnet "github.com/pivotal-cf/go-pivnet"
	"github.com/pivotal-cf/pivnet-resource/concourse"
	"github.com/pivotal-cf/pivnet-resource/metadata"
)

type ReleaseCreator struct {
	pivnet          releaseClient
	semverConverter semverConverter
	logger          *log.Logger
	metadata        metadata.Metadata
	sourcesDir      string
	productSlug     string
	params          concourse.OutParams
	source          concourse.Source
}

//go:generate counterfeiter --fake-name ReleaseClient . releaseClient
type releaseClient interface {
	EULAs() ([]pivnet.EULA, error)
	ReleaseTypes() ([]pivnet.ReleaseType, error)
	ReleasesForProductSlug(string) ([]pivnet.Release, error)
	CreateRelease(pivnet.CreateReleaseConfig) (pivnet.Release, error)
	ProductVersions(productSlug string, releases []pivnet.Release) ([]string, error)
}

//go:generate counterfeiter --fake-name FakeSemverConverter . semverConverter
type semverConverter interface {
	ToValidSemver(string) (semver.Version, error)
}

func NewReleaseCreator(
	pivnet releaseClient,
	semverConverter semverConverter,
	logger *log.Logger,
	metadata metadata.Metadata,
	params concourse.OutParams,
	source concourse.Source,
	sourcesDir,
	productSlug string,
) ReleaseCreator {
	return ReleaseCreator{
		pivnet:          pivnet,
		semverConverter: semverConverter,
		logger:          logger,
		metadata:        metadata,
		sourcesDir:      sourcesDir,
		params:          params,
		source:          source,
		productSlug:     productSlug,
	}
}

func (rc ReleaseCreator) Create() (pivnet.Release, error) {
	productVersion := rc.metadata.Release.Version

	if rc.source.SortBy == concourse.SortBySemver {
		v, err := rc.semverConverter.ToValidSemver(productVersion)
		if err != nil {
			return pivnet.Release{}, err
		}
		rc.logger.Println(fmt.Sprintf("Successfully parsed semver as: '%s'", v.String()))
	}

	if rc.source.ProductVersion != "" {
		rc.logger.Println(fmt.Sprintf(
			"Validating product version: '%s' against regex: '%s'",
			productVersion,
			rc.source.ProductVersion,
		))

		match, err := regexp.MatchString(rc.source.ProductVersion, productVersion)
		if err != nil {
			return pivnet.Release{}, err
		}

		if !match {
			return pivnet.Release{}, fmt.Errorf(
				"provided product version: '%s' does not match regex in source: '%s'",
				productVersion,
				rc.source.ProductVersion,
			)
		}
	}

	rc.logger.Println(fmt.Sprintf("Getting existing releases for product slug: '%s'", rc.productSlug))
	releases, err := rc.pivnet.ReleasesForProductSlug(rc.productSlug)
	if err != nil {
		return pivnet.Release{}, err
	}

	existingVersions, err := rc.pivnet.ProductVersions(rc.productSlug, releases)
	if err != nil {
		return pivnet.Release{}, err
	}

	for _, v := range existingVersions {
		if v == productVersion {
			return pivnet.Release{},
				fmt.Errorf("release already exists with version: '%s'", productVersion)
		}
	}

	eulaSlug := rc.metadata.Release.EULASlug

	rc.logger.Println(fmt.Sprintf("Validating EULA: '%s'", eulaSlug))

	eulas, err := rc.pivnet.EULAs()
	if err != nil {
		return pivnet.Release{}, err
	}

	eulaSlugs := make([]string, len(eulas))
	for i, e := range eulas {
		eulaSlugs[i] = e.Slug
	}

	var containsSlug bool
	for _, slug := range eulaSlugs {
		if eulaSlug == slug {
			containsSlug = true
			break
		}
	}

	if !containsSlug {
		eulaSlugsPrintable := fmt.Sprintf("['%s']", strings.Join(eulaSlugs, "', '"))
		return pivnet.Release{}, fmt.Errorf(
			"provided EULA slug: '%s' must be one of: %s",
			eulaSlug,
			eulaSlugsPrintable,
		)
	}

	releaseType := pivnet.ReleaseType(rc.metadata.Release.ReleaseType)

	rc.logger.Println(fmt.Sprintf("Validating release type: '%s'", releaseType))

	releaseTypes, err := rc.pivnet.ReleaseTypes()
	if err != nil {
		return pivnet.Release{}, err
	}

	releaseTypesAsStrings := make([]string, len(releaseTypes))
	for i, r := range releaseTypes {
		releaseTypesAsStrings[i] = string(r)
	}

	var containsReleaseType bool
	for _, t := range releaseTypes {
		if releaseType == t {
			containsReleaseType = true
			break
		}
	}

	if !containsReleaseType {
		releaseTypesPrintable := fmt.Sprintf(
			"['%s']",
			strings.Join(releaseTypesAsStrings, "', '"),
		)
		return pivnet.Release{}, fmt.Errorf(
			"provided release type: '%s' must be one of: %s",
			releaseType,
			releaseTypesPrintable,
		)
	}

	if pivnet.ReleaseType(rc.source.ReleaseType) != "" &&
		pivnet.ReleaseType(rc.source.ReleaseType) != releaseType {
		return pivnet.Release{}, fmt.Errorf(
			"provided release type: '%s' must match '%s' from source configuration",
			releaseType,
			rc.source.ReleaseType,
		)
	}

	config := pivnet.CreateReleaseConfig{
		ProductSlug:           rc.productSlug,
		ReleaseType:           string(releaseType),
		EULASlug:              eulaSlug,
		ProductVersion:        productVersion,
		Description:           rc.metadata.Release.Description,
		ReleaseNotesURL:       rc.metadata.Release.ReleaseNotesURL,
		ReleaseDate:           rc.metadata.Release.ReleaseDate,
		Controlled:            rc.metadata.Release.Controlled,
		ECCN:                  rc.metadata.Release.ECCN,
		LicenseException:      rc.metadata.Release.LicenseException,
		EndOfSupportDate:      rc.metadata.Release.EndOfSupportDate,
		EndOfGuidanceDate:     rc.metadata.Release.EndOfGuidanceDate,
		EndOfAvailabilityDate: rc.metadata.Release.EndOfAvailabilityDate,
	}

	rc.logger.Println(fmt.Sprintf("Creating new release with config: %+v", config))
	release, err := rc.pivnet.CreateRelease(config)
	if err != nil {
		return pivnet.Release{}, err
	}

	rc.logger.Println(fmt.Sprintf("Created new release with ID: %d", release.ID))
	return release, nil
}
<commit_msg>Remove unnecessary log line when creating release.<commit_after>package release

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/blang/semver"
	pivnet "github.com/pivotal-cf/go-pivnet"
	"github.com/pivotal-cf/pivnet-resource/concourse"
	"github.com/pivotal-cf/pivnet-resource/metadata"
)

type ReleaseCreator struct {
	pivnet          releaseClient
	semverConverter semverConverter
	logger          *log.Logger
	metadata        metadata.Metadata
	sourcesDir      string
	productSlug     string
	params          concourse.OutParams
	source          concourse.Source
}

//go:generate counterfeiter --fake-name ReleaseClient . releaseClient
type releaseClient interface {
	EULAs() ([]pivnet.EULA, error)
	ReleaseTypes() ([]pivnet.ReleaseType, error)
	ReleasesForProductSlug(string) ([]pivnet.Release, error)
	CreateRelease(pivnet.CreateReleaseConfig) (pivnet.Release, error)
	ProductVersions(productSlug string, releases []pivnet.Release) ([]string, error)
}

//go:generate counterfeiter --fake-name FakeSemverConverter . semverConverter
type semverConverter interface {
	ToValidSemver(string) (semver.Version, error)
}

func NewReleaseCreator(
	pivnet releaseClient,
	semverConverter semverConverter,
	logger *log.Logger,
	metadata metadata.Metadata,
	params concourse.OutParams,
	source concourse.Source,
	sourcesDir,
	productSlug string,
) ReleaseCreator {
	return ReleaseCreator{
		pivnet:          pivnet,
		semverConverter: semverConverter,
		logger:          logger,
		metadata:        metadata,
		sourcesDir:      sourcesDir,
		params:          params,
		source:          source,
		productSlug:     productSlug,
	}
}

func (rc ReleaseCreator) Create() (pivnet.Release, error) {
	productVersion := rc.metadata.Release.Version

	if rc.source.SortBy == concourse.SortBySemver {
		v, err := rc.semverConverter.ToValidSemver(productVersion)
		if err != nil {
			return pivnet.Release{}, err
		}
		rc.logger.Println(fmt.Sprintf("Successfully parsed semver as: '%s'", v.String()))
	}

	if rc.source.ProductVersion != "" {
		rc.logger.Println(fmt.Sprintf(
			"Validating product version: '%s' against regex: '%s'",
			productVersion,
			rc.source.ProductVersion,
		))

		match, err := regexp.MatchString(rc.source.ProductVersion, productVersion)
		if err != nil {
			return pivnet.Release{}, err
		}

		if !match {
			return pivnet.Release{}, fmt.Errorf(
				"provided product version: '%s' does not match regex in source: '%s'",
				productVersion,
				rc.source.ProductVersion,
			)
		}
	}

	releases, err := rc.pivnet.ReleasesForProductSlug(rc.productSlug)
	if err != nil {
		return pivnet.Release{}, err
	}

	existingVersions, err := rc.pivnet.ProductVersions(rc.productSlug, releases)
	if err != nil {
		return pivnet.Release{}, err
	}

	for _, v := range existingVersions {
		if v == productVersion {
			return pivnet.Release{},
				fmt.Errorf("release already exists with version: '%s'", productVersion)
		}
	}

	eulaSlug := rc.metadata.Release.EULASlug

	rc.logger.Println(fmt.Sprintf("Validating EULA: '%s'", eulaSlug))

	eulas, err := rc.pivnet.EULAs()
	if err != nil {
		return pivnet.Release{}, err
	}

	eulaSlugs := make([]string, len(eulas))
	for i, e := range eulas {
		eulaSlugs[i] = e.Slug
	}

	var containsSlug bool
	for _, slug := range eulaSlugs {
		if eulaSlug == slug {
			containsSlug = true
			break
		}
	}

	if !containsSlug {
		eulaSlugsPrintable := fmt.Sprintf("['%s']", strings.Join(eulaSlugs, "', '"))
		return pivnet.Release{}, fmt.Errorf(
			"provided EULA slug: '%s' must be one of: %s",
			eulaSlug,
			eulaSlugsPrintable,
		)
	}

	releaseType := pivnet.ReleaseType(rc.metadata.Release.ReleaseType)

	rc.logger.Println(fmt.Sprintf("Validating release type: '%s'", releaseType))

	releaseTypes, err := rc.pivnet.ReleaseTypes()
	if err != nil {
		return pivnet.Release{}, err
	}

	releaseTypesAsStrings := make([]string, len(releaseTypes))
	for i, r := range releaseTypes {
		releaseTypesAsStrings[i] = string(r)
	}

	var containsReleaseType bool
	for _, t := range releaseTypes {
		if releaseType == t {
			containsReleaseType = true
			break
		}
	}

	if !containsReleaseType {
		releaseTypesPrintable := fmt.Sprintf(
			"['%s']",
			strings.Join(releaseTypesAsStrings, "', '"),
		)
		return pivnet.Release{}, fmt.Errorf(
			"provided release type: '%s' must be one of: %s",
			releaseType,
			releaseTypesPrintable,
		)
	}

	if pivnet.ReleaseType(rc.source.ReleaseType) != "" &&
		pivnet.ReleaseType(rc.source.ReleaseType) != releaseType {
		return pivnet.Release{}, fmt.Errorf(
			"provided release type: '%s' must match '%s' from source configuration",
			releaseType,
			rc.source.ReleaseType,
		)
	}

	config := pivnet.CreateReleaseConfig{
		ProductSlug:           rc.productSlug,
		ReleaseType:           string(releaseType),
		EULASlug:              eulaSlug,
		ProductVersion:        productVersion,
		Description:           rc.metadata.Release.Description,
		ReleaseNotesURL:       rc.metadata.Release.ReleaseNotesURL,
		ReleaseDate:           rc.metadata.Release.ReleaseDate,
		Controlled:            rc.metadata.Release.Controlled,
		ECCN:                  rc.metadata.Release.ECCN,
		LicenseException:      rc.metadata.Release.LicenseException,
		EndOfSupportDate:      rc.metadata.Release.EndOfSupportDate,
		EndOfGuidanceDate:     rc.metadata.Release.EndOfGuidanceDate,
		EndOfAvailabilityDate: rc.metadata.Release.EndOfAvailabilityDate,
	}

	rc.logger.Println(fmt.Sprintf("Creating new release with config: %+v", config))
	release, err := rc.pivnet.CreateRelease(config)
	if err != nil {
		return pivnet.Release{}, err
	}

	rc.logger.Println(fmt.Sprintf("Created new release with ID: %d", release.ID))
	return release, nil
}
<|endoftext|>


<commit_before>package connmgr

import (
	"context"
	"testing"

	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	tu "github.com/libp2p/go-testutil"
)

type tconn struct {
	inet.Conn
	peer   peer.ID
	closed bool
}

func (c *tconn) Close() error {
	c.closed = true
	return nil
}

func (c *tconn) RemotePeer() peer.ID {
	return c.peer
}

func randConn(t *testing.T) inet.Conn {
	pid := tu.RandPeerIDFatal(t)
	return &tconn{peer: pid}
}

func TestConnTrimming(t *testing.T) {
	cm := NewConnManager(200, 300, 0)
	not := cm.Notifee()

	var conns []inet.Conn
	for i := 0; i < 300; i++ {
		rc := randConn(t)
		conns = append(conns, rc)
		not.Connected(nil, rc)
	}

	for _, c := range conns {
		if c.(*tconn).closed {
			t.Fatal("nothing should be closed yet")
		}
	}

	for i := 0; i < 100; i++ {
		cm.TagPeer(conns[i].RemotePeer(), "foo", 10)
	}

	cm.TagPeer(conns[299].RemotePeer(), "badfoo", -5)

	cm.TrimOpenConns(context.Background())

	for i := 0; i < 100; i++ {
		c := conns[i]
		if c.(*tconn).closed {
			t.Fatal("these shouldnt be closed")
		}
	}

	if !conns[299].(*tconn).closed {
		t.Fatal("conn with bad tag should have gotten closed")
	}
}
<commit_msg>lift test coverage<commit_after>package connmgr

import (
	"context"
	"testing"
	"time"

	inet "github.com/libp2p/go-libp2p-net"
	peer "github.com/libp2p/go-libp2p-peer"
	tu "github.com/libp2p/go-testutil"
	ma "github.com/multiformats/go-multiaddr"
)

type tconn struct {
	inet.Conn
	peer   peer.ID
	closed bool
}

func (c *tconn) Close() error {
	c.closed = true
	return nil
}

func (c *tconn) RemotePeer() peer.ID {
	return c.peer
}

func (c *tconn) RemoteMultiaddr() ma.Multiaddr {
	addr, err := ma.NewMultiaddr("/ip4/127.0.0.1/udp/1234")
	if err != nil {
		panic("cannot create multiaddr")
	}
	return addr
}

func randConn(t *testing.T) inet.Conn {
	pid := tu.RandPeerIDFatal(t)
	return &tconn{peer: pid}
}

func TestConnTrimming(t *testing.T) {
	cm := NewConnManager(200, 300, 0)
	not := cm.Notifee()

	var conns []inet.Conn
	for i := 0; i < 300; i++ {
		rc := randConn(t)
		conns = append(conns, rc)
		not.Connected(nil, rc)
	}

	for _, c := range conns {
		if c.(*tconn).closed {
			t.Fatal("nothing should be closed yet")
		}
	}

	for i := 0; i < 100; i++ {
		cm.TagPeer(conns[i].RemotePeer(), "foo", 10)
	}

	cm.TagPeer(conns[299].RemotePeer(), "badfoo", -5)

	cm.TrimOpenConns(context.Background())

	for i := 0; i < 100; i++ {
		c := conns[i]
		if c.(*tconn).closed {
			t.Fatal("these shouldnt be closed")
		}
	}

	if !conns[299].(*tconn).closed {
		t.Fatal("conn with bad tag should have gotten closed")
	}
}

func TestConnsToClose(t *testing.T) {
	cm := NewConnManager(0, 10, 0)
	conns := cm.getConnsToClose(context.Background())
	if conns != nil {
		t.Fatal("expected no connections")
	}

	cm = NewConnManager(10, 0, 0)
	conns = cm.getConnsToClose(context.Background())
	if conns != nil {
		t.Fatal("expected no connections")
	}

	cm = NewConnManager(1, 1, 0)
	conns = cm.getConnsToClose(context.Background())
	if conns != nil {
		t.Fatal("expected no connections")
	}

	cm = NewConnManager(1, 1, time.Duration(10*time.Minute))
	not := cm.Notifee()
	for i := 0; i < 5; i++ {
		conn := randConn(t)
		not.Connected(nil, conn)
	}
	conns = cm.getConnsToClose(context.Background())
	if len(conns) != 0 {
		t.Fatal("expected no connections")
	}
}

func TestGetTagInfo(t *testing.T) {
	start := time.Now()
	cm := NewConnManager(1, 1, time.Duration(10*time.Minute))
	not := cm.Notifee()
	conn := randConn(t)
	not.Connected(nil, conn)
	end := time.Now()

	other := tu.RandPeerIDFatal(t)
	tag := cm.GetTagInfo(other)
	if tag != nil {
		t.Fatal("expected no tag")
	}

	tag = cm.GetTagInfo(conn.RemotePeer())
	if tag == nil {
		t.Fatal("expected tag")
	}
	if tag.FirstSeen.Before(start) || tag.FirstSeen.After(end) {
		t.Fatal("expected first seen time")
	}
	if tag.Value != 0 {
		t.Fatal("expected zero value")
	}
	if len(tag.Tags) != 0 {
		t.Fatal("expected no tags")
	}
	if len(tag.Conns) != 1 {
		t.Fatal("expected one connection")
	}
	for s, tm := range tag.Conns {
		if s != conn.RemoteMultiaddr().String() {
			t.Fatal("unexpected multiaddr")
		}
		if tm.Before(start) || tm.After(end) {
			t.Fatal("unexpected connection time")
		}
	}

	cm.TagPeer(conn.RemotePeer(), "tag", 5)
	tag = cm.GetTagInfo(conn.RemotePeer())
	if tag == nil {
		t.Fatal("expected tag")
	}
	if tag.FirstSeen.Before(start) || tag.FirstSeen.After(end) {
		t.Fatal("expected first seen time")
	}
	if tag.Value != 5 {
		t.Fatal("expected five value")
	}
	if len(tag.Tags) != 1 {
		t.Fatal("expected no tags")
	}
	for tString, v := range tag.Tags {
		if tString != "tag" || v != 5 {
			t.Fatal("expected tag value")
		}
	}
	if len(tag.Conns) != 1 {
		t.Fatal("expected one connection")
	}
	for s, tm := range tag.Conns {
		if s != conn.RemoteMultiaddr().String() {
			t.Fatal("unexpected multiaddr")
		}
		if tm.Before(start) || tm.After(end) {
			t.Fatal("unexpected connection time")
		}
	}
}

func TestTagPeerNonExistant(t *testing.T) {
	cm := NewConnManager(1, 1, time.Duration(10*time.Minute))

	id := tu.RandPeerIDFatal(t)
	cm.TagPeer(id, "test", 1)

	if len(cm.peers) != 0 {
		t.Fatal("expected zero peers")
	}
}

func TestUntagPeer(t *testing.T) {
	cm := NewConnManager(1, 1, time.Duration(10*time.Minute))
	not := cm.Notifee()
	conn := randConn(t)
	not.Connected(nil, conn)
	rp := conn.RemotePeer()
	cm.TagPeer(rp, "tag", 5)
	cm.TagPeer(rp, "tag two", 5)

	id := tu.RandPeerIDFatal(t)
	cm.UntagPeer(id, "test")
	if len(cm.peers[rp].tags) != 2 {
		t.Fatal("expected tags to be uneffected")
	}

	cm.UntagPeer(conn.RemotePeer(), "test")
	if len(cm.peers[rp].tags) != 2 {
		t.Fatal("expected tags to be uneffected")
	}

	cm.UntagPeer(conn.RemotePeer(), "tag")
	if len(cm.peers[rp].tags) != 1 {
		t.Fatal("expected tag to be removed")
	}
	if cm.peers[rp].value != 5 {
		t.Fatal("expected aggreagte tag value to be 5")
	}
}

func TestGetInfo(t *testing.T) {
	start := time.Now()
	gp := time.Duration(10 * time.Minute)
	cm := NewConnManager(1, 5, gp)
	not := cm.Notifee()
	conn := randConn(t)
	not.Connected(nil, conn)
	cm.TrimOpenConns(context.Background())
	end := time.Now()

	info := cm.GetInfo()
	if info.HighWater != 5 {
		t.Fatal("expected highwater to be 5")
	}
	if info.LowWater != 1 {
		t.Fatal("expected highwater to be 1")
	}
	if info.LastTrim.Before(start) || info.LastTrim.After(end) {
		t.Fatal("unexpected last trim time")
	}
	if info.GracePeriod != gp {
		t.Fatal("unexpected grace period")
	}
	if info.ConnCount != 1 {
		t.Fatal("unexpected number of connections")
	}
}

func TestDoubleConnection(t *testing.T) {
	gp := time.Duration(10 * time.Minute)
	cm := NewConnManager(1, 5, gp)
	not := cm.Notifee()
	conn := randConn(t)
	not.Connected(nil, conn)
	cm.TagPeer(conn.RemotePeer(), "foo", 10)
	not.Connected(nil, conn)
	if cm.connCount != 1 {
		t.Fatal("unexpected number of connections")
	}
	if cm.peers[conn.RemotePeer()].value != 10 {
		t.Fatal("unexpected peer value")
	}
}

func TestDisconnected(t *testing.T) {
	gp := time.Duration(10 * time.Minute)
	cm := NewConnManager(1, 5, gp)
	not := cm.Notifee()
	conn := randConn(t)
	not.Connected(nil, conn)
	cm.TagPeer(conn.RemotePeer(), "foo", 10)

	not.Disconnected(nil, randConn(t))
	if cm.connCount != 1 {
		t.Fatal("unexpected number of connections")
	}
	if cm.peers[conn.RemotePeer()].value != 10 {
		t.Fatal("unexpected peer value")
	}

	not.Disconnected(nil, &tconn{peer: conn.RemotePeer()})
	if cm.connCount != 1 {
		t.Fatal("unexpected number of connections")
	}
	if cm.peers[conn.RemotePeer()].value != 10 {
		t.Fatal("unexpected peer value")
	}

	not.Disconnected(nil, conn)
	if cm.connCount != 0 {
		t.Fatal("unexpected number of connections")
	}
	if len(cm.peers) != 0 {
		t.Fatal("unexpected number of peers")
	}
}
<|endoftext|>


<commit_before>package generate

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func guessColumnType(goType string) (string, error) {
	if goType == "int" {
		return "qb.Int()", nil
	} else if goType == "int64" {
		return "qb.BigInt()", nil
	} else if goType == "string" {
		return "qb.Varchar()", nil
	} else if goType == "*string" {
		return "qb.Varchar()", nil
	} else if goType == "bool" {
		return "qb.Boolean()", nil
	} else if goType == "time.Time" {
		return "qb.Timestamp()", nil
	} else if goType == "*time.Time" {
		return "qb.Timestamp()", nil
	} else if goType == "uuid.UUID" {
		return "qb.UUID()", nil
	} else if goType == "uuid.NullUUID" {
		return "qb.UUID()", nil
	}
	return "", fmt.Errorf("Cannot guess column type for go type %s", goType)
}

func makeColumnName(name string) string {
	return ToDBName(name)
}

func getEmptyValue(goType string) string {
	if goType[0] == '*' {
		return "nil"
	} else if goType == "string" {
		return `""`
	} else if goType[0:3] == "int" {
		return "0"
	} else if goType == "time.Time" {
		return "(time.Time{})"
	} else if goType == "uuid.UUID" {
		return "(uuid.UUID{})"
	} else if goType == "uuid.NullUUID" {
		return "(uuid.NullUUID{})"
	}
	panic(fmt.Sprintf("I have no empty value for type '%v'", goType))
}

func prepareFieldData(str *StructData, f *FieldData) {
	var err error
	if f.ColumnName == "" {
		f.ColumnName = makeColumnName(f.Name)
	}
	if f.ColumnType == "" {
		f.ColumnType, err = guessColumnType(f.Type)
		if err != nil {
			panic(fmt.Sprintf("Failure on field '%s': Got err '%s'",
				f.Name, err))
		}
	}
	if f.ColumnModifiers == "" {
		if f.Tags.PrimaryKey {
			f.ColumnModifiers += ".PrimaryKey()"
		}
		if f.Tags.AutoIncrement {
			f.ColumnModifiers += ".AutoIncrement()"
			str.AutoIncrementPKey = f
		}
		if f.Tags.Null {
			f.ColumnModifiers += ".Null()"
		} else if f.Tags.NotNull {
			f.ColumnModifiers += ".NotNull()"
		} else if f.Type[0] == '*' || strings.Contains(f.Type, "Null") {
			f.ColumnModifiers += ".Null()"
		} else {
			f.ColumnModifiers += ".NotNull()"
		}
	}
	if f.EmptyValue == "" && f.Tags.PrimaryKey {
		f.EmptyValue = getEmptyValue(f.Type)
	}
	if f.NameConst == "" {
		f.NameConst = fmt.Sprintf(
			"%s%s",
			str.Name, f.Name,
		)
	}
	if f.ColumnNameConst == "" {
		f.ColumnNameConst = fmt.Sprintf(
			"%s%sColumnName",
			str.Name, f.Name,
		)
	}
}

func prepareStructData(str *StructData, fd FileData) {
	str.File = fd
	str.PrivateBasename = strings.ToLower(str.Name[0:1]) + str.Name[1:]
	for i := range str.Fields {
		prepareFieldData(str, &str.Fields[i])
	}
}

func loadEmbedded(path string, structs map[string]*StructData, fd FileData) []*StructData {
	var newStructs []*StructData

	var hasEmbed bool

	for _, str := range structs {
		if len(str.Embed) != 0 {
			hasEmbed = true
		}
	}

	if !hasEmbed {
		return []*StructData{}
	}

	otherStructsByName := make(map[string]*StructData)

	var err error
	newStructs, err = ParseDir(path)
	if err != nil {
		panic(err)
	}
	for _, str := range newStructs {
		prepareStructData(str, fd)
		otherStructsByName[str.Name] = str
	}

	allStructs := []*StructData{}
	for _, str := range structs {
		allStructs = append(allStructs, str)
	}
	allStructs = append(allStructs, newStructs...)

	for _, str := range allStructs {
		for _, name := range str.Embed {
			embedded, ok := structs[name]
			if !ok {
				embedded, ok = otherStructsByName[name]
			}
			if ok {
				for index, fields := range embedded.Indexes {
					if _, ok := str.Indexes[index]; !ok {
						str.Indexes[index] = []int{}
					}
					for _, fieldIndex := range fields {
						str.Indexes[index] = append(str.Indexes[index], len(str.Fields)+fieldIndex)
					}
				}
				for _, field := range embedded.Fields {
					field.FromEmbedded = true
					str.Fields = append(str.Fields, field)
				}
			} else {
				fmt.Println(
					"Could not find embedded struct definition for '" + name + "'")
			}
		}
	}
	return newStructs
}

func postPrepare(filedata *FileData, structs map[string]*StructData) {
	for _, str := range structs {
		for i := range str.Fields {
			if str.Fields[i].Tags.PrimaryKey {
				str.PKeyFields = append(str.PKeyFields, &str.Fields[i])
			}
		}
		if len(str.PKeyFields) == 0 {
			panic(fmt.Sprintf("No Primary Key found on %s", str.Name))
		}
	}
	for _, str := range structs {
		if str.Imported {
			continue
		}
		for i, f := range str.Fields {
			if f.Tags.PrimaryKey && str.Fields[i].Type == "uuid.UUID" {
				filedata.Imports["github.com/m4rw3r/uuid"] = true
			}
			for _, fkDef := range str.Fields[i].Tags.ForeignKeys {
				var (
					fk           string
					structName   string
					refFieldName string
					refStruct    *StructData
					refField     *FieldData
					onUpdate     string
					onDelete     string
				)
				if strings.Index(fkDef, " ") != -1 {
					splitted := strings.Split(fkDef, " ")
					fk = splitted[0]
					for i, w := range splitted[1 : len(splitted)-1] {
						if strings.ToUpper(w) == "ONUPDATE" {
							onUpdate = strings.ToUpper(splitted[i+2])
						}
						if strings.ToUpper(w) == "ONDELETE" {
							onDelete = strings.ToUpper(splitted[i+2])
						}
					}
				} else {
					fk = fkDef
				}
				if strings.Index(fk, ".") != -1 {
					splitted := strings.Split(fk, ".")
					structName = splitted[0]
					refFieldName = splitted[1]
				} else {
					structName = fk
				}
				refStruct = structs[structName]
				if refFieldName == "" {
					refField = refStruct.PKeyFields[0]
				} else {
					for i := range refStruct.Fields {
						if refStruct.Fields[i].Name == refFieldName {
							refField = &refStruct.Fields[i]
						}
					}
				}

				str.ForeignKeys = append(str.ForeignKeys, FKData{
					Column:    &str.Fields[i],
					RefTable:  refStruct,
					RefColumn: refField,
					OnUpdate:  onUpdate,
					OnDelete:  onDelete,
				})
			}
		}
	}
}

// ProcessFile processes a go file and generates mapper and mappedstruct
// interfaces implementations for the yago structs.
func ProcessFile(logger *log.Logger, path string, file string, pack string, output string, fmt bool) error {

	ext := filepath.Ext(file)
	base := strings.TrimSuffix(file, ext)

	if output == "" {
		output = filepath.Join(path, base+"_yago"+ext)
	}

	filedata := FileData{Package: pack, Imports: make(map[string]bool)}

	structs, err := ParseFile(filepath.Join(path, file))
	if err != nil {
		return err
	}

	structsByName := make(map[string]*StructData)
	for _, str := range structs {
		prepareStructData(str, filedata)
		structsByName[str.Name] = str
		if !str.NoTable {
			filedata.HasTables = true
		}
	}
	otherStructs := loadEmbedded(path, structsByName, filedata)
	for _, str := range otherStructs {
		if _, ok := structsByName[str.Name]; !ok {
			str.Imported = true
			structsByName[str.Name] = str
		}
	}
	postPrepare(&filedata, structsByName)

	outf, err := os.Create(output)
	if err != nil {
		return err
	}

	{
		defer outf.Close()

		if err := prologTemplate.Execute(outf, &filedata); err != nil {
			return err
		}

		for _, str := range structs {
			if err := structPreambleTemplate.Execute(outf, &str); err != nil {
				return err
			}
			if str.NoTable {
				continue
			}
			if err := structTemplate.Execute(outf, &str); err != nil {
				return err
			}
		}
	}

	if fmt {
		cmd := exec.Command("gofmt", "-s", "-w", output)
		if err := cmd.Run(); err != nil {
			logger.Fatal(err)
		}
	}

	return nil
}
<commit_msg>Add uint support<commit_after>package generate

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

// ColumnTypesMap associate column types to go types.
// It is used to guess the column type at generation time.
var ColumnTypesMap = map[string]string{
	"int":           "qb.Int()",
	"uint":          "qb.Int().Unsigned()",
	"int64":         "qb.BigInt()",
	"uint64":        "qb.BigInt().Unsigned()",
	"string":        "qb.Varchar()",
	"*string":       "qb.Varchar()",
	"bool":          "qb.Boolean()",
	"time.Time":     "qb.Timestamp()",
	"*time.Time":    "qb.Timestamp()",
	"uuid.UUID":     "qb.UUID()",
	"uuid.NullUUID": "qb.UUID()",
}

func guessColumnType(goType string) (string, error) {
	columnType, ok := ColumnTypesMap[goType]
	if ok {
		return columnType, nil
	}
	return "", fmt.Errorf("Cannot guess column type for go type %s", goType)
}

func makeColumnName(name string) string {
	return ToDBName(name)
}

func getEmptyValue(goType string) string {
	if goType[0] == '*' {
		return "nil"
	} else if goType == "string" {
		return `""`
	} else if goType[0:3] == "int" {
		return "0"
	} else if goType == "time.Time" {
		return "(time.Time{})"
	} else if goType == "uuid.UUID" {
		return "(uuid.UUID{})"
	} else if goType == "uuid.NullUUID" {
		return "(uuid.NullUUID{})"
	}
	panic(fmt.Sprintf("I have no empty value for type '%v'", goType))
}

func prepareFieldData(str *StructData, f *FieldData) {
	var err error
	if f.ColumnName == "" {
		f.ColumnName = makeColumnName(f.Name)
	}
	if f.ColumnType == "" {
		f.ColumnType, err = guessColumnType(f.Type)
		if err != nil {
			panic(fmt.Sprintf("Failure on field '%s': Got err '%s'",
				f.Name, err))
		}
	}
	if f.ColumnModifiers == "" {
		if f.Tags.PrimaryKey {
			f.ColumnModifiers += ".PrimaryKey()"
		}
		if f.Tags.AutoIncrement {
			f.ColumnModifiers += ".AutoIncrement()"
			str.AutoIncrementPKey = f
		}
		if f.Tags.Null {
			f.ColumnModifiers += ".Null()"
		} else if f.Tags.NotNull {
			f.ColumnModifiers += ".NotNull()"
		} else if f.Type[0] == '*' || strings.Contains(f.Type, "Null") {
			f.ColumnModifiers += ".Null()"
		} else {
			f.ColumnModifiers += ".NotNull()"
		}
	}
	if f.EmptyValue == "" && f.Tags.PrimaryKey {
		f.EmptyValue = getEmptyValue(f.Type)
	}
	if f.NameConst == "" {
		f.NameConst = fmt.Sprintf(
			"%s%s",
			str.Name, f.Name,
		)
	}
	if f.ColumnNameConst == "" {
		f.ColumnNameConst = fmt.Sprintf(
			"%s%sColumnName",
			str.Name, f.Name,
		)
	}
}

func prepareStructData(str *StructData, fd FileData) {
	str.File = fd
	str.PrivateBasename = strings.ToLower(str.Name[0:1]) + str.Name[1:]
	for i := range str.Fields {
		prepareFieldData(str, &str.Fields[i])
	}
}

func loadEmbedded(path string, structs map[string]*StructData, fd FileData) []*StructData {
	var newStructs []*StructData

	var hasEmbed bool

	for _, str := range structs {
		if len(str.Embed) != 0 {
			hasEmbed = true
		}
	}

	if !hasEmbed {
		return []*StructData{}
	}

	otherStructsByName := make(map[string]*StructData)

	var err error
	newStructs, err = ParseDir(path)
	if err != nil {
		panic(err)
	}
	for _, str := range newStructs {
		prepareStructData(str, fd)
		otherStructsByName[str.Name] = str
	}

	allStructs := []*StructData{}
	for _, str := range structs {
		allStructs = append(allStructs, str)
	}
	allStructs = append(allStructs, newStructs...)

	for _, str := range allStructs {
		for _, name := range str.Embed {
			embedded, ok := structs[name]
			if !ok {
				embedded, ok = otherStructsByName[name]
			}
			if ok {
				for index, fields := range embedded.Indexes {
					if _, ok := str.Indexes[index]; !ok {
						str.Indexes[index] = []int{}
					}
					for _, fieldIndex := range fields {
						str.Indexes[index] = append(str.Indexes[index], len(str.Fields)+fieldIndex)
					}
				}
				for _, field := range embedded.Fields {
					field.FromEmbedded = true
					str.Fields = append(str.Fields, field)
				}
			} else {
				fmt.Println(
					"Could not find embedded struct definition for '" + name + "'")
			}
		}
	}
	return newStructs
}

func postPrepare(filedata *FileData, structs map[string]*StructData) {
	for _, str := range structs {
		for i := range str.Fields {
			if str.Fields[i].Tags.PrimaryKey {
				str.PKeyFields = append(str.PKeyFields, &str.Fields[i])
			}
		}
		if len(str.PKeyFields) == 0 {
			panic(fmt.Sprintf("No Primary Key found on %s", str.Name))
		}
	}
	for _, str := range structs {
		if str.Imported {
			continue
		}
		for i, f := range str.Fields {
			if f.Tags.PrimaryKey && str.Fields[i].Type == "uuid.UUID" {
				filedata.Imports["github.com/m4rw3r/uuid"] = true
			}
			for _, fkDef := range str.Fields[i].Tags.ForeignKeys {
				var (
					fk           string
					structName   string
					refFieldName string
					refStruct    *StructData
					refField     *FieldData
					onUpdate     string
					onDelete     string
				)
				if strings.Index(fkDef, " ") != -1 {
					splitted := strings.Split(fkDef, " ")
					fk = splitted[0]
					for i, w := range splitted[1 : len(splitted)-1] {
						if strings.ToUpper(w) == "ONUPDATE" {
							onUpdate = strings.ToUpper(splitted[i+2])
						}
						if strings.ToUpper(w) == "ONDELETE" {
							onDelete = strings.ToUpper(splitted[i+2])
						}
					}
				} else {
					fk = fkDef
				}
				if strings.Index(fk, ".") != -1 {
					splitted := strings.Split(fk, ".")
					structName = splitted[0]
					refFieldName = splitted[1]
				} else {
					structName = fk
				}
				refStruct = structs[structName]
				if refFieldName == "" {
					refField = refStruct.PKeyFields[0]
				} else {
					for i := range refStruct.Fields {
						if refStruct.Fields[i].Name == refFieldName {
							refField = &refStruct.Fields[i]
						}
					}
				}

				str.ForeignKeys = append(str.ForeignKeys, FKData{
					Column:    &str.Fields[i],
					RefTable:  refStruct,
					RefColumn: refField,
					OnUpdate:  onUpdate,
					OnDelete:  onDelete,
				})
			}
		}
	}
}

// ProcessFile processes a go file and generates mapper and mappedstruct
// interfaces implementations for the yago structs.
func ProcessFile(logger *log.Logger, path string, file string, pack string, output string, fmt bool) error {

	ext := filepath.Ext(file)
	base := strings.TrimSuffix(file, ext)

	if output == "" {
		output = filepath.Join(path, base+"_yago"+ext)
	}

	filedata := FileData{Package: pack, Imports: make(map[string]bool)}

	structs, err := ParseFile(filepath.Join(path, file))
	if err != nil {
		return err
	}

	structsByName := make(map[string]*StructData)
	for _, str := range structs {
		prepareStructData(str, filedata)
		structsByName[str.Name] = str
		if !str.NoTable {
			filedata.HasTables = true
		}
	}
	otherStructs := loadEmbedded(path, structsByName, filedata)
	for _, str := range otherStructs {
		if _, ok := structsByName[str.Name]; !ok {
			str.Imported = true
			structsByName[str.Name] = str
		}
	}
	postPrepare(&filedata, structsByName)

	outf, err := os.Create(output)
	if err != nil {
		return err
	}

	{
		defer outf.Close()

		if err := prologTemplate.Execute(outf, &filedata); err != nil {
			return err
		}

		for _, str := range structs {
			if err := structPreambleTemplate.Execute(outf, &str); err != nil {
				return err
			}
			if str.NoTable {
				continue
			}
			if err := structTemplate.Execute(outf, &str); err != nil {
				return err
			}
		}
	}

	if fmt {
		cmd := exec.Command("gofmt", "-s", "-w", output)
		if err := cmd.Run(); err != nil {
			logger.Fatal(err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package geom

import (
	"errors"
	"sort"

	"github.com/omniscale/imposm3/element"
	"github.com/omniscale/imposm3/geom/geos"
)

type PreparedRelation struct {
	rings []*ring
	rel   *element.Relation
	srid  int
}

// PrepareRelation is the first step in building a (multi-)polygon of a Relation.
// It builds rings from all ways and returns an error if there are unclosed rings.
// It also merges the Relation.Tags with the Tags of the outer way.
func PrepareRelation(rel *element.Relation, srid int, maxRingGap float64) (PreparedRelation, error) {
	rings, err := buildRings(rel, maxRingGap)
	if err != nil {
		return PreparedRelation{}, err
	}

	rel.Tags = relationTags(rel.Tags, rings[0].ways[0].Tags)

	return PreparedRelation{rings, rel, srid}, nil
}

// Build creates the (multi)polygon Geometry of the Relation.
func (prep *PreparedRelation) Build() (Geometry, error) {
	g := geos.NewGeos()
	g.SetHandleSrid(prep.srid)
	defer g.Finish()

	geom, err := buildRelGeometry(g, prep.rel, prep.rings)
	if err != nil {
		return Geometry{}, err
	}

	wkb := g.AsEwkbHex(geom)
	if wkb == nil {
		return Geometry{}, errors.New("unable to create WKB for relation")
	}
	return Geometry{Geom: geom, Wkb: wkb}, nil
}

func destroyRings(g *geos.Geos, rings []*ring) {
	for _, r := range rings {
		if r.geom != nil {
			g.Destroy(r.geom)
			r.geom = nil
		}
	}
}

func buildRings(rel *element.Relation, maxRingGap float64) ([]*ring, error) {
	var rings []*ring
	var incompleteRings []*ring
	var completeRings []*ring
	var mergedRings []*ring
	var err error
	g := geos.NewGeos()
	defer g.Finish()

	defer func() {
		if err != nil {
			destroyRings(g, mergedRings)
			destroyRings(g, completeRings)
		}
	}()

	// create rings for all WAY members
	for _, member := range rel.Members {
		if member.Way == nil {
			continue
		}
		rings = append(rings, newRing(member.Way))
	}

	// create geometries for closed rings, collect incomplete rings
	for _, r := range rings {
		if r.isClosed() {
			r.geom, err = Polygon(g, r.nodes)
			if err != nil {
				return nil, err
			}
			completeRings = append(completeRings, r)
		} else {
			incompleteRings = append(incompleteRings, r)
		}
	}
	// merge incomplete rings
	mergedRings = mergeRings(incompleteRings)

	// create geometries for merged rings
	for _, ring := range mergedRings {
		if !ring.isClosed() && !ring.tryClose(maxRingGap) {
			continue
		}
		ring.geom, err = Polygon(g, ring.nodes)
		if err != nil {
			return nil, err
		}
		completeRings = append(completeRings, ring)
	}

	if len(completeRings) == 0 {
		err = ErrorNoRing // for defer
		return nil, err
	}

	// sort by area (large to small)
	for _, r := range completeRings {
		r.area = r.geom.Area()
	}
	sort.Sort(sortableRingsDesc(completeRings))

	return completeRings, nil
}

type sortableRingsDesc []*ring

func (r sortableRingsDesc) Len() int           { return len(r) }
func (r sortableRingsDesc) Less(i, j int) bool { return r[i].area > r[j].area }
func (r sortableRingsDesc) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }

// buildRelGeometry builds the geometry of rel by creating a multipolygon of all rings.
// rings need to be sorted by area (large to small).
func buildRelGeometry(g *geos.Geos, rel *element.Relation, rings []*ring) (*geos.Geom, error) {
	totalRings := len(rings)
	shells := map[*ring]bool{rings[0]: true}
	for i := 0; i < totalRings; i++ {
		testGeom := g.Prepare(rings[i].geom)
		if testGeom == nil {
			return nil, errors.New("Error while preparing geometry")
		}
		for j := i + 1; j < totalRings; j++ {
			if g.PreparedContains(testGeom, rings[j].geom) {
				if rings[j].containedBy != -1 {
					// j is inside a larger ring, remove that relationship
					// e.g. j is hole inside a hole (i)
					delete(rings[rings[j].containedBy].holes, rings[j])
					delete(shells, rings[j])
				}
				// remember parent
				rings[j].containedBy = i
				// add ring as hole or shell
				if ringIsHole(rings, j) {
					rings[i].holes[rings[j]] = true
					rings[i].outer = false
				} else {
					shells[rings[j]] = true
					rings[i].outer = true
				}
			}
		}
		if rings[i].containedBy == -1 {
			// add as shell if it is not a hole
			shells[rings[i]] = true
			rings[i].outer = true
		}
		g.PreparedDestroy(testGeom)
	}

	var polygons []*geos.Geom
	for shell, _ := range shells {
		var interiors []*geos.Geom
		for hole, _ := range shell.holes {
			ring := g.Clone(g.ExteriorRing(hole.geom))
			g.Destroy(hole.geom)
			if ring == nil {
				return nil, errors.New("Error while getting exterior ring.")
			}
			interiors = append(interiors, ring)
		}
		exterior := g.Clone(g.ExteriorRing(shell.geom))
		g.Destroy(shell.geom)
		if exterior == nil {
			return nil, errors.New("Error while getting exterior ring.")
		}
		polygon := g.Polygon(exterior, interiors)
		if polygon == nil {
			return nil, errors.New("Error while building polygon.")
		}
		polygons = append(polygons, polygon)
	}
	var result *geos.Geom

	if len(polygons) == 1 {
		result = polygons[0]
	} else {
		result = g.MultiPolygon(polygons)
		if result == nil {
			return nil, errors.New("Error while building multi-polygon.")
		}
	}
	var err error
	result, err = g.MakeValid(result)
	if err != nil {
		return nil, err
	}

	g.DestroyLater(result)

	outer := make(map[int64]struct{})
	for i := range rings {
		if rings[i].outer {
			for _, w := range rings[i].ways {
				outer[w.Id] = struct{}{}
			}
		}
	}
	for i := range rel.Members {
		mid := rel.Members[i].Id
		if _, ok := outer[mid]; ok {
			rel.Members[i].Role = "outer"
		} else {
			rel.Members[i].Role = "inner"
		}
	}

	return result, nil
}

func relationTags(relTags, wayTags element.Tags) element.Tags {
	result := make(element.Tags)
	for k, v := range relTags {
		if k == "name" || k == "type" {
			continue
		}
		result[k] = v
	}

	if len(result) == 0 {
		// relation does not have tags? use way tags
		for k, v := range wayTags {
			result[k] = v
		}
	} else {
		// add back name (if present)
		if name, ok := relTags["name"]; ok {
			result["name"] = name
		}
	}
	return result
}

// ringIsHole returns true if rings[idx] is a hole, False if it is a
// shell (also if hole in a hole, etc)
func ringIsHole(rings []*ring, idx int) bool {

	containedCounter := 0
	for {
		idx = rings[idx].containedBy
		if idx == -1 {

			break
		}
		containedCounter += 1
	}
	return containedCounter%2 == 1
}
<commit_msg>MultiPolygon builder only uses members with inner or outer role.<commit_after>package geom

import (
	"errors"
	"sort"

	"github.com/omniscale/imposm3/element"
	"github.com/omniscale/imposm3/geom/geos"
)

type PreparedRelation struct {
	rings []*ring
	rel   *element.Relation
	srid  int
}

// PrepareRelation is the first step in building a (multi-)polygon of a Relation.
// It builds rings from all ways and returns an error if there are unclosed rings.
// It also merges the Relation.Tags with the Tags of the outer way.
func PrepareRelation(rel *element.Relation, srid int, maxRingGap float64) (PreparedRelation, error) {
	rings, err := buildRings(rel, maxRingGap)
	if err != nil {
		return PreparedRelation{}, err
	}

	rel.Tags = relationTags(rel.Tags, rings[0].ways[0].Tags)

	return PreparedRelation{rings, rel, srid}, nil
}

// Build creates the (multi)polygon Geometry of the Relation.
func (prep *PreparedRelation) Build() (Geometry, error) {
	g := geos.NewGeos()
	g.SetHandleSrid(prep.srid)
	defer g.Finish()

	geom, err := buildRelGeometry(g, prep.rel, prep.rings)
	if err != nil {
		return Geometry{}, err
	}

	wkb := g.AsEwkbHex(geom)
	if wkb == nil {
		return Geometry{}, errors.New("unable to create WKB for relation")
	}
	return Geometry{Geom: geom, Wkb: wkb}, nil
}

func destroyRings(g *geos.Geos, rings []*ring) {
	for _, r := range rings {
		if r.geom != nil {
			g.Destroy(r.geom)
			r.geom = nil
		}
	}
}

func buildRings(rel *element.Relation, maxRingGap float64) ([]*ring, error) {
	var rings []*ring
	var incompleteRings []*ring
	var completeRings []*ring
	var mergedRings []*ring
	var err error
	g := geos.NewGeos()
	defer g.Finish()

	defer func() {
		if err != nil {
			destroyRings(g, mergedRings)
			destroyRings(g, completeRings)
		}
	}()

	// create rings for all WAY members
	for _, member := range rel.Members {
		if member.Way == nil {
			continue
		}
		if member.Role == "inner" || member.Role == "outer" {
			rings = append(rings, newRing(member.Way))
		}
	}

	// create geometries for closed rings, collect incomplete rings
	for _, r := range rings {
		if r.isClosed() {
			r.geom, err = Polygon(g, r.nodes)
			if err != nil {
				return nil, err
			}
			completeRings = append(completeRings, r)
		} else {
			incompleteRings = append(incompleteRings, r)
		}
	}
	// merge incomplete rings
	mergedRings = mergeRings(incompleteRings)

	// create geometries for merged rings
	for _, ring := range mergedRings {
		if !ring.isClosed() && !ring.tryClose(maxRingGap) {
			continue
		}
		ring.geom, err = Polygon(g, ring.nodes)
		if err != nil {
			return nil, err
		}
		completeRings = append(completeRings, ring)
	}

	if len(completeRings) == 0 {
		err = ErrorNoRing // for defer
		return nil, err
	}

	// sort by area (large to small)
	for _, r := range completeRings {
		r.area = r.geom.Area()
	}
	sort.Sort(sortableRingsDesc(completeRings))

	return completeRings, nil
}

type sortableRingsDesc []*ring

func (r sortableRingsDesc) Len() int           { return len(r) }
func (r sortableRingsDesc) Less(i, j int) bool { return r[i].area > r[j].area }
func (r sortableRingsDesc) Swap(i, j int)      { r[i], r[j] = r[j], r[i] }

// buildRelGeometry builds the geometry of rel by creating a multipolygon of all rings.
// rings need to be sorted by area (large to small).
func buildRelGeometry(g *geos.Geos, rel *element.Relation, rings []*ring) (*geos.Geom, error) {
	totalRings := len(rings)
	shells := map[*ring]bool{rings[0]: true}
	for i := 0; i < totalRings; i++ {
		testGeom := g.Prepare(rings[i].geom)
		if testGeom == nil {
			return nil, errors.New("Error while preparing geometry")
		}
		for j := i + 1; j < totalRings; j++ {
			if g.PreparedContains(testGeom, rings[j].geom) {
				if rings[j].containedBy != -1 {
					// j is inside a larger ring, remove that relationship
					// e.g. j is hole inside a hole (i)
					delete(rings[rings[j].containedBy].holes, rings[j])
					delete(shells, rings[j])
				}
				// remember parent
				rings[j].containedBy = i
				// add ring as hole or shell
				if ringIsHole(rings, j) {
					rings[i].holes[rings[j]] = true
					rings[i].outer = false
				} else {
					shells[rings[j]] = true
					rings[i].outer = true
				}
			}
		}
		if rings[i].containedBy == -1 {
			// add as shell if it is not a hole
			shells[rings[i]] = true
			rings[i].outer = true
		}
		g.PreparedDestroy(testGeom)
	}

	var polygons []*geos.Geom
	for shell, _ := range shells {
		var interiors []*geos.Geom
		for hole, _ := range shell.holes {
			ring := g.Clone(g.ExteriorRing(hole.geom))
			g.Destroy(hole.geom)
			if ring == nil {
				return nil, errors.New("Error while getting exterior ring.")
			}
			interiors = append(interiors, ring)
		}
		exterior := g.Clone(g.ExteriorRing(shell.geom))
		g.Destroy(shell.geom)
		if exterior == nil {
			return nil, errors.New("Error while getting exterior ring.")
		}
		polygon := g.Polygon(exterior, interiors)
		if polygon == nil {
			return nil, errors.New("Error while building polygon.")
		}
		polygons = append(polygons, polygon)
	}
	var result *geos.Geom

	if len(polygons) == 1 {
		result = polygons[0]
	} else {
		result = g.MultiPolygon(polygons)
		if result == nil {
			return nil, errors.New("Error while building multi-polygon.")
		}
	}
	var err error
	result, err = g.MakeValid(result)
	if err != nil {
		return nil, err
	}

	g.DestroyLater(result)

	outer := make(map[int64]struct{})
	for i := range rings {
		if rings[i].outer {
			for _, w := range rings[i].ways {
				outer[w.Id] = struct{}{}
			}
		}
	}
	for i := range rel.Members {
		mid := rel.Members[i].Id
		if _, ok := outer[mid]; ok {
			rel.Members[i].Role = "outer"
		} else {
			rel.Members[i].Role = "inner"
		}
	}

	return result, nil
}

func relationTags(relTags, wayTags element.Tags) element.Tags {
	result := make(element.Tags)
	for k, v := range relTags {
		if k == "name" || k == "type" {
			continue
		}
		result[k] = v
	}

	if len(result) == 0 {
		// relation does not have tags? use way tags
		for k, v := range wayTags {
			result[k] = v
		}
	} else {
		// add back name (if present)
		if name, ok := relTags["name"]; ok {
			result["name"] = name
		}
	}
	return result
}

// ringIsHole returns true if rings[idx] is a hole, False if it is a
// shell (also if hole in a hole, etc)
func ringIsHole(rings []*ring, idx int) bool {

	containedCounter := 0
	for {
		idx = rings[idx].containedBy
		if idx == -1 {

			break
		}
		containedCounter += 1
	}
	return containedCounter%2 == 1
}
<|endoftext|>


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

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestUser_marshall(t *testing.T) {
	testJSONMarshal(t, &User{}, "{}")

	u := &User{
		Login:           String("l"),
		ID:              Int64(1),
		URL:             String("u"),
		AvatarURL:       String("a"),
		GravatarID:      String("g"),
		Name:            String("n"),
		Company:         String("c"),
		Blog:            String("b"),
		Location:        String("l"),
		Email:           String("e"),
		Hireable:        Bool(true),
		Bio:             String("b"),
		TwitterUsername: String("t"),
		PublicRepos:     Int(1),
		Followers:       Int(1),
		Following:       Int(1),
		CreatedAt:       &Timestamp{referenceTime},
		SuspendedAt:     &Timestamp{referenceTime},
	}
	want := `{
		"login": "l",
		"id": 1,
		"avatar_url": "a",
		"gravatar_id": "g",
		"name": "n",
		"company": "c",
		"blog": "b",
		"location": "l",
		"email": "e",
		"hireable": true,
		"bio": "b",
		"twitter_username": "t",
		"public_repos": 1,
		"followers": 1,
		"following": 1,
		"created_at": ` + referenceTimeStr + `,
		"suspended_at": ` + referenceTimeStr + `,
		"url": "u"
	}`
	testJSONMarshal(t, u, want)
}

func TestUsersService_Get_authenticatedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Get(ctx, "")
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Get returned %+v, want %+v", user, want)
	}
}

func TestUsersService_Get_specifiedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Get(ctx, "u")
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Get returned %+v, want %+v", user, want)
	}
}

func TestUsersService_Get_invalidUser(t *testing.T) {
	client, _, _, teardown := setup()
	defer teardown()

	ctx := context.Background()
	_, _, err := client.Users.Get(ctx, "%")
	testURLParseError(t, err)
}

func TestUsersService_GetByID(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.GetByID(ctx, 1)
	if err != nil {
		t.Fatalf("Users.GetByID returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.GetByID returned %+v, want %+v", user, want)
	}
}

func TestUsersService_Edit(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &User{Name: String("n")}

	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		v := new(User)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		if !reflect.DeepEqual(v, input) {
			t.Errorf("Request body = %+v, want %+v", v, input)
		}

		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Edit(ctx, input)
	if err != nil {
		t.Errorf("Users.Edit returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Edit returned %+v, want %+v", user, want)
	}
}

func TestUsersService_GetHovercard(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u/hovercard", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{"subject_type": "repository", "subject_id": "20180408"})
		fmt.Fprint(w, `{"contexts": [{"message":"Owns this repository", "octicon": "repo"}]}`)
	})

	opt := &HovercardOptions{SubjectType: "repository", SubjectID: "20180408"}
	ctx := context.Background()
	hovercard, _, err := client.Users.GetHovercard(ctx, "u", opt)
	if err != nil {
		t.Errorf("Users.GetHovercard returned error: %v", err)
	}

	want := &Hovercard{Contexts: []*UserContext{{Message: String("Owns this repository"), Octicon: String("repo")}}}
	if !reflect.DeepEqual(hovercard, want) {
		t.Errorf("Users.GetHovercard returned %+v, want %+v", hovercard, want)
	}
}

func TestUsersService_ListAll(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{"since": "1", "page": "2"})
		fmt.Fprint(w, `[{"id":2}]`)
	})

	opt := &UserListOptions{1, ListOptions{Page: 2}}
	ctx := context.Background()
	users, _, err := client.Users.ListAll(ctx, opt)
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := []*User{{ID: Int64(2)}}
	if !reflect.DeepEqual(users, want) {
		t.Errorf("Users.ListAll returned %+v, want %+v", users, want)
	}
}

func TestUsersService_ListInvitations(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
	})

	ctx := context.Background()
	got, _, err := client.Users.ListInvitations(ctx, nil)
	if err != nil {
		t.Errorf("Users.ListInvitations returned error: %v", err)
	}

	want := []*RepositoryInvitation{{ID: Int64(1)}, {ID: Int64(2)}}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("Users.ListInvitations = %+v, want %+v", got, want)
	}
}

func TestUsersService_ListInvitations_withOptions(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
	})

	ctx := context.Background()
	_, _, err := client.Users.ListInvitations(ctx, &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Users.ListInvitations returned error: %v", err)
	}
}
func TestUsersService_AcceptInvitation(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "PATCH")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	if _, err := client.Users.AcceptInvitation(ctx, 1); err != nil {
		t.Errorf("Users.AcceptInvitation returned error: %v", err)
	}
}

func TestUsersService_DeclineInvitation(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "DELETE")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	if _, err := client.Users.DeclineInvitation(ctx, 1); err != nil {
		t.Errorf("Users.DeclineInvitation returned error: %v", err)
	}
}
<commit_msg>Improve users.go coverage (#1696)<commit_after>// Copyright 2013 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

func TestUser_marshall(t *testing.T) {
	testJSONMarshal(t, &User{}, "{}")

	u := &User{
		Login:           String("l"),
		ID:              Int64(1),
		URL:             String("u"),
		AvatarURL:       String("a"),
		GravatarID:      String("g"),
		Name:            String("n"),
		Company:         String("c"),
		Blog:            String("b"),
		Location:        String("l"),
		Email:           String("e"),
		Hireable:        Bool(true),
		Bio:             String("b"),
		TwitterUsername: String("t"),
		PublicRepos:     Int(1),
		Followers:       Int(1),
		Following:       Int(1),
		CreatedAt:       &Timestamp{referenceTime},
		SuspendedAt:     &Timestamp{referenceTime},
	}
	want := `{
		"login": "l",
		"id": 1,
		"avatar_url": "a",
		"gravatar_id": "g",
		"name": "n",
		"company": "c",
		"blog": "b",
		"location": "l",
		"email": "e",
		"hireable": true,
		"bio": "b",
		"twitter_username": "t",
		"public_repos": 1,
		"followers": 1,
		"following": 1,
		"created_at": ` + referenceTimeStr + `,
		"suspended_at": ` + referenceTimeStr + `,
		"url": "u"
	}`
	testJSONMarshal(t, u, want)
}

func TestUsersService_Get_authenticatedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Get(ctx, "")
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Get returned %+v, want %+v", user, want)
	}

	const methodName = "Get"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Users.Get(ctx, "\n")
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.Get(ctx, "")
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_Get_specifiedUser(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Get(ctx, "u")
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Get returned %+v, want %+v", user, want)
	}
}

func TestUsersService_Get_invalidUser(t *testing.T) {
	client, _, _, teardown := setup()
	defer teardown()

	ctx := context.Background()
	_, _, err := client.Users.Get(ctx, "%")
	testURLParseError(t, err)
}

func TestUsersService_GetByID(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.GetByID(ctx, 1)
	if err != nil {
		t.Fatalf("Users.GetByID returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.GetByID returned %+v, want %+v", user, want)
	}

	const methodName = "GetByID"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Users.GetByID(ctx, -1)
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.GetByID(ctx, 1)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_Edit(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	input := &User{Name: String("n")}

	mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		v := new(User)
		json.NewDecoder(r.Body).Decode(v)

		testMethod(t, r, "PATCH")
		if !reflect.DeepEqual(v, input) {
			t.Errorf("Request body = %+v, want %+v", v, input)
		}

		fmt.Fprint(w, `{"id":1}`)
	})

	ctx := context.Background()
	user, _, err := client.Users.Edit(ctx, input)
	if err != nil {
		t.Errorf("Users.Edit returned error: %v", err)
	}

	want := &User{ID: Int64(1)}
	if !reflect.DeepEqual(user, want) {
		t.Errorf("Users.Edit returned %+v, want %+v", user, want)
	}

	const methodName = "Edit"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.Edit(ctx, input)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_GetHovercard(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users/u/hovercard", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{"subject_type": "repository", "subject_id": "20180408"})
		fmt.Fprint(w, `{"contexts": [{"message":"Owns this repository", "octicon": "repo"}]}`)
	})

	opt := &HovercardOptions{SubjectType: "repository", SubjectID: "20180408"}
	ctx := context.Background()
	hovercard, _, err := client.Users.GetHovercard(ctx, "u", opt)
	if err != nil {
		t.Errorf("Users.GetHovercard returned error: %v", err)
	}

	want := &Hovercard{Contexts: []*UserContext{{Message: String("Owns this repository"), Octicon: String("repo")}}}
	if !reflect.DeepEqual(hovercard, want) {
		t.Errorf("Users.GetHovercard returned %+v, want %+v", hovercard, want)
	}

	const methodName = "GetHovercard"
	testBadOptions(t, methodName, func() (err error) {
		_, _, err = client.Users.GetHovercard(ctx, "\n", opt)
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.GetHovercard(ctx, "u", opt)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_ListAll(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{"since": "1", "page": "2"})
		fmt.Fprint(w, `[{"id":2}]`)
	})

	opt := &UserListOptions{1, ListOptions{Page: 2}}
	ctx := context.Background()
	users, _, err := client.Users.ListAll(ctx, opt)
	if err != nil {
		t.Errorf("Users.Get returned error: %v", err)
	}

	want := []*User{{ID: Int64(2)}}
	if !reflect.DeepEqual(users, want) {
		t.Errorf("Users.ListAll returned %+v, want %+v", users, want)
	}

	const methodName = "ListAll"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.ListAll(ctx, opt)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_ListInvitations(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
	})

	ctx := context.Background()
	got, _, err := client.Users.ListInvitations(ctx, nil)
	if err != nil {
		t.Errorf("Users.ListInvitations returned error: %v", err)
	}

	want := []*RepositoryInvitation{{ID: Int64(1)}, {ID: Int64(2)}}
	if !reflect.DeepEqual(got, want) {
		t.Errorf("Users.ListInvitations = %+v, want %+v", got, want)
	}

	const methodName = "ListInvitations"
	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		got, resp, err := client.Users.ListInvitations(ctx, nil)
		if got != nil {
			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
		}
		return resp, err
	})
}

func TestUsersService_ListInvitations_withOptions(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "GET")
		testFormValues(t, r, values{
			"page": "2",
		})
		fmt.Fprintf(w, `[{"id":1}, {"id":2}]`)
	})

	ctx := context.Background()
	_, _, err := client.Users.ListInvitations(ctx, &ListOptions{Page: 2})
	if err != nil {
		t.Errorf("Users.ListInvitations returned error: %v", err)
	}
}

func TestUsersService_AcceptInvitation(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "PATCH")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	if _, err := client.Users.AcceptInvitation(ctx, 1); err != nil {
		t.Errorf("Users.AcceptInvitation returned error: %v", err)
	}

	const methodName = "AcceptInvitation"
	testBadOptions(t, methodName, func() (err error) {
		_, err = client.Users.AcceptInvitation(ctx, -1)
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		return client.Users.AcceptInvitation(ctx, 1)
	})
}

func TestUsersService_DeclineInvitation(t *testing.T) {
	client, mux, _, teardown := setup()
	defer teardown()

	mux.HandleFunc("/user/repository_invitations/1", func(w http.ResponseWriter, r *http.Request) {
		testMethod(t, r, "DELETE")
		w.WriteHeader(http.StatusNoContent)
	})

	ctx := context.Background()
	if _, err := client.Users.DeclineInvitation(ctx, 1); err != nil {
		t.Errorf("Users.DeclineInvitation returned error: %v", err)
	}

	const methodName = "DeclineInvitation"
	testBadOptions(t, methodName, func() (err error) {
		_, err = client.Users.DeclineInvitation(ctx, -1)
		return err
	})

	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
		return client.Users.DeclineInvitation(ctx, 1)
	})
}
<|endoftext|>


<commit_before>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

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

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

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

import (
	"database/sql"
	"encoding/binary"
	"path/filepath"
	"sync"

	"github.com/openark/golib/sqlutils"

	"github.com/hashicorp/raft"
)

const raftStoreFile = "raft_store.db"

var createQueries = []string{
	`
		CREATE TABLE IF NOT EXISTS raft_log (
			log_index integer,
			term bigint not null,
			log_type int not null,
			data blob not null,
			PRIMARY KEY (log_index)
		)
	`,
	`
		CREATE TABLE IF NOT EXISTS raft_store (
			store_id integer,
			store_key varbinary(512) not null,
			store_value blob not null,
			PRIMARY KEY (store_id)
		)
	`,
	`
		CREATE INDEX IF NOT EXISTS store_key_idx_raft_store ON raft_store (store_key)
	`,
}

var dbMutex sync.Mutex

// RelationalStoreimplements:
// - hashicorp/raft.StableStore
// - hashicorp/log.LogStore
type RelationalStore struct {
	dataDir string
	backend *sql.DB
}

func NewRelationalStore(dataDir string) *RelationalStore {
	return &RelationalStore{
		dataDir: dataDir,
	}
}

func (relStore *RelationalStore) openDB() (*sql.DB, error) {
	dbMutex.Lock()
	defer dbMutex.Unlock()

	if relStore.backend == nil {
		relStoreFile := filepath.Join(relStore.dataDir, raftStoreFile)
		sqliteDB, _, err := sqlutils.GetSQLiteDB(relStoreFile)
		if err != nil {
			return nil, err
		}
		sqliteDB.SetMaxOpenConns(1)
		sqliteDB.SetMaxIdleConns(1)
		for _, query := range createQueries {
			if _, err := sqliteDB.Exec(sqlutils.ToSqlite3Dialect(query)); err != nil {
				return nil, err
			}
		}
		relStore.backend = sqliteDB
	}
	return relStore.backend, nil
}

func (relStore *RelationalStore) Set(key []byte, val []byte) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	stmt, err := tx.Prepare(`delete from raft_store where store_key = ?`)
	if err != nil {
		return err
	}
	_, err = stmt.Exec(key)
	if err != nil {
		tx.Rollback()
		return err
	}
	stmt, err = tx.Prepare(`insert into raft_store (store_key, store_value) values (?, ?)`)
	if err != nil {
		tx.Rollback()
		return err
	}
	_, err = stmt.Exec(key, val)
	if err != nil {
		tx.Rollback()
		return err
	}
	err = tx.Commit()

	return err
}

// Get returns the value for key, or an empty byte slice if key was not found.
func (relStore *RelationalStore) Get(key []byte) (val []byte, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return val, err
	}
	err = db.QueryRow("select min(store_value) from raft_store where store_key = ?", key).Scan(&val)
	return val, err
}

func (relStore *RelationalStore) SetUint64(key []byte, val uint64) error {
	b := make([]byte, 8)
	binary.LittleEndian.PutUint64(b, val)

	return relStore.Set(key, b)
}

// GetUint64 returns the uint64 value for key, or 0 if key was not found.
func (relStore *RelationalStore) GetUint64(key []byte) (uint64, error) {
	b, err := relStore.Get(key)
	if err != nil {
		return 0, err
	}
	if len(b) == 0 {
		// Not found
		return 0, nil
	}
	i := binary.LittleEndian.Uint64(b)
	return i, nil
}

func (relStore *RelationalStore) FirstIndex() (idx uint64, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return idx, err
	}
	err = db.QueryRow("select ifnull(min(log_index), 0) from raft_log").Scan(&idx)
	return idx, err
}

// LastIndex returns the last index written. 0 for no entries.
func (relStore *RelationalStore) LastIndex() (idx uint64, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return idx, err
	}
	err = db.QueryRow("select ifnull(max(log_index), 0) from raft_log").Scan(&idx)
	return idx, err
}

// GetLog gets a log entry at a given index.
func (relStore *RelationalStore) GetLog(index uint64, log *raft.Log) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	err = db.QueryRow(`
    select log_index, term, log_type, data
      from raft_log
      where log_index = ?
    `, index).Scan(&log.Index, &log.Term, &log.Type, &log.Data)
	if err == sql.ErrNoRows {
		return raft.ErrLogNotFound
	}
	return err
}

// StoreLog stores a log entry.
func (relStore *RelationalStore) StoreLog(log *raft.Log) error {
	return relStore.StoreLogs([]*raft.Log{log})
}

// StoreLogs stores multiple log entries.
func (relStore *RelationalStore) StoreLogs(logs []*raft.Log) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	stmt, err := tx.Prepare(`
    replace into raft_log (
      log_index, term, log_type, data
    ) values (
      ?, ?, ?, ?
    )`)
	if err != nil {
		return err
	}
	for _, raftLog := range logs {
		_, err = stmt.Exec(raftLog.Index, raftLog.Term, int(raftLog.Type), raftLog.Data)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

// DeleteRange deletes a range of log entries. The range is inclusive.
func (relStore *RelationalStore) DeleteRange(min, max uint64) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	_, err = db.Exec("delete from raft_log where log_index >= ? and log_index <= ?", min, max)
	return err
}

func (relStore *RelationalStore) DeleteAll() error {
	firstIndex, err := relStore.FirstIndex()
	if err != nil {
		return err
	}
	lastIndex, err := relStore.LastIndex()
	if err != nil {
		return err
	}
	return relStore.DeleteRange(firstIndex, lastIndex)
}
<commit_msg>more debug at store initialization<commit_after>/*
   Copyright 2017 Shlomi Noach, GitHub Inc.

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

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

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

import (
	"database/sql"
	"encoding/binary"
	"path/filepath"
	"sync"

	"github.com/openark/golib/log"
	"github.com/openark/golib/sqlutils"

	"github.com/hashicorp/raft"
)

const raftStoreFile = "raft_store.db"

var createQueries = []string{
	`
		CREATE TABLE IF NOT EXISTS raft_log (
			log_index integer,
			term bigint not null,
			log_type int not null,
			data blob not null,
			PRIMARY KEY (log_index)
		)
	`,
	`
		CREATE TABLE IF NOT EXISTS raft_store (
			store_id integer,
			store_key varbinary(512) not null,
			store_value blob not null,
			PRIMARY KEY (store_id)
		)
	`,
	`
		CREATE INDEX IF NOT EXISTS store_key_idx_raft_store ON raft_store (store_key)
	`,
}

var dbMutex sync.Mutex

// RelationalStoreimplements:
// - hashicorp/raft.StableStore
// - hashicorp/log.LogStore
type RelationalStore struct {
	dataDir string
	backend *sql.DB
}

func NewRelationalStore(dataDir string) *RelationalStore {
	return &RelationalStore{
		dataDir: dataDir,
	}
}

func (relStore *RelationalStore) openDB() (*sql.DB, error) {
	dbMutex.Lock()
	defer dbMutex.Unlock()

	if relStore.backend == nil {
		relStoreFile := filepath.Join(relStore.dataDir, raftStoreFile)
		sqliteDB, _, err := sqlutils.GetSQLiteDB(relStoreFile)
		if err != nil {
			return nil, err
		}
		sqliteDB.SetMaxOpenConns(1)
		sqliteDB.SetMaxIdleConns(1)
		for _, query := range createQueries {
			if _, err := sqliteDB.Exec(sqlutils.ToSqlite3Dialect(query)); err != nil {
				return nil, err
			}
		}
		relStore.backend = sqliteDB
		log.Infof("raft: store initialized at %+v", relStoreFile)
	}
	return relStore.backend, nil
}

func (relStore *RelationalStore) Set(key []byte, val []byte) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	stmt, err := tx.Prepare(`delete from raft_store where store_key = ?`)
	if err != nil {
		return err
	}
	_, err = stmt.Exec(key)
	if err != nil {
		tx.Rollback()
		return err
	}
	stmt, err = tx.Prepare(`insert into raft_store (store_key, store_value) values (?, ?)`)
	if err != nil {
		tx.Rollback()
		return err
	}
	_, err = stmt.Exec(key, val)
	if err != nil {
		tx.Rollback()
		return err
	}
	err = tx.Commit()

	return err
}

// Get returns the value for key, or an empty byte slice if key was not found.
func (relStore *RelationalStore) Get(key []byte) (val []byte, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return val, err
	}
	err = db.QueryRow("select min(store_value) from raft_store where store_key = ?", key).Scan(&val)
	return val, err
}

func (relStore *RelationalStore) SetUint64(key []byte, val uint64) error {
	b := make([]byte, 8)
	binary.LittleEndian.PutUint64(b, val)

	return relStore.Set(key, b)
}

// GetUint64 returns the uint64 value for key, or 0 if key was not found.
func (relStore *RelationalStore) GetUint64(key []byte) (uint64, error) {
	b, err := relStore.Get(key)
	if err != nil {
		return 0, err
	}
	if len(b) == 0 {
		// Not found
		return 0, nil
	}
	i := binary.LittleEndian.Uint64(b)
	return i, nil
}

func (relStore *RelationalStore) FirstIndex() (idx uint64, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return idx, err
	}
	err = db.QueryRow("select ifnull(min(log_index), 0) from raft_log").Scan(&idx)
	return idx, err
}

// LastIndex returns the last index written. 0 for no entries.
func (relStore *RelationalStore) LastIndex() (idx uint64, err error) {
	db, err := relStore.openDB()
	if err != nil {
		return idx, err
	}
	err = db.QueryRow("select ifnull(max(log_index), 0) from raft_log").Scan(&idx)
	return idx, err
}

// GetLog gets a log entry at a given index.
func (relStore *RelationalStore) GetLog(index uint64, log *raft.Log) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	err = db.QueryRow(`
    select log_index, term, log_type, data
      from raft_log
      where log_index = ?
    `, index).Scan(&log.Index, &log.Term, &log.Type, &log.Data)
	if err == sql.ErrNoRows {
		return raft.ErrLogNotFound
	}
	return err
}

// StoreLog stores a log entry.
func (relStore *RelationalStore) StoreLog(log *raft.Log) error {
	return relStore.StoreLogs([]*raft.Log{log})
}

// StoreLogs stores multiple log entries.
func (relStore *RelationalStore) StoreLogs(logs []*raft.Log) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	tx, err := db.Begin()
	if err != nil {
		return err
	}
	stmt, err := tx.Prepare(`
    replace into raft_log (
      log_index, term, log_type, data
    ) values (
      ?, ?, ?, ?
    )`)
	if err != nil {
		return err
	}
	for _, raftLog := range logs {
		_, err = stmt.Exec(raftLog.Index, raftLog.Term, int(raftLog.Type), raftLog.Data)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	return tx.Commit()
}

// DeleteRange deletes a range of log entries. The range is inclusive.
func (relStore *RelationalStore) DeleteRange(min, max uint64) error {
	db, err := relStore.openDB()
	if err != nil {
		return err
	}
	_, err = db.Exec("delete from raft_log where log_index >= ? and log_index <= ?", min, max)
	return err
}

func (relStore *RelationalStore) DeleteAll() error {
	firstIndex, err := relStore.FirstIndex()
	if err != nil {
		return err
	}
	lastIndex, err := relStore.LastIndex()
	if err != nil {
		return err
	}
	return relStore.DeleteRange(firstIndex, lastIndex)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/glendc/cgreader"
)

type program struct{}

func (p *program) Update(input string) {
	fmt.Println(input)
}

func main() {
	flag.Parse()
	if flag.NArg() == 1 {
		input := fmt.Sprintf("../input/super_computer_%s.txt", flag.Arg(0))
		ch, ok := cgreader.RunProgram(input)
		app := program{}
		for <-ok {
			app.Update(<-ch)
		}
	}
}
<commit_msg>Super computer passes test 1<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/glendc/cgreader"
)

type program struct {
	N            int
	Calculations map[int]int
}

func (p *program) Update(input string) {
	if p.N == 0 {
		fmt.Sscanf(input, "%d\n", &p.N)
		p.Calculations = make(map[int]int, p.N)
	} else {
		var start, duration int
		fmt.Sscanf(input, "%d %d\n", &start, &duration)

		if _, ok := p.Calculations[start]; !ok {
			p.Calculations[start] = duration
		}

		//for k,v := range p.Calculations {
		//}
	}
}

func (p *program) GetOutput() string {
	return fmt.Sprintf("%d\n", len(p.Calculations))
}

func main() {
	flag.Parse()
	n := flag.NArg()
	if n > 0 {
		input := fmt.Sprintf("../input/super_computer_%s.txt", flag.Arg(0))
		ch, ok := cgreader.RunProgram(input)
		app := program{}
		for <-ok {
			app.Update(<-ch)
		}
		output := app.GetOutput()
		fmt.Printf("Output:\n%s\n", output)
		if n > 1 {
			test := fmt.Sprintf("../output/super_computer_%s.txt", flag.Arg(0))
			fmt.Print("Test: ")
			if cgreader.TestProgram(test, output) {
				fmt.Print("Program is correct")
			} else {
				fmt.Print("Program is incorrect")
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"github.com/osrg/gobgp/api"
	"github.com/osrg/gobgp/packet"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"io"
	"os"
)

func NewMonitorCmd() *cobra.Command {
	ribCmd := &cobra.Command{
		Use: CMD_RIB,
		Run: func(cmd *cobra.Command, args []string) {
			family, err := checkAddressFamily(bgp.RouteFamily(0))
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			arg := &gobgpapi.Arguments{
				Resource: gobgpapi.Resource_GLOBAL,
				Family:   uint32(family),
			}

			stream, err := client.MonitorBestChanged(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				d, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				p, err := ApiStruct2Path(d.Paths[0])
				if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}

				if globalOpts.Json {
					j, _ := json.Marshal(p)
					fmt.Println(string(j))
				} else {
					ShowRoute(p, false, false, false, true, false)
				}
			}

		},
	}
	ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")

	globalCmd := &cobra.Command{
		Use: CMD_GLOBAL,
	}
	globalCmd.AddCommand(ribCmd)

	neighborCmd := &cobra.Command{
		Use: CMD_NEIGHBOR,
		Run: func(cmd *cobra.Command, args []string) {
			var arg *gobgpapi.Arguments
			if len(args) > 0 {
				arg = &gobgpapi.Arguments{
					Name: args[0],
				}
			} else {
				arg = &gobgpapi.Arguments{}
			}

			stream, err := client.MonitorPeerState(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(s)
					fmt.Println(string(j))
				} else {
					fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Conf.NeighborAddress, s.Info.BgpState, s.Info.AdminState)
				}
			}
		},
	}

	rpkiCmd := &cobra.Command{
		Use: CMD_RPKI,
		Run: func(cmd *cobra.Command, args []string) {
			stream, err := client.MonitorROAValidation(context.Background(), &gobgpapi.Arguments{})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(s)
					fmt.Println(string(j))
				} else {
					fmt.Println("validation:", s)
				}
			}
		},
	}

	monitorCmd := &cobra.Command{
		Use: CMD_MONITOR,
	}
	monitorCmd.AddCommand(globalCmd)
	monitorCmd.AddCommand(neighborCmd)
	monitorCmd.AddCommand(rpkiCmd)

	return monitorCmd
}
<commit_msg>gobgp: improve rpki monitor output<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 cmd

import (
	"encoding/json"
	"fmt"
	"github.com/osrg/gobgp/api"
	"github.com/osrg/gobgp/packet"
	"github.com/spf13/cobra"
	"golang.org/x/net/context"
	"io"
	"net"
	"os"
	"strconv"
	"time"
)

func NewMonitorCmd() *cobra.Command {
	ribCmd := &cobra.Command{
		Use: CMD_RIB,
		Run: func(cmd *cobra.Command, args []string) {
			family, err := checkAddressFamily(bgp.RouteFamily(0))
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			arg := &gobgpapi.Arguments{
				Resource: gobgpapi.Resource_GLOBAL,
				Family:   uint32(family),
			}

			stream, err := client.MonitorBestChanged(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				d, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				p, err := ApiStruct2Path(d.Paths[0])
				if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}

				if globalOpts.Json {
					j, _ := json.Marshal(p)
					fmt.Println(string(j))
				} else {
					ShowRoute(p, false, false, false, true, false)
				}
			}

		},
	}
	ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family")

	globalCmd := &cobra.Command{
		Use: CMD_GLOBAL,
	}
	globalCmd.AddCommand(ribCmd)

	neighborCmd := &cobra.Command{
		Use: CMD_NEIGHBOR,
		Run: func(cmd *cobra.Command, args []string) {
			var arg *gobgpapi.Arguments
			if len(args) > 0 {
				arg = &gobgpapi.Arguments{
					Name: args[0],
				}
			} else {
				arg = &gobgpapi.Arguments{}
			}

			stream, err := client.MonitorPeerState(context.Background(), arg)
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(s)
					fmt.Println(string(j))
				} else {
					fmt.Printf("[NEIGH] %s fsm: %s admin: %s\n", s.Conf.NeighborAddress, s.Info.BgpState, s.Info.AdminState)
				}
			}
		},
	}

	rpkiCmd := &cobra.Command{
		Use: CMD_RPKI,
		Run: func(cmd *cobra.Command, args []string) {
			stream, err := client.MonitorROAValidation(context.Background(), &gobgpapi.Arguments{})
			if err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
			for {
				s, err := stream.Recv()
				if err == io.EOF {
					break
				} else if err != nil {
					fmt.Println(err)
					os.Exit(1)
				}
				if globalOpts.Json {
					j, _ := json.Marshal(s)
					fmt.Println(string(j))
				} else {
					reason := "Update"
					if s.Reason == gobgpapi.ROAResult_WITHDRAW {
						reason = "Withdraw"
					} else if s.Reason == gobgpapi.ROAResult_PEER_DOWN {
						reason = "PeerDown"
					}
					aspath := &bgp.PathAttributeAsPath{}
					aspath.DecodeFromBytes(s.AspathAttr)
					fmt.Printf("[VALIDATION] Reason: %s, Peer: %s, Timestamp: %s, Prefix:%s, OriginAS:%d, ASPath:%s, Old:%s, New:%s", reason, s.Address, time.Unix(s.Timestamp, 0).String(), s.Prefix, s.OriginAs, aspath.String(), s.OldResult, s.NewResult)
					if len(s.Roas) == 0 {
						fmt.Printf("\n")
					} else {
						fmt.Printf(", ROAs:")
						for i, roa := range s.Roas {
							if i != 0 {
								fmt.Printf(",")
							}
							fmt.Printf(" [Source: %s, AS: %v, Prefix: %s, Prefixlen: %v, Maxlen: %v]", net.JoinHostPort(roa.Conf.Address, strconv.Itoa(int(roa.Conf.RemotePort))), roa.As, roa.Prefix, roa.Prefixlen, roa.Maxlen)
						}
						fmt.Printf("\n")
					}
				}
			}
		},
	}

	monitorCmd := &cobra.Command{
		Use: CMD_MONITOR,
	}
	monitorCmd.AddCommand(globalCmd)
	monitorCmd.AddCommand(neighborCmd)
	monitorCmd.AddCommand(rpkiCmd)

	return monitorCmd
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"regexp"
	"strings"
)

// given an email address get the i2p destination name for it
func parseFromI2PAddr(email string) (name string) {
	idx_at := strings.Index(email, "@")
	if strings.HasSuffix(email, ".b32.i2p") {
		name = email[idx_at+1:]
	} else if strings.HasSuffix(email, ".i2p") {
		idx_i2p := strings.LastIndex(email, ".i2p")
		name = fmt.Sprintf("smtp.%s.i2p", email[idx_at+1:idx_i2p])
	}
	name = strings.Trim(name, ",= \t\r\n\f\b")
	return
}

var re_email = regexp.MustCompile(`[a-zA-Z0-9]+@[a-zA-Z0-9]+\.i2p`)

func normalizeEmail(email string) (e string) {
	e = re_email.FindString(email)
	return
}
<commit_msg>try fixing email normalization<commit_after>package server

import (
	"fmt"
	"regexp"
	"strings"
)

// given an email address get the i2p destination name for it
func parseFromI2PAddr(email string) (name string) {
	idx_at := strings.Index(email, "@")
	if strings.HasSuffix(email, ".b32.i2p") {
		name = email[idx_at+1:]
	} else if strings.HasSuffix(email, ".i2p") {
		idx_i2p := strings.LastIndex(email, ".i2p")
		name = fmt.Sprintf("smtp.%s.i2p", email[idx_at+1:idx_i2p])
	}
	name = strings.Trim(name, ",= \t\r\n\f\b")
	return
}

var re_email = regexp.MustCompile(`[a-zA-Z0-9]+@[a-zA-Z0-9]+.i2p`)

func normalizeEmail(email string) (e string) {
	e = re_email.FindString(email)
	return
}
<|endoftext|>