<commit_before>package blockstore

import (
	"context"
	"sync/atomic"
	"time"

	"github.com/ipfs/go-ipfs/blocks"

	"gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
	cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
	bloom "gx/ipfs/QmeiMCBkYHxkDkDfnDadzz4YxY5ruL5Pj499essE4vRsGM/bbloom"
)

// bloomCached returns Blockstore that caches Has requests using Bloom filter
// Size is size of bloom filter in bytes
func bloomCached(bs Blockstore, ctx context.Context, bloomSize, hashCount int) (*bloomcache, error) {
	bl, err := bloom.New(float64(bloomSize), float64(hashCount))
	if err != nil {
		return nil, err
	}
	bc := &bloomcache{blockstore: bs, bloom: bl}
	bc.hits = metrics.NewCtx(ctx, "bloom.hits_total",
		"Number of cache hits in bloom cache").Counter()
	bc.total = metrics.NewCtx(ctx, "bloom_total",
		"Total number of requests to bloom cache").Counter()

	bc.Invalidate()
	go bc.Rebuild(ctx)
	if metrics.Active() {
		go func() {
			fill := metrics.NewCtx(ctx, "bloom_fill_ratio",
				"Ratio of bloom filter fullnes, (updated once a minute)").Gauge()

			<-bc.rebuildChan
			t := time.NewTicker(1 * time.Minute)
			for {
				select {
				case <-ctx.Done():
					t.Stop()
					return
				case <-t.C:
					fill.Set(bc.bloom.FillRatio())
				}
			}
		}()
	}
	return bc, nil
}

type bloomcache struct {
	bloom  *bloom.Bloom
	active int32

	// This chan is only used for testing to wait for bloom to enable
	rebuildChan chan struct{}
	blockstore  Blockstore

	// Statistics
	hits  metrics.Counter
	total metrics.Counter
}

func (b *bloomcache) Invalidate() {
	b.rebuildChan = make(chan struct{})
	atomic.StoreInt32(&b.active, 0)
}

func (b *bloomcache) BloomActive() bool {
	return atomic.LoadInt32(&b.active) != 0
}

func (b *bloomcache) Rebuild(ctx context.Context) {
	evt := log.EventBegin(ctx, "bloomcache.Rebuild")
	defer evt.Done()

	ch, err := b.blockstore.AllKeysChan(ctx)
	if err != nil {
		log.Errorf("AllKeysChan failed in bloomcache rebuild with: %v", err)
		return
	}
	finish := false
	for !finish {
		select {
		case key, ok := <-ch:
			if ok {
				b.bloom.AddTS(key.Bytes()) // Use binary key, the more compact the better
			} else {
				finish = true
			}
		case <-ctx.Done():
			log.Warning("Cache rebuild closed by context finishing.")
			return
		}
	}
	close(b.rebuildChan)
	atomic.StoreInt32(&b.active, 1)
}

func (b *bloomcache) DeleteBlock(k *cid.Cid) error {
	if has, ok := b.hasCached(k); ok && !has {
		return ErrNotFound
	}

	return b.blockstore.DeleteBlock(k)
}

// if ok == false has is inconclusive
// if ok == true then has respons to question: is it contained
func (b *bloomcache) hasCached(k *cid.Cid) (has bool, ok bool) {
	b.total.Inc()
	if k == nil {
		log.Error("nil cid in bloom cache")
		// Return cache invalid so call to blockstore
		// in case of invalid key is forwarded deeper
		return false, false
	}
	if b.BloomActive() {
		blr := b.bloom.HasTS(k.Bytes())
		if blr == false { // not contained in bloom is only conclusive answer bloom gives
			b.hits.Inc()
			return false, true
		}
	}
	return false, false
}

func (b *bloomcache) Has(k *cid.Cid) (bool, error) {
	if has, ok := b.hasCached(k); ok {
		return has, nil
	}

	return b.blockstore.Has(k)
}

func (b *bloomcache) Get(k *cid.Cid) (blocks.Block, error) {
	if has, ok := b.hasCached(k); ok && !has {
		return nil, ErrNotFound
	}

	return b.blockstore.Get(k)
}

func (b *bloomcache) Put(bl blocks.Block) error {
	if has, ok := b.hasCached(bl.Cid()); ok && has {
		return nil
	}

	err := b.blockstore.Put(bl)
	if err == nil {
		b.bloom.AddTS(bl.Cid().Bytes())
	}
	return err
}

func (b *bloomcache) PutMany(bs []blocks.Block) error {
	// bloom cache gives only conclusive resulty if key is not contained
	// to reduce number of puts we need conclusive infomration if block is contained
	// this means that PutMany can't be improved with bloom cache so we just
	// just do a passthrough.
	err := b.blockstore.PutMany(bs)
	if err != nil {
		return err
	}
	for _, bl := range bs {
		b.bloom.AddTS(bl.Cid().Bytes())
	}
	return nil
}

func (b *bloomcache) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
	return b.blockstore.AllKeysChan(ctx)
}

func (b *bloomcache) GCLock() Unlocker {
	return b.blockstore.(GCBlockstore).GCLock()
}

func (b *bloomcache) PinLock() Unlocker {
	return b.blockstore.(GCBlockstore).PinLock()
}

func (b *bloomcache) GCRequested() bool {
	return b.blockstore.(GCBlockstore).GCRequested()
}
<commit_msg>fix: remove bloom filter check on Put call in blockstore<commit_after>package blockstore

import (
	"context"
	"sync/atomic"
	"time"

	"github.com/ipfs/go-ipfs/blocks"

	"gx/ipfs/QmRg1gKTHzc3CZXSKzem8aR4E3TubFhbgXwfVuWnSK5CC5/go-metrics-interface"
	cid "gx/ipfs/QmV5gPoRsjN1Gid3LMdNZTyfCtP2DsvqEbMAmz82RmmiGk/go-cid"
	bloom "gx/ipfs/QmeiMCBkYHxkDkDfnDadzz4YxY5ruL5Pj499essE4vRsGM/bbloom"
)

// bloomCached returns Blockstore that caches Has requests using Bloom filter
// Size is size of bloom filter in bytes
func bloomCached(bs Blockstore, ctx context.Context, bloomSize, hashCount int) (*bloomcache, error) {
	bl, err := bloom.New(float64(bloomSize), float64(hashCount))
	if err != nil {
		return nil, err
	}
	bc := &bloomcache{blockstore: bs, bloom: bl}
	bc.hits = metrics.NewCtx(ctx, "bloom.hits_total",
		"Number of cache hits in bloom cache").Counter()
	bc.total = metrics.NewCtx(ctx, "bloom_total",
		"Total number of requests to bloom cache").Counter()

	bc.Invalidate()
	go bc.Rebuild(ctx)
	if metrics.Active() {
		go func() {
			fill := metrics.NewCtx(ctx, "bloom_fill_ratio",
				"Ratio of bloom filter fullnes, (updated once a minute)").Gauge()

			<-bc.rebuildChan
			t := time.NewTicker(1 * time.Minute)
			for {
				select {
				case <-ctx.Done():
					t.Stop()
					return
				case <-t.C:
					fill.Set(bc.bloom.FillRatio())
				}
			}
		}()
	}
	return bc, nil
}

type bloomcache struct {
	bloom  *bloom.Bloom
	active int32

	// This chan is only used for testing to wait for bloom to enable
	rebuildChan chan struct{}
	blockstore  Blockstore

	// Statistics
	hits  metrics.Counter
	total metrics.Counter
}

func (b *bloomcache) Invalidate() {
	b.rebuildChan = make(chan struct{})
	atomic.StoreInt32(&b.active, 0)
}

func (b *bloomcache) BloomActive() bool {
	return atomic.LoadInt32(&b.active) != 0
}

func (b *bloomcache) Rebuild(ctx context.Context) {
	evt := log.EventBegin(ctx, "bloomcache.Rebuild")
	defer evt.Done()

	ch, err := b.blockstore.AllKeysChan(ctx)
	if err != nil {
		log.Errorf("AllKeysChan failed in bloomcache rebuild with: %v", err)
		return
	}
	finish := false
	for !finish {
		select {
		case key, ok := <-ch:
			if ok {
				b.bloom.AddTS(key.Bytes()) // Use binary key, the more compact the better
			} else {
				finish = true
			}
		case <-ctx.Done():
			log.Warning("Cache rebuild closed by context finishing.")
			return
		}
	}
	close(b.rebuildChan)
	atomic.StoreInt32(&b.active, 1)
}

func (b *bloomcache) DeleteBlock(k *cid.Cid) error {
	if has, ok := b.hasCached(k); ok && !has {
		return ErrNotFound
	}

	return b.blockstore.DeleteBlock(k)
}

// if ok == false has is inconclusive
// if ok == true then has respons to question: is it contained
func (b *bloomcache) hasCached(k *cid.Cid) (has bool, ok bool) {
	b.total.Inc()
	if k == nil {
		log.Error("nil cid in bloom cache")
		// Return cache invalid so call to blockstore
		// in case of invalid key is forwarded deeper
		return false, false
	}
	if b.BloomActive() {
		blr := b.bloom.HasTS(k.Bytes())
		if blr == false { // not contained in bloom is only conclusive answer bloom gives
			b.hits.Inc()
			return false, true
		}
	}
	return false, false
}

func (b *bloomcache) Has(k *cid.Cid) (bool, error) {
	if has, ok := b.hasCached(k); ok {
		return has, nil
	}

	return b.blockstore.Has(k)
}

func (b *bloomcache) Get(k *cid.Cid) (blocks.Block, error) {
	if has, ok := b.hasCached(k); ok && !has {
		return nil, ErrNotFound
	}

	return b.blockstore.Get(k)
}

func (b *bloomcache) Put(bl blocks.Block) error {
	// See comment in PutMany
	err := b.blockstore.Put(bl)
	if err == nil {
		b.bloom.AddTS(bl.Cid().Bytes())
	}
	return err
}

func (b *bloomcache) PutMany(bs []blocks.Block) error {
	// bloom cache gives only conclusive resulty if key is not contained
	// to reduce number of puts we need conclusive information if block is contained
	// this means that PutMany can't be improved with bloom cache so we just
	// just do a passthrough.
	err := b.blockstore.PutMany(bs)
	if err != nil {
		return err
	}
	for _, bl := range bs {
		b.bloom.AddTS(bl.Cid().Bytes())
	}
	return nil
}

func (b *bloomcache) AllKeysChan(ctx context.Context) (<-chan *cid.Cid, error) {
	return b.blockstore.AllKeysChan(ctx)
}

func (b *bloomcache) GCLock() Unlocker {
	return b.blockstore.(GCBlockstore).GCLock()
}

func (b *bloomcache) PinLock() Unlocker {
	return b.blockstore.(GCBlockstore).PinLock()
}

func (b *bloomcache) GCRequested() bool {
	return b.blockstore.(GCBlockstore).GCRequested()
}
<|endoftext|>


<commit_before><commit_msg>Remove unpacked files after deploy<commit_after><|endoftext|>


<commit_before>// errchk $G -e $D/$F.go

// Copyright 2009 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.

package main

var m0 map[string]int
var m1 *map[string]int
var m2 *map[string]int = &m0
var m3 map[string]int = map[string]int{"a": 1}
var m4 *map[string]int = &m3

var s0 string
var s1 *string
var s2 *string = &s0
var s3 string = "a"
var s4 *string = &s3

var a0 [10]int
var a1 *[10]int
var a2 *[10]int = &a0

var b0 []int
var b1 *[]int
var b2 *[]int = &b0
var b3 []int = []int{1, 2, 3}
var b4 *[]int = &b3

func f()
{
	// this is spaced funny so that
	// the compiler will print a different
	// line number for each len call when
	// it decides there are type errors.
	x :=
		len(m0)+
		len(m1)+	// ERROR "illegal"
		len(m2)+	// ERROR "illegal"
		len(m3)+
		len(m4)+	// ERROR "illegal"

		len(s0)+
		len(s1)+	// ERROR "illegal"
		len(s2)+	// ERROR "illegal"
		len(s3)+
		len(s4)+	// ERROR "illegal"

		len(a0)+
		len(a1)+
		len(a2)+

		cap(a0)+
		cap(a1)+
		cap(a2)+

		len(b0)+
		len(b1)+	// ERROR "illegal"
		len(b2)+	// ERROR "illegal"
		len(b3)+
		len(b4)+	// ERROR "illegal"

		cap(b0)+
		cap(b1)+	// ERROR "illegal"
		cap(b2)+	// ERROR "illegal"
		cap(b3)+
		cap(b4);	// ERROR "illegal"
}
<commit_msg>Recognize gccgo error messages.<commit_after>// errchk $G -e $D/$F.go

// Copyright 2009 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.

package main

var m0 map[string]int
var m1 *map[string]int
var m2 *map[string]int = &m0
var m3 map[string]int = map[string]int{"a": 1}
var m4 *map[string]int = &m3

var s0 string
var s1 *string
var s2 *string = &s0
var s3 string = "a"
var s4 *string = &s3

var a0 [10]int
var a1 *[10]int
var a2 *[10]int = &a0

var b0 []int
var b1 *[]int
var b2 *[]int = &b0
var b3 []int = []int{1, 2, 3}
var b4 *[]int = &b3

func f()
{
	// this is spaced funny so that
	// the compiler will print a different
	// line number for each len call when
	// it decides there are type errors.
	x :=
		len(m0)+
		len(m1)+	// ERROR "illegal|must be"
		len(m2)+	// ERROR "illegal|must be"
		len(m3)+
		len(m4)+	// ERROR "illegal|must be"

		len(s0)+
		len(s1)+	// ERROR "illegal|must be"
		len(s2)+	// ERROR "illegal|must be"
		len(s3)+
		len(s4)+	// ERROR "illegal|must be"

		len(a0)+
		len(a1)+
		len(a2)+

		cap(a0)+
		cap(a1)+
		cap(a2)+

		len(b0)+
		len(b1)+	// ERROR "illegal|must be"
		len(b2)+	// ERROR "illegal|must be"
		len(b3)+
		len(b4)+	// ERROR "illegal|must be"

		cap(b0)+
		cap(b1)+	// ERROR "illegal|must be"
		cap(b2)+	// ERROR "illegal|must be"
		cap(b3)+
		cap(b4);	// ERROR "illegal|must be"
}
<|endoftext|>


<commit_before>// Package zalando contains Zalando specific definitions for
// authorization.
package zalando

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/zalando/gin-oauth2"
	"golang.org/x/oauth2"
)

// AccessTuples has to be set by the client to grant access.
var AccessTuples []AccessTuple

// AccessTuple is the type defined for use in AccessTuples.
type AccessTuple struct {
	Realm string // p.e. "employees", "services"
	Uid   string // UnixName
	Cn    string // RealName
}

// TeamInfo is defined like in TeamAPI json.
type TeamInfo struct {
	Id      string
	Id_name string
	Team_id string
	Type    string
	Name    string
	Mail    []string
}

// OAuth2Endpoint is similar to the definitions in golang.org/x/oauth2
var OAuth2Endpoint = oauth2.Endpoint{
	AuthURL:  "https://token.auth.zalando.com/access_token",
	TokenURL: "https://info.services.auth.zalando.com/oauth2/tokeninfo",
}

// TeamAPI is a custom API
var TeamAPI string = "https://teams.auth.zalando.com/api/teams"

// RequestTeamInfo is a function that returns team information for a
// given token.
func RequestTeamInfo(tc *ginoauth2.TokenContainer, uri string) ([]byte, error) {
	var uv = make(url.Values)
	uv.Set("member", tc.Scopes["uid"].(string))
	info_url := uri + "?" + uv.Encode()
	client := &http.Client{Transport: &ginoauth2.Transport}
	req, err := http.NewRequest("GET", info_url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tc.Token.AccessToken))

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

// GroupCheck is an authorization function that checks, if the Token
// was issued for an employee of a specified team. The given
// TokenContainer must be valid.
func GroupCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		glog.Error("failed to get team info, caused by: ", err)
		return false
	}
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
		return false
	}
	granted := false
	for _, teamInfo := range data {
		for idx := range AccessTuples {
			at := AccessTuples[idx]
			if teamInfo.Id == at.Uid {
				granted = true
				glog.Infof("Grant access to %s as team member of \"%s\"\n", tc.Scopes["uid"].(string), teamInfo.Id)
			}
			if teamInfo.Type == "official" {
				ctx.Set("uid", tc.Scopes["uid"].(string))
				ctx.Set("team", teamInfo.Id)
			}
		}
	}
	return granted
}

// UidCheck is an authorization function that checks UID scope
// TokenContainer must be Valid.
func UidCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	uid := tc.Scopes["uid"].(string)
	for idx := range AccessTuples {
		at := AccessTuples[idx]
		if uid == at.Uid {
			ctx.Set("uid", uid) //in this way I can set the authorized uid
			glog.Infof("Grant access to %s\n", uid)
			return true
		}
	}

	return false
}

// NoAuthorization sets "team" and "uid" in the context without
// checking if the user/team is authorized.
func NoAuthorization(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
	}
	for _, teamInfo := range data {
		if teamInfo.Type == "official" {
			ctx.Set("uid", tc.Scopes["uid"].(string))
			ctx.Set("team", teamInfo.Id)
			return true
		}
	}
	return true
}
<commit_msg>Annotate AccessTuple for easy use in configs.<commit_after>// Package zalando contains Zalando specific definitions for
// authorization.
package zalando

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"github.com/gin-gonic/gin"
	"github.com/golang/glog"
	"github.com/zalando/gin-oauth2"
	"golang.org/x/oauth2"
)

// AccessTuples has to be set by the client to grant access.
var AccessTuples []AccessTuple

// AccessTuple is the type defined for use in AccessTuples.
type AccessTuple struct {
	Realm string `yaml:"Realm,omitempty"` // p.e. "employees", "services"
	UID   string `yaml:"Uid,omitempty"`   // UnixName
	Cn    string `yaml:"Cn,omitempty"`    // RealName
}

// TeamInfo is defined like in TeamAPI json.
type TeamInfo struct {
	Id      string
	Id_name string
	Team_id string
	Type    string
	Name    string
	Mail    []string
}

// OAuth2Endpoint is similar to the definitions in golang.org/x/oauth2
var OAuth2Endpoint = oauth2.Endpoint{
	AuthURL:  "https://token.auth.zalando.com/access_token",
	TokenURL: "https://info.services.auth.zalando.com/oauth2/tokeninfo",
}

// TeamAPI is a custom API
var TeamAPI string = "https://teams.auth.zalando.com/api/teams"

// RequestTeamInfo is a function that returns team information for a
// given token.
func RequestTeamInfo(tc *ginoauth2.TokenContainer, uri string) ([]byte, error) {
	var uv = make(url.Values)
	uv.Set("member", tc.Scopes["uid"].(string))
	info_url := uri + "?" + uv.Encode()
	client := &http.Client{Transport: &ginoauth2.Transport}
	req, err := http.NewRequest("GET", info_url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tc.Token.AccessToken))

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ioutil.ReadAll(resp.Body)
}

// GroupCheck is an authorization function that checks, if the Token
// was issued for an employee of a specified team. The given
// TokenContainer must be valid.
func GroupCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	if err != nil {
		glog.Error("failed to get team info, caused by: ", err)
		return false
	}
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
		return false
	}
	granted := false
	for _, teamInfo := range data {
		for idx := range AccessTuples {
			at := AccessTuples[idx]
			if teamInfo.Id == at.UID {
				granted = true
				glog.Infof("Grant access to %s as team member of \"%s\"\n", tc.Scopes["uid"].(string), teamInfo.Id)
			}
			if teamInfo.Type == "official" {
				ctx.Set("uid", tc.Scopes["uid"].(string))
				ctx.Set("team", teamInfo.Id)
			}
		}
	}
	return granted
}

// UidCheck is an authorization function that checks UID scope
// TokenContainer must be Valid.
func UidCheck(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	uid := tc.Scopes["uid"].(string)
	for idx := range AccessTuples {
		at := AccessTuples[idx]
		if uid == at.UID {
			ctx.Set("uid", uid) //in this way I can set the authorized uid
			glog.Infof("Grant access to %s\n", uid)
			return true
		}
	}

	return false
}

// NoAuthorization sets "team" and "uid" in the context without
// checking if the user/team is authorized.
func NoAuthorization(tc *ginoauth2.TokenContainer, ctx *gin.Context) bool {
	blob, err := RequestTeamInfo(tc, TeamAPI)
	var data []TeamInfo
	err = json.Unmarshal(blob, &data)
	if err != nil {
		glog.Errorf("JSON.Unmarshal failed, caused by: %s", err)
	}
	for _, teamInfo := range data {
		if teamInfo.Type == "official" {
			ctx.Set("uid", tc.Scopes["uid"].(string))
			ctx.Set("team", teamInfo.Id)
			return true
		}
	}
	return true
}
<|endoftext|>


<commit_before>package datastore

import (
	"log"
)

// Here are some basic datastore implementations.

// MapDatastore uses a standard Go map for internal storage.
type keyMap map[Key]interface{}
type MapDatastore struct {
	values keyMap
}

func NewMapDatastore() (d *MapDatastore) {
	return &MapDatastore{
		values: keyMap{},
	}
}

func (d *MapDatastore) Put(key Key, value interface{}) (err error) {
	d.values[key] = value
	return nil
}

func (d *MapDatastore) Get(key Key) (value interface{}, err error) {
	val, found := d.values[key]
	if !found {
		return nil, ErrNotFound
	}
	return val, nil
}

func (d *MapDatastore) Has(key Key) (exists bool, err error) {
	_, found := d.values[key]
	return found, nil
}

func (d *MapDatastore) Delete(key Key) (err error) {
	delete(d.values, key)
	return nil
}

// NullDatastore stores nothing, but conforms to the API.
// Useful to test with.
type NullDatastore struct {
}

func NewNullDatastore() *NullDatastore {
	return &NullDatastore{}
}

func (d *NullDatastore) Put(key Key, value interface{}) (err error) {
	return nil
}

func (d *NullDatastore) Get(key Key) (value interface{}, err error) {
	return nil, nil
}

func (d *NullDatastore) Has(key Key) (exists bool, err error) {
	return false, nil
}

func (d *NullDatastore) Delete(key Key) (err error) {
	return nil
}

// LogDatastore logs all accesses through the datastore.
type LogDatastore struct {
	Child Datastore
}

func NewLogDatastore(ds Datastore) *LogDatastore {
	return &LogDatastore{Child: ds}
}

func (d *LogDatastore) Put(key Key, value interface{}) (err error) {
	log.Printf("LogDatastore: Put %s", key)
	return d.Child.Put(key, value)
}

func (d *LogDatastore) Get(key Key) (value interface{}, err error) {
	log.Printf("LogDatastore: Get %s", key)
	return d.Child.Get(key)
}

func (d *LogDatastore) Has(key Key) (exists bool, err error) {
	log.Printf("LogDatastore: Has %s", key)
	return d.Child.Has(key)
}

func (d *LogDatastore) Delete(key Key) (err error) {
	log.Printf("LogDatastore: Delete %s", key)
	return d.Child.Delete(key)
}
<commit_msg>log: name<commit_after>package datastore

import (
	"log"
)

// Here are some basic datastore implementations.

// MapDatastore uses a standard Go map for internal storage.
type keyMap map[Key]interface{}
type MapDatastore struct {
	values keyMap
}

func NewMapDatastore() (d *MapDatastore) {
	return &MapDatastore{
		values: keyMap{},
	}
}

func (d *MapDatastore) Put(key Key, value interface{}) (err error) {
	d.values[key] = value
	return nil
}

func (d *MapDatastore) Get(key Key) (value interface{}, err error) {
	val, found := d.values[key]
	if !found {
		return nil, ErrNotFound
	}
	return val, nil
}

func (d *MapDatastore) Has(key Key) (exists bool, err error) {
	_, found := d.values[key]
	return found, nil
}

func (d *MapDatastore) Delete(key Key) (err error) {
	delete(d.values, key)
	return nil
}

// NullDatastore stores nothing, but conforms to the API.
// Useful to test with.
type NullDatastore struct {
}

func NewNullDatastore() *NullDatastore {
	return &NullDatastore{}
}

func (d *NullDatastore) Put(key Key, value interface{}) (err error) {
	return nil
}

func (d *NullDatastore) Get(key Key) (value interface{}, err error) {
	return nil, nil
}

func (d *NullDatastore) Has(key Key) (exists bool, err error) {
	return false, nil
}

func (d *NullDatastore) Delete(key Key) (err error) {
	return nil
}

// LogDatastore logs all accesses through the datastore.
type LogDatastore struct {
	Name string
	Child Datastore
}

func NewLogDatastore(ds Datastore, name string) *LogDatastore {
	if len(name) < 1 {
		name = "LogDatastore"
	}
	return &LogDatastore{Name: name, Child: ds}
}

func (d *LogDatastore) Put(key Key, value interface{}) (err error) {
	log.Printf("%s: Put %s", d.Name, key)
	log.Printf("%s: Put %s ```%s```", d.Name, key, value)
	return d.Child.Put(key, value)
}

func (d *LogDatastore) Get(key Key) (value interface{}, err error) {
	log.Printf("%s: Get %s", d.Name, key)
	return d.Child.Get(key)
}

func (d *LogDatastore) Has(key Key) (exists bool, err error) {
	log.Printf("%s: Has %s", d.Name, key)
	return d.Child.Has(key)
}

func (d *LogDatastore) Delete(key Key) (err error) {
	log.Printf("%s: Delete %s", d.Name, key)
	return d.Child.Delete(key)
}
<|endoftext|>


<commit_before>package gorobdd

import (
	"fmt"
	"github.com/callpraths/gorobdd/internal/node"
	"testing"
)

func ExamplePrintLeaf() {
	fmt.Println(&BDD{
		[]string{},
		&node.Node{
			Type: node.LeafType,
			Leaf: node.Leaf{true},
		},
	})
	// Output: T
}

func ExamplePrintInternal() {
	fmt.Println(&BDD{
		[]string{"a"},
		&node.Node{
			Type: node.InternalType,
			Internal: node.Internal{
				True: &node.Node{
					Type: node.LeafType,
					Leaf: node.Leaf{false},
				},
				False: &node.Node{
					Type: node.LeafType,
					Leaf: node.Leaf{true},
				},
			},
		},
	})
	// Output: (a/T: F, a/F: T)
}

func ExampleTrivialBDDFromTuples() {
	v, _ := FromTuples([]string{}, [][]bool{})
	fmt.Println(v)
	// Output: F
}

func ExampleFalseBDDFromTuples() {
	v, _ := FromTuples([]string{"a"}, [][]bool{})
	fmt.Println(v)
	// Output: (a/T: F, a/F: F)
}

func ExampleBDDFromSingleTuple() {
	v, _ := FromTuples([]string{"a", "b"}, [][]bool{{true, false}})
	fmt.Println(v)
	// Output: (a/T: (b/T: F, b/F: T), a/F: (b/T: F, b/F: F))
}

func ExampleBDDFromTuples() {
	v, _ := FromTuples([]string{"a", "b"}, [][]bool{{true, false}, {false, true}})
	fmt.Println(v)
	// Output: (a/T: (b/T: F, b/F: T), a/F: (b/T: T, b/F: F))
}

func TestBDDFromTuplesChecksTupleLengths(t *testing.T) {
	v, e := FromTuples([]string{"a", "b"}, [][]bool{{true}})
	if e == nil {
		t.Error("Unexpected BDD from tuples: %v", v)
	}
}

func TestBinaryOpsCheckVocabulary(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
	}{
		{True([]string{"a"}), True([]string{"a", "b"})},
		{True([]string{"a", "b"}), True([]string{"a"})},
		{True([]string{"a", "b"}), True([]string{})},
		{True([]string{"a", "b"}), True([]string{"b", "a"})},
		{True([]string{"a", "b"}), True([]string{"a", "a"})},
	}
	for _, tt := range tests {
		if _, e := Equal(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := And(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := Or(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Or(%v, %v)", tt.lhs, tt.rhs)
		}
	}
}

func fromTuplesNoError(t *testing.T, v []string, tu [][]bool) *BDD {
	b, e := FromTuples(v, tu)
	if e != nil {
		t.Fatalf("FromTuples(%v, %v) returned error: %v", v, tu, e)
	}
	return b
}

func TestBDDEqual(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
		eq  bool
	}{
		{True([]string{}), True([]string{}), true},
		{False([]string{}), False([]string{}), true},
		{True([]string{}), False([]string{}), false},
		{False([]string{}), True([]string{}), false},
		{True([]string{"a"}), True([]string{"a"}), true},
		{False([]string{"a"}), False([]string{"a"}), true},
		{True([]string{"a"}), False([]string{"a"}), false},
		{False([]string{"a"}), True([]string{"a"}), false},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			true,
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{false, false}}),
			false,
		},
	}
	for _, tt := range tests {
		eq, e := Equal(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Equal(%v, %v) failed: %v", tt.lhs, tt.rhs, e)
		}
		if eq != tt.eq {
			t.Errorf("Equal(%v, %v) = %v, want %v", tt.lhs, tt.rhs, eq, tt.eq)
		}
	}
}

func TestTrivialBDDBinaryOps(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
		and *BDD
		or  *BDD
	}{
		{True([]string{}), True([]string{}), True([]string{}), True([]string{})},
		{True([]string{}), False([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), True([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), False([]string{}), False([]string{}), False([]string{})},
	}
	for _, tt := range tests {
		var and, or *BDD
		var eq bool
		var e error
		and, e = And(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(and, tt.and)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("And(%v, %v) = %v, want %v", tt.lhs, tt.rhs, and, tt.and)
		}
		or, e = Or(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Or(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(or, tt.or)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("Or(%v, %v) = %v, want %v", tt.lhs, tt.rhs, or, tt.or)
		}
	}
}

func TestTrivialBDDNot(t *testing.T) {
	var tests = []struct {
		in  *BDD
		ans *BDD
	}{
		{True([]string{}), False([]string{})},
		{False([]string{}), True([]string{})},
	}
	for _, tt := range tests {
		ans, e1 := Not(tt.in)
		if e1 != nil {
			t.Errorf("Not(%v) returned error %v", tt.in, e1)
		}
		eq, e2 := Equal(ans, tt.ans)
		if e2 != nil {
			t.Errorf("Equal(%v, %v) returned error %v", ans, tt.ans, e2)
		}
		if !eq {
			t.Errorf("Not(%v) = %v, want %v", tt.in, ans, tt.ans)
		}
	}
}
<commit_msg>(wip) Non-trivial binary ops<commit_after>package gorobdd

import (
	"fmt"
	"github.com/callpraths/gorobdd/internal/node"
	"testing"
)

func ExamplePrintLeaf() {
	fmt.Println(&BDD{
		[]string{},
		&node.Node{
			Type: node.LeafType,
			Leaf: node.Leaf{true},
		},
	})
	// Output: T
}

func ExamplePrintInternal() {
	fmt.Println(&BDD{
		[]string{"a"},
		&node.Node{
			Type: node.InternalType,
			Internal: node.Internal{
				True: &node.Node{
					Type: node.LeafType,
					Leaf: node.Leaf{false},
				},
				False: &node.Node{
					Type: node.LeafType,
					Leaf: node.Leaf{true},
				},
			},
		},
	})
	// Output: (a/T: F, a/F: T)
}

func ExampleTrivialBDDFromTuples() {
	v, _ := FromTuples([]string{}, [][]bool{})
	fmt.Println(v)
	// Output: F
}

func ExampleFalseBDDFromTuples() {
	v, _ := FromTuples([]string{"a"}, [][]bool{})
	fmt.Println(v)
	// Output: (a/T: F, a/F: F)
}

func ExampleBDDFromSingleTuple() {
	v, _ := FromTuples([]string{"a", "b"}, [][]bool{{true, false}})
	fmt.Println(v)
	// Output: (a/T: (b/T: F, b/F: T), a/F: (b/T: F, b/F: F))
}

func ExampleBDDFromTuples() {
	v, _ := FromTuples([]string{"a", "b"}, [][]bool{{true, false}, {false, true}})
	fmt.Println(v)
	// Output: (a/T: (b/T: F, b/F: T), a/F: (b/T: T, b/F: F))
}

func TestBDDFromTuplesChecksTupleLengths(t *testing.T) {
	v, e := FromTuples([]string{"a", "b"}, [][]bool{{true}})
	if e == nil {
		t.Error("Unexpected BDD from tuples: %v", v)
	}
}

func TestBinaryOpsCheckVocabulary(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
	}{
		{True([]string{"a"}), True([]string{"a", "b"})},
		{True([]string{"a", "b"}), True([]string{"a"})},
		{True([]string{"a", "b"}), True([]string{})},
		{True([]string{"a", "b"}), True([]string{"b", "a"})},
		{True([]string{"a", "b"}), True([]string{"a", "a"})},
	}
	for _, tt := range tests {
		if _, e := Equal(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := And(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from And(%v, %v)", tt.lhs, tt.rhs)
		}
		if _, e := Or(tt.lhs, tt.rhs); e == nil {
			t.Errorf("No error raised from Or(%v, %v)", tt.lhs, tt.rhs)
		}
	}
}

func fromTuplesNoError(t *testing.T, v []string, tu [][]bool) *BDD {
	b, e := FromTuples(v, tu)
	if e != nil {
		t.Fatalf("FromTuples(%v, %v) returned error: %v", v, tu, e)
	}
	return b
}

func TestBDDEqual(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
		eq  bool
	}{
		{True([]string{}), True([]string{}), true},
		{False([]string{}), False([]string{}), true},
		{True([]string{}), False([]string{}), false},
		{False([]string{}), True([]string{}), false},
		{True([]string{"a"}), True([]string{"a"}), true},
		{False([]string{"a"}), False([]string{"a"}), true},
		{True([]string{"a"}), False([]string{"a"}), false},
		{False([]string{"a"}), True([]string{"a"}), false},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			true,
		},
		{
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{true, false}}),
			fromTuplesNoError(t, []string{"a", "b"}, [][]bool{{false, false}}),
			false,
		},
	}
	for _, tt := range tests {
		eq, e := Equal(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Equal(%v, %v) failed: %v", tt.lhs, tt.rhs, e)
		}
		if eq != tt.eq {
			t.Errorf("Equal(%v, %v) = %v, want %v", tt.lhs, tt.rhs, eq, tt.eq)
		}
	}
}

func TestTrivialBDDBinaryOps(t *testing.T) {
	var tests = []struct {
		lhs *BDD
		rhs *BDD
		and *BDD
		or  *BDD
	}{
		{True([]string{}), True([]string{}), True([]string{}), True([]string{})},
		{True([]string{}), False([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), True([]string{}), False([]string{}), True([]string{})},
		{False([]string{}), False([]string{}), False([]string{}), False([]string{})},
		{True([]string{"a"}), True([]string{"a"}), True([]string{"a"}), True([]string{"a"})},
		{True([]string{"a"}), False([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), True([]string{"a"}), False([]string{"a"}), True([]string{"a"})},
		{False([]string{"a"}), False([]string{"a"}), False([]string{"a"}), False([]string{"a"})},
	}
	for _, tt := range tests {
		var and, or *BDD
		var eq bool
		var e error
		and, e = And(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(and, tt.and)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("And(%v, %v) = %v, want %v", tt.lhs, tt.rhs, and, tt.and)
		}
		or, e = Or(tt.lhs, tt.rhs)
		if e != nil {
			t.Errorf("Or(%v, %v) returned error %v", tt.lhs, tt.rhs, e)
		}
		eq, e = Equal(or, tt.or)
		if e != nil {
			t.Errorf("And(%v, %v) returned error %v", and, tt.and, e)
		}
		if !eq {
			t.Errorf("Or(%v, %v) = %v, want %v", tt.lhs, tt.rhs, or, tt.or)
		}
	}
}

func TestTrivialBDDNot(t *testing.T) {
	var tests = []struct {
		in  *BDD
		ans *BDD
	}{
		{True([]string{}), False([]string{})},
		{False([]string{}), True([]string{})},
	}
	for _, tt := range tests {
		ans, e1 := Not(tt.in)
		if e1 != nil {
			t.Errorf("Not(%v) returned error %v", tt.in, e1)
		}
		eq, e2 := Equal(ans, tt.ans)
		if e2 != nil {
			t.Errorf("Equal(%v, %v) returned error %v", ans, tt.ans, e2)
		}
		if !eq {
			t.Errorf("Not(%v) = %v, want %v", tt.in, ans, tt.ans)
		}
	}
}
<|endoftext|>


<commit_before>package executehelpers

import (
	"github.com/concourse/atc"
	"github.com/concourse/fly/commands/internal/deprecated"
	"github.com/concourse/fly/rc"
	"github.com/concourse/go-concourse/concourse"
	"github.com/tedsuo/rata"
)

func CreateBuild(
	atcRequester *deprecated.AtcRequester,
	client concourse.Client,
	privileged bool,
	inputs []Input,
	outputs []Output,
	config atc.TaskConfig,
	tags []string,
	target string,
) (atc.Build, error) {
	if err := config.Validate(); err != nil {
		return atc.Build{}, err
	}

	targetProps, err := rc.SelectTarget(target)
	if err != nil {
		return atc.Build{}, err
	}

	buildInputs := atc.AggregatePlan{}
	for i, input := range inputs {
		var getPlan atc.GetPlan
		if input.Path != "" {
			readPipe, err := atcRequester.CreateRequest(
				atc.ReadPipe,
				rata.Params{"pipe_id": input.Pipe.ID},
				nil,
			)
			if err != nil {
				return atc.Build{}, err
			}

			source := atc.Source{
				"uri": readPipe.URL.String(),
			}

			if targetProps.Token != nil {
				source["authorization"] = targetProps.Token.Type + " " + targetProps.Token.Value
			}
			getPlan = atc.GetPlan{
				Name:   input.Name,
				Type:   "archive",
				Source: source,
			}
		} else {
			getPlan = atc.GetPlan{
				Name:    input.Name,
				Type:    input.BuildInput.Type,
				Source:  input.BuildInput.Source,
				Version: input.BuildInput.Version,
				Params:  input.BuildInput.Params,
				Tags:    input.BuildInput.Tags,
			}
		}

		buildInputs = append(buildInputs, atc.Plan{
			Location: &atc.Location{
				// offset by 2 because aggregate gets parallelgroup ID 1
				ID:            uint(i) + 2,
				ParentID:      0,
				ParallelGroup: 1,
			},
			Get: &getPlan,
		})
	}

	taskPlan := atc.Plan{
		Location: &atc.Location{
			// offset by 1 because aggregate gets parallelgroup ID 1
			ID:       uint(len(inputs)) + 2,
			ParentID: 0,
		},
		Task: &atc.TaskPlan{
			Name:       "one-off",
			Privileged: privileged,
			Config:     &config,
		},
	}

	if len(tags) != 0 {
		taskPlan.Task.Tags = tags
	}

	buildOutputs := atc.AggregatePlan{}
	for i, output := range outputs {
		writePipe, err := atcRequester.CreateRequest(
			atc.WritePipe,
			rata.Params{"pipe_id": output.Pipe.ID},
			nil,
		)
		if err != nil {
			return atc.Build{}, err
		}
		source := atc.Source{
			"uri": writePipe.URL.String(),
		}

		params := atc.Params{
			"directory": output.Name,
		}

		if targetProps.Token != nil {
			source["authorization"] = targetProps.Token.Type + " " + targetProps.Token.Value
		}

		buildOutputs = append(buildOutputs, atc.Plan{
			Location: &atc.Location{
				ID:            taskPlan.Location.ID + 2 + uint(i),
				ParentID:      0,
				ParallelGroup: taskPlan.Location.ID + 1,
			},
			Put: &atc.PutPlan{
				Name:   output.Name,
				Type:   "archive",
				Source: source,
				Params: params,
			},
		})
	}

	var plan atc.Plan
	if len(buildOutputs) == 0 {
		plan = atc.Plan{
			OnSuccess: &atc.OnSuccessPlan{
				Step: atc.Plan{
					Aggregate: &buildInputs,
				},
				Next: taskPlan,
			},
		}
	} else {
		plan = atc.Plan{
			OnSuccess: &atc.OnSuccessPlan{
				Step: atc.Plan{
					Aggregate: &buildInputs,
				},
				Next: atc.Plan{
					Ensure: &atc.EnsurePlan{
						Step: taskPlan,
						Next: atc.Plan{
							Aggregate: &buildOutputs,
						},
					},
				},
			},
		}
	}

	return client.CreateBuild(plan)
}
<commit_msg>use new plan construction<commit_after>package executehelpers

import (
	"github.com/concourse/atc"
	"github.com/concourse/fly/commands/internal/deprecated"
	"github.com/concourse/fly/rc"
	"github.com/concourse/go-concourse/concourse"
	"github.com/tedsuo/rata"
)

func CreateBuild(
	atcRequester *deprecated.AtcRequester,
	client concourse.Client,
	privileged bool,
	inputs []Input,
	outputs []Output,
	config atc.TaskConfig,
	tags []string,
	target string,
) (atc.Build, error) {
	fact := atc.NewPlanFactory(0)

	if err := config.Validate(); err != nil {
		return atc.Build{}, err
	}

	targetProps, err := rc.SelectTarget(target)
	if err != nil {
		return atc.Build{}, err
	}

	buildInputs := atc.AggregatePlan{}
	for _, input := range inputs {
		var getPlan atc.GetPlan
		if input.Path != "" {
			readPipe, err := atcRequester.CreateRequest(
				atc.ReadPipe,
				rata.Params{"pipe_id": input.Pipe.ID},
				nil,
			)
			if err != nil {
				return atc.Build{}, err
			}

			source := atc.Source{
				"uri": readPipe.URL.String(),
			}

			if targetProps.Token != nil {
				source["authorization"] = targetProps.Token.Type + " " + targetProps.Token.Value
			}
			getPlan = atc.GetPlan{
				Name:   input.Name,
				Type:   "archive",
				Source: source,
			}
		} else {
			getPlan = atc.GetPlan{
				Name:    input.Name,
				Type:    input.BuildInput.Type,
				Source:  input.BuildInput.Source,
				Version: input.BuildInput.Version,
				Params:  input.BuildInput.Params,
				Tags:    input.BuildInput.Tags,
			}
		}

		buildInputs = append(buildInputs, fact.NewPlan(getPlan))
	}

	taskPlan := fact.NewPlan(atc.TaskPlan{
		Name:       "one-off",
		Privileged: privileged,
		Config:     &config,
	})

	if len(tags) != 0 {
		taskPlan.Task.Tags = tags
	}

	buildOutputs := atc.AggregatePlan{}
	for _, output := range outputs {
		writePipe, err := atcRequester.CreateRequest(
			atc.WritePipe,
			rata.Params{"pipe_id": output.Pipe.ID},
			nil,
		)
		if err != nil {
			return atc.Build{}, err
		}
		source := atc.Source{
			"uri": writePipe.URL.String(),
		}

		params := atc.Params{
			"directory": output.Name,
		}

		if targetProps.Token != nil {
			source["authorization"] = targetProps.Token.Type + " " + targetProps.Token.Value
		}

		buildOutputs = append(buildOutputs, fact.NewPlan(atc.PutPlan{
			Name:   output.Name,
			Type:   "archive",
			Source: source,
			Params: params,
		}))
	}

	var plan atc.Plan
	if len(buildOutputs) == 0 {
		plan = fact.NewPlan(atc.OnSuccessPlan{
			Step: fact.NewPlan(buildInputs),
			Next: taskPlan,
		})
	} else {
		plan = fact.NewPlan(atc.OnSuccessPlan{
			Step: fact.NewPlan(buildInputs),
			Next: fact.NewPlan(atc.EnsurePlan{
				Step: taskPlan,
				Next: fact.NewPlan(buildOutputs),
			}),
		})
	}

	return client.CreateBuild(plan)
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package k8s

import (
	"sync"

	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"

	api "k8s.io/api/core/v1"
)

type podCache struct {
	sync.RWMutex
	defaultKubeCacheEventHandler
	graph.DefaultGraphListener
	*kubeCache
	graph            *graph.Graph
	containerIndexer *graph.MetadataIndexer
	nodeIndexer      *graph.MetadataIndexer
}

func newPodIndex(g *graph.Graph, by string) *graph.MetadataIndexer {
	return graph.NewMetadataIndexer(g, graph.Metadata{"Type": "pod"}, by)
}

func newPodIndexerByHost(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndex(g, "Pod.NodeName")
}

func newPodIndexerByNamespace(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndex(g, "Pod.Namespace")
}

func newPodIndexerByName(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndex(g, "Name")
}

func podUID(pod *api.Pod) graph.Identifier {
	return graph.Identifier(pod.GetUID())
}

func (p *podCache) newMetadata(pod *api.Pod) graph.Metadata {
	return newMetadata("pod", pod.GetName(), pod)
}

func (p *podCache) linkPodToNode(pod *api.Pod, podNode *graph.Node) {
	nodeNodes := p.nodeIndexer.Get(pod.Spec.NodeName)
	if len(nodeNodes) == 0 {
		return
	}
	linkPodToNode(p.graph, nodeNodes[0], podNode)
}

func (p *podCache) onAdd(obj interface{}) {
	pod, ok := obj.(*api.Pod)
	if !ok {
		return
	}

	podNode := p.graph.NewNode(podUID(pod), p.newMetadata(pod))

	containerNodes := p.containerIndexer.Get(pod.Namespace, pod.Name)
	for _, containerNode := range containerNodes {
		p.graph.Link(podNode, containerNode, podToContainerMetadata)
	}

	p.linkPodToNode(pod, podNode)
}

func (p *podCache) OnAdd(obj interface{}) {
	pod, ok := obj.(*api.Pod)
	if !ok {
		return
	}

	p.Lock()
	defer p.Unlock()

	p.graph.Lock()
	defer p.graph.Unlock()

	logging.GetLogger().Infof("Creating node for pod{%s}", pod.GetName())

	p.onAdd(obj)
}

func (p *podCache) OnUpdate(oldObj, newObj interface{}) {
	oldPod := oldObj.(*api.Pod)
	newPod := newObj.(*api.Pod)

	p.Lock()
	defer p.Unlock()

	p.graph.Lock()
	defer p.graph.Unlock()

	podNode := p.graph.GetNode(podUID(newPod))
	if podNode == nil {
		logging.GetLogger().Infof("Updating (re-adding) node for pod{%s}", newPod.GetName())
		p.onAdd(newObj)
		return
	}

	logging.GetLogger().Infof("Updating node for pod{%s}", newPod.GetName())
	if oldPod.Spec.NodeName == "" && newPod.Spec.NodeName != "" {
		p.linkPodToNode(newPod, podNode)
	}

	addMetadata(p.graph, podNode, newPod)
}

func (p *podCache) OnDelete(obj interface{}) {
	if pod, ok := obj.(*api.Pod); ok {
		logging.GetLogger().Infof("Deleting node for pod{%s}", pod.GetName())
		p.graph.Lock()
		if podNode := p.graph.GetNode(podUID(pod)); podNode != nil {
			p.graph.DelNode(podNode)
		}
		p.graph.Unlock()
	}
}

func linkPodsToNode(g *graph.Graph, host *graph.Node, pods []*graph.Node) {
	for _, pod := range pods {
		linkPodToNode(g, host, pod)
	}
}

func linkPodToNode(g *graph.Graph, node, pod *graph.Node) {
	topology.AddOwnershipLink(g, node, pod, nil)
}

func (p *podCache) List() (pods []*api.Pod) {
	for _, pod := range p.cache.List() {
		pods = append(pods, pod.(*api.Pod))
	}
	return
}

func (p *podCache) GetByKey(key string) *api.Pod {
	if pod, found, _ := p.cache.GetByKey(key); found {
		return pod.(*api.Pod)
	}
	return nil
}

func (p *podCache) Start() {
	p.containerIndexer.AddEventListener(p)
	p.nodeIndexer.AddEventListener(p)
	p.kubeCache.Start()
}

func (p *podCache) Stop() {
	p.containerIndexer.RemoveEventListener(p)
	p.nodeIndexer.RemoveEventListener(p)
	p.kubeCache.Stop()
}

func newPodCache(client *kubeClient, g *graph.Graph) *podCache {
	p := &podCache{
		graph:            g,
		containerIndexer: newContainerIndexer(g),
		nodeIndexer:      newNodeIndexer(g),
	}
	p.kubeCache = client.getCacheFor(client.Core().RESTClient(), &api.Pod{}, "pods", p)
	return p
}
<commit_msg>k8s: replaced k8s.newPodIndex() -> k8s.newPodIndexer()<commit_after>/*
 * Copyright (C) 2017 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

package k8s

import (
	"sync"

	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"

	api "k8s.io/api/core/v1"
)

type podCache struct {
	sync.RWMutex
	defaultKubeCacheEventHandler
	graph.DefaultGraphListener
	*kubeCache
	graph            *graph.Graph
	containerIndexer *graph.MetadataIndexer
	nodeIndexer      *graph.MetadataIndexer
}

func newPodIndexer(g *graph.Graph, by string) *graph.MetadataIndexer {
	return graph.NewMetadataIndexer(g, graph.Metadata{"Type": "pod"}, by)
}

func newPodIndexerByHost(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndexer(g, "Pod.NodeName")
}

func newPodIndexerByNamespace(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndexer(g, "Pod.Namespace")
}

func newPodIndexerByName(g *graph.Graph) *graph.MetadataIndexer {
	return newPodIndexer(g, "Name")
}

func podUID(pod *api.Pod) graph.Identifier {
	return graph.Identifier(pod.GetUID())
}

func (p *podCache) newMetadata(pod *api.Pod) graph.Metadata {
	return newMetadata("pod", pod.GetName(), pod)
}

func (p *podCache) linkPodToNode(pod *api.Pod, podNode *graph.Node) {
	nodeNodes := p.nodeIndexer.Get(pod.Spec.NodeName)
	if len(nodeNodes) == 0 {
		return
	}
	linkPodToNode(p.graph, nodeNodes[0], podNode)
}

func (p *podCache) onAdd(obj interface{}) {
	pod, ok := obj.(*api.Pod)
	if !ok {
		return
	}

	podNode := p.graph.NewNode(podUID(pod), p.newMetadata(pod))

	containerNodes := p.containerIndexer.Get(pod.Namespace, pod.Name)
	for _, containerNode := range containerNodes {
		p.graph.Link(podNode, containerNode, podToContainerMetadata)
	}

	p.linkPodToNode(pod, podNode)
}

func (p *podCache) OnAdd(obj interface{}) {
	pod, ok := obj.(*api.Pod)
	if !ok {
		return
	}

	p.Lock()
	defer p.Unlock()

	p.graph.Lock()
	defer p.graph.Unlock()

	logging.GetLogger().Infof("Creating node for pod{%s}", pod.GetName())

	p.onAdd(obj)
}

func (p *podCache) OnUpdate(oldObj, newObj interface{}) {
	oldPod := oldObj.(*api.Pod)
	newPod := newObj.(*api.Pod)

	p.Lock()
	defer p.Unlock()

	p.graph.Lock()
	defer p.graph.Unlock()

	podNode := p.graph.GetNode(podUID(newPod))
	if podNode == nil {
		logging.GetLogger().Infof("Updating (re-adding) node for pod{%s}", newPod.GetName())
		p.onAdd(newObj)
		return
	}

	logging.GetLogger().Infof("Updating node for pod{%s}", newPod.GetName())
	if oldPod.Spec.NodeName == "" && newPod.Spec.NodeName != "" {
		p.linkPodToNode(newPod, podNode)
	}

	addMetadata(p.graph, podNode, newPod)
}

func (p *podCache) OnDelete(obj interface{}) {
	if pod, ok := obj.(*api.Pod); ok {
		logging.GetLogger().Infof("Deleting node for pod{%s}", pod.GetName())
		p.graph.Lock()
		if podNode := p.graph.GetNode(podUID(pod)); podNode != nil {
			p.graph.DelNode(podNode)
		}
		p.graph.Unlock()
	}
}

func linkPodsToNode(g *graph.Graph, host *graph.Node, pods []*graph.Node) {
	for _, pod := range pods {
		linkPodToNode(g, host, pod)
	}
}

func linkPodToNode(g *graph.Graph, node, pod *graph.Node) {
	topology.AddOwnershipLink(g, node, pod, nil)
}

func (p *podCache) List() (pods []*api.Pod) {
	for _, pod := range p.cache.List() {
		pods = append(pods, pod.(*api.Pod))
	}
	return
}

func (p *podCache) GetByKey(key string) *api.Pod {
	if pod, found, _ := p.cache.GetByKey(key); found {
		return pod.(*api.Pod)
	}
	return nil
}

func (p *podCache) Start() {
	p.containerIndexer.AddEventListener(p)
	p.nodeIndexer.AddEventListener(p)
	p.kubeCache.Start()
}

func (p *podCache) Stop() {
	p.containerIndexer.RemoveEventListener(p)
	p.nodeIndexer.RemoveEventListener(p)
	p.kubeCache.Stop()
}

func newPodCache(client *kubeClient, g *graph.Graph) *podCache {
	p := &podCache{
		graph:            g,
		containerIndexer: newContainerIndexer(g),
		nodeIndexer:      newNodeIndexer(g),
	}
	p.kubeCache = client.getCacheFor(client.Core().RESTClient(), &api.Pod{}, "pods", p)
	return p
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"strings"
)

/*
Following is the command menu for constructing the bot with @BotFather.
Use the /setcommands command and reply with the following list of commands.
---------------------
start - Start a new game.
join - Join the game.
leave - Leave the game.
challenge - Challenge the word that was entered.
help - Display game rules and other instructions.
shutdown - Shutdown the bot (DEBUG ONLY)
*/

var torigemubot = botEventHandlers{
	onMessage:     torigemubotOnMessage,
	onInlineQuery: torigemubotOnInlineQuery}

func torigemubotOnMessage(bot *tgbotapi.BotAPI, msg *tgbotapi.Message) bool {
	msgTextCmd := strings.ToLower(msg.Text)

	log.Printf("[%s] %s", msg.From.UserName, msg.Text)
	if strings.HasPrefix(msgTextCmd, "/shutdown") {
		log.Println("Received shutdown command.")
		bot.Send(tgbotapi.NewMessage(msg.Chat.ID, "Shutting down..."))
		return false
	}

	replyMsg := tgbotapi.NewMessage(msg.Chat.ID, msg.From.FirstName+" said: "+msg.Text)
	//replyMsg.ReplyToMessageID = msg.MessageID
	bot.Send(replyMsg)
	return true
}

func torigemubotOnInlineQuery(bot *tgbotapi.BotAPI, query *tgbotapi.InlineQuery) bool {
	log.Println("Received inline query from " + query.From.FirstName + ": " + query.Query)
	var answer = tgbotapi.InlineConfig{
		InlineQueryID: query.ID,
		IsPersonal:    true}

	if len(query.Query) > 0 {
		answer.Results = append(answer.Results, tgbotapi.NewInlineQueryResultArticle(query.ID, "回答を提出する", query.Query))
	}
	bot.AnswerInlineQuery(answer)
	return true
}
<commit_msg>Beginning to implement real command handlers. More work to do on handling multiple chat groups simultaneously.<commit_after>package main

import (
	"container/list"
	"fmt"
	tg "github.com/go-telegram-bot-api/telegram-bot-api"
	"log"
	"strings"
)

/*
Following is the command menu for constructing the bot with @BotFather.
Use the /setcommands command and reply with the following list of commands.
---------------------
newgame - Start a new game with a fresh word list.
showword - Show the current word.
showscores - Show the current scores.
challenge - Challenge the word that was entered.
help - Display game rules and other instructions.
shutdown - Shutdown the bot (DEBUG ONLY)
*/

var torigemubot = botEventHandlers{
	onMessage:     torigemubotOnMessage,
	onInlineQuery: torigemubotOnInlineQuery,
	//	onChosenInlineResult: torigemubotOnChosenInlineResult,
}

// TODO: Keep historical record of words played. Will be used to verify words are not reused, and for reverting after a challenge.
// TODO: Create a map of chatID -> currentWord, chatID -> players.
var currentWord string

// TODO: Enhance the players struct to track their current score.
var players *list.List

func torigemubotOnMessage(bot *tg.BotAPI, msg *tg.Message) bool {
	msgTextCmd := strings.ToLower(msg.Text)

	log.Printf("[%s] %s", msg.From.UserName, msg.Text)
	switch {
	case strings.HasPrefix(msgTextCmd, "/newgame"):
		doNewGame(bot, msg)
	case strings.HasPrefix(msgTextCmd, "/showword"):
		doShowWord(bot, msg)
	case strings.HasPrefix(msgTextCmd, "/showscores"):
		doShowScores(bot, msg)
	case strings.HasPrefix(msgTextCmd, "/challenge"):
		doChallenge(bot, msg)
	case strings.HasPrefix(msgTextCmd, "/help"):
		doHelp(bot, msg)
	case strings.HasPrefix(msgTextCmd, "/shutdown"):
		doShutdown(bot, msg)
		return false
	default:
		doWordEntry(bot, msg)
	}
	return true
}

func torigemubotOnInlineQuery(bot *tg.BotAPI, query *tg.InlineQuery) bool {
	log.Printf("OnInlineQuery: %s %s [%s] %s", query.From.FirstName, query.From.LastName, query.From.UserName, query.Query)
	var answer = tg.InlineConfig{
		InlineQueryID: query.ID,
		IsPersonal:    true}

	if len(query.Query) > 0 {
		answer.Results = append(answer.Results, tg.NewInlineQueryResultArticle(query.ID, "回答を提出する", query.Query))
	}
	bot.AnswerInlineQuery(answer)
	return true
}

func doNewGame(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received newgame command.")
	// TODO: Add some safety checks so that one other person must agree. Give a lazy consensus time.
	// If noone objects within 1 minute, then the game starts new. If someone agrees, it starts new right away.
	// If someone objects, then the reset is canceled.
	newGame(msg.Chat)
	joinGame(bot, msg)
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("New game started by %s %s.\nWho wants to go first?", msg.From.FirstName, msg.From.LastName)))
}

// For when a user leaves the chat.
func doLeave(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received leave command.")
	pelem := findPlayer(msg.Chat, msg.From)
	if pelem == nil {
		return
	}

	players.Remove(pelem)
	player := pelem.Value.(*tg.User)
	bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%s %s left the game.", player.FirstName, player.LastName)))
	if players.Len() == 0 {
		// Game over.
		newGame(msg.Chat)
	}
}

func doShowWord(bot *tg.BotAPI, msg *tg.Message) {
	var reply string
	if len(currentWord) == 0 {
		reply = "There is no current word."
	} else {
		reply = fmt.Sprintf("Current word: %s", currentWord)
	}
	bot.Send(tg.NewMessage(msg.Chat.ID, reply))
}

func doShowScores(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received showscores command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "Four Score and Seven Words Ago..."))
}

func doChallenge(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received challenge command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "Ready.... FIGHT!!!"))
}

func doWordEntry(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received a NEW word!.")
	// Auto-join the game.
	joinGame(bot, msg)
	currentWord = msg.Text
	// TODO: Calculate scores. If only one person, then no scores awarded.
	// TODO: Display the name of person and amount of points won/lost for this word entry.
	doShowWord(bot, msg)
}

func doHelp(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received help command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "Bots help those who help themselves."))
}

func doShutdown(bot *tg.BotAPI, msg *tg.Message) {
	log.Println("Received shutdown command.")
	bot.Send(tg.NewMessage(msg.Chat.ID, "Shutting down..."))
}

// TODO: Do a new game if the bot is kicked out of chat.
func newGame(chat *tg.Chat) {
	currentWord = ""
	players = nil
}

func joinGame(bot *tg.BotAPI, msg *tg.Message) {
	if players == nil {
		players = list.New()
	}

	player := msg.From
	if findPlayer(msg.Chat, player) == nil {
		var gamename string

		switch msg.Chat.Type {
		case "group":
			gamename = fmt.Sprintf("%s [%d]", msg.Chat.Title, msg.Chat.ID)
		default:
			gamename = fmt.Sprintf("%s %s [%d]", msg.Chat.FirstName, msg.Chat.LastName, msg.Chat.ID)
		}
		log.Printf("Adding player %s %s [%s] to game %s.", player.FirstName, player.LastName, player.UserName, gamename)
		players.PushBack(player)
		bot.Send(tg.NewMessage(msg.Chat.ID, fmt.Sprintf("%s %s joined the game.", player.FirstName, player.LastName)))
	}
}

func findPlayer(chat *tg.Chat, user *tg.User) *list.Element {
	if players == nil {
		return nil
	}

	var player *tg.User
	for e := players.Front(); e != nil; e = e.Next() {
		player = e.Value.(*tg.User)
		if player.FirstName == user.FirstName &&
			player.LastName == user.LastName &&
			player.UserName == user.UserName {
			return e
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2014-2015, Civis Analytics

package gelf

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
	"time"
	"unicode/utf8"
)

// Message meets the Graylog2 Extended Log Format.
// http://graylog2.org/gelf#specs
type Message struct {
	Version          string                 `json:"version"`
	Host             string                 `json:"host"`
	ShortMessage     string                 `json:"short_message"`
	FullMessage      string                 `json:"full_message,omitempty"`
	Timestamp        int64                  `json:"timestamp"`
	Level            Level                  `json:"level"`
	AdditionalFields string                 `json:",omitempty"`
	additional       map[string]interface{} `json:"a,omitempty"`
}

// Remote is a type for message destination configuration
type Remote int

const (
	RemoteStdout Remote = iota
	RemoteUdp
)

var reservedFields = []string{"version", "host", "short_message", "full_message", "timestamp", "level", "_id"}

var host = ""
var remote Remote

func init() {
	remote = RemoteStdout

	var err error
	host, err = os.Hostname()
	if err != nil {
		host = "localhost"
	}
}

func SetRemote(r Remote) (err error) {
	if r == RemoteStdout {
		remote = r
	} else if r == RemoteUdp {
		return errors.New("UDP not yet implemented")
	} else {
		return errors.New("Invalid GELF remote")
	}
	return nil
}

// NewMessage returns a new Graylog2 Extended Log Format message.
func NewMessage(l Level, short string, full string) *Message {
	a := make(map[string]interface{})

	return &Message{
		Version:      GELFVersion,
		Host:         host,
		ShortMessage: short,
		FullMessage:  full,
		Timestamp:    time.Now().UnixNano(),
		Level:        l,
		additional:   a,
	}
}

func typeOf(v interface{}) string {
	return fmt.Sprintf("%T", v)
}

// Add will add additional fields to a message in the form of a key and value
// pair. Values can be of JavaScript string or number type.
func (m *Message) Add(key string, value interface{}) error {
	// Verify additional fields against reserved field names.
	// If field is not reserved, add to message.
	for _, rf := range reservedFields {
		if key == rf {
			return fmt.Errorf("Invalid field[%s]", key)
		}
	}

	// Verify value is a JavaScript string or number.
	if typeOf(value) != "string" && typeOf(value) != "float64" && typeOf(value) != "int" {
		return fmt.Errorf("Invalid field type[%s]", typeOf(value))
	}

	// Verify underscore prefix
	r, _ := utf8.DecodeRuneInString(key)
	if string(r) == "_" {
		m.additional[key] = value
	} else {
		m.additional["_"+key] = value
	}

	return nil
}

// String is a convience method that meets the fmt.String interface providing an
// easy way to print the string JSON representation of a message.
func (m *Message) String() string {
	if len(m.additional) == 0 {
		baseMessageFields, _ := json.Marshal(m)
		return string(baseMessageFields)
	}

	// Maps do not marshal to JSON as top-level objects.
	// To work around we marshal the map of additional fields, modify the string
	// and append to the outbound JSON encoded struct.
	additionalFields, _ := json.Marshal(m.additional)
	filteredFields := strings.Replace(string(additionalFields[1:]), "\\\"", "\"", -1)

	baseMessageFields, _ := json.Marshal(m)
	trimBaseMessageFields := strings.TrimRight(string(baseMessageFields), "}")

	return trimBaseMessageFields + "," + filteredFields
}

// Send will currently print message's string to STDOUT
func (m *Message) Send() {
	if remote == RemoteStdout {
		fmt.Println(m.String())
	} else if remote == RemoteUdp {
		// TODO: implement UDP
	}
}
<commit_msg>support writing to STDERR<commit_after>// Copyright © 2014-2015, Civis Analytics

package gelf

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
	"time"
	"unicode/utf8"
)

// Message meets the Graylog2 Extended Log Format.
// http://graylog2.org/gelf#specs
type Message struct {
	Version          string                 `json:"version"`
	Host             string                 `json:"host"`
	ShortMessage     string                 `json:"short_message"`
	FullMessage      string                 `json:"full_message,omitempty"`
	Timestamp        int64                  `json:"timestamp"`
	Level            Level                  `json:"level"`
	AdditionalFields string                 `json:",omitempty"`
	additional       map[string]interface{} `json:"a,omitempty"`
}

// Remote is a type for message destination configuration
type Remote int

const (
	RemoteStdout Remote = iota
	RemoteStderr
	RemoteUdp
)

var reservedFields = []string{"version", "host", "short_message", "full_message", "timestamp", "level", "_id"}

var host = ""
var remote Remote

func init() {
	remote = RemoteStdout

	var err error
	host, err = os.Hostname()
	if err != nil {
		host = "localhost"
	}
}

func SetRemote(r Remote) (err error) {
	if r == RemoteStdout {
		remote = r
	} else if r == RemoteStderr {
		remote = r
	} else if r == RemoteUdp {
		return errors.New("UDP not yet implemented")
	} else {
		return errors.New("Invalid GELF remote")
	}
	return nil
}

// NewMessage returns a new Graylog2 Extended Log Format message.
func NewMessage(l Level, short string, full string) *Message {
	a := make(map[string]interface{})

	return &Message{
		Version:      GELFVersion,
		Host:         host,
		ShortMessage: short,
		FullMessage:  full,
		Timestamp:    time.Now().UnixNano(),
		Level:        l,
		additional:   a,
	}
}

func typeOf(v interface{}) string {
	return fmt.Sprintf("%T", v)
}

// Add will add additional fields to a message in the form of a key and value
// pair. Values can be of JavaScript string or number type.
func (m *Message) Add(key string, value interface{}) error {
	// Verify additional fields against reserved field names.
	// If field is not reserved, add to message.
	for _, rf := range reservedFields {
		if key == rf {
			return fmt.Errorf("Invalid field[%s]", key)
		}
	}

	// Verify value is a JavaScript string or number.
	if typeOf(value) != "string" && typeOf(value) != "float64" && typeOf(value) != "int" {
		return fmt.Errorf("Invalid field type[%s]", typeOf(value))
	}

	// Verify underscore prefix
	r, _ := utf8.DecodeRuneInString(key)
	if string(r) == "_" {
		m.additional[key] = value
	} else {
		m.additional["_"+key] = value
	}

	return nil
}

// String is a convience method that meets the fmt.String interface providing an
// easy way to print the string JSON representation of a message.
func (m *Message) String() string {
	if len(m.additional) == 0 {
		baseMessageFields, _ := json.Marshal(m)
		return string(baseMessageFields)
	}

	// Maps do not marshal to JSON as top-level objects.
	// To work around we marshal the map of additional fields, modify the string
	// and append to the outbound JSON encoded struct.
	additionalFields, _ := json.Marshal(m.additional)
	filteredFields := strings.Replace(string(additionalFields[1:]), "\\\"", "\"", -1)

	baseMessageFields, _ := json.Marshal(m)
	trimBaseMessageFields := strings.TrimRight(string(baseMessageFields), "}")

	return trimBaseMessageFields + "," + filteredFields
}

// Send will currently print message's string to STDOUT
func (m *Message) Send() {
	if remote == RemoteStdout {
		fmt.Println(m.String())
	} else if remote == RemoteStderr {
		fmt.Fprintf(os.Stderr, "%s\n", m.String())
	} else if remote == RemoteUdp {
		// TODO: implement UDP
	}
}
<|endoftext|>


<commit_before>package geocodio_test

import (
	"fmt"
	"testing"

	"github.com/stevepartridge/geocodio"
)

func TestGeocodeWithEmptyAddress(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	_, err = Geocodio.Geocode("")
	if err == nil {
		t.Error("Error should not be nil.")
	}
}

func TestGeocodeDebugResponseAsString(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.Geocode(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	if result.ResponseAsString() == "" {
		t.Error("Response should be a valid string.")
	}

}

func TestGeocodeFullAddress(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.Geocode(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}
}

func TestGeocodeFullAddressReturningTimezone(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.GeocodeAndReturnTimezone(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}

	if result.Results[0].Fields.Timezone.Name == "" {
		t.Error("Timezone field not found")
	}

	if !result.Results[0].Fields.Timezone.ObservesDST {
		t.Error("Timezone field does not match", result.Results[0].Fields.Timezone)
	}
}

func TestGeocodeFullAddressReturningCongressionalDistrict(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
		t.Fail()
	}
	result, err := Geocodio.GeocodeAndReturnCongressionalDistrict(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
		t.Fail()
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Error("Location latitude does not match", result.Results[0].Location.Latitude, AddressTestOneLatitude)
		t.Fail()
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Error("Location longitude does not match", result.Results[0].Location.Longitude, AddressTestOneLongitude)
		t.Fail()
	}

	fmt.Printf("data %+v", result.Results)

	if result.Results[0].Fields.CongressionalDistrict.Name == "" {
		t.Error("Congressional District field not found", result.Results[0].Fields.CongressionalDistrict)
		t.Fail()
	}

	if result.Results[0].Fields.CongressionalDistrict.DistrictNumber != 36 {
		t.Error("Congressional District field does not match", result.Results[0].Fields.CongressionalDistrict)
		t.Fail()
	}
}

func TestGeocodeFullAddressReturningStateLegislativeDistricts(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
		t.Fail()
	}

	result, err := Geocodio.GeocodeAndReturnStateLegislativeDistricts(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0", result)
		t.Fail()
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
		t.Fail()
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
		t.Fail()
	}

	if result.Results[0].Fields.StateLegislativeDistricts.House.DistrictNumber != "42" {
		t.Error("State Legislative Districts house does not match", result.Results[0].Fields.StateLegislativeDistricts.House)
		t.Fail()
	}

	if result.Results[0].Fields.StateLegislativeDistricts.Senate.DistrictNumber != "28" {
		t.Error("State Legislative Districts senate does not match", result.Results[0].Fields.StateLegislativeDistricts.Senate)
		t.Fail()
	}
}

func TestGeocodeFullAddressReturningMultipleFields(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.GeocodeReturnFields(AddressTestOneFull, "timezone", "cd")
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Error("Location latitude does not match", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Error("Location longitude does not match", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}

	if result.Results[0].Fields.Timezone.Name == "" {
		t.Error("Timezone field not found")
	}

	if !result.Results[0].Fields.Timezone.ObservesDST {
		t.Error("Timezone field does not match", result.Results[0].Fields.Timezone)
	}

	// check congressional district
	if result.Results[0].Fields.CongressionalDistrict.Name == "" {
		t.Error("Congressional District field not found", result.Results[0].Fields.CongressionalDistrict)
	}

	if result.Results[0].Fields.CongressionalDistrict.DistrictNumber != 36 {
		t.Error("Congressional District field does not match", result.Results[0].Fields.CongressionalDistrict)
	}

}

// TODO: School District (school)
<commit_msg>Add basic zip4 test<commit_after>package geocodio_test

import (
	"testing"

	"github.com/stevepartridge/geocodio"
)

func TestGeocodeWithEmptyAddress(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	_, err = Geocodio.Geocode("")
	if err == nil {
		t.Error("Error should not be nil.")
	}
}

func TestGeocodeDebugResponseAsString(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.Geocode(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	if result.ResponseAsString() == "" {
		t.Error("Response should be a valid string.")
	}

}

func TestGeocodeFullAddress(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.Geocode(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}
}

func TestGeocodeFullAddressReturningTimezone(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.GeocodeAndReturnTimezone(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}

	if result.Results[0].Fields.Timezone.Name == "" {
		t.Error("Timezone field not found")
	}

	if !result.Results[0].Fields.Timezone.ObservesDST {
		t.Error("Timezone field does not match", result.Results[0].Fields.Timezone)
	}
}

func TestGeocodeFullAddressReturningZip4(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.GeocodeAndReturnZip4(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// fmt.Println(result.Debug.RequestedURL)

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}

	if len(result.Results[0].Fields.Zip4.Plus4) == 0 {
		t.Error("Zip4 field not found")
	}

	// if !result.Results[0].Fields.Timezone.ObservesDST {
	// 	t.Error("Zip4 field does not match", result.Results[0].Fields.Timezone)
	// }
}

func TestGeocodeFullAddressReturningCongressionalDistrict(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
		t.Fail()
	}
	result, err := Geocodio.GeocodeAndReturnCongressionalDistrict(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
		t.Fail()
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Error("Location latitude does not match", result.Results[0].Location.Latitude, AddressTestOneLatitude)
		t.Fail()
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Error("Location longitude does not match", result.Results[0].Location.Longitude, AddressTestOneLongitude)
		t.Fail()
	}

	if len(result.Results[0].Fields.CongressionalDistricts) == 0 {
		t.Error("Congressional District field not found", result.Results[0].Fields.CongressionalDistrict)
		t.Fail()
	}

	if result.Results[0].Fields.CongressionalDistricts[0].Name == "" {
		t.Error("Congressional District field not found", result.Results[0].Fields.CongressionalDistricts[0])
		t.Fail()
	}

	if result.Results[0].Fields.CongressionalDistricts[0].DistrictNumber != 8 {
		t.Error("Congressional District field does not match", result.Results[0].Fields.CongressionalDistrict)
		t.Fail()
	}
}

func TestGeocodeFullAddressReturningStateLegislativeDistricts(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
		t.Fail()
	}

	result, err := Geocodio.GeocodeAndReturnStateLegislativeDistricts(AddressTestOneFull)
	if err != nil {
		t.Error(err)
	}

	// t.Log(result.ResponseAsString())

	if len(result.Results) == 0 {
		t.Error("Results length is 0", result)
		t.Fail()
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Errorf("Location latitude %f does not match %f", result.Results[0].Location.Latitude, AddressTestOneLatitude)
		t.Fail()
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Errorf("Location longitude %f does not match %f", result.Results[0].Location.Longitude, AddressTestOneLongitude)
		t.Fail()
	}

	if result.Results[0].Fields.StateLegislativeDistricts.House.DistrictNumber != "47" {
		t.Error("State Legislative Districts house does not match", result.Results[0].Fields.StateLegislativeDistricts.House)
		t.Fail()
	}

	if result.Results[0].Fields.StateLegislativeDistricts.Senate.DistrictNumber != "31" {
		t.Error("State Legislative Districts senate does not match", result.Results[0].Fields.StateLegislativeDistricts.Senate)
		t.Fail()
	}
}

func TestGeocodeFullAddressReturningMultipleFields(t *testing.T) {
	Geocodio, err := geocodio.NewGeocodio(APIKey())
	if err != nil {
		t.Error("Failed with API KEY set.", err)
	}
	result, err := Geocodio.GeocodeReturnFields(AddressTestOneFull, "timezone", "cd")
	if err != nil {
		t.Error(err)
	}

	// fmt.Println(result.Debug.RequestedURL)

	if len(result.Results) == 0 {
		t.Error("Results length is 0")
	}

	if result.Results[0].Location.Latitude != AddressTestOneLatitude {
		t.Error("Location latitude does not match", result.Results[0].Location.Latitude, AddressTestOneLatitude)
	}

	if result.Results[0].Location.Longitude != AddressTestOneLongitude {
		t.Error("Location longitude does not match", result.Results[0].Location.Longitude, AddressTestOneLongitude)
	}

	if result.Results[0].Fields.Timezone.Name == "" {
		t.Error("Timezone field not found")
	}

	if !result.Results[0].Fields.Timezone.ObservesDST {
		t.Error("Timezone field does not match", result.Results[0].Fields.Timezone)
	}

	congressionalDistrict := geocodio.CongressionalDistrict{}

	// check congressional district
	if result.Results[0].Fields.CongressionalDistrict.Name != "" {
		congressionalDistrict = result.Results[0].Fields.CongressionalDistrict
	} else if len(result.Results[0].Fields.CongressionalDistricts) > 0 {
		congressionalDistrict = result.Results[0].Fields.CongressionalDistricts[0]
	}

	if congressionalDistrict.Name == "" {
		t.Error("Congressional District field not found", congressionalDistrict)
	}

	if congressionalDistrict.DistrictNumber != 8 {
		t.Error("Congressional District field does not match", result.Results[0].Fields.CongressionalDistrict)
	}

}

// TODO: School District (school)
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package variable

import (
	"github.com/pingcap/tidb/context"
	mysql "github.com/pingcap/tidb/mysqldef"
	"github.com/pingcap/tidb/stmt"
)

// SessionVars is to handle user-defined or global varaibles in current session
type SessionVars struct {
	// user-defined variables
	Users map[string]string
	// system variables
	Systems map[string]string
	// prepared statement
	PreparedStmts map[string]stmt.Statement
	// prepared statement auto increament id
	preparedStmtID uint32

	// following variables are specail for current session
	Status       uint16
	LastInsertID uint64
	AffectedRows uint64

	// Client Capability
	ClientCapability uint32 // Client capability

	// Disable autocommit
	DisableAutocommit bool

	// Found rows
	FoundRows uint64
}

// sessionVarsKeyType is a dummy type to avoid naming collision in context.
type sessionVarsKeyType int

// define a Stringer function for debugging and pretty printting
func (k sessionVarsKeyType) String() string {
	return "session_vars"
}

const sessionVarsKey sessionVarsKeyType = 0

// BindSessionVars creates a session vars object and bind it to context
func BindSessionVars(ctx context.Context) {
	v := &SessionVars{
		Users:         make(map[string]string),
		Systems:       make(map[string]string),
		PreparedStmts: make(map[string]stmt.Statement),
	}

	ctx.SetValue(sessionVarsKey, v)
}

// GetSessionVars gets the session vars from context
func GetSessionVars(ctx context.Context) *SessionVars {
	v, ok := ctx.Value(sessionVarsKey).(*SessionVars)
	if !ok {
		return nil
	}
	return v
}

// SetLastInsertID saves the last insert id to the session context
func (s *SessionVars) SetLastInsertID(insertID uint64) {
	s.LastInsertID = insertID

	// TODO: we may store the result for last_insert_id sys var later.
}

// SetAffectedRows saves the affected rows to the session context
func (s *SessionVars) SetAffectedRows(affectedRows uint64) {
	s.AffectedRows = affectedRows
}

// AddAffectedRows adds affected rows with the argument rows
func (s *SessionVars) AddAffectedRows(rows uint64) {
	s.AffectedRows += rows
}

// AddFoundRows adds found rows with the argument rows
func (s *SessionVars) AddFoundRows(rows uint64) {
	s.FoundRows += rows
}

// SetStatus sets the session server status variable
func (s *SessionVars) SetStatus(status uint16) {
	s.Status = status
}

func (s *SessionVars) SetStatusInTrans(isInTrans bool) {
	if isInTrans {
		s.Status = s.Status | mysql.ServerStatusInTrans
		return
	}
	s.Status = s.Status & (^mysql.ServerStatusInTrans)
}

// GetNextPreparedStmtID generates and return the next session scope prepared statement id
func (s *SessionVars) GetNextPreparedStmtID() uint32 {
	s.preparedStmtID++
	return s.preparedStmtID
}

// IsAutocommit checks if it is in autocommit enviroment
func IsAutocommit(ctx context.Context) bool {
	// With START TRANSACTION, autocommit remains disabled until you end
	// the transaction with COMMIT or ROLLBACK.
	if GetSessionVars(ctx).Status&mysql.ServerStatusAutocommit > 0 &&
		!GetSessionVars(ctx).DisableAutocommit {
		return true
	}
	return false
}
<commit_msg>sessionctx: add ServerStatusInTrans and comments<commit_after>// Copyright 2015 PingCAP, 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package variable

import (
	"github.com/pingcap/tidb/context"
	mysql "github.com/pingcap/tidb/mysqldef"
	"github.com/pingcap/tidb/stmt"
)

// SessionVars is to handle user-defined or global varaibles in current session
type SessionVars struct {
	// user-defined variables
	Users map[string]string
	// system variables
	Systems map[string]string
	// prepared statement
	PreparedStmts map[string]stmt.Statement
	// prepared statement auto increament id
	preparedStmtID uint32

	// following variables are specail for current session
	Status       uint16
	LastInsertID uint64
	AffectedRows uint64

	// Client Capability
	ClientCapability uint32 // Client capability

	// Disable autocommit
	DisableAutocommit bool

	// Found rows
	FoundRows uint64
}

// sessionVarsKeyType is a dummy type to avoid naming collision in context.
type sessionVarsKeyType int

// define a Stringer function for debugging and pretty printting
func (k sessionVarsKeyType) String() string {
	return "session_vars"
}

const sessionVarsKey sessionVarsKeyType = 0

// BindSessionVars creates a session vars object and bind it to context
func BindSessionVars(ctx context.Context) {
	v := &SessionVars{
		Users:         make(map[string]string),
		Systems:       make(map[string]string),
		PreparedStmts: make(map[string]stmt.Statement),
	}

	ctx.SetValue(sessionVarsKey, v)
}

// GetSessionVars gets the session vars from context
func GetSessionVars(ctx context.Context) *SessionVars {
	v, ok := ctx.Value(sessionVarsKey).(*SessionVars)
	if !ok {
		return nil
	}
	return v
}

// SetLastInsertID saves the last insert id to the session context
func (s *SessionVars) SetLastInsertID(insertID uint64) {
	s.LastInsertID = insertID

	// TODO: we may store the result for last_insert_id sys var later.
}

// SetAffectedRows saves the affected rows to the session context
func (s *SessionVars) SetAffectedRows(affectedRows uint64) {
	s.AffectedRows = affectedRows
}

// AddAffectedRows adds affected rows with the argument rows
func (s *SessionVars) AddAffectedRows(rows uint64) {
	s.AffectedRows += rows
}

// AddFoundRows adds found rows with the argument rows
func (s *SessionVars) AddFoundRows(rows uint64) {
	s.FoundRows += rows
}

// SetStatus sets the session server status variable
func (s *SessionVars) SetStatus(status uint16) {
	s.Status = status
}

// SetStatusInTrans sets the status flags about SERVER_STATUS_IN_TRANS
func (s *SessionVars) SetStatusInTrans(isInTrans bool) {
	if isInTrans {
		s.Status = s.Status | mysql.ServerStatusInTrans
		return
	}
	s.Status = s.Status & (^mysql.ServerStatusInTrans)
}

// GetNextPreparedStmtID generates and return the next session scope prepared statement id
func (s *SessionVars) GetNextPreparedStmtID() uint32 {
	s.preparedStmtID++
	return s.preparedStmtID
}

// IsAutocommit checks if it is in autocommit enviroment
func IsAutocommit(ctx context.Context) bool {
	// With START TRANSACTION, autocommit remains disabled until you end
	// the transaction with COMMIT or ROLLBACK.
	if GetSessionVars(ctx).Status&mysql.ServerStatusAutocommit > 0 &&
		!GetSessionVars(ctx).DisableAutocommit {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"net/url"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceAwsIamGroupPolicy() *schema.Resource {
	return &schema.Resource{
		// PutGroupPolicy API is idempotent, so these can be the same.
		Create: resourceAwsIamGroupPolicyPut,
		Update: resourceAwsIamGroupPolicyPut,

		Read:   resourceAwsIamGroupPolicyRead,
		Delete: resourceAwsIamGroupPolicyDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"policy": {
				Type:     schema.TypeString,
				Required: true,
			},
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
			},
			"group": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsIamGroupPolicyPut(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.PutGroupPolicyInput{
		GroupName:      aws.String(d.Get("group").(string)),
		PolicyDocument: aws.String(d.Get("policy").(string)),
	}

	var policyName string
	if v, ok := d.GetOk("name"); ok {
		policyName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		policyName = resource.PrefixedUniqueId(v.(string))
	} else {
		policyName = resource.UniqueId()
	}
	request.PolicyName = aws.String(policyName)

	if _, err := iamconn.PutGroupPolicy(request); err != nil {
		return fmt.Errorf("Error putting IAM group policy %s: %s", *request.PolicyName, err)
	}

	d.SetId(fmt.Sprintf("%s:%s", *request.GroupName, *request.PolicyName))
	return nil
}

func resourceAwsIamGroupPolicyRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	group, name, err := resourceAwsIamGroupPolicyParseId(d.Id())
	if err != nil {
		return err
	}

	request := &iam.GetGroupPolicyInput{
		PolicyName: aws.String(name),
		GroupName:  aws.String(group),
	}

	getResp, err := iamconn.GetGroupPolicy(request)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			log.Printf("[WARN] IAM Group Policy (%s) for %s not found, removing from state", name, group)
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM policy %s from group %s: %s", name, group, err)
	}

	if getResp.PolicyDocument == nil {
		return fmt.Errorf("GetGroupPolicy returned a nil policy document")
	}

	policy, err := url.QueryUnescape(*getResp.PolicyDocument)
	if err != nil {
		return err
	}

	if err := d.Set("policy", policy); err != nil {
		return fmt.Errorf("error setting policy: %s", err)
	}

	if err := d.Set("name", name); err != nil {
		return fmt.Errorf("error setting name: %s", err)
	}

	if err := d.Set("group", group); err != nil {
		return fmt.Errorf("error setting group: %s", err)
	}

	return nil
}

func resourceAwsIamGroupPolicyDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	group, name, err := resourceAwsIamGroupPolicyParseId(d.Id())
	if err != nil {
		return err
	}

	request := &iam.DeleteGroupPolicyInput{
		PolicyName: aws.String(name),
		GroupName:  aws.String(group),
	}

	if _, err := iamconn.DeleteGroupPolicy(request); err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			return nil
		}
		return fmt.Errorf("Error deleting IAM group policy %s: %s", d.Id(), err)
	}
	return nil
}

func resourceAwsIamGroupPolicyParseId(id string) (groupName, policyName string, err error) {
	parts := strings.SplitN(id, ":", 2)
	if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
		err = fmt.Errorf("group_policy id must be of the form <group name>:<policy name>")
		return
	}

	groupName = parts[0]
	policyName = parts[1]
	return
}
<commit_msg>resource/aws_iam_group_policy: Add IAM Policy JSON difference suppression and validation to policy argument (#9660)<commit_after>package aws

import (
	"fmt"
	"log"
	"net/url"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/iam"

	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceAwsIamGroupPolicy() *schema.Resource {
	return &schema.Resource{
		// PutGroupPolicy API is idempotent, so these can be the same.
		Create: resourceAwsIamGroupPolicyPut,
		Update: resourceAwsIamGroupPolicyPut,

		Read:   resourceAwsIamGroupPolicyRead,
		Delete: resourceAwsIamGroupPolicyDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"policy": {
				Type:             schema.TypeString,
				Required:         true,
				ValidateFunc:     validateIAMPolicyJson,
				DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs,
			},
			"name": {
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
			},
			"name_prefix": {
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name"},
			},
			"group": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
		},
	}
}

func resourceAwsIamGroupPolicyPut(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	request := &iam.PutGroupPolicyInput{
		GroupName:      aws.String(d.Get("group").(string)),
		PolicyDocument: aws.String(d.Get("policy").(string)),
	}

	var policyName string
	if v, ok := d.GetOk("name"); ok {
		policyName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		policyName = resource.PrefixedUniqueId(v.(string))
	} else {
		policyName = resource.UniqueId()
	}
	request.PolicyName = aws.String(policyName)

	if _, err := iamconn.PutGroupPolicy(request); err != nil {
		return fmt.Errorf("Error putting IAM group policy %s: %s", *request.PolicyName, err)
	}

	d.SetId(fmt.Sprintf("%s:%s", *request.GroupName, *request.PolicyName))
	return nil
}

func resourceAwsIamGroupPolicyRead(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	group, name, err := resourceAwsIamGroupPolicyParseId(d.Id())
	if err != nil {
		return err
	}

	request := &iam.GetGroupPolicyInput{
		PolicyName: aws.String(name),
		GroupName:  aws.String(group),
	}

	getResp, err := iamconn.GetGroupPolicy(request)
	if err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			log.Printf("[WARN] IAM Group Policy (%s) for %s not found, removing from state", name, group)
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading IAM policy %s from group %s: %s", name, group, err)
	}

	if getResp.PolicyDocument == nil {
		return fmt.Errorf("GetGroupPolicy returned a nil policy document")
	}

	policy, err := url.QueryUnescape(*getResp.PolicyDocument)
	if err != nil {
		return err
	}

	if err := d.Set("policy", policy); err != nil {
		return fmt.Errorf("error setting policy: %s", err)
	}

	if err := d.Set("name", name); err != nil {
		return fmt.Errorf("error setting name: %s", err)
	}

	if err := d.Set("group", group); err != nil {
		return fmt.Errorf("error setting group: %s", err)
	}

	return nil
}

func resourceAwsIamGroupPolicyDelete(d *schema.ResourceData, meta interface{}) error {
	iamconn := meta.(*AWSClient).iamconn

	group, name, err := resourceAwsIamGroupPolicyParseId(d.Id())
	if err != nil {
		return err
	}

	request := &iam.DeleteGroupPolicyInput{
		PolicyName: aws.String(name),
		GroupName:  aws.String(group),
	}

	if _, err := iamconn.DeleteGroupPolicy(request); err != nil {
		if isAWSErr(err, iam.ErrCodeNoSuchEntityException, "") {
			return nil
		}
		return fmt.Errorf("Error deleting IAM group policy %s: %s", d.Id(), err)
	}
	return nil
}

func resourceAwsIamGroupPolicyParseId(id string) (groupName, policyName string, err error) {
	parts := strings.SplitN(id, ":", 2)
	if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
		err = fmt.Errorf("group_policy id must be of the form <group name>:<policy name>")
		return
	}

	groupName = parts[0]
	policyName = parts[1]
	return
}
<|endoftext|>