<commit_before>package internal

import (
	"archive/tar"
	"errors"
	"fmt"

	"github.com/cloudfoundry-incubator/executor"
	"github.com/pivotal-golang/lager"
)

const MAX_RESULT_SIZE = 1024 * 10

var ErrResultFileTooLarge = errors.New(
	fmt.Sprintf("result file is too large (over %d bytes)", MAX_RESULT_SIZE),
)

//go:generate counterfeiter -o fake_internal/fake_container_delegate.go container_delegate.go ContainerDelegate

type ContainerDelegate interface {
	GetContainer(logger lager.Logger, guid string) (executor.Container, bool)
	RunContainer(logger lager.Logger, guid string) bool
	StopContainer(logger lager.Logger, guid string) bool
	DeleteContainer(logger lager.Logger, guid string) bool
	FetchContainerResult(logger lager.Logger, guid string, filename string) (string, error)
}

type containerDelegate struct {
	client executor.Client
}

func NewContainerDelegate(client executor.Client) ContainerDelegate {
	return &containerDelegate{
		client: client,
	}
}

func (d *containerDelegate) GetContainer(logger lager.Logger, guid string) (executor.Container, bool) {
	logger.Info("fetch-container")
	container, err := d.client.GetContainer(guid)
	if err != nil {
		logger.Error("faileed-fetch-container", err)
		return container, false
	}
	logger.Info("succeeded-fetch-container")
	return container, true
}

func (d *containerDelegate) RunContainer(logger lager.Logger, guid string) bool {
	logger.Info("running-container")
	err := d.client.RunContainer(guid)
	if err != nil {
		logger.Error("failed-running-container", err)
		d.DeleteContainer(logger, guid)
		return false
	}
	logger.Info("succeeded-running-container")
	return true
}

func (d *containerDelegate) StopContainer(logger lager.Logger, guid string) bool {
	logger.Info("stopping-container")
	err := d.client.StopContainer(guid)
	if err != nil {
		logger.Error("failed-stopping-container", err)
		return false
	}
	logger.Info("succeeded-stopping-container")
	return true
}

func (d *containerDelegate) DeleteContainer(logger lager.Logger, guid string) bool {
	logger.Info("deleting-container")
	err := d.client.DeleteContainer(guid)
	if err != nil {
		logger.Error("failed-deleting-container", err)
		return false
	}
	logger.Info("succeeded-deleting-container")
	return true
}

func (d *containerDelegate) FetchContainerResult(logger lager.Logger, guid string, filename string) (string, error) {
	stream, err := d.client.GetFiles(guid, filename)
	if err != nil {
		return "", err
	}

	defer stream.Close()

	tarReader := tar.NewReader(stream)

	_, err = tarReader.Next()
	if err != nil {
		return "", err
	}

	buf := make([]byte, MAX_RESULT_SIZE+1)
	n, err := tarReader.Read(buf)
	if n > MAX_RESULT_SIZE {
		return "", ErrResultFileTooLarge
	}

	return string(buf[:n]), nil
}
<commit_msg>Speeling anyone?<commit_after>package internal

import (
	"archive/tar"
	"errors"
	"fmt"

	"github.com/cloudfoundry-incubator/executor"
	"github.com/pivotal-golang/lager"
)

const MAX_RESULT_SIZE = 1024 * 10

var ErrResultFileTooLarge = errors.New(
	fmt.Sprintf("result file is too large (over %d bytes)", MAX_RESULT_SIZE),
)

//go:generate counterfeiter -o fake_internal/fake_container_delegate.go container_delegate.go ContainerDelegate

type ContainerDelegate interface {
	GetContainer(logger lager.Logger, guid string) (executor.Container, bool)
	RunContainer(logger lager.Logger, guid string) bool
	StopContainer(logger lager.Logger, guid string) bool
	DeleteContainer(logger lager.Logger, guid string) bool
	FetchContainerResult(logger lager.Logger, guid string, filename string) (string, error)
}

type containerDelegate struct {
	client executor.Client
}

func NewContainerDelegate(client executor.Client) ContainerDelegate {
	return &containerDelegate{
		client: client,
	}
}

func (d *containerDelegate) GetContainer(logger lager.Logger, guid string) (executor.Container, bool) {
	logger.Info("fetch-container")
	container, err := d.client.GetContainer(guid)
	if err != nil {
		logger.Error("failed-fetch-container", err)
		return container, false
	}
	logger.Info("succeeded-fetch-container")
	return container, true
}

func (d *containerDelegate) RunContainer(logger lager.Logger, guid string) bool {
	logger.Info("running-container")
	err := d.client.RunContainer(guid)
	if err != nil {
		logger.Error("failed-running-container", err)
		d.DeleteContainer(logger, guid)
		return false
	}
	logger.Info("succeeded-running-container")
	return true
}

func (d *containerDelegate) StopContainer(logger lager.Logger, guid string) bool {
	logger.Info("stopping-container")
	err := d.client.StopContainer(guid)
	if err != nil {
		logger.Error("failed-stopping-container", err)
		return false
	}
	logger.Info("succeeded-stopping-container")
	return true
}

func (d *containerDelegate) DeleteContainer(logger lager.Logger, guid string) bool {
	logger.Info("deleting-container")
	err := d.client.DeleteContainer(guid)
	if err != nil {
		logger.Error("failed-deleting-container", err)
		return false
	}
	logger.Info("succeeded-deleting-container")
	return true
}

func (d *containerDelegate) FetchContainerResult(logger lager.Logger, guid string, filename string) (string, error) {
	stream, err := d.client.GetFiles(guid, filename)
	if err != nil {
		return "", err
	}

	defer stream.Close()

	tarReader := tar.NewReader(stream)

	_, err = tarReader.Next()
	if err != nil {
		return "", err
	}

	buf := make([]byte, MAX_RESULT_SIZE+1)
	n, err := tarReader.Read(buf)
	if n > MAX_RESULT_SIZE {
		return "", ErrResultFileTooLarge
	}

	return string(buf[:n]), nil
}
<|endoftext|>


<commit_before>package appcast

import (
	"encoding/xml"
	"fmt"
	"regexp"
)

// SparkleRSSFeedAppcaster is the interface that wraps the SparkleRSSFeedAppcast
// methods.
type SparkleRSSFeedAppcaster interface {
	Appcaster
}

// SparkleRSSFeedAppcast represents the "Sparkle RSS Feed" appcast which is
// generated by Sparkle Framework.
type SparkleRSSFeedAppcast struct {
	Appcast
	channel *SparkleRSSFeedAppcastChannel
}

// SparkleRSSFeedAppcastChannel represents the "Sparkle RSS Feed" appcast
// channel data.
type SparkleRSSFeedAppcastChannel struct {
	Title       string
	Link        string
	Description string
	Language    string
}

// unmarshalSparkleRSSFeed represents an RSS itself for unmarshal purposes.
type unmarshalSparkleRSSFeed struct {
	Channel unmarshalSparkleRSSFeedChannel `xml:"channel"`
}

// unmarshalSparkleRSSFeedChannel represents the "Sparkle RSS Feed" channel for
// unmarshal purposes.
type unmarshalSparkleRSSFeedChannel struct {
	Title       string                        `xml:"title"`
	Link        string                        `xml:"link"`
	Description string                        `xml:"description"`
	Language    string                        `xml:"language"`
	Items       []unmarshalSparkleRSSFeedItem `xml:"item"`
}

// unmarshalSparkleRSSFeedItem represents an RSS item.
type unmarshalSparkleRSSFeedItem struct {
	Title                string                           `xml:"title"`
	Description          string                           `xml:"description"`
	MinimumSystemVersion string                           `xml:"minimumSystemVersion"`
	PubDate              string                           `xml:"pubDate"`
	Enclosure            unmarshalSparkleRSSFeedEnclosure `xml:"enclosure"`
	Version              string                           `xml:"version"`
	ShortVersionString   string                           `xml:"shortVersionString"`
}

// unmarshalSparkleRSSFeedEnclosure represents the "Sparkle RSS Feed" item
// enclosure for for unmarshal purposes.
type unmarshalSparkleRSSFeedEnclosure struct {
	Version            string `xml:"version,attr"`
	ShortVersionString string `xml:"shortVersionString,attr"`
	URL                string `xml:"url,attr"`
	Length             int    `xml:"length,attr"`
	Type               string `xml:"type,attr"`
}

// UnmarshalReleases unmarshals the Appcast.source.content into the
// Appcast.releases for the "Sparkle RSS Feed" provider.
func (a *SparkleRSSFeedAppcast) UnmarshalReleases() error {
	var x unmarshalSparkleRSSFeed
	var version, build string

	xml.Unmarshal(a.source.Content(), &x)

	a.channel = &SparkleRSSFeedAppcastChannel{
		Title:       x.Channel.Title,
		Link:        x.Channel.Link,
		Description: x.Channel.Description,
		Language:    x.Channel.Language,
	}

	items := make([]Releaser, len(x.Channel.Items))
	for i, item := range x.Channel.Items {
		if item.Enclosure.ShortVersionString == "" && item.ShortVersionString != "" {
			version = item.ShortVersionString
		} else {
			version = item.Enclosure.ShortVersionString
		}

		if item.Enclosure.Version == "" && item.Version != "" {
			build = item.Version
		} else {
			build = item.Enclosure.Version
		}

		if version == "" && build == "" {
			return fmt.Errorf("version is required, but it's not specified in release #%d", i+1)
		} else if version == "" && build != "" {
			version = build
		}

		// new release
		r, err := NewRelease(version, build)
		if err != nil {
			return err
		}

		r.SetTitle(item.Title)
		r.SetDescription(item.Description)
		r.ParsePublishedDateTime(item.PubDate)

		// prerelease
		if r.Version().Prerelease() != "" {
			r.SetIsPreRelease(true)
		}

		// downloads
		d := NewDownload(item.Enclosure.URL, item.Enclosure.Type, item.Enclosure.Length)
		r.AddDownload(*d)

		items[i] = r
	}

	a.releases = items

	return nil
}

// Uncomment uncomments XML tags in SparkleRSSFeedAppcast.source.content.
func (a *SparkleRSSFeedAppcast) Uncomment() error {
	if a.source == nil || len(a.source.Content()) == 0 {
		return fmt.Errorf("no source")
	}

	regex := regexp.MustCompile(`(<!--([[:space:]]*)?)|(([[:space:]]*)?-->)`)
	if regex.Match(a.source.Content()) {
		a.source.SetContent(regex.ReplaceAll(a.source.Content(), []byte("")))
	}

	return nil
}

// Channel is a SparkleRSSFeedAppcast.channel getter.
func (a *SparkleRSSFeedAppcast) Channel() *SparkleRSSFeedAppcastChannel {
	return a.channel
}

// SetChannel is a SparkleRSSFeedAppcast.channel setter.
func (a *SparkleRSSFeedAppcast) SetChannel(channel *SparkleRSSFeedAppcastChannel) {
	a.channel = channel
}
<commit_msg>Add missing Channel and SetChannel in the SparkleRSSFeedAppcaster interface<commit_after>package appcast

import (
	"encoding/xml"
	"fmt"
	"regexp"
)

// SparkleRSSFeedAppcaster is the interface that wraps the SparkleRSSFeedAppcast
// methods.
type SparkleRSSFeedAppcaster interface {
	Appcaster
	Channel() *SparkleRSSFeedAppcastChannel
	SetChannel(channel *SparkleRSSFeedAppcastChannel)
}

// SparkleRSSFeedAppcast represents the "Sparkle RSS Feed" appcast which is
// generated by Sparkle Framework.
type SparkleRSSFeedAppcast struct {
	Appcast
	channel *SparkleRSSFeedAppcastChannel
}

// SparkleRSSFeedAppcastChannel represents the "Sparkle RSS Feed" appcast
// channel data.
type SparkleRSSFeedAppcastChannel struct {
	Title       string
	Link        string
	Description string
	Language    string
}

// unmarshalSparkleRSSFeed represents an RSS itself for unmarshal purposes.
type unmarshalSparkleRSSFeed struct {
	Channel unmarshalSparkleRSSFeedChannel `xml:"channel"`
}

// unmarshalSparkleRSSFeedChannel represents the "Sparkle RSS Feed" channel for
// unmarshal purposes.
type unmarshalSparkleRSSFeedChannel struct {
	Title       string                        `xml:"title"`
	Link        string                        `xml:"link"`
	Description string                        `xml:"description"`
	Language    string                        `xml:"language"`
	Items       []unmarshalSparkleRSSFeedItem `xml:"item"`
}

// unmarshalSparkleRSSFeedItem represents an RSS item.
type unmarshalSparkleRSSFeedItem struct {
	Title                string                           `xml:"title"`
	Description          string                           `xml:"description"`
	MinimumSystemVersion string                           `xml:"minimumSystemVersion"`
	PubDate              string                           `xml:"pubDate"`
	Enclosure            unmarshalSparkleRSSFeedEnclosure `xml:"enclosure"`
	Version              string                           `xml:"version"`
	ShortVersionString   string                           `xml:"shortVersionString"`
}

// unmarshalSparkleRSSFeedEnclosure represents the "Sparkle RSS Feed" item
// enclosure for unmarshal purposes.
type unmarshalSparkleRSSFeedEnclosure struct {
	Version            string `xml:"version,attr"`
	ShortVersionString string `xml:"shortVersionString,attr"`
	URL                string `xml:"url,attr"`
	Length             int    `xml:"length,attr"`
	Type               string `xml:"type,attr"`
}

// UnmarshalReleases unmarshals the Appcast.source.content into the
// Appcast.releases for the "Sparkle RSS Feed" provider.
func (a *SparkleRSSFeedAppcast) UnmarshalReleases() error {
	var x unmarshalSparkleRSSFeed
	var version, build string

	xml.Unmarshal(a.source.Content(), &x)

	a.channel = &SparkleRSSFeedAppcastChannel{
		Title:       x.Channel.Title,
		Link:        x.Channel.Link,
		Description: x.Channel.Description,
		Language:    x.Channel.Language,
	}

	items := make([]Releaser, len(x.Channel.Items))
	for i, item := range x.Channel.Items {
		if item.Enclosure.ShortVersionString == "" && item.ShortVersionString != "" {
			version = item.ShortVersionString
		} else {
			version = item.Enclosure.ShortVersionString
		}

		if item.Enclosure.Version == "" && item.Version != "" {
			build = item.Version
		} else {
			build = item.Enclosure.Version
		}

		if version == "" && build == "" {
			return fmt.Errorf("version is required, but it's not specified in release #%d", i+1)
		} else if version == "" && build != "" {
			version = build
		}

		// new release
		r, err := NewRelease(version, build)
		if err != nil {
			return err
		}

		r.SetTitle(item.Title)
		r.SetDescription(item.Description)
		r.ParsePublishedDateTime(item.PubDate)

		// prerelease
		if r.Version().Prerelease() != "" {
			r.SetIsPreRelease(true)
		}

		// downloads
		d := NewDownload(item.Enclosure.URL, item.Enclosure.Type, item.Enclosure.Length)
		r.AddDownload(*d)

		items[i] = r
	}

	a.releases = items

	return nil
}

// Uncomment uncomments XML tags in SparkleRSSFeedAppcast.source.content.
func (a *SparkleRSSFeedAppcast) Uncomment() error {
	if a.source == nil || len(a.source.Content()) == 0 {
		return fmt.Errorf("no source")
	}

	regex := regexp.MustCompile(`(<!--([[:space:]]*)?)|(([[:space:]]*)?-->)`)
	if regex.Match(a.source.Content()) {
		a.source.SetContent(regex.ReplaceAll(a.source.Content(), []byte("")))
	}

	return nil
}

// Channel is a SparkleRSSFeedAppcast.channel getter.
func (a *SparkleRSSFeedAppcast) Channel() *SparkleRSSFeedAppcastChannel {
	return a.channel
}

// SetChannel is a SparkleRSSFeedAppcast.channel setter.
func (a *SparkleRSSFeedAppcast) SetChannel(channel *SparkleRSSFeedAppcastChannel) {
	a.channel = channel
}
<|endoftext|>


<commit_before>package scrud

import (
	"errors"
	"reflect"
	"time"

	"github.com/cxr29/scrud/format"
	"github.com/cxr29/scrud/internal/table"
	. "github.com/cxr29/scrud/query"
)

func (db *DB) Snapshot() *Snapshot {
	return &Snapshot{xr: db}
}

func (tx *Tx) Snapshot() *Snapshot {
	return &Snapshot{xr: tx}
}

// snapshot manager
type Snapshot struct {
	xr faker
}

func (s *Snapshot) Insert(data interface{}) (int64, time.Time, error) {
	var zt time.Time

	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return 0, zt, errors.New("scrud: snapshot insert nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return 0, zt, err
	}

	tableName, _, timeName := format.SnapshotName(x.Type.Name(), x.Name)

	i := Insert(tableName)

	st := time.Now()
	i.Columns(timeName)
	i.Values(st)

	for _, c := range x.Columns {
		if c.IsManyRelation() {
			continue
		}
		if v, err := c.GetValue(v); err != nil {
			return 0, zt, err
		} else {
			i.Columns(c.Name)
			i.Values(v)
		}
	}

	q, a, err := i.Expand(s.xr.Starter())
	if err != nil {
		return 0, zt, err
	}

	r, err := s.xr.Exec(q, a...)
	if err != nil {
		return 0, zt, err
	}

	ai, err := r.LastInsertId()
	if err != nil {
		return 0, zt, err
	}

	return ai, st, nil
}

func (s *Snapshot) Select(id int64, data interface{}, columns ...string) (time.Time, error) {
	var zt time.Time

	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return zt, errors.New("scrud: snapshot select nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return zt, err
	}

	tableName, idName, timeName := format.SnapshotName(x.Type.Name(), x.Name)

	columnMap, exclude, err := tidyColumns("snapshot select", x, columns...)
	if err != nil {
		return zt, err
	}
	count := len(columnMap)

	var st time.Time

	elect := []interface{}{timeName}
	set := make(map[int]*table.Column)
	scans := []interface{}{&st}
	for _, c := range x.Columns {
		if c.IsManyRelation() {
			continue
		}
		if count > 0 {
			if _, ok := columnMap[c.Index]; (ok && exclude) || (!ok && !exclude) {
				continue
			}
		}
		elect = append(elect, c.Name)
		if c.HasEncoding() || c.HasSetter() {
			set[len(scans)] = c
		}
		scans = append(scans, c.Scan(v))
	}

	q, a, err := Select(elect...).From(tableName).Where(Eq(idName, id)).Expand(s.xr.Starter())
	if err != nil {
		return zt, err
	}

	if err := s.xr.QueryRow(q, a...).Scan(scans...); err != nil {
		return zt, err
	}

	for i, c := range set {
		if err := c.SetValue(v, reflect.ValueOf(scans[i]).Elem().Interface()); err != nil {
			return zt, err
		}
	}

	return st, nil
}

func (s *Snapshot) Delete(id int64, data interface{}) error {
	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return errors.New("scrud: snapshot delete nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return err
	}

	tableName, idName, _ := format.SnapshotName(x.Type.Name(), x.Name)

	q, a, err := Delete(tableName).Where(Eq(idName, id)).Limit(1).Expand(s.xr.Starter())
	if err == nil {
		_, err = s.xr.Exec(q, a...)
	}

	return err
}
<commit_msg>Fix snapshot insert only one value<commit_after>package scrud

import (
	"errors"
	"reflect"
	"time"

	"github.com/cxr29/scrud/format"
	"github.com/cxr29/scrud/internal/table"
	. "github.com/cxr29/scrud/query"
)

func (db *DB) Snapshot() *Snapshot {
	return &Snapshot{xr: db}
}

func (tx *Tx) Snapshot() *Snapshot {
	return &Snapshot{xr: tx}
}

// snapshot manager
type Snapshot struct {
	xr faker
}

func (s *Snapshot) Insert(data interface{}) (int64, time.Time, error) {
	var zt time.Time

	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return 0, zt, errors.New("scrud: snapshot insert nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return 0, zt, err
	}

	tableName, _, timeName := format.SnapshotName(x.Type.Name(), x.Name)

	i := Insert(tableName)

	st := time.Now()
	i.Columns(timeName)
	values := []interface{}{st}

	for _, c := range x.Columns {
		if c.IsManyRelation() {
			continue
		}
		if v, err := c.GetValue(v); err != nil {
			return 0, zt, err
		} else {
			i.Columns(c.Name)
			values = append(values, v)
		}
	}
	i.Values(values)

	q, a, err := i.Expand(s.xr.Starter())
	if err != nil {
		return 0, zt, err
	}

	r, err := s.xr.Exec(q, a...)
	if err != nil {
		return 0, zt, err
	}

	ai, err := r.LastInsertId()
	if err != nil {
		return 0, zt, err
	}

	return ai, st, nil
}

func (s *Snapshot) Select(id int64, data interface{}, columns ...string) (time.Time, error) {
	var zt time.Time

	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return zt, errors.New("scrud: snapshot select nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return zt, err
	}

	tableName, idName, timeName := format.SnapshotName(x.Type.Name(), x.Name)

	columnMap, exclude, err := tidyColumns("snapshot select", x, columns...)
	if err != nil {
		return zt, err
	}
	count := len(columnMap)

	var st time.Time

	elect := []interface{}{timeName}
	set := make(map[int]*table.Column)
	scans := []interface{}{&st}
	for _, c := range x.Columns {
		if c.IsManyRelation() {
			continue
		}
		if count > 0 {
			if _, ok := columnMap[c.Index]; (ok && exclude) || (!ok && !exclude) {
				continue
			}
		}
		elect = append(elect, c.Name)
		if c.HasEncoding() || c.HasSetter() {
			set[len(scans)] = c
		}
		scans = append(scans, c.Scan(v))
	}

	q, a, err := Select(elect...).From(tableName).Where(Eq(idName, id)).Expand(s.xr.Starter())
	if err != nil {
		return zt, err
	}

	if err := s.xr.QueryRow(q, a...).Scan(scans...); err != nil {
		return zt, err
	}

	for i, c := range set {
		if err := c.SetValue(v, reflect.ValueOf(scans[i]).Elem().Interface()); err != nil {
			return zt, err
		}
	}

	return st, nil
}

func (s *Snapshot) Delete(id int64, data interface{}) error {
	v := reflect.ValueOf(data)
	t := v.Type()
	if v.Kind() == reflect.Ptr {
		if v.IsNil() {
			return errors.New("scrud: snapshot delete nil")
		}
		v = v.Elem()
		t = v.Type()
	}

	x, err := table.TableOf(t)
	if err != nil {
		return err
	}

	tableName, idName, _ := format.SnapshotName(x.Type.Name(), x.Name)

	q, a, err := Delete(tableName).Where(Eq(idName, id)).Limit(1).Expand(s.xr.Starter())
	if err == nil {
		_, err = s.xr.Exec(q, a...)
	}

	return err
}
<|endoftext|>


<commit_before>//+build !windows

package forward

import (
	"bytes"
	"github.com/stretchr/testify/assert"
	"net"
	"testing"
)

func TestMarshalInit(t *testing.T) {
	h := getOutgoingMessage()
	var buf bytes.Buffer
	assert.Nil(t, writeInitMessage(&buf, h))
	hh, err := readInitMessage(&buf)
	assert.Nil(t, err)
	assert.Equal(t, h, hh)

}

func TestMarshalCommand(t *testing.T) {
	c := bindIpv4Command
	var buf bytes.Buffer
	assert.Nil(t, writeCommand(&buf, c))
	cc, err := readCommand(&buf)
	assert.Nil(t, err)
	assert.Equal(t, c, cc)
}

func TestMarshalBindIpv4(t *testing.T) {
	b := bindIpv4{
		IP:   net.ParseIP("127.0.0.1"),
		Port: 1234,
		TCP:  false,
	}
	var buf bytes.Buffer
	assert.Nil(t, writeBindIpv4(&buf, b))
	bb, err := readBindIpv4(&buf)
	assert.Nil(t, err)
	assert.Equal(t, b, *bb)
}

func TestBindVmnetd(t *testing.T) {
	localhost := net.ParseIP("127.0.0.1")
	f, err := listenTCPVmnet(localhost, 8081)
	assert.Nil(t, err)
	defer f.Close()
}
<commit_msg>Improve the TCP Listen test case<commit_after>//+build !windows

package forward

import (
	"bytes"
	"github.com/stretchr/testify/assert"
	"io"
	"net"
	"testing"
)

func TestMarshalInit(t *testing.T) {
	h := getOutgoingMessage()
	var buf bytes.Buffer
	assert.Nil(t, writeInitMessage(&buf, h))
	hh, err := readInitMessage(&buf)
	assert.Nil(t, err)
	assert.Equal(t, h, hh)

}

func TestMarshalCommand(t *testing.T) {
	c := bindIpv4Command
	var buf bytes.Buffer
	assert.Nil(t, writeCommand(&buf, c))
	cc, err := readCommand(&buf)
	assert.Nil(t, err)
	assert.Equal(t, c, cc)
}

func TestMarshalBindIpv4(t *testing.T) {
	b := bindIpv4{
		IP:   net.ParseIP("127.0.0.1"),
		Port: 1234,
		TCP:  false,
	}
	var buf bytes.Buffer
	assert.Nil(t, writeBindIpv4(&buf, b))
	bb, err := readBindIpv4(&buf)
	assert.Nil(t, err)
	assert.Equal(t, b, *bb)
}

func TestBindVmnetd(t *testing.T) {
	localhost := net.ParseIP("127.0.0.1")
	f, err := listenTCPVmnet(localhost, 8081)
	assert.Nil(t, err)
	hello := []byte("hello\n")
	go func() {
		client, err := net.Dial("tcp", "localhost:8081")
		assert.Nil(t, err)
		buf := bytes.NewBuffer(hello)
		_, err = io.Copy(client, buf)
		assert.Nil(t, err)
		assert.Nil(t, client.Close())
	}()
	conn, err := f.Accept()
	assert.Nil(t, err)
	var buf bytes.Buffer
	_, err = io.Copy(&buf, conn)
	assert.Nil(t, err)
	assert.Equal(t, hello, buf.Bytes())
	assert.Nil(t, conn.Close())
	assert.Nil(t, f.Close())
}
<|endoftext|>


<commit_before>package sl

import "time"

// SubnetDatacenter is a regular Datacenter, but lists less fields which
// are typicaly not used within subnet context.
type SubnetDatacenter struct {
	ID       int    `json:"id,omitempty"`
	Name     string `json:"name,omitempty"`
	LongName string `json:"longName,omitempty"`
}

// Subnet represents a single Softlayer subnet.
type Subnet struct {
	ID         int              `json:"id,omitempty"`
	NetworkID  string           `json:"networkIdentifier,omitempty"`
	Type       string           `json:"subnetType,omitempty"`
	Netmaks    string           `json:"netmask,omitempty"`
	Broadcast  string           `json:"broadcastAddress,omitempty"`
	Gateway    string           `json:"gateway,omitempty"`
	CIDR       int              `json:"cidr,omitempty"`
	Total      int              `json:"totalIpAddresses,omitempty"`
	Available  int              `json:"usableIpAddressCount,omitempty"`
	POD        string           `json:"pod,omitempty"`
	Datacenter SubnetDatacenter `json:"datacenter,omitempty"`
}

// vlanMask represents objectMask for the VLAN struct.
var vlanMask = ObjectMask((*VLAN)(nil))

// VLAN represents a single Softlayer VLAN
type VLAN struct {
	ID            int            `json:"id,omitempty"`
	InternalID    int            `json:"vlanNumber,omitempty"`
	Name          string         `json:"name,omitempty"`
	ModifyDate    time.Time      `json:"modifyDate,omitempty"`
	RoutingID     int            `json:"networkVrfId,omitempty"`
	InstanceCount int            `json:"virtualGuestCount,omitempty"`
	Subnet        Subnet         `json:"primarySubnet,omitempty"`
	Subnets       []Subnet       `json:"subnets,omitempty"`
	TagReferences []TagReference `json:"tagReferences,omitempty"`

	Tags Tags `json:"-"`
}

func (v *VLAN) decode() {
	v.Tags = NewTagsFromRefs(v.TagReferences)
}

// VLANs is a conveniance type for a list of VLANs that supports filtering.
type VLANs []*VLAN

// ByID filters the VLANs by ID.
func (v VLANs) ByID(id int) VLANs {
	if id == 0 {
		return v
	}
	for _, vlan := range v {
		if vlan.ID == id {
			return VLANs{vlan}
		}
	}
	return nil
}

// ByTags filters the vlans by tags.
func (v VLANs) ByTags(tags Tags) (res VLANs) {
	if len(tags) == 0 {
		return v
	}
	for _, vlan := range v {
		if vlan.Tags.Matches(tags) {
			res = append(res, vlan)
		}
	}
	return res
}

// ByDatacenter filters the vlans by datacenter name.
func (v VLANs) ByDatacenter(datacenter string) (res VLANs) {
	if datacenter == "" {
		return v
	}
	for _, vlan := range v {
		if vlan.Subnet.Datacenter.Name == datacenter {
			res = append(res, vlan)
		}
	}
	return res
}

// Filter applies the given filter to VLANs.
func (v *VLANs) Filter(f *Filter) {
	*v = v.ByID(f.ID).ByDatacenter(f.Datacenter).ByTags(f.Tags)
}

// Decode implements the ResourceDecoder interface.
func (v VLANs) Decode() {
	for _, vlan := range v {
		vlan.decode()
	}
}

// Sorts the VLANs by modify date.
func (v VLANs) Len() int           { return len(v) }
func (v VLANs) Less(j, k int) bool { return v[j].ModifyDate.After(v[k].ModifyDate) }
func (v VLANs) Swap(j, k int)      { v[j], v[k] = v[k], v[j] }
<commit_msg>kloud: workaround querying vlan that have no primary subnet info<commit_after>package sl

import "time"

// SubnetDatacenter is a regular Datacenter, but lists less fields which
// are typicaly not used within subnet context.
type SubnetDatacenter struct {
	ID       int    `json:"id,omitempty"`
	Name     string `json:"name,omitempty"`
	LongName string `json:"longName,omitempty"`
}

// Subnet represents a single Softlayer subnet.
type Subnet struct {
	ID         int              `json:"id,omitempty"`
	NetworkID  string           `json:"networkIdentifier,omitempty"`
	Type       string           `json:"subnetType,omitempty"`
	Netmaks    string           `json:"netmask,omitempty"`
	Broadcast  string           `json:"broadcastAddress,omitempty"`
	Gateway    string           `json:"gateway,omitempty"`
	CIDR       int              `json:"cidr,omitempty"`
	Total      int              `json:"totalIpAddresses,omitempty"`
	Available  int              `json:"usableIpAddressCount,omitempty"`
	POD        string           `json:"pod,omitempty"`
	Datacenter SubnetDatacenter `json:"datacenter,omitempty"`
}

// vlanMask represents objectMask for the VLAN struct.
var vlanMask = ObjectMask((*VLAN)(nil))

// VLAN represents a single Softlayer VLAN
type VLAN struct {
	ID            int            `json:"id,omitempty"`
	InternalID    int            `json:"vlanNumber,omitempty"`
	Name          string         `json:"name,omitempty"`
	ModifyDate    time.Time      `json:"modifyDate,omitempty"`
	RoutingID     int            `json:"networkVrfId,omitempty"`
	InstanceCount int            `json:"virtualGuestCount,omitempty"`
	Subnet        Subnet         `json:"primarySubnet,omitempty"`
	Subnets       []Subnet       `json:"subnets,omitempty"`
	TagReferences []TagReference `json:"tagReferences,omitempty"`

	Tags Tags `json:"-"`
}

func (v *VLAN) decode() {
	v.Tags = NewTagsFromRefs(v.TagReferences)
}

// VLANs is a conveniance type for a list of VLANs that supports filtering.
type VLANs []*VLAN

// ByID filters the VLANs by ID.
func (v VLANs) ByID(id int) VLANs {
	if id == 0 {
		return v
	}
	for _, vlan := range v {
		if vlan.ID == id {
			return VLANs{vlan}
		}
	}
	return nil
}

// ByTags filters the vlans by tags.
func (v VLANs) ByTags(tags Tags) (res VLANs) {
	if len(tags) == 0 {
		return v
	}
	for _, vlan := range v {
		if vlan.Tags.Matches(tags) {
			res = append(res, vlan)
		}
	}
	return res
}

// ByDatacenter filters the vlans by datacenter name.
func (v VLANs) ByDatacenter(datacenter string) (res VLANs) {
	if datacenter == "" {
		return v
	}
	for _, vlan := range v {
		if vlan.Subnet.Datacenter.Name == datacenter {
			res = append(res, vlan)
			continue
		}
		if len(vlan.Subnets) != 0 && vlan.Subnets[0].Datacenter.Name == datacenter {
			res = append(res, vlan)
		}
	}
	return res
}

// Filter applies the given filter to VLANs.
func (v *VLANs) Filter(f *Filter) {
	*v = v.ByID(f.ID).ByDatacenter(f.Datacenter).ByTags(f.Tags)
}

// Decode implements the ResourceDecoder interface.
func (v VLANs) Decode() {
	for _, vlan := range v {
		vlan.decode()
	}
}

// Sorts the VLANs by modify date.
func (v VLANs) Len() int           { return len(v) }
func (v VLANs) Less(j, k int) bool { return v[j].ModifyDate.After(v[k].ModifyDate) }
func (v VLANs) Swap(j, k int)      { v[j], v[k] = v[k], v[j] }
<|endoftext|>


<commit_before>package koding

import (
	"fmt"
	"koding/kites/kloud/klient"
	"time"

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

	"github.com/koding/kloud/machinestate"
	"github.com/koding/kloud/protocol"
)

func (p *Provider) Info(opts *protocol.Machine) (result *protocol.InfoArtifact, err error) {
	a, err := p.NewClient(opts)
	if err != nil {
		return nil, err
	}

	// otherwise ask AWS to get an machine state
	infoResp, err := a.Info()
	if err != nil {
		return nil, err
	}

	resultState := infoResp.State

	p.Log.Info("[%s] info initials: current db state is '%s'. amazon ec2 state is '%s'",
		opts.MachineId, opts.State, infoResp.State)

	// corresponding states defines a map that defines a relationship from a DB
	// state to Amazon state.  That means say in DB we have the state
	// "machinestate.Building", this means the machine is in either Starting
	// mode or Terminated mode (if it was terminated before and not running
	// yet). Another example say we have the state "machinestate.Starting".
	// That means the state can be in Amazon: Starting, Running or even Stopped
	// (between the time Start is called and and info method is made.
	matchStates := map[machinestate.State][]machinestate.State{
		machinestate.Building: []machinestate.State{
			machinestate.Starting, machinestate.Terminated, machinestate.NotInitialized,
		},
		machinestate.Starting: []machinestate.State{
			machinestate.Starting, machinestate.Running, machinestate.Stopped,
		},
		machinestate.Stopping: []machinestate.State{
			machinestate.Stopping, machinestate.Stopped,
		},
		machinestate.Terminating: []machinestate.State{
			machinestate.Terminating, machinestate.Terminated,
		},
		machinestate.Stopped: []machinestate.State{
			machinestate.Stopped, machinestate.Stopping,
		},
		machinestate.Updating:   []machinestate.State{machinestate.Running},
		machinestate.Terminated: []machinestate.State{machinestate.Terminated},
	}

	// check now whether the amazon ec2 state does match one and is in
	// comparable bounds with the current state
	if infoResp.State.In(matchStates[opts.State]...) {
		p.Log.Info("[%s] info result  : db state complies with amazon state. returning current state '%s'",
			opts.MachineId, opts.State)

		return &protocol.InfoArtifact{
			State: opts.State,
			Name:  infoResp.Name,
		}, nil
	}

	// we don't check if the state is something else. Klient is only available
	// when the machine is running
	if opts.State.In(machinestate.Running, machinestate.Stopped) && infoResp.State == machinestate.Running {
		resultState = opts.State

		// for the rest ask again to klient so we know if it's running or not
		machineData, ok := opts.CurrentData.(*Machine)
		if !ok {
			return nil, fmt.Errorf("current data is malformed: %v", opts.CurrentData)
		}

		p.Log.Info("[%s] amazon machine state is '%s'. pinging klient again to be sure.",
			opts.MachineId, infoResp.State)

		klientRef, err := klient.NewWithTimeout(p.Kite, machineData.QueryString, time.Second*5)
		if err != nil {
			p.Log.Warning("[%s] state is '%s' but I can't connect to klient.",
				opts.MachineId, resultState)
			resultState = machinestate.Stopped
		} else {
			defer klientRef.Close()

			// now assume it's running
			resultState = machinestate.Running

			// ping the klient again just to see if it can respond to us
			if err := klientRef.Ping(); err != nil {
				p.Log.Warning("[%s] state is '%s' but I can't send a ping. Err: %s",
					opts.MachineId, resultState, err.Error())

				// seems we can't send even a simple ping! It's not
				// functional so we assume it's stoped
				resultState = machinestate.Stopped
			}
		}

		p.Log.Info("[%s] info result  : fetched result from klient. returning '%s'",
			opts.MachineId, resultState)

		p.CheckAndUpdateState(opts.MachineId, resultState)

		return &protocol.InfoArtifact{
			State: resultState,
			Name:  infoResp.Name,
		}, nil

	}

	p.Log.Info("[%s] info result  : state is incosistent. correcting it to amazon state '%s'",
		opts.MachineId, infoResp.State)

	// fix the inconsistency
	p.CheckAndUpdateState(opts.MachineId, infoResp.State)

	// there is an inconsistency between the DB state and Amazon EC2 state. So
	// we are saying that the EC2 state is the correct one.
	return &protocol.InfoArtifact{
		State: infoResp.State,
		Name:  infoResp.Name,
	}, nil
}

// CheckAndUpdate state updates only if the given machine id is not used by
// anyone else
func (p *Provider) CheckAndUpdateState(id string, state machinestate.State) error {
	p.Log.Info("[%s] storage state update request to state %v", id, state)
	err := p.Session.Run("jMachines", func(c *mgo.Collection) error {
		return c.Update(
			bson.M{
				"_id": bson.ObjectIdHex(id),
				"assignee.inProgress": false, // only update if it's not locked by someone else
			},
			bson.M{
				"$set": bson.M{
					"status.state":      state.String(),
					"status.modifiedAt": time.Now().UTC(),
				},
			},
		)
	})

	if err == mgo.ErrNotFound {
		p.Log.Warning("[%s] can't update state because lock is acquired by someone else", id)
	}

	return err
}
<commit_msg>kloud/info: update for each state<commit_after>package koding

import (
	"fmt"
	"koding/kites/kloud/klient"
	"time"

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

	"github.com/koding/kloud/machinestate"
	"github.com/koding/kloud/protocol"
)

func (p *Provider) Info(opts *protocol.Machine) (result *protocol.InfoArtifact, err error) {
	a, err := p.NewClient(opts)
	if err != nil {
		return nil, err
	}

	// otherwise ask AWS to get an machine state
	infoResp, err := a.Info()
	if err != nil {
		return nil, err
	}

	resultState := infoResp.State

	p.Log.Info("[%s] info initials: current db state is '%s'. amazon ec2 state is '%s'",
		opts.MachineId, opts.State, infoResp.State)

	// corresponding states defines a map that defines a relationship from a DB
	// state to Amazon state.  That means say in DB we have the state
	// "machinestate.Building", this means the machine is in either Starting
	// mode or Terminated mode (if it was terminated before and not running
	// yet). Another example say we have the state "machinestate.Starting".
	// That means the state can be in Amazon: Starting, Running or even Stopped
	// (between the time Start is called and and info method is made.
	matchStates := map[machinestate.State][]machinestate.State{
		machinestate.Building: []machinestate.State{
			machinestate.Starting, machinestate.Terminated, machinestate.NotInitialized,
		},
		machinestate.Starting: []machinestate.State{
			machinestate.Starting, machinestate.Running, machinestate.Stopped,
		},
		machinestate.Stopping: []machinestate.State{
			machinestate.Stopping, machinestate.Stopped,
		},
		machinestate.Terminating: []machinestate.State{
			machinestate.Terminating, machinestate.Terminated,
		},
		machinestate.Stopped: []machinestate.State{
			machinestate.Stopped, machinestate.Stopping,
		},
		machinestate.Updating:   []machinestate.State{machinestate.Running},
		machinestate.Terminated: []machinestate.State{machinestate.Terminated},
	}

	// check now whether the amazon ec2 state does match one and is in
	// comparable bounds with the current state
	if infoResp.State.In(matchStates[opts.State]...) {
		p.Log.Info("[%s] info result  : db state complies with amazon state. returning current state '%s'",
			opts.MachineId, opts.State)

		// save the value in DB, this is only set if the lock is unlocked.
		// Thefore it will not change the db state if there is an ongoing
		// process.
		p.CheckAndUpdateState(opts.MachineId, infoResp.State)

		// Return the old DB state
		return &protocol.InfoArtifact{
			State: opts.State,
			Name:  infoResp.Name,
		}, nil
	}

	// we don't check if the state is something else. Klient is only available
	// when the machine is running
	if opts.State.In(machinestate.Running, machinestate.Stopped) && infoResp.State == machinestate.Running {
		resultState = opts.State

		// for the rest ask again to klient so we know if it's running or not
		machineData, ok := opts.CurrentData.(*Machine)
		if !ok {
			return nil, fmt.Errorf("current data is malformed: %v", opts.CurrentData)
		}

		p.Log.Info("[%s] amazon machine state is '%s'. pinging klient again to be sure.",
			opts.MachineId, infoResp.State)

		klientRef, err := klient.NewWithTimeout(p.Kite, machineData.QueryString, time.Second*5)
		if err != nil {
			p.Log.Warning("[%s] state is '%s' but I can't connect to klient.",
				opts.MachineId, resultState)
			resultState = machinestate.Stopped
		} else {
			defer klientRef.Close()

			// now assume it's running
			resultState = machinestate.Running

			// ping the klient again just to see if it can respond to us
			if err := klientRef.Ping(); err != nil {
				p.Log.Warning("[%s] state is '%s' but I can't send a ping. Err: %s",
					opts.MachineId, resultState, err.Error())

				// seems we can't send even a simple ping! It's not
				// functional so we assume it's stoped
				resultState = machinestate.Stopped
			}
		}

		p.Log.Info("[%s] info result  : fetched result from klient. returning '%s'",
			opts.MachineId, resultState)

		p.CheckAndUpdateState(opts.MachineId, resultState)

		return &protocol.InfoArtifact{
			State: resultState,
			Name:  infoResp.Name,
		}, nil

	}

	p.Log.Info("[%s] info result  : state is incosistent. correcting it to amazon state '%s'",
		opts.MachineId, infoResp.State)

	// fix the inconsistency
	p.CheckAndUpdateState(opts.MachineId, infoResp.State)

	// there is an inconsistency between the DB state and Amazon EC2 state. So
	// we are saying that the EC2 state is the correct one.
	return &protocol.InfoArtifact{
		State: infoResp.State,
		Name:  infoResp.Name,
	}, nil
}

// CheckAndUpdate state updates only if the given machine id is not used by
// anyone else
func (p *Provider) CheckAndUpdateState(id string, state machinestate.State) error {
	p.Log.Info("[%s] storage state update request to state %v", id, state)
	err := p.Session.Run("jMachines", func(c *mgo.Collection) error {
		return c.Update(
			bson.M{
				"_id": bson.ObjectIdHex(id),
				"assignee.inProgress": false, // only update if it's not locked by someone else
			},
			bson.M{
				"$set": bson.M{
					"status.state":      state.String(),
					"status.modifiedAt": time.Now().UTC(),
				},
			},
		)
	})

	if err == mgo.ErrNotFound {
		p.Log.Warning("[%s] can't update state because lock is acquired by someone else", id)
	}

	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2020 The Vitess Authors.

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

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

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

package semantics

import (
	"vitess.io/vitess/go/vt/key"
	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vtgate/vindexes"

	"vitess.io/vitess/go/vt/sqlparser"
)

type (
	TableInfo interface {
		Matches(name sqlparser.TableName) bool
		Authoritative() bool
		Name() (sqlparser.TableName, error)
		GetExpr() *sqlparser.AliasedTableExpr
		GetColumns() []ColumnInfo
	}

	ColumnInfo struct {
		Name string
		Type querypb.Type
	}

	// RealTable contains the alias table expr and vindex table
	RealTable struct {
		dbName, tableName string
		ASTNode           *sqlparser.AliasedTableExpr
		Table             *vindexes.Table
	}

	// AliasedTable contains the alias table expr and vindex table
	AliasedTable struct {
		tableName string
		ASTNode   *sqlparser.AliasedTableExpr
		Table     *vindexes.Table
	}

	// TableSet is how a set of tables is expressed.
	// Tables get unique bits assigned in the order that they are encountered during semantic analysis
	TableSet uint64 // we can only join 64 tables with this underlying data type
	// TODO : change uint64 to struct to support arbitrary number of tables.

	// SemTable contains semantic analysis information about the query.
	SemTable struct {
		Tables           []TableInfo
		exprDependencies map[sqlparser.Expr]TableSet
		selectScope      map[*sqlparser.Select]*scope
	}

	scope struct {
		parent *scope
		tables []TableInfo
	}

	// SchemaInformation is used tp provide table information from Vschema.
	SchemaInformation interface {
		FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error)
	}
)

var _ TableInfo = (*RealTable)(nil)
var _ TableInfo = (*AliasedTable)(nil)

func vindexTableToColumnInfo(tbl *vindexes.Table) []ColumnInfo {
	cols := make([]ColumnInfo, 0, len(tbl.Columns))
	for _, col := range tbl.Columns {
		cols = append(cols, ColumnInfo{
			Name: col.Name.String(),
			Type: col.Type,
		})
	}
	return cols
}

func (a *AliasedTable) GetColumns() []ColumnInfo {
	return vindexTableToColumnInfo(a.Table)
}

func (a *AliasedTable) GetExpr() *sqlparser.AliasedTableExpr {
	return a.ASTNode
}

func (a *AliasedTable) Name() (sqlparser.TableName, error) {
	return a.ASTNode.TableName()
}

func (a *AliasedTable) Authoritative() bool {
	return a.Table != nil && a.Table.ColumnListAuthoritative
}

func (a *AliasedTable) Matches(name sqlparser.TableName) bool {
	return a.tableName == name.Name.String() && name.Qualifier.IsEmpty()
}

func (r *RealTable) GetColumns() []ColumnInfo {
	return vindexTableToColumnInfo(r.Table)
}

func (r *RealTable) GetExpr() *sqlparser.AliasedTableExpr {
	return r.ASTNode
}

func (r *RealTable) Name() (sqlparser.TableName, error) {
	return r.ASTNode.TableName()
}

func (r *RealTable) Authoritative() bool {
	return r.Table != nil && r.Table.ColumnListAuthoritative
}

func (r *RealTable) Matches(name sqlparser.TableName) bool {
	if !name.Qualifier.IsEmpty() {
		if r.dbName != name.Qualifier.String() {
			return false
		}
	}
	return r.tableName == name.Name.String()
}

// NewSemTable creates a new empty SemTable
func NewSemTable() *SemTable {
	return &SemTable{exprDependencies: map[sqlparser.Expr]TableSet{}}
}

// TableSetFor returns the bitmask for this particular table
func (st *SemTable) TableSetFor(t *sqlparser.AliasedTableExpr) TableSet {
	for idx, t2 := range st.Tables {
		if t == t2.GetExpr() {
			return 1 << idx
		}
	}
	return 0
}

// TableInfoFor returns the table info for the table set. It should contains only single table.
func (st *SemTable) TableInfoFor(id TableSet) (TableInfo, error) {
	if id.NumberOfTables() > 1 {
		return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] should only be used for single tables")
	}
	return st.Tables[id.TableOffset()], nil
}

// Dependencies return the table dependencies of the expression.
func (st *SemTable) Dependencies(expr sqlparser.Expr) TableSet {
	deps, found := st.exprDependencies[expr]
	if found {
		return deps
	}

	_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
		colName, ok := node.(*sqlparser.ColName)
		if ok {
			set := st.exprDependencies[colName]
			deps |= set
		}
		return true, nil
	}, expr)

	st.exprDependencies[expr] = deps

	return deps
}

func (st *SemTable) GetSelectTables(node *sqlparser.Select) []TableInfo {
	scope := st.selectScope[node]
	return scope.tables
}

// AddExprs adds new select exprs to the SemTable.
func (st *SemTable) AddExprs(tbl *sqlparser.AliasedTableExpr, cols sqlparser.SelectExprs) {
	tableSet := st.TableSetFor(tbl)
	for _, col := range cols {
		st.exprDependencies[col.(*sqlparser.AliasedExpr).Expr] = tableSet
	}
}

func newScope(parent *scope) *scope {
	return &scope{parent: parent}
}

func (s *scope) addTable(info TableInfo) error {
	for _, scopeTable := range s.tables {
		scopeTableName, err := scopeTable.Name()
		if err != nil {
			return err
		}
		if info.Matches(scopeTableName) {
			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.NonUniqTable, "Not unique table/alias: '%s'", scopeTableName.Name.String())
		}
	}
	s.tables = append(s.tables, info)
	return nil
}

// IsOverlapping returns true if at least one table exists in both sets
func (ts TableSet) IsOverlapping(b TableSet) bool { return ts&b != 0 }

// IsSolvedBy returns true if all of `ts` is contained in `b`
func (ts TableSet) IsSolvedBy(b TableSet) bool { return ts&b == ts }

// NumberOfTables returns the number of bits set
func (ts TableSet) NumberOfTables() int {
	// Brian Kernighan’s Algorithm
	count := 0
	for ts > 0 {
		ts &= ts - 1
		count++
	}
	return count
}

// TableOffset returns the offset in the Tables array from TableSet
func (ts TableSet) TableOffset() int {
	offset := 0
	for ts > 1 {
		ts = ts >> 1
		offset++
	}
	return offset
}

// Constituents returns an slice with all the
// individual tables in their own TableSet identifier
func (ts TableSet) Constituents() (result []TableSet) {
	mask := ts

	for mask > 0 {
		maskLeft := mask & (mask - 1)
		constituent := mask ^ maskLeft
		mask = maskLeft
		result = append(result, constituent)
	}
	return
}

// Merge creates a TableSet that contains both inputs
func (ts TableSet) Merge(other TableSet) TableSet {
	return ts | other
}
<commit_msg>Commented types and methods in semantic_state.go<commit_after>/*
Copyright 2020 The Vitess Authors.

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

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

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

package semantics

import (
	"vitess.io/vitess/go/vt/key"
	querypb "vitess.io/vitess/go/vt/proto/query"
	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
	"vitess.io/vitess/go/vt/vterrors"
	"vitess.io/vitess/go/vt/vtgate/vindexes"

	"vitess.io/vitess/go/vt/sqlparser"
)

type (
	// TableInfo contains information about tables
	TableInfo interface {
		Matches(name sqlparser.TableName) bool
		Authoritative() bool
		Name() (sqlparser.TableName, error)
		GetExpr() *sqlparser.AliasedTableExpr
		GetColumns() []ColumnInfo
	}

	// ColumnInfo contains information about columns
	ColumnInfo struct {
		Name string
		Type querypb.Type
	}

	// RealTable contains the alias table expr and vindex table
	RealTable struct {
		dbName, tableName string
		ASTNode           *sqlparser.AliasedTableExpr
		Table             *vindexes.Table
	}

	// AliasedTable contains the alias table expr and vindex table
	AliasedTable struct {
		tableName string
		ASTNode   *sqlparser.AliasedTableExpr
		Table     *vindexes.Table
	}

	// TableSet is how a set of tables is expressed.
	// Tables get unique bits assigned in the order that they are encountered during semantic analysis
	TableSet uint64 // we can only join 64 tables with this underlying data type
	// TODO : change uint64 to struct to support arbitrary number of tables.

	// SemTable contains semantic analysis information about the query.
	SemTable struct {
		Tables           []TableInfo
		exprDependencies map[sqlparser.Expr]TableSet
		selectScope      map[*sqlparser.Select]*scope
	}

	scope struct {
		parent *scope
		tables []TableInfo
	}

	// SchemaInformation is used tp provide table information from Vschema.
	SchemaInformation interface {
		FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error)
	}
)

var _ TableInfo = (*RealTable)(nil)
var _ TableInfo = (*AliasedTable)(nil)

func vindexTableToColumnInfo(tbl *vindexes.Table) []ColumnInfo {
	cols := make([]ColumnInfo, 0, len(tbl.Columns))
	for _, col := range tbl.Columns {
		cols = append(cols, ColumnInfo{
			Name: col.Name.String(),
			Type: col.Type,
		})
	}
	return cols
}

// GetColumns implements the TableInfo interface
func (a *AliasedTable) GetColumns() []ColumnInfo {
	return vindexTableToColumnInfo(a.Table)
}

// GetExpr implements the TableInfo interface
func (a *AliasedTable) GetExpr() *sqlparser.AliasedTableExpr {
	return a.ASTNode
}

// Name implements the TableInfo interface
func (a *AliasedTable) Name() (sqlparser.TableName, error) {
	return a.ASTNode.TableName()
}

// Authoritative implements the TableInfo interface
func (a *AliasedTable) Authoritative() bool {
	return a.Table != nil && a.Table.ColumnListAuthoritative
}

// Matches implements the TableInfo interface
func (a *AliasedTable) Matches(name sqlparser.TableName) bool {
	return a.tableName == name.Name.String() && name.Qualifier.IsEmpty()
}

// GetColumns implements the TableInfo interface
func (r *RealTable) GetColumns() []ColumnInfo {
	return vindexTableToColumnInfo(r.Table)
}

// GetExpr implements the TableInfo interface
func (r *RealTable) GetExpr() *sqlparser.AliasedTableExpr {
	return r.ASTNode
}

// Name implements the TableInfo interface
func (r *RealTable) Name() (sqlparser.TableName, error) {
	return r.ASTNode.TableName()
}

// Authoritative implements the TableInfo interface
func (r *RealTable) Authoritative() bool {
	return r.Table != nil && r.Table.ColumnListAuthoritative
}

// Matches implements the TableInfo interface
func (r *RealTable) Matches(name sqlparser.TableName) bool {
	if !name.Qualifier.IsEmpty() {
		if r.dbName != name.Qualifier.String() {
			return false
		}
	}
	return r.tableName == name.Name.String()
}

// NewSemTable creates a new empty SemTable
func NewSemTable() *SemTable {
	return &SemTable{exprDependencies: map[sqlparser.Expr]TableSet{}}
}

// TableSetFor returns the bitmask for this particular table
func (st *SemTable) TableSetFor(t *sqlparser.AliasedTableExpr) TableSet {
	for idx, t2 := range st.Tables {
		if t == t2.GetExpr() {
			return 1 << idx
		}
	}
	return 0
}

// TableInfoFor returns the table info for the table set. It should contains only single table.
func (st *SemTable) TableInfoFor(id TableSet) (TableInfo, error) {
	if id.NumberOfTables() > 1 {
		return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "[BUG] should only be used for single tables")
	}
	return st.Tables[id.TableOffset()], nil
}

// Dependencies return the table dependencies of the expression.
func (st *SemTable) Dependencies(expr sqlparser.Expr) TableSet {
	deps, found := st.exprDependencies[expr]
	if found {
		return deps
	}

	_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
		colName, ok := node.(*sqlparser.ColName)
		if ok {
			set := st.exprDependencies[colName]
			deps |= set
		}
		return true, nil
	}, expr)

	st.exprDependencies[expr] = deps

	return deps
}

// GetSelectTables returns the table in the select.
func (st *SemTable) GetSelectTables(node *sqlparser.Select) []TableInfo {
	scope := st.selectScope[node]
	return scope.tables
}

// AddExprs adds new select exprs to the SemTable.
func (st *SemTable) AddExprs(tbl *sqlparser.AliasedTableExpr, cols sqlparser.SelectExprs) {
	tableSet := st.TableSetFor(tbl)
	for _, col := range cols {
		st.exprDependencies[col.(*sqlparser.AliasedExpr).Expr] = tableSet
	}
}

func newScope(parent *scope) *scope {
	return &scope{parent: parent}
}

func (s *scope) addTable(info TableInfo) error {
	for _, scopeTable := range s.tables {
		scopeTableName, err := scopeTable.Name()
		if err != nil {
			return err
		}
		if info.Matches(scopeTableName) {
			return vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.NonUniqTable, "Not unique table/alias: '%s'", scopeTableName.Name.String())
		}
	}
	s.tables = append(s.tables, info)
	return nil
}

// IsOverlapping returns true if at least one table exists in both sets
func (ts TableSet) IsOverlapping(b TableSet) bool { return ts&b != 0 }

// IsSolvedBy returns true if all of `ts` is contained in `b`
func (ts TableSet) IsSolvedBy(b TableSet) bool { return ts&b == ts }

// NumberOfTables returns the number of bits set
func (ts TableSet) NumberOfTables() int {
	// Brian Kernighan’s Algorithm
	count := 0
	for ts > 0 {
		ts &= ts - 1
		count++
	}
	return count
}

// TableOffset returns the offset in the Tables array from TableSet
func (ts TableSet) TableOffset() int {
	offset := 0
	for ts > 1 {
		ts = ts >> 1
		offset++
	}
	return offset
}

// Constituents returns an slice with all the
// individual tables in their own TableSet identifier
func (ts TableSet) Constituents() (result []TableSet) {
	mask := ts

	for mask > 0 {
		maskLeft := mask & (mask - 1)
		constituent := mask ^ maskLeft
		mask = maskLeft
		result = append(result, constituent)
	}
	return
}

// Merge creates a TableSet that contains both inputs
func (ts TableSet) Merge(other TableSet) TableSet {
	return ts | other
}
<|endoftext|>


<commit_before>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package vtworkerclient contains the generic client side of the remote vtworker protocol.
package vtworkerclient

import (
	"flag"
	"fmt"
	"time"

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

	logutilpb "github.com/youtube/vitess/go/vt/proto/logutil"
)

// VtworkerClientProtocol specifices which RPC client implementation should be used.
var VtworkerClientProtocol = flag.String("vtworker_client_protocol", "grpc", "the protocol to use to talk to the vtworker server")

// ErrFunc is returned by streaming queries to get the error
type ErrFunc func() error

// VtworkerClient defines the interface used to send remote vtworker commands
type VtworkerClient interface {
	// ExecuteVtworkerCommand will execute the command remotely.
	// NOTE: ErrFunc should only be checked after the returned channel was closed to avoid races.
	ExecuteVtworkerCommand(ctx context.Context, args []string) (<-chan *logutilpb.Event, ErrFunc, error)

	// Close will terminate the connection. This object won't be
	// used after this.
	Close()
}

// Factory functions are registered by client implementations.
type Factory func(addr string, connectTimeout time.Duration) (VtworkerClient, error)

var factories = make(map[string]Factory)

// RegisterFactory allows a client implementation to register itself.
func RegisterFactory(name string, factory Factory) {
	if _, ok := factories[name]; ok {
		log.Fatalf("RegisterFactory %s already exists", name)
	}
	factories[name] = factory
}

// New allows a user of the client library to get its implementation.
func New(addr string, connectTimeout time.Duration) (VtworkerClient, error) {
	factory, ok := factories[*VtworkerClientProtocol]
	if !ok {
		return nil, fmt.Errorf("unknown vtworker client protocol: %v", *VtworkerClientProtocol)
	}
	return factory(addr, connectTimeout)
}
<commit_msg>vtworkerclient: Reduce visibility of flag.<commit_after>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package vtworkerclient contains the generic client side of the remote vtworker protocol.
package vtworkerclient

import (
	"flag"
	"fmt"
	"time"

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

	logutilpb "github.com/youtube/vitess/go/vt/proto/logutil"
)

// protocol specifices which RPC client implementation should be used.
var protocol = flag.String("vtworker_client_protocol", "grpc", "the protocol to use to talk to the vtworker server")

// ErrFunc is returned by streaming queries to get the error
type ErrFunc func() error

// VtworkerClient defines the interface used to send remote vtworker commands
type VtworkerClient interface {
	// ExecuteVtworkerCommand will execute the command remotely.
	// NOTE: ErrFunc should only be checked after the returned channel was closed to avoid races.
	ExecuteVtworkerCommand(ctx context.Context, args []string) (<-chan *logutilpb.Event, ErrFunc, error)

	// Close will terminate the connection. This object won't be
	// used after this.
	Close()
}

// Factory functions are registered by client implementations.
type Factory func(addr string, connectTimeout time.Duration) (VtworkerClient, error)

var factories = make(map[string]Factory)

// RegisterFactory allows a client implementation to register itself.
func RegisterFactory(name string, factory Factory) {
	if _, ok := factories[name]; ok {
		log.Fatalf("RegisterFactory %s already exists", name)
	}
	factories[name] = factory
}

// New allows a user of the client library to get its implementation.
func New(addr string, connectTimeout time.Duration) (VtworkerClient, error) {
	factory, ok := factories[*protocol]
	if !ok {
		return nil, fmt.Errorf("unknown vtworker client protocol: %v", *protocol)
	}
	return factory(addr, connectTimeout)
}
<|endoftext|>


<commit_before>package encoding_ext

import (
	"fmt"
	"testing"
)

func TestCharsetConv(t *testing.T) {
	origin := []byte("你好，世界!")

	gbk, err := PutBytes(origin, "GB18030")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(origin))
	fmt.Println(string(gbk))

	utf8, err := GetBytes(gbk, "GBK")
	fmt.Println(string(utf8))
}
<commit_msg>Update charset_conv_test.go<commit_after>package encoding_ext

import (
	"fmt"
	"testing"
)

func TestCharsetConv(t *testing.T) {
	origin := []byte("你好，世界!")
	fmt.Println(string(origin))

	gbk, err := PutBytes(origin, "GB18030")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(gbk))

	utf8, err := GetBytes(gbk, "GBK")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(utf8))
}
<|endoftext|>


<commit_before>package aws

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"os/exec"
)

type MyEC2Conn interface {
	CreateRoute(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)
	ReplaceRoute(*ec2.ReplaceRouteInput) (*ec2.ReplaceRouteOutput, error)
	DescribeRouteTables(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error)
	DeleteRoute(*ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)
	DescribeNetworkInterfaces(*ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error)
	DescribeInstanceAttribute(*ec2.DescribeInstanceAttributeInput) (*ec2.DescribeInstanceAttributeOutput, error)
}

type RouteTableManager interface {
	GetRouteTables() ([]*ec2.RouteTable, error)
	ManageInstanceRoute(ec2.RouteTable, ManageRoutesSpec, bool) error
	InstanceIsRouter(string) bool
}

type RouteTableManagerEC2 struct {
	Region string
	conn   MyEC2Conn
}

func (m RouteTableManagerEC2) InstanceIsRouter(id string) bool {
	if v, ok := srcdstcheckForInstance[id]; ok {
		return v
	}
	out, err := m.conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
		Attribute:  aws.String("sourceDestCheck"),
		InstanceId: &id,
	})
	if err != nil {
		panic(err)
	}
	srcdstcheckForInstance[id] = !*(out.SourceDestCheck.Value)
	return srcdstcheckForInstance[id]
}

func getCreateRouteInput(rtb ec2.RouteTable, cidr string, instance string, noop bool) ec2.CreateRouteInput {
	return ec2.CreateRouteInput{
		RouteTableId:         rtb.RouteTableId,
		DestinationCidrBlock: aws.String(cidr),
		InstanceId:           aws.String(instance),
		DryRun:               aws.Bool(noop),
	}
}

func (r RouteTableManagerEC2) ManageInstanceRoute(rtb ec2.RouteTable, rs ManageRoutesSpec, noop bool) error {
	route := findRouteFromRouteTable(rtb, rs.Cidr)
	contextLogger := log.WithFields(log.Fields{
		"vpc":         *(rtb.VpcId),
		"rtb":         *(rtb.RouteTableId),
		"noop":        noop,
		"cidr":        rs.Cidr,
		"my_instance": rs.Instance,
	})
	if rs.HealthcheckName != "" {
		contextLogger = contextLogger.WithFields(log.Fields{
			"healthcheck":         rs.HealthcheckName,
			"healthcheck_healthy": rs.healthcheck.IsHealthy(),
			"healthcheck_ready":   rs.healthcheck.CanPassYet(),
		})
	}
	if rs.RemoteHealthcheckName != "" {
		contextLogger = contextLogger.WithFields(log.Fields{
			"remote_healthcheck": rs.RemoteHealthcheckName,
		})
	}
	if route != nil {
		if route.InstanceId != nil {
			contextLogger = contextLogger.WithFields(log.Fields{
				"instance_id": *(route.InstanceId),
			})
			if *(route.InstanceId) == rs.Instance {
				if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() && rs.healthcheck.CanPassYet() {
					if rs.NeverDelete {
						contextLogger.Info("Healthcheck unhealthy, but set to never_delete - ignoring")
						return nil
					}
					contextLogger.Info("Healthcheck unhealthy: deleting route")
					if len(rs.RunBeforeDeleteRoute) > 0 {
						cmd := rs.RunBeforeDeleteRoute[0]
						if err := exec.Command(cmd, rs.RunBeforeDeleteRoute[1:]...).Run(); err != nil {
							contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunBeforeDeleteRoute failed")
						}
					}
					if err := r.DeleteInstanceRoute(rtb.RouteTableId, route, rs.Cidr, rs.Instance, noop); err != nil {
						return err
					}
					if len(rs.RunAfterDeleteRoute) > 0 {
						cmd := rs.RunAfterDeleteRoute[0]
						if err := exec.Command(cmd, rs.RunAfterDeleteRoute[1:]...).Run(); err != nil {
							contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunAfterDeleteRoute failed")
						}
					}
					return nil
				}
				contextLogger.Debug("Currently routed by this instance, doing nothing")
				return nil
			} else {
				contextLogger.Debug("Not routed by my instance - evaluate for replacement")
			}
		}

		if err := r.ReplaceInstanceRoute(rtb.RouteTableId, route, rs, noop); err != nil {
			return err
		}
		return nil
	}

	// These is no pre-existing route
	if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() {
		if rs.healthcheck.CanPassYet() {
			contextLogger.Info("Healthcheck unhealthy: not creating route")
		} else {
			contextLogger.Debug("Healthcheck cannot be healthy yet: not creating route")
		}
		return nil
	}

	opts := getCreateRouteInput(rtb, rs.Cidr, rs.Instance, noop)

	contextLogger.Info("Creating route to my instance")
	if _, err := r.conn.CreateRoute(&opts); err != nil {
		return err
	}
	return nil
}

func findRouteFromRouteTable(rtb ec2.RouteTable, cidr string) *ec2.Route {
	for _, route := range rtb.Routes {
		if route.DestinationCidrBlock != nil && *(route.DestinationCidrBlock) == cidr {
			return route
		}
	}
	return nil
}

func (r RouteTableManagerEC2) DeleteInstanceRoute(routeTableId *string, route *ec2.Route, cidr string, instance string, noop bool) error {
	params := &ec2.DeleteRouteInput{
		DestinationCidrBlock: aws.String(cidr),
		RouteTableId:         routeTableId,
		DryRun:               aws.Bool(noop),
	}
	_, err := r.conn.DeleteRoute(params)
	contextLogger := log.WithFields(log.Fields{
		"cidr": cidr,
		"rtb":  *routeTableId,
	})
	if err != nil {
		// Print the error, cast err to awserr.Error to get the Code and
		// Message from an error.
		contextLogger.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error deleting route")
		return err
	}
	contextLogger.Debug("Successfully deleted route")
	return nil
}

func (r RouteTableManagerEC2) checkRemoteHealthCheck(contextLogger *log.Entry, route *ec2.Route, rs ManageRoutesSpec) bool {
	contextLogger = contextLogger.WithFields(log.Fields{
		"remote_healthcheck": rs.RemoteHealthcheckName,
		"current_eni":        *(route.NetworkInterfaceId),
	})
	contextLogger.Info("Has remote healthcheck ")
	if ip, ok := eniToIP[*route.NetworkInterfaceId]; ok {
		contextLogger = contextLogger.WithFields(log.Fields{"current_ip": ip})
		if hc, ok := rs.remotehealthchecks[ip]; ok {
			contextLogger = contextLogger.WithFields(log.Fields{
				"healthcheck_healthy": hc.IsHealthy(),
				"healthcheck_ready":   hc.CanPassYet(),
			})
			contextLogger.Info("Has remote healthcheck instance")
			if hc.CanPassYet() {
				if hc.IsHealthy() {
					contextLogger.Debug("Not replacing route, as current route is healthy")
					return false
				} else {
					contextLogger.Debug("Replacing route as remote healthcheck is unhealthy")
				}
			} else {
				contextLogger.Debug("Not replacing route as remote healthcheck cannot pass yet")
				return false
			}
		} else {
			contextLogger.Error("Cannot find healthcheck")
			return false
		}
	} else {
		contextLogger.Error("Cannot find ip for ENI")
		return false
	}
	return true
}

func (r RouteTableManagerEC2) ReplaceInstanceRoute(routeTableId *string, route *ec2.Route, rs ManageRoutesSpec, noop bool) error {
	cidr := rs.Cidr
	instance := rs.Instance
	ifUnhealthy := rs.IfUnhealthy
	params := &ec2.ReplaceRouteInput{
		DestinationCidrBlock: aws.String(cidr),
		RouteTableId:         routeTableId,
		InstanceId:           aws.String(instance),
		DryRun:               aws.Bool(noop),
	}
	contextLogger := log.WithFields(log.Fields{
		"cidr":                cidr,
		"rtb":                 *routeTableId,
		"instance_id":         instance,
		"current_route_state": *(route.State),
	})
	if route.InstanceId != nil {
		contextLogger = contextLogger.WithFields(log.Fields{"current_instance_id": *(route.InstanceId)})
	}
	if ifUnhealthy {
		if *(route.State) == "active" {
			if rs.RemoteHealthcheckName != "" {
				if !r.checkRemoteHealthCheck(contextLogger, route, rs) {
					return nil
				}
			} else {
				contextLogger.Info("Not replacing route, as current route is active (no remote healthcheck)")
				return nil
			}
		}
	}
	if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() && rs.healthcheck.CanPassYet() {
		contextLogger.Info("Not replacing route, as healthcheck is failing")
		return nil
	}
	if len(rs.RunBeforeReplaceRoute) > 0 {
		cmd := rs.RunBeforeReplaceRoute[0]
		if err := exec.Command(cmd, rs.RunBeforeReplaceRoute[1:]...).Run(); err != nil {
			contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunBeforeReplaceRoute failed")
		}
	}
	_, err := r.conn.ReplaceRoute(params)
	if err != nil {
		contextLogger.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error replacing route")
		return err
	}
	contextLogger.Info("Replaced route")
	if len(rs.RunAfterReplaceRoute) > 0 {
		cmd := rs.RunAfterReplaceRoute[0]
		if err := exec.Command(cmd, rs.RunAfterReplaceRoute[1:]...).Run(); err != nil {
			contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunAfterReplaceRoute failed")
		}
	}
	return nil
}

func (r RouteTableManagerEC2) GetRouteTables() ([]*ec2.RouteTable, error) {
	resp, err := r.conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{})
	if err != nil {
		log.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error on DescribeRouteTables")
		return []*ec2.RouteTable{}, err
	}
	return resp.RouteTables, nil
}

func NewRouteTableManager(region string, debug bool) RouteTableManager {
	r := RouteTableManagerEC2{}
	sess := session.New(&aws.Config{
		Region:     aws.String(region),
		MaxRetries: aws.Int(3),
	})
	r.conn = ec2.New(sess)
	return r
}
<commit_msg>Info instead of debug<commit_after>package aws

import (
	log "github.com/Sirupsen/logrus"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"os/exec"
)

type MyEC2Conn interface {
	CreateRoute(*ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)
	ReplaceRoute(*ec2.ReplaceRouteInput) (*ec2.ReplaceRouteOutput, error)
	DescribeRouteTables(*ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error)
	DeleteRoute(*ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)
	DescribeNetworkInterfaces(*ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error)
	DescribeInstanceAttribute(*ec2.DescribeInstanceAttributeInput) (*ec2.DescribeInstanceAttributeOutput, error)
}

type RouteTableManager interface {
	GetRouteTables() ([]*ec2.RouteTable, error)
	ManageInstanceRoute(ec2.RouteTable, ManageRoutesSpec, bool) error
	InstanceIsRouter(string) bool
}

type RouteTableManagerEC2 struct {
	Region string
	conn   MyEC2Conn
}

func (m RouteTableManagerEC2) InstanceIsRouter(id string) bool {
	if v, ok := srcdstcheckForInstance[id]; ok {
		return v
	}
	out, err := m.conn.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
		Attribute:  aws.String("sourceDestCheck"),
		InstanceId: &id,
	})
	if err != nil {
		panic(err)
	}
	srcdstcheckForInstance[id] = !*(out.SourceDestCheck.Value)
	return srcdstcheckForInstance[id]
}

func getCreateRouteInput(rtb ec2.RouteTable, cidr string, instance string, noop bool) ec2.CreateRouteInput {
	return ec2.CreateRouteInput{
		RouteTableId:         rtb.RouteTableId,
		DestinationCidrBlock: aws.String(cidr),
		InstanceId:           aws.String(instance),
		DryRun:               aws.Bool(noop),
	}
}

func (r RouteTableManagerEC2) ManageInstanceRoute(rtb ec2.RouteTable, rs ManageRoutesSpec, noop bool) error {
	route := findRouteFromRouteTable(rtb, rs.Cidr)
	contextLogger := log.WithFields(log.Fields{
		"vpc":         *(rtb.VpcId),
		"rtb":         *(rtb.RouteTableId),
		"noop":        noop,
		"cidr":        rs.Cidr,
		"my_instance": rs.Instance,
	})
	if rs.HealthcheckName != "" {
		contextLogger = contextLogger.WithFields(log.Fields{
			"healthcheck":         rs.HealthcheckName,
			"healthcheck_healthy": rs.healthcheck.IsHealthy(),
			"healthcheck_ready":   rs.healthcheck.CanPassYet(),
		})
	}
	if rs.RemoteHealthcheckName != "" {
		contextLogger = contextLogger.WithFields(log.Fields{
			"remote_healthcheck": rs.RemoteHealthcheckName,
		})
	}
	if route != nil {
		if route.InstanceId != nil {
			contextLogger = contextLogger.WithFields(log.Fields{
				"instance_id": *(route.InstanceId),
			})
			if *(route.InstanceId) == rs.Instance {
				if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() && rs.healthcheck.CanPassYet() {
					if rs.NeverDelete {
						contextLogger.Info("Healthcheck unhealthy, but set to never_delete - ignoring")
						return nil
					}
					contextLogger.Info("Healthcheck unhealthy: deleting route")
					if len(rs.RunBeforeDeleteRoute) > 0 {
						cmd := rs.RunBeforeDeleteRoute[0]
						if err := exec.Command(cmd, rs.RunBeforeDeleteRoute[1:]...).Run(); err != nil {
							contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunBeforeDeleteRoute failed")
						}
					}
					if err := r.DeleteInstanceRoute(rtb.RouteTableId, route, rs.Cidr, rs.Instance, noop); err != nil {
						return err
					}
					if len(rs.RunAfterDeleteRoute) > 0 {
						cmd := rs.RunAfterDeleteRoute[0]
						if err := exec.Command(cmd, rs.RunAfterDeleteRoute[1:]...).Run(); err != nil {
							contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunAfterDeleteRoute failed")
						}
					}
					return nil
				}
				contextLogger.Debug("Currently routed by this instance, doing nothing")
				return nil
			} else {
				contextLogger.Debug("Not routed by my instance - evaluate for replacement")
			}
		}

		if err := r.ReplaceInstanceRoute(rtb.RouteTableId, route, rs, noop); err != nil {
			return err
		}
		return nil
	}

	// These is no pre-existing route
	if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() {
		if rs.healthcheck.CanPassYet() {
			contextLogger.Info("Healthcheck unhealthy: not creating route")
		} else {
			contextLogger.Debug("Healthcheck cannot be healthy yet: not creating route")
		}
		return nil
	}

	opts := getCreateRouteInput(rtb, rs.Cidr, rs.Instance, noop)

	contextLogger.Info("Creating route to my instance")
	if _, err := r.conn.CreateRoute(&opts); err != nil {
		return err
	}
	return nil
}

func findRouteFromRouteTable(rtb ec2.RouteTable, cidr string) *ec2.Route {
	for _, route := range rtb.Routes {
		if route.DestinationCidrBlock != nil && *(route.DestinationCidrBlock) == cidr {
			return route
		}
	}
	return nil
}

func (r RouteTableManagerEC2) DeleteInstanceRoute(routeTableId *string, route *ec2.Route, cidr string, instance string, noop bool) error {
	params := &ec2.DeleteRouteInput{
		DestinationCidrBlock: aws.String(cidr),
		RouteTableId:         routeTableId,
		DryRun:               aws.Bool(noop),
	}
	_, err := r.conn.DeleteRoute(params)
	contextLogger := log.WithFields(log.Fields{
		"cidr": cidr,
		"rtb":  *routeTableId,
	})
	if err != nil {
		// Print the error, cast err to awserr.Error to get the Code and
		// Message from an error.
		contextLogger.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error deleting route")
		return err
	}
	contextLogger.Debug("Successfully deleted route")
	return nil
}

func (r RouteTableManagerEC2) checkRemoteHealthCheck(contextLogger *log.Entry, route *ec2.Route, rs ManageRoutesSpec) bool {
	contextLogger = contextLogger.WithFields(log.Fields{
		"remote_healthcheck": rs.RemoteHealthcheckName,
		"current_eni":        *(route.NetworkInterfaceId),
	})
	contextLogger.Info("Has remote healthcheck ")
	if ip, ok := eniToIP[*route.NetworkInterfaceId]; ok {
		contextLogger = contextLogger.WithFields(log.Fields{"current_ip": ip})
		if hc, ok := rs.remotehealthchecks[ip]; ok {
			contextLogger = contextLogger.WithFields(log.Fields{
				"healthcheck_healthy": hc.IsHealthy(),
				"healthcheck_ready":   hc.CanPassYet(),
			})
			contextLogger.Info("Has remote healthcheck instance")
			if hc.CanPassYet() {
				if hc.IsHealthy() {
					contextLogger.Info("Not replacing route, as current route and remote healthcheck is healthy")
					return false
				} else {
					contextLogger.Debug("Replacing route as remote healthcheck is unhealthy")
				}
			} else {
				contextLogger.Debug("Not replacing route as remote healthcheck cannot pass yet")
				return false
			}
		} else {
			contextLogger.Error("Cannot find healthcheck")
			return false
		}
	} else {
		contextLogger.Error("Cannot find ip for ENI")
		return false
	}
	return true
}

func (r RouteTableManagerEC2) ReplaceInstanceRoute(routeTableId *string, route *ec2.Route, rs ManageRoutesSpec, noop bool) error {
	cidr := rs.Cidr
	instance := rs.Instance
	ifUnhealthy := rs.IfUnhealthy
	params := &ec2.ReplaceRouteInput{
		DestinationCidrBlock: aws.String(cidr),
		RouteTableId:         routeTableId,
		InstanceId:           aws.String(instance),
		DryRun:               aws.Bool(noop),
	}
	contextLogger := log.WithFields(log.Fields{
		"cidr":                cidr,
		"rtb":                 *routeTableId,
		"instance_id":         instance,
		"current_route_state": *(route.State),
	})
	if route.InstanceId != nil {
		contextLogger = contextLogger.WithFields(log.Fields{"current_instance_id": *(route.InstanceId)})
	}
	if ifUnhealthy {
		if *(route.State) == "active" {
			if rs.RemoteHealthcheckName != "" {
				if !r.checkRemoteHealthCheck(contextLogger, route, rs) {
					return nil
				}
			} else {
				contextLogger.Info("Not replacing route, as current route is active (no remote healthcheck)")
				return nil
			}
		}
	}
	if rs.HealthcheckName != "" && !rs.healthcheck.IsHealthy() && rs.healthcheck.CanPassYet() {
		contextLogger.Info("Not replacing route, as local healthcheck is failing")
		return nil
	}
	if len(rs.RunBeforeReplaceRoute) > 0 {
		cmd := rs.RunBeforeReplaceRoute[0]
		if err := exec.Command(cmd, rs.RunBeforeReplaceRoute[1:]...).Run(); err != nil {
			contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunBeforeReplaceRoute failed")
		}
	}
	_, err := r.conn.ReplaceRoute(params)
	if err != nil {
		contextLogger.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error replacing route")
		return err
	}
	contextLogger.Info("Replaced route")
	if len(rs.RunAfterReplaceRoute) > 0 {
		cmd := rs.RunAfterReplaceRoute[0]
		if err := exec.Command(cmd, rs.RunAfterReplaceRoute[1:]...).Run(); err != nil {
			contextLogger.WithFields(log.Fields{"err": err.Error()}).Debug("RunAfterReplaceRoute failed")
		}
	}
	return nil
}

func (r RouteTableManagerEC2) GetRouteTables() ([]*ec2.RouteTable, error) {
	resp, err := r.conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{})
	if err != nil {
		log.WithFields(log.Fields{
			"err": err.Error(),
		}).Warn("Error on DescribeRouteTables")
		return []*ec2.RouteTable{}, err
	}
	return resp.RouteTables, nil
}

func NewRouteTableManager(region string, debug bool) RouteTableManager {
	r := RouteTableManagerEC2{}
	sess := session.New(&aws.Config{
		Region:     aws.String(region),
		MaxRetries: aws.Int(3),
	})
	r.conn = ec2.New(sess)
	return r
}
<|endoftext|>


<commit_before>package fusefrontend

import "syscall"

// prealloc - preallocate space without changing the file size. This prevents
// us from running out of space in the middle of an operation.
func prealloc(fd int, off int64, len int64) (err error) {
	for {
		err = syscall.Fallocate(fd, FALLOC_FL_KEEP_SIZE, off, len)
		if err == syscall.EINTR {
			// fallocate, like many syscalls, can return EINTR. This is not an
			// error and just signifies that the operation was interrupted by a
			// signal and we should try again.
			continue
		}
		return err
	}
}
<commit_msg>prelloc: warn and continue if fallocate(2) is not supported<commit_after>package fusefrontend

import (
	"sync"
	"syscall"
)

import "github.com/rfjakob/gocryptfs/internal/toggledlog"

var preallocWarn sync.Once

// prealloc - preallocate space without changing the file size. This prevents
// us from running out of space in the middle of an operation.
func prealloc(fd int, off int64, len int64) (err error) {
	for {
		err = syscall.Fallocate(fd, FALLOC_FL_KEEP_SIZE, off, len)
		if err == syscall.EINTR {
			// fallocate, like many syscalls, can return EINTR. This is not an
			// error and just signifies that the operation was interrupted by a
			// signal and we should try again.
			continue
		}
		if err == syscall.EOPNOTSUPP {
			// ZFS does not support fallocate which caused gocryptfs to abort
			// every write operation: https://github.com/rfjakob/gocryptfs/issues/22
			preallocWarn.Do(func() {
				toggledlog.Warn.Printf("Warning: The underlying filesystem " +
					"does not support fallocate(2). gocryptfs will continue working " +
					"but is no longer resistant against out-of-space errors.\n")
			})
			return nil
		}
		return err
	}
}
<|endoftext|>


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

// The code in this file is based largely on the code in
// cmd/guru/implements.go. The guru implementation supports
// looking up "implementers" of methods also, but that
// code has been cut out here for now for simplicity.

package source

import (
	"context"
	"fmt"
	"go/types"
	"sort"

	"golang.org/x/tools/go/types/typeutil"
	"golang.org/x/tools/internal/lsp/protocol"
)

func (i *IdentifierInfo) Implementation(ctx context.Context) ([]protocol.Location, error) {
	res, err := i.implementations(ctx)
	if err != nil {
		return nil, err
	}

	var objs []types.Object
	pkgs := map[types.Object]Package{}

	if res.toMethod != nil {
		// If we looked up a method, results are in toMethod.
		for _, s := range res.toMethod {
			// Determine package of receiver.
			recv := s.Recv()
			if p, ok := recv.(*types.Pointer); ok {
				recv = p.Elem()
			}
			if n, ok := recv.(*types.Named); ok {
				pkg := res.pkgs[n]
				pkgs[s.Obj()] = pkg
			}
			// Add object to objs.
			objs = append(objs, s.Obj())
		}
	} else {
		// Otherwise, the results are in to.
		for _, t := range res.to {
			// We'll provide implementations that are named types and pointers to named types.
			if p, ok := t.(*types.Pointer); ok {
				t = p.Elem()
			}
			if n, ok := t.(*types.Named); ok {
				pkg := res.pkgs[n]
				objs = append(objs, n.Obj())
				pkgs[n.Obj()] = pkg
			}
		}
	}

	var locations []protocol.Location

	for _, obj := range objs {
		pkg := pkgs[obj]
		if pkgs[obj] == nil || len(pkg.CompiledGoFiles()) == 0 {
			continue
		}
		file, _, err := i.Snapshot.View().FindPosInPackage(pkgs[obj], obj.Pos())
		if err != nil {
			return nil, err
		}
		ident, err := findIdentifier(i.Snapshot, pkg, file, obj.Pos())
		if err != nil {
			return nil, err
		}
		decRange, err := ident.Declaration.Range()
		if err != nil {
			return nil, err
		}
		locations = append(locations, protocol.Location{
			URI:   protocol.NewURI(ident.Declaration.URI()),
			Range: decRange,
		})
	}

	return locations, nil
}
func (i *IdentifierInfo) implementations(ctx context.Context) (implementsResult, error) {
	var T types.Type
	var method *types.Func
	if i.Type.Object == nil {
		// This isn't a type. Is it a method?
		obj, ok := i.Declaration.obj.(*types.Func)
		if !ok {
			return implementsResult{}, fmt.Errorf("no type info object for identifier %q", i.Name)
		}
		recv := obj.Type().(*types.Signature).Recv()
		if recv == nil {
			return implementsResult{}, fmt.Errorf("this function is not a method")
		}
		method = obj
		T = recv.Type()
	} else {
		T = i.Type.Object.Type()
	}

	// Find all named types, even local types (which can have
	// methods due to promotion) and the built-in "error".
	// We ignore aliases 'type M = N' to avoid duplicate
	// reporting of the Named type N.
	var allNamed []*types.Named
	pkgs := map[*types.Named]Package{}
	for _, pkg := range i.Snapshot.KnownPackages(ctx) {
		info := pkg.GetTypesInfo()
		for _, obj := range info.Defs {
			if obj, ok := obj.(*types.TypeName); ok && !obj.IsAlias() {
				if named, ok := obj.Type().(*types.Named); ok {
					allNamed = append(allNamed, named)
					pkgs[named] = pkg
				}
			}
		}
	}

	allNamed = append(allNamed, types.Universe.Lookup("error").Type().(*types.Named))

	var msets typeutil.MethodSetCache

	// TODO(matloob): We only use the to and toMethod result for now. Figure out if we want to
	// surface the from and fromPtr results to users.
	// Test each named type.
	var to, from, fromPtr []types.Type
	for _, U := range allNamed {
		if isInterface(T) {
			if msets.MethodSet(T).Len() == 0 {
				continue // empty interface
			}
			if isInterface(U) {
				if msets.MethodSet(U).Len() == 0 {
					continue // empty interface
				}

				// T interface, U interface
				if !types.Identical(T, U) {
					if types.AssignableTo(U, T) {
						to = append(to, U)
					}
					if types.AssignableTo(T, U) {
						from = append(from, U)
					}
				}
			} else {
				// T interface, U concrete
				if types.AssignableTo(U, T) {
					to = append(to, U)
				} else if pU := types.NewPointer(U); types.AssignableTo(pU, T) {
					to = append(to, pU)
				}
			}
		} else if isInterface(U) {
			if msets.MethodSet(U).Len() == 0 {
				continue // empty interface
			}

			// T concrete, U interface
			if types.AssignableTo(T, U) {
				from = append(from, U)
			} else if pT := types.NewPointer(T); types.AssignableTo(pT, U) {
				fromPtr = append(fromPtr, U)
			}
		}
	}

	// Sort types (arbitrarily) to ensure test determinism.
	sort.Sort(typesByString(to))
	sort.Sort(typesByString(from))
	sort.Sort(typesByString(fromPtr))

	var toMethod []*types.Selection // contain nils
	if method != nil {
		for _, t := range to {
			toMethod = append(toMethod,
				types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
		}
	}

	return implementsResult{pkgs, to, from, fromPtr, toMethod}, nil
}

// implementsResult contains the results of an implements query.
type implementsResult struct {
	pkgs     map[*types.Named]Package
	to       []types.Type // named or ptr-to-named types assignable to interface T
	from     []types.Type // named interfaces assignable from T
	fromPtr  []types.Type // named interfaces assignable only from *T
	toMethod []*types.Selection
}

type typesByString []types.Type

func (p typesByString) Len() int           { return len(p) }
func (p typesByString) Less(i, j int) bool { return p[i].String() < p[j].String() }
func (p typesByString) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
<commit_msg>internal/lsp: do not return interface itself when finding implementations<commit_after>// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The code in this file is based largely on the code in
// cmd/guru/implements.go. The guru implementation supports
// looking up "implementers" of methods also, but that
// code has been cut out here for now for simplicity.

package source

import (
	"context"
	"fmt"
	"go/types"
	"sort"

	"golang.org/x/tools/go/types/typeutil"
	"golang.org/x/tools/internal/lsp/protocol"
)

func (i *IdentifierInfo) Implementation(ctx context.Context) ([]protocol.Location, error) {
	res, err := i.implementations(ctx)
	if err != nil {
		return nil, err
	}

	var objs []types.Object
	pkgs := map[types.Object]Package{}

	if res.toMethod != nil {
		// If we looked up a method, results are in toMethod.
		for _, s := range res.toMethod {
			// Determine package of receiver.
			recv := s.Recv()
			if p, ok := recv.(*types.Pointer); ok {
				recv = p.Elem()
			}
			if n, ok := recv.(*types.Named); ok {
				pkg := res.pkgs[n]
				pkgs[s.Obj()] = pkg
			}
			// Add object to objs.
			objs = append(objs, s.Obj())
		}
	} else {
		// Otherwise, the results are in to.
		for _, t := range res.to {
			// We'll provide implementations that are named types and pointers to named types.
			if p, ok := t.(*types.Pointer); ok {
				t = p.Elem()
			}
			if n, ok := t.(*types.Named); ok {
				pkg := res.pkgs[n]
				objs = append(objs, n.Obj())
				pkgs[n.Obj()] = pkg
			}
		}
	}

	var locations []protocol.Location

	for _, obj := range objs {
		pkg := pkgs[obj]
		if pkgs[obj] == nil || len(pkg.CompiledGoFiles()) == 0 {
			continue
		}
		file, _, err := i.Snapshot.View().FindPosInPackage(pkgs[obj], obj.Pos())
		if err != nil {
			return nil, err
		}
		ident, err := findIdentifier(i.Snapshot, pkg, file, obj.Pos())
		if err != nil {
			return nil, err
		}
		decRange, err := ident.Declaration.Range()
		if err != nil {
			return nil, err
		}
		// Do not add interface itself to the list.
		if ident.Declaration.spanRange == i.Declaration.spanRange {
			continue
		}
		locations = append(locations, protocol.Location{
			URI:   protocol.NewURI(ident.Declaration.URI()),
			Range: decRange,
		})
	}

	return locations, nil
}
func (i *IdentifierInfo) implementations(ctx context.Context) (implementsResult, error) {
	var T types.Type
	var method *types.Func
	if i.Type.Object == nil {
		// This isn't a type. Is it a method?
		obj, ok := i.Declaration.obj.(*types.Func)
		if !ok {
			return implementsResult{}, fmt.Errorf("no type info object for identifier %q", i.Name)
		}
		recv := obj.Type().(*types.Signature).Recv()
		if recv == nil {
			return implementsResult{}, fmt.Errorf("this function is not a method")
		}
		method = obj
		T = recv.Type()
	} else {
		T = i.Type.Object.Type()
	}

	// Find all named types, even local types (which can have
	// methods due to promotion) and the built-in "error".
	// We ignore aliases 'type M = N' to avoid duplicate
	// reporting of the Named type N.
	var allNamed []*types.Named
	pkgs := map[*types.Named]Package{}
	for _, pkg := range i.Snapshot.KnownPackages(ctx) {
		info := pkg.GetTypesInfo()
		for _, obj := range info.Defs {
			if obj, ok := obj.(*types.TypeName); ok && !obj.IsAlias() {
				if named, ok := obj.Type().(*types.Named); ok {
					allNamed = append(allNamed, named)
					pkgs[named] = pkg
				}
			}
		}
	}

	allNamed = append(allNamed, types.Universe.Lookup("error").Type().(*types.Named))

	var msets typeutil.MethodSetCache

	// TODO(matloob): We only use the to and toMethod result for now. Figure out if we want to
	// surface the from and fromPtr results to users.
	// Test each named type.
	var to, from, fromPtr []types.Type
	for _, U := range allNamed {
		if isInterface(T) {
			if msets.MethodSet(T).Len() == 0 {
				continue // empty interface
			}
			if isInterface(U) {
				if msets.MethodSet(U).Len() == 0 {
					continue // empty interface
				}

				// T interface, U interface
				if !types.Identical(T, U) {
					if types.AssignableTo(U, T) {
						to = append(to, U)
					}
					if types.AssignableTo(T, U) {
						from = append(from, U)
					}
				}
			} else {
				// T interface, U concrete
				if types.AssignableTo(U, T) {
					to = append(to, U)
				} else if pU := types.NewPointer(U); types.AssignableTo(pU, T) {
					to = append(to, pU)
				}
			}
		} else if isInterface(U) {
			if msets.MethodSet(U).Len() == 0 {
				continue // empty interface
			}

			// T concrete, U interface
			if types.AssignableTo(T, U) {
				from = append(from, U)
			} else if pT := types.NewPointer(T); types.AssignableTo(pT, U) {
				fromPtr = append(fromPtr, U)
			}
		}
	}

	// Sort types (arbitrarily) to ensure test determinism.
	sort.Sort(typesByString(to))
	sort.Sort(typesByString(from))
	sort.Sort(typesByString(fromPtr))

	var toMethod []*types.Selection // contain nils
	if method != nil {
		for _, t := range to {
			toMethod = append(toMethod,
				types.NewMethodSet(t).Lookup(method.Pkg(), method.Name()))
		}
	}

	return implementsResult{pkgs, to, from, fromPtr, toMethod}, nil
}

// implementsResult contains the results of an implements query.
type implementsResult struct {
	pkgs     map[*types.Named]Package
	to       []types.Type // named or ptr-to-named types assignable to interface T
	from     []types.Type // named interfaces assignable from T
	fromPtr  []types.Type // named interfaces assignable only from *T
	toMethod []*types.Selection
}

type typesByString []types.Type

func (p typesByString) Len() int           { return len(p) }
func (p typesByString) Less(i, j int) bool { return p[i].String() < p[j].String() }
func (p typesByString) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
<|endoftext|>