<commit_before>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

// Package component contains code that is shared by all components (discovery, router, broker, networkserver, handler)
package component

import (
	"crypto/ecdsa"
	"crypto/tls"
	"fmt"
	"net/http"
	"runtime"
	"time"

	"github.com/TheThingsNetwork/go-account-lib/claims"
	"github.com/TheThingsNetwork/go-account-lib/tokenkey"
	pb_discovery "github.com/TheThingsNetwork/ttn/api/discovery"
	pb_monitor "github.com/TheThingsNetwork/ttn/api/monitor"
	"github.com/apex/log"
	"github.com/spf13/viper"
	"golang.org/x/net/context" // See https://github.com/grpc/grpc-go/issues/711"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
)

// Component contains the common attributes for all TTN components
type Component struct {
	Config           Config
	Identity         *pb_discovery.Announcement
	Discovery        pb_discovery.Client
	Monitors         map[string]*pb_monitor.Client
	Ctx              log.Interface
	AccessToken      string
	privateKey       *ecdsa.PrivateKey
	tlsConfig        *tls.Config
	TokenKeyProvider tokenkey.Provider
	status           int64
	healthServer     *health.Server
}

type Interface interface {
	RegisterRPC(s *grpc.Server)
	Init(c *Component) error
	Shutdown()
	ValidateNetworkContext(ctx context.Context) (*pb_discovery.Announcement, error)
	ValidateTTNAuthContext(ctx context.Context) (*claims.Claims, error)
}

type ManagementInterface interface {
	RegisterManager(s *grpc.Server)
}

// New creates a new Component
func New(ctx log.Interface, serviceName string, announcedAddress string) (*Component, error) {
	go func() {
		memstats := new(runtime.MemStats)
		for range time.Tick(time.Minute) {
			runtime.ReadMemStats(memstats)
			ctx.WithFields(log.Fields{
				"Goroutines": runtime.NumGoroutine(),
				"Memory":     float64(memstats.Alloc) / 1000000,
			}).Debugf("Stats")
		}
	}()

	// Disable gRPC tracing
	// SEE: https://github.com/grpc/grpc-go/issues/695
	grpc.EnableTracing = false

	component := &Component{
		Config: ConfigFromViper(),
		Ctx:    ctx,
		Identity: &pb_discovery.Announcement{
			Id:             viper.GetString("id"),
			Description:    viper.GetString("description"),
			ServiceName:    serviceName,
			ServiceVersion: fmt.Sprintf("%s-%s (%s)", viper.GetString("version"), viper.GetString("gitCommit"), viper.GetString("buildDate")),
			NetAddress:     announcedAddress,
			Public:         viper.GetBool("public"),
		},
		AccessToken: viper.GetString("auth-token"),
	}

	if err := component.InitAuth(); err != nil {
		return nil, err
	}

	if serviceName != "discovery" && serviceName != "networkserver" {
		var err error
		component.Discovery, err = pb_discovery.NewClient(
			viper.GetString("discovery-address"),
			component.Identity,
			func() string {
				token, _ := component.BuildJWT()
				return token
			},
		)
		if err != nil {
			return nil, err
		}
	}

	if healthPort := viper.GetInt("health-port"); healthPort > 0 {
		http.HandleFunc("/healthz", func(w http.ResponseWriter, req *http.Request) {
			switch component.GetStatus() {
			case StatusHealthy:
				w.WriteHeader(200)
				w.Write([]byte("Status is HEALTHY"))
				return
			case StatusUnhealthy:
				w.WriteHeader(503)
				w.Write([]byte("Status is UNHEALTHY"))
				return
			}
		})
		go http.ListenAndServe(fmt.Sprintf(":%d", healthPort), nil)
	}

	if monitors := viper.GetStringMapString("monitor-servers"); len(monitors) != 0 {
		component.Monitors = make(map[string]*pb_monitor.Client)
		for name, addr := range monitors {
			var err error
			component.Monitors[name], err = pb_monitor.NewClient(ctx.WithField("Monitor", name), addr)
			if err != nil {
				return nil, err
			}
		}
	}

	return component, nil
}
<commit_msg>Configure Trace prefix for component<commit_after>// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

// Package component contains code that is shared by all components (discovery, router, broker, networkserver, handler)
package component

import (
	"crypto/ecdsa"
	"crypto/tls"
	"fmt"
	"net/http"
	"runtime"
	"time"

	"github.com/TheThingsNetwork/go-account-lib/claims"
	"github.com/TheThingsNetwork/go-account-lib/tokenkey"
	pb_discovery "github.com/TheThingsNetwork/ttn/api/discovery"
	pb_monitor "github.com/TheThingsNetwork/ttn/api/monitor"
	"github.com/TheThingsNetwork/ttn/api/trace"
	"github.com/apex/log"
	"github.com/spf13/viper"
	"golang.org/x/net/context" // See https://github.com/grpc/grpc-go/issues/711"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
)

// Component contains the common attributes for all TTN components
type Component struct {
	Config           Config
	Identity         *pb_discovery.Announcement
	Discovery        pb_discovery.Client
	Monitors         map[string]*pb_monitor.Client
	Ctx              log.Interface
	AccessToken      string
	privateKey       *ecdsa.PrivateKey
	tlsConfig        *tls.Config
	TokenKeyProvider tokenkey.Provider
	status           int64
	healthServer     *health.Server
}

type Interface interface {
	RegisterRPC(s *grpc.Server)
	Init(c *Component) error
	Shutdown()
	ValidateNetworkContext(ctx context.Context) (*pb_discovery.Announcement, error)
	ValidateTTNAuthContext(ctx context.Context) (*claims.Claims, error)
}

type ManagementInterface interface {
	RegisterManager(s *grpc.Server)
}

// New creates a new Component
func New(ctx log.Interface, serviceName string, announcedAddress string) (*Component, error) {
	go func() {
		memstats := new(runtime.MemStats)
		for range time.Tick(time.Minute) {
			runtime.ReadMemStats(memstats)
			ctx.WithFields(log.Fields{
				"Goroutines": runtime.NumGoroutine(),
				"Memory":     float64(memstats.Alloc) / 1000000,
			}).Debugf("Stats")
		}
	}()

	// Disable gRPC tracing
	// SEE: https://github.com/grpc/grpc-go/issues/695
	grpc.EnableTracing = false

	component := &Component{
		Config: ConfigFromViper(),
		Ctx:    ctx,
		Identity: &pb_discovery.Announcement{
			Id:             viper.GetString("id"),
			Description:    viper.GetString("description"),
			ServiceName:    serviceName,
			ServiceVersion: fmt.Sprintf("%s-%s (%s)", viper.GetString("version"), viper.GetString("gitCommit"), viper.GetString("buildDate")),
			NetAddress:     announcedAddress,
			Public:         viper.GetBool("public"),
		},
		AccessToken: viper.GetString("auth-token"),
	}

	trace.SetIdentifierPrefix(fmt.Sprintf("%s %s ", component.Identity.ServiceName, component.Identity.Id))

	if err := component.InitAuth(); err != nil {
		return nil, err
	}

	if serviceName != "discovery" && serviceName != "networkserver" {
		var err error
		component.Discovery, err = pb_discovery.NewClient(
			viper.GetString("discovery-address"),
			component.Identity,
			func() string {
				token, _ := component.BuildJWT()
				return token
			},
		)
		if err != nil {
			return nil, err
		}
	}

	if healthPort := viper.GetInt("health-port"); healthPort > 0 {
		http.HandleFunc("/healthz", func(w http.ResponseWriter, req *http.Request) {
			switch component.GetStatus() {
			case StatusHealthy:
				w.WriteHeader(200)
				w.Write([]byte("Status is HEALTHY"))
				return
			case StatusUnhealthy:
				w.WriteHeader(503)
				w.Write([]byte("Status is UNHEALTHY"))
				return
			}
		})
		go http.ListenAndServe(fmt.Sprintf(":%d", healthPort), nil)
	}

	if monitors := viper.GetStringMapString("monitor-servers"); len(monitors) != 0 {
		component.Monitors = make(map[string]*pb_monitor.Client)
		for name, addr := range monitors {
			var err error
			component.Monitors[name], err = pb_monitor.NewClient(ctx.WithField("Monitor", name), addr)
			if err != nil {
				return nil, err
			}
		}
	}

	return component, nil
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package discovery

import (
	"math/rand"
	"sync"
	"time"
)

// Discovery is the interface that consolidates bootstrap peer membership
// selection and validating peer selection for non-validating peers
type Discovery interface {
	AddNode(string) bool           // Add an address to the discovery list
	RemoveNode(string) bool        // Remove an address from the discovery list
	GetAllNodes() []string         // Return all addresses this peer maintains
	GetRandomNodes(n int) []string // Return n random addresses for this peer to connect to
	FindNode(string) bool          // Find a node in the discovery list
}

// DiscoveryImpl is an implementation of Discovery
type DiscoveryImpl struct {
	sync.RWMutex
	nodes  map[string]bool
	seq    []string
	random *rand.Rand
}

// NewDiscoveryImpl is a constructor of a Discovery implementation
func NewDiscoveryImpl() *DiscoveryImpl {
	di := DiscoveryImpl{}
	di.nodes = make(map[string]bool)
	di.random = rand.New(rand.NewSource(time.Now().Unix()))
	return &di
}

// AddNode adds an address to the discovery list
func (di *DiscoveryImpl) AddNode(address string) bool {
	di.Lock()
	defer di.Unlock()
	if _, ok := di.nodes[address]; !ok {
		di.seq = append(di.seq, address)
		di.nodes[address] = true
	}
	return di.nodes[address]
}

// RemoveNode removes an address from the discovery list
func (di *DiscoveryImpl) RemoveNode(address string) bool {
	di.Lock()
	defer di.Unlock()
	if _, ok := di.nodes[address]; ok {
		di.nodes[address] = false
		return true
	}
	return false
}

// GetAllNodes returns an array of all addresses saved in the discovery list
func (di *DiscoveryImpl) GetAllNodes() []string {
	di.Lock()
	defer di.Unlock()
	var addresses []string
	for address, valid := range di.nodes {
		if valid {
			addresses = append(addresses, address) // TODO Expensive, don't quite like it
		}
	}
	return addresses
}

// GetRandomNodes returns n random nodes
func (di *DiscoveryImpl) GetRandomNodes(n int) []string {
	var pick string
	randomNodes := make([]string, n)
	di.Lock()
	defer di.Unlock()
	for i := 0; i < n; i++ {
		for {
			pick = di.seq[di.random.Intn(len(di.nodes))]
			if di.nodes[pick] && !inArray(pick, randomNodes) {
				break
			}
		}
		randomNodes[i] = pick
	}
	return randomNodes
}

// FindNode returns true if its address is stored in the discovery list
func (di *DiscoveryImpl) FindNode(address string) bool {
	di.Lock()
	defer di.Unlock()
	_, ok := di.nodes[address]
	return ok
}

func inArray(element string, array []string) bool {
	for _, val := range array {
		if val == element {
			return true
		}
	}
	return false
}
<commit_msg>Use read lock for query methods in discovery.go<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package discovery

import (
	"math/rand"
	"sync"
	"time"
)

// Discovery is the interface that consolidates bootstrap peer membership
// selection and validating peer selection for non-validating peers
type Discovery interface {
	AddNode(string) bool           // Add an address to the discovery list
	RemoveNode(string) bool        // Remove an address from the discovery list
	GetAllNodes() []string         // Return all addresses this peer maintains
	GetRandomNodes(n int) []string // Return n random addresses for this peer to connect to
	FindNode(string) bool          // Find a node in the discovery list
}

// DiscoveryImpl is an implementation of Discovery
type DiscoveryImpl struct {
	sync.RWMutex
	nodes  map[string]bool
	seq    []string
	random *rand.Rand
}

// NewDiscoveryImpl is a constructor of a Discovery implementation
func NewDiscoveryImpl() *DiscoveryImpl {
	di := DiscoveryImpl{}
	di.nodes = make(map[string]bool)
	di.random = rand.New(rand.NewSource(time.Now().Unix()))
	return &di
}

// AddNode adds an address to the discovery list
func (di *DiscoveryImpl) AddNode(address string) bool {
	di.Lock()
	defer di.Unlock()
	if _, ok := di.nodes[address]; !ok {
		di.seq = append(di.seq, address)
		di.nodes[address] = true
	}
	return di.nodes[address]
}

// RemoveNode removes an address from the discovery list
func (di *DiscoveryImpl) RemoveNode(address string) bool {
	di.Lock()
	defer di.Unlock()
	if _, ok := di.nodes[address]; ok {
		di.nodes[address] = false
		return true
	}
	return false
}

// GetAllNodes returns an array of all addresses saved in the discovery list
func (di *DiscoveryImpl) GetAllNodes() []string {
	di.RLock()
	defer di.RUnlock()
	var addresses []string
	for address, valid := range di.nodes {
		if valid {
			addresses = append(addresses, address) // TODO Expensive, don't quite like it
		}
	}
	return addresses
}

// GetRandomNodes returns n random nodes
func (di *DiscoveryImpl) GetRandomNodes(n int) []string {
	var pick string
	randomNodes := make([]string, n)
	di.RLock()
	defer di.RUnlock()
	for i := 0; i < n; i++ {
		for {
			pick = di.seq[di.random.Intn(len(di.nodes))]
			if di.nodes[pick] && !inArray(pick, randomNodes) {
				break
			}
		}
		randomNodes[i] = pick
	}
	return randomNodes
}

// FindNode returns true if its address is stored in the discovery list
func (di *DiscoveryImpl) FindNode(address string) bool {
	di.RLock()
	defer di.RUnlock()
	_, ok := di.nodes[address]
	return ok
}

func inArray(element string, array []string) bool {
	for _, val := range array {
		if val == element {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package api

import (
	"time"
)

// OperationClassTask represents the Task OperationClass
const OperationClassTask = "task"

// OperationClassWebsocket represents the Websocket OperationClass
const OperationClassWebsocket = "websocket"

// OperationClassToken represents the Token OperationClass
const OperationClassToken = "token"

// Operation represents a LXD background operation
//
// swagger:model
type Operation struct {
	// UUID of the operation
	// Example: 6916c8a6-9b7d-4abd-90b3-aedfec7ec7da
	ID string `json:"id" yaml:"id"`

	// Type of operation (task, token or websocket)
	// Example: websocket
	Class string `json:"class" yaml:"class"`

	// Description of the operation
	// Example: Executing command
	Description string `json:"description" yaml:"description"`

	// Operation creation time
	// Example: 2021-03-23T17:38:37.753398689-04:00
	CreatedAt time.Time `json:"created_at" yaml:"created_at"`

	// Operation last change
	// Example: 2021-03-23T17:38:37.753398689-04:00
	UpdatedAt time.Time `json:"updated_at" yaml:"updated_at"`

	// Status name
	// Example: Running
	Status string `json:"status" yaml:"status"`

	// Status code
	// Example: 103
	StatusCode StatusCode `json:"status_code" yaml:"status_code"`

	// Affected resourcs
	// Example: {"containers": ["/1.0/containers/foo"], "instances": ["/1.0/instances/foo"]}
	Resources map[string][]string `json:"resources" yaml:"resources"`

	// Operation specific metadata
	// Example: {"command": ["bash"], "environment": {"HOME": "/root", "LANG": "C.UTF-8", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM": "xterm", "USER": "root"}, "fds": {"0": "da3046cf02c0116febf4ef3fe4eaecdf308e720c05e5a9c730ce1a6f15417f66", "1": "05896879d8692607bd6e4a09475667da3b5f6714418ab0ee0e5720b4c57f754b"}, "interactive": true}
	Metadata map[string]interface{} `json:"metadata" yaml:"metadata"`

	// Whether the operation can be canceled
	// Example: false
	MayCancel bool `json:"may_cancel" yaml:"may_cancel"`

	// Operation error mesage
	// Example: Some error message
	Err string `json:"err" yaml:"err"`

	// What cluster member this record was found on
	// Example: lxd01
	//
	// API extension: operation_location
	Location string `json:"location" yaml:"location"`
}
<commit_msg>shared/api: Add ToCertificateAddToken<commit_after>package api

import (
	"fmt"
	"time"
)

// OperationClassTask represents the Task OperationClass
const OperationClassTask = "task"

// OperationClassWebsocket represents the Websocket OperationClass
const OperationClassWebsocket = "websocket"

// OperationClassToken represents the Token OperationClass
const OperationClassToken = "token"

// Operation represents a LXD background operation
//
// swagger:model
type Operation struct {
	// UUID of the operation
	// Example: 6916c8a6-9b7d-4abd-90b3-aedfec7ec7da
	ID string `json:"id" yaml:"id"`

	// Type of operation (task, token or websocket)
	// Example: websocket
	Class string `json:"class" yaml:"class"`

	// Description of the operation
	// Example: Executing command
	Description string `json:"description" yaml:"description"`

	// Operation creation time
	// Example: 2021-03-23T17:38:37.753398689-04:00
	CreatedAt time.Time `json:"created_at" yaml:"created_at"`

	// Operation last change
	// Example: 2021-03-23T17:38:37.753398689-04:00
	UpdatedAt time.Time `json:"updated_at" yaml:"updated_at"`

	// Status name
	// Example: Running
	Status string `json:"status" yaml:"status"`

	// Status code
	// Example: 103
	StatusCode StatusCode `json:"status_code" yaml:"status_code"`

	// Affected resourcs
	// Example: {"containers": ["/1.0/containers/foo"], "instances": ["/1.0/instances/foo"]}
	Resources map[string][]string `json:"resources" yaml:"resources"`

	// Operation specific metadata
	// Example: {"command": ["bash"], "environment": {"HOME": "/root", "LANG": "C.UTF-8", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM": "xterm", "USER": "root"}, "fds": {"0": "da3046cf02c0116febf4ef3fe4eaecdf308e720c05e5a9c730ce1a6f15417f66", "1": "05896879d8692607bd6e4a09475667da3b5f6714418ab0ee0e5720b4c57f754b"}, "interactive": true}
	Metadata map[string]interface{} `json:"metadata" yaml:"metadata"`

	// Whether the operation can be canceled
	// Example: false
	MayCancel bool `json:"may_cancel" yaml:"may_cancel"`

	// Operation error mesage
	// Example: Some error message
	Err string `json:"err" yaml:"err"`

	// What cluster member this record was found on
	// Example: lxd01
	//
	// API extension: operation_location
	Location string `json:"location" yaml:"location"`
}

// ToCertificateAddToken creates a certificate add token from the operation metadata.
func (op *Operation) ToCertificateAddToken() (*CertificateAddToken, error) {
	req, ok := op.Metadata["request"].(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Operation request is type %T not map[string]interface{}", op.Metadata["request"])
	}

	clientName, ok := req["name"].(string)
	if !ok {
		return nil, fmt.Errorf("Failed to get client name")
	}

	secret, ok := op.Metadata["secret"].(string)
	if !ok {
		return nil, fmt.Errorf("Operation secret is type %T not string", op.Metadata["secret"])
	}

	fingerprint, ok := op.Metadata["fingerprint"].(string)
	if !ok {
		return nil, fmt.Errorf("Operation fingerprint is type %T not string", op.Metadata["fingerprint"])
	}

	addresses, ok := op.Metadata["addresses"].([]interface{})
	if !ok {
		return nil, fmt.Errorf("Operation addresses is type %T not []interface{}", op.Metadata["addresses"])
	}

	joinToken := CertificateAddToken{
		ClientName:  clientName,
		Secret:      secret,
		Fingerprint: fingerprint,
		Addresses:   make([]string, 0, len(addresses)),
	}

	for i, address := range addresses {
		addressString, ok := address.(string)
		if !ok {
			return nil, fmt.Errorf("Operation address index %d is type %T not string", i, address)
		}

		joinToken.Addresses = append(joinToken.Addresses, addressString)
	}

	return &joinToken, nil
}
<|endoftext|>


<commit_before>package color

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseColor(t *testing.T) {
	var c RGBA
	var err error
	c, err = Parse("#f63")
	assert.NoError(t, err)
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c, err = Parse("#ff6633")
	assert.NoError(t, err)
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c, err = Parse("")
	assert.Error(t, err)
	c, err = Parse("ff66")
	assert.Error(t, err)
	c, err = Parse("ff6633f")
	assert.Error(t, err)

	for name, hex := range cssColors {
		c, err = Parse(name)
		assert.NoError(t, err)
		assert.Equal(t, hex, c.String())
	}
}

func TestColorString(t *testing.T) {
	assert.Equal(t, "#ff6633", MustParse("#f63").String())
	assert.Equal(t, "#fa623d", MustParse("#fA623D").String())
	assert.Equal(t, "rgba(0, 0, 0, 0.0000)", RGBA{0, 0, 0, 0}.String())
	assert.Equal(t, "rgba(204, 255, 153, 0.4000)", RGBA{0.8, 1.0, 0.6, 0.4}.String())
	assert.Equal(t, "#ccff99", RGBA{0.8, 1.0, 0.6, 1}.String())
}

func TestMustParseColor(t *testing.T) {
	var c RGBA
	c = MustParse("#f63")
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c = MustParse("#ff6633")
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	assert.Panics(t, func() {
		MustParse("")
	})
	assert.Panics(t, func() {
		MustParse("#ff66")
	})
	assert.Panics(t, func() {
		MustParse("#ff6633f")
	})
	assert.Panics(t, func() {
		MustParse("#rottentomato")
	})
}

func TestHSLColor(t *testing.T) {
	var c HSLA
	c = RGBA{1.0, 1.0, 1.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 1.0, 0.0})
	c = RGBA{0.0, 0.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 0.0, 0.0})
	c = RGBA{0.5, 0.5, 0.5, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 0.5, 0.0})

	c = RGBA{1.0, 0.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 1.0, 0.5, 0.0})
	c = RGBA{0.0, 1.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{120.0, 1.0, 0.5, 0.0})
	c = RGBA{0.0, 0.0, 1.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{240.0, 1.0, 0.5, 0.0})
}

func TestRGBColor(t *testing.T) {
	var c RGBA
	c = HSLA{0, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{1.0, 0.0, 0.0, 0.0})
	c = HSLA{120, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{0.0, 1.0, 0.0, 0.0})
	c = HSLA{240, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{0.0, 0.0, 1.0, 0.0})
}

func TestRGBHSLColor(t *testing.T) {
	assert.Equal(t, RGBA{1.0, 1.0, 1.0, 0.0}.HSL().RGB(), RGBA{1.0, 1.0, 1.0, 0.0})
	assert.Equal(t, RGBA{0.0, 0.0, 0.0, 0.0}.HSL().RGB(), RGBA{0.0, 0.0, 0.0, 0.0})
	assert.Equal(t, RGBA{1.0, 0.0, 0.0, 0.0}.HSL().RGB(), RGBA{1.0, 0.0, 0.0, 0.0})
	assert.Equal(t, RGBA{0.0, 1.0, 0.0, 0.0}.HSL().RGB(), RGBA{0.0, 1.0, 0.0, 0.0})
	assert.Equal(t, RGBA{0.0, 0.0, 1.0, 0.0}.HSL().RGB(), RGBA{0.0, 0.0, 1.0, 0.0})
}

func TestFunctionsColor(t *testing.T) {
	assert.Equal(t, "#ed2b1a", Lighten(MustParse("#dd2211"), .05).Hex())
	assert.Equal(t, "#dc1e11", Darken(MustParse("#ed2b1a"), .05).Hex())

	assert.Equal(t, "#f32213", Saturate(MustParse("#ed2b1a"), .05).Hex())
	assert.Equal(t, "#ec2719", Desaturate(MustParse("#f32213"), .05).Hex())

	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.05}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.0}, .05))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.5}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.0}, .50))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.7}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.2}, .50))

	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.45}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.5}, .05))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.0}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.5}, .50))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.4}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.9}, .50))

	assert.Equal(t, "#00ff00", Spin(MustParse("#ff0000"), 120).Hex())
	assert.Equal(t, "#0000ff", Spin(MustParse("#00ff00"), 120).Hex())
	assert.Equal(t, "#ff0000", Spin(MustParse("#0000ff"), 120).Hex())

	assert.Equal(t, "#7f6633", Multiply(MustParse("#ffcc66"), 0.5).Hex())
	assert.Equal(t, "#fecc66", Multiply(MustParse("#7f6633"), 2).Hex())
}

func TestSetHue(t *testing.T) {
	assert.Equal(t, SetHue(MustParse("#737373"), MustParse("red")).Hex(), "#727372") //still grey

	// SetHue uses HuSL color space to keep saturation and lightning
	assert.Equal(t, SetHue(MustParse("#996644"), MustParse("red")).Hex(), "#c64444")
	// should differ from calculations with HSL
	hsl := MustParse("#996644").HSL()
	hsl.H = MustParse("red").HSL().H
	assert.Equal(t, hsl.RGB().Hex(), "#994444")
}
<commit_msg>fix test for rgba formatting<commit_after>package color

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseColor(t *testing.T) {
	var c RGBA
	var err error
	c, err = Parse("#f63")
	assert.NoError(t, err)
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c, err = Parse("#ff6633")
	assert.NoError(t, err)
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c, err = Parse("")
	assert.Error(t, err)
	c, err = Parse("ff66")
	assert.Error(t, err)
	c, err = Parse("ff6633f")
	assert.Error(t, err)

	for name, hex := range cssColors {
		c, err = Parse(name)
		assert.NoError(t, err)
		assert.Equal(t, hex, c.String())
	}
}

func TestColorString(t *testing.T) {
	assert.Equal(t, "#ff6633", MustParse("#f63").String())
	assert.Equal(t, "#fa623d", MustParse("#fA623D").String())
	assert.Equal(t, "rgba(0, 0, 0, 0.00000)", RGBA{0, 0, 0, 0}.String())
	assert.Equal(t, "rgba(204, 255, 153, 0.40000)", RGBA{0.8, 1.0, 0.6, 0.4}.String())
	assert.Equal(t, "#ccff99", RGBA{0.8, 1.0, 0.6, 1}.String())
}

func TestMustParseColor(t *testing.T) {
	var c RGBA
	c = MustParse("#f63")
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	c = MustParse("#ff6633")
	assert.Equal(t, c, RGBA{1.0, 0.4, 0.2, 1.0})

	assert.Panics(t, func() {
		MustParse("")
	})
	assert.Panics(t, func() {
		MustParse("#ff66")
	})
	assert.Panics(t, func() {
		MustParse("#ff6633f")
	})
	assert.Panics(t, func() {
		MustParse("#rottentomato")
	})
}

func TestHSLColor(t *testing.T) {
	var c HSLA
	c = RGBA{1.0, 1.0, 1.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 1.0, 0.0})
	c = RGBA{0.0, 0.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 0.0, 0.0})
	c = RGBA{0.5, 0.5, 0.5, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 0.0, 0.5, 0.0})

	c = RGBA{1.0, 0.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{0.0, 1.0, 0.5, 0.0})
	c = RGBA{0.0, 1.0, 0.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{120.0, 1.0, 0.5, 0.0})
	c = RGBA{0.0, 0.0, 1.0, 0.0}.HSL()
	assert.Equal(t, c, HSLA{240.0, 1.0, 0.5, 0.0})
}

func TestRGBColor(t *testing.T) {
	var c RGBA
	c = HSLA{0, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{1.0, 0.0, 0.0, 0.0})
	c = HSLA{120, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{0.0, 1.0, 0.0, 0.0})
	c = HSLA{240, 1.0, 0.5, 0.0}.RGB()
	assert.Equal(t, c, RGBA{0.0, 0.0, 1.0, 0.0})
}

func TestRGBHSLColor(t *testing.T) {
	assert.Equal(t, RGBA{1.0, 1.0, 1.0, 0.0}.HSL().RGB(), RGBA{1.0, 1.0, 1.0, 0.0})
	assert.Equal(t, RGBA{0.0, 0.0, 0.0, 0.0}.HSL().RGB(), RGBA{0.0, 0.0, 0.0, 0.0})
	assert.Equal(t, RGBA{1.0, 0.0, 0.0, 0.0}.HSL().RGB(), RGBA{1.0, 0.0, 0.0, 0.0})
	assert.Equal(t, RGBA{0.0, 1.0, 0.0, 0.0}.HSL().RGB(), RGBA{0.0, 1.0, 0.0, 0.0})
	assert.Equal(t, RGBA{0.0, 0.0, 1.0, 0.0}.HSL().RGB(), RGBA{0.0, 0.0, 1.0, 0.0})
}

func TestFunctionsColor(t *testing.T) {
	assert.Equal(t, "#ed2b1a", Lighten(MustParse("#dd2211"), .05).Hex())
	assert.Equal(t, "#dc1e11", Darken(MustParse("#ed2b1a"), .05).Hex())

	assert.Equal(t, "#f32213", Saturate(MustParse("#ed2b1a"), .05).Hex())
	assert.Equal(t, "#ec2719", Desaturate(MustParse("#f32213"), .05).Hex())

	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.05}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.0}, .05))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.5}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.0}, .50))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.7}, FadeIn(RGBA{0.5, 0.5, 0.5, 0.2}, .50))

	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.45}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.5}, .05))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.0}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.5}, .50))
	assert.Equal(t, RGBA{0.5, 0.5, 0.5, 0.4}, FadeOut(RGBA{0.5, 0.5, 0.5, 0.9}, .50))

	assert.Equal(t, "#00ff00", Spin(MustParse("#ff0000"), 120).Hex())
	assert.Equal(t, "#0000ff", Spin(MustParse("#00ff00"), 120).Hex())
	assert.Equal(t, "#ff0000", Spin(MustParse("#0000ff"), 120).Hex())

	assert.Equal(t, "#7f6633", Multiply(MustParse("#ffcc66"), 0.5).Hex())
	assert.Equal(t, "#fecc66", Multiply(MustParse("#7f6633"), 2).Hex())
}

func TestSetHue(t *testing.T) {
	assert.Equal(t, SetHue(MustParse("#737373"), MustParse("red")).Hex(), "#727372") //still grey

	// SetHue uses HuSL color space to keep saturation and lightning
	assert.Equal(t, SetHue(MustParse("#996644"), MustParse("red")).Hex(), "#c64444")
	// should differ from calculations with HSL
	hsl := MustParse("#996644").HSL()
	hsl.H = MustParse("red").HSL().H
	assert.Equal(t, hsl.RGB().Hex(), "#994444")
}
<|endoftext|>


<commit_before>package command

import (
	"time"

	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/metadata"
)

func metadataGenerators(conf *config.Config) []*metadata.Generator {
	generators := make([]*metadata.Generator, 0, len(conf.MetadataPlugins))

	for name, pluginConfig := range conf.MetadataPlugins {
		generator := &metadata.Generator{
			Name:   name,
			Config: pluginConfig,
		}
		logger.Debugf("Metadata plugin generator created: %v", generator)
		generators = append(generators, generator)
	}

	return generators
}

type metadataResult struct {
	namespace string
	metadata  interface{}
}

func runMetadataLoop(c *Context, termMetadataCh <-chan struct{}, quit <-chan struct{}) {
	resultCh := make(chan *metadataResult)
	for _, g := range c.Agent.MetadataGenerators {
		go runEachMetadataLoop(g, resultCh, quit)
	}

	exit := false
	for !exit {
		select {
		case <-time.After(1 * time.Minute):
		case <-termMetadataCh:
			logger.Debugf("received 'term' chan for metadata loop")
			exit = true
		}

		results := []*metadataResult{}
		hasResult := true
		for hasResult {
			select {
			case result := <-resultCh:
				results = append(results, result)
			default:
				hasResult = false
			}
		}

		for _, result := range results {
			err := c.API.PutMetadata(c.Host.ID, result.namespace, result.metadata)
			if err != nil {
				logger.Errorf("put metadata %q failed: %s", result.namespace, err.Error())
				// TODO: error handling (re-enqueue?)
			}
		}
	}
}

func runEachMetadataLoop(g *metadata.Generator, resultCh chan<- *metadataResult, quit <-chan struct{}) {
	interval := g.Interval()
	nextInterval := 10 * time.Second
	nextTime := time.Now()

	for {
		select {
		case <-time.After(nextInterval):
			metadata, err := g.Fetch()

			// case for laptop sleep mode (now >> nextTime + interval)
			now := time.Now()
			nextInterval = interval - (now.Sub(nextTime) % interval)
			nextTime = now.Add(nextInterval)

			if err != nil {
				logger.Warningf("metadata %q: %s", g.Name, err.Error())
				continue
			}
			logger.Debugf("metadata %q: %v", g.Name, metadata)
			resultCh <- &metadataResult{
				namespace: g.Name,
				metadata:  metadata,
			}

		case <-quit:
			return
		}
	}
}
<commit_msg>improve debug message<commit_after>package command

import (
	"time"

	"github.com/mackerelio/mackerel-agent/config"
	"github.com/mackerelio/mackerel-agent/metadata"
)

func metadataGenerators(conf *config.Config) []*metadata.Generator {
	generators := make([]*metadata.Generator, 0, len(conf.MetadataPlugins))

	for name, pluginConfig := range conf.MetadataPlugins {
		generator := &metadata.Generator{
			Name:   name,
			Config: pluginConfig,
		}
		logger.Debugf("Metadata plugin generator created: %#v %#v", generator, generator.Config)
		generators = append(generators, generator)
	}

	return generators
}

type metadataResult struct {
	namespace string
	metadata  interface{}
}

func runMetadataLoop(c *Context, termMetadataCh <-chan struct{}, quit <-chan struct{}) {
	resultCh := make(chan *metadataResult)
	for _, g := range c.Agent.MetadataGenerators {
		go runEachMetadataLoop(g, resultCh, quit)
	}

	exit := false
	for !exit {
		select {
		case <-time.After(1 * time.Minute):
		case <-termMetadataCh:
			logger.Debugf("received 'term' chan for metadata loop")
			exit = true
		}

		results := []*metadataResult{}
		hasResult := true
		for hasResult {
			select {
			case result := <-resultCh:
				results = append(results, result)
			default:
				hasResult = false
			}
		}

		for _, result := range results {
			err := c.API.PutMetadata(c.Host.ID, result.namespace, result.metadata)
			if err != nil {
				logger.Errorf("put metadata %q failed: %s", result.namespace, err.Error())
				// TODO: error handling (re-enqueue?)
			}
		}
	}
}

func runEachMetadataLoop(g *metadata.Generator, resultCh chan<- *metadataResult, quit <-chan struct{}) {
	interval := g.Interval()
	nextInterval := 10 * time.Second
	nextTime := time.Now()

	for {
		select {
		case <-time.After(nextInterval):
			metadata, err := g.Fetch()

			// case for laptop sleep mode (now >> nextTime + interval)
			now := time.Now()
			nextInterval = interval - (now.Sub(nextTime) % interval)
			nextTime = now.Add(nextInterval)

			if err != nil {
				logger.Warningf("metadata %q: %s", g.Name, err.Error())
				continue
			}
			logger.Debugf("metadata %q: %v", g.Name, metadata)
			resultCh <- &metadataResult{
				namespace: g.Name,
				metadata:  metadata,
			}

		case <-quit:
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The go-python 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 bind

import (
	"golang.org/x/tools/go/types"
)

type Object interface {
	Package() *Package
	ID() string
	Doc() string
	GoName() string
}

type Type interface {
	Object
	GoType() types.Type
}

func needWrapType(typ types.Type) bool {
	switch typ.(type) {
	case *types.Struct:
		return true
	case *types.Named:
		switch typ.Underlying().(type) {
		case *types.Struct:
			return true
		}
	case *types.Array:
		return true
	case *types.Slice:
		return true
	case *types.Interface:
		return true
	}
	return false
}
<commit_msg>bind: needWrapType - preliminary support for interfaces+namedtypes<commit_after>// Copyright 2015 The go-python 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 bind

import (
	"golang.org/x/tools/go/types"
)

type Object interface {
	Package() *Package
	ID() string
	Doc() string
	GoName() string
}

type Type interface {
	Object
	GoType() types.Type
}

func needWrapType(typ types.Type) bool {
	switch typ.(type) {
	case *types.Basic:
		return false
	case *types.Struct:
		return true
	case *types.Named:
		switch ut := typ.Underlying().(type) {
		case *types.Basic:
			return false
		default:
			return needWrapType(ut)
		}
	case *types.Array:
		return true
	case *types.Slice:
		return true
	case *types.Interface:
		wrap := true
		if typ.Underlying() == universe.syms["error"].GoType().Underlying() {
			wrap = false
		}
		return wrap
	case *types.Signature:
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/pubsubsql/client"
)

/* MAKE SURE TO RUN PUBSUBSQL SERVER WHEN RUNNING THE EXAMPLE */

func checkError(client *pubsubsql.Client, str string) {
	if client.Failed() {
		fmt.Println("Error:", client.Error(), str)
	}
}

func main() {
	client := new(pubsubsql.Client)
	subscriber := new(pubsubsql.Client)

	//----------------------------------------------------------------------------------------------------
	// CONNECT
	//----------------------------------------------------------------------------------------------------

	address := "localhost:7777"
	client.Connect(address)
	checkError(client, "client connect failed")
	subscriber.Connect(address)
	checkError(client, "subscriber connect failed")

	//----------------------------------------------------------------------------------------------------
	// INDEX
	// only optional ddl commands available are
	// key (unique index) and/or tag (non unique index)
	// table and columns are auto created
	//----------------------------------------------------------------------------------------------------

	// Creates key (unique index) for table Stocks on column Ticker
	client.Execute("key Stocks Ticker")
	// Creates tag (non unique index) for table Stocks on column MarketCap
	client.Execute("tag Stocks MarketCap")

	//----------------------------------------------------------------------------------------------------
	// SUBSCRIBE
	//----------------------------------------------------------------------------------------------------

	subscriber.Execute("subscribe * from Stocks where MarketCap = 'MEGA CAP'")
	checkError(subscriber, "subscribe failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH INSERT
	//----------------------------------------------------------------------------------------------------

	// all commands must be in lowercase string single quotes are optional unless
	// data contains special characters: whitespace, single quote or comma
	client.Execute("insert into Stocks (Ticker, Price, MarketCap) values (GOOG, '1,200.22', 'MEGA CAP')")
	checkError(client, "insert GOOG failed")

	//----------------------------------------------------------------------------------------------------
	// PROCESS PUBLISHED INSERT
	//----------------------------------------------------------------------------------------------------

	timeout := 1000
	for subscriber.WaitForPubSub(timeout) {
		fmt.Println("*********************************")
		fmt.Println("Action:", subscriber.Action())
		for subscriber.NextRow() {
			fmt.Println("New MEGA CAP stock:", subscriber.Value("Ticker"))
			fmt.Println("Price:", subscriber.Value("Price"))
		}
		checkError(subscriber, "NextRow failed")
	}
	checkError(subscriber, "WaitForPubSub failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH UPDATE
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = '1,500.00' where Ticker = GOOG")
	checkError(client, "update GOOG failed")

	//----------------------------------------------------------------------------------------------------
	// DO NOT PUBLISH INSERT
	// we only subscribed to 'MEGA CAP'
	//----------------------------------------------------------------------------------------------------

	client.Execute("insert into Stocks (Ticker, Price, MarketCap) values (IBM, 168, 'LARGE CAP')")
	checkError(client, "insert IBM failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH ADD
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = 230.45, MarketCap = 'MEGA CAP' where Ticker = IBM")
	checkError(client, "update IBM to MEGA CAP failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH REMOVE
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = 170, MarketCap = 'LARGE CAP' where Ticker = IBM")
	checkError(client, "update IBM to LARGE CAP failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH DELETE
	//----------------------------------------------------------------------------------------------------

	client.Execute("delete from Stocks")
	checkError(client, "delete failed")

	//----------------------------------------------------------------------------------------------------
	// PROCESS PUBLISHED ALL
	//----------------------------------------------------------------------------------------------------

	for subscriber.WaitForPubSub(timeout) {
		fmt.Println("*********************************")
		fmt.Println("Action:", subscriber.Action())
		for subscriber.NextRow() {
			for ordinal, column :=  range subscriber.Columns() {
				fmt.Printf("%s:%s ", column, subscriber.ValueByOrdinal(ordinal))
			}
			fmt.Println("")
		}
		checkError(subscriber, "NextRow failed")
	}
	checkError(subscriber, "NextRow failed")

	//----------------------------------------------------------------------------------------------------
	// DISCONNECT
	//----------------------------------------------------------------------------------------------------

	client.Disconnect()
	subscriber.Disconnect()
}

<commit_msg>QuickStart add select, unsubscribe<commit_after>package main

import (
	"fmt"
	"github.com/pubsubsql/client"
)

/* MAKE SURE TO RUN PUBSUBSQL SERVER WHEN RUNNING THE EXAMPLE */

func checkError(client *pubsubsql.Client, str string) {
	if client.Failed() {
		fmt.Println("Error:", client.Error(), str)
	}
}

func main() {
	client := new(pubsubsql.Client)
	subscriber := new(pubsubsql.Client)

	//----------------------------------------------------------------------------------------------------
	// CONNECT
	//----------------------------------------------------------------------------------------------------

	address := "localhost:7777"
	client.Connect(address)
	checkError(client, "client connect failed")
	subscriber.Connect(address)
	checkError(client, "subscriber connect failed")

	//----------------------------------------------------------------------------------------------------
	// INDEX
	// only optional ddl commands available are
	// key (unique index) and/or tag (non unique index)
	// table and columns are auto created
	//----------------------------------------------------------------------------------------------------

	// Creates key (unique index) for table Stocks on column Ticker
	client.Execute("key Stocks Ticker")
	// Creates tag (non unique index) for table Stocks on column MarketCap
	client.Execute("tag Stocks MarketCap")

	//----------------------------------------------------------------------------------------------------
	// SUBSCRIBE
	//----------------------------------------------------------------------------------------------------

	subscriber.Execute("subscribe * from Stocks where MarketCap = 'MEGA CAP'")
	pubsubid := subscriber.PubSubId()
	fmt.Println("subscribed to Stocks pubsubid:", pubsubid)
	checkError(subscriber, "subscribe failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH INSERT
	//----------------------------------------------------------------------------------------------------

	// all commands must be in lowercase string single quotes are optional unless
	// data contains special characters: whitespace, single quote or comma
	client.Execute("insert into Stocks (Ticker, Price, MarketCap) values (GOOG, '1,200.22', 'MEGA CAP')")
	checkError(client, "insert GOOG failed")
	client.Execute("insert into Stocks (Ticker, Price, MarketCap) values (MSFT, 38,'MEGA CAP')")
	checkError(client, "insert MSFT failed")

	//----------------------------------------------------------------------------------------------------
	// SELECT
	//----------------------------------------------------------------------------------------------------

	client.Execute("select id, Ticker from Stocks")
	checkError(client, "select failed")
	for client.NextRow() {
		fmt.Println("*********************************")
		fmt.Printf("id:%s Ticker:%s \n", client.Value("id"), client.Value("Ticker"))
	}
	checkError(client, "NextRow failed")

	//----------------------------------------------------------------------------------------------------
	// PROCESS PUBLISHED INSERT
	//----------------------------------------------------------------------------------------------------

	timeout := 100
	for subscriber.WaitForPubSub(timeout) {
		fmt.Println("*********************************")
		fmt.Println("Action:", subscriber.Action())
		for subscriber.NextRow() {
			fmt.Println("New MEGA CAP stock:", subscriber.Value("Ticker"))
			fmt.Println("Price:", subscriber.Value("Price"))
		}
		checkError(subscriber, "NextRow failed")
	}
	checkError(subscriber, "WaitForPubSub failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH UPDATE
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = '1,500.00' where Ticker = GOOG")
	checkError(client, "update GOOG failed")

	//----------------------------------------------------------------------------------------------------
	// DOES NOT PUBLISH INSERT
	// we only subscribed to 'MEGA CAP'
	//----------------------------------------------------------------------------------------------------

	client.Execute("insert into Stocks (Ticker, Price, MarketCap) values (IBM, 168, 'LARGE CAP')")
	checkError(client, "insert IBM failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH ADD
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = 230.45, MarketCap = 'MEGA CAP' where Ticker = IBM")
	checkError(client, "update IBM to MEGA CAP failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH REMOVE
	//----------------------------------------------------------------------------------------------------

	client.Execute("update Stocks set Price = 170, MarketCap = 'LARGE CAP' where Ticker = IBM")
	checkError(client, "update IBM to LARGE CAP failed")

	//----------------------------------------------------------------------------------------------------
	// PUBLISH DELETE
	//----------------------------------------------------------------------------------------------------

	client.Execute("delete from Stocks")
	checkError(client, "delete failed")

	//----------------------------------------------------------------------------------------------------
	// PROCESS PUBLISHED ALL
	//----------------------------------------------------------------------------------------------------

	for subscriber.WaitForPubSub(timeout) {
		fmt.Println("*********************************")
		fmt.Println("Action:", subscriber.Action())
		for subscriber.NextRow() {
			for ordinal, column :=  range subscriber.Columns() {
				fmt.Printf("%s:%s ", column, subscriber.ValueByOrdinal(ordinal))
			}
			fmt.Println("")
		}
		checkError(subscriber, "NextRow failed")
	}
	checkError(subscriber, "NextRow failed")

	//----------------------------------------------------------------------------------------------------
	// UNSUBSCRIBE
	//----------------------------------------------------------------------------------------------------

	subscriber.Execute("unsubscribe from Stocks")
	checkError(subscriber, "NextRow failed")

	//----------------------------------------------------------------------------------------------------
	// DISCONNECT
	//----------------------------------------------------------------------------------------------------

	client.Disconnect()
	subscriber.Disconnect()
}

<|endoftext|>


<commit_before>package commands

import (
	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/commands/steps"
	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors/env"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/display"
)

var (

	// DestroyCmd ...
	DestroyCmd = &cobra.Command{
		Use:   "destroy",
		Short: "Destroys the current project and removes it from Nanobox",
		Long: `
Destroys the current project and removes it from Nanobox, destroying
the filesystem mount, associated dns aliases, and local app data.
		`,
		PreRun: steps.Run("start"),
		Run:    destroyFunc,
	}
)

// destroyFunc ...
func destroyFunc(ccmd *cobra.Command, args []string) {
	envModel, _ := models.FindEnvByID(config.EnvID())
	display.CommandErr(env.Destroy(envModel))
}
<commit_msg>shortcut a nanobox destroy so it doesnt error fixes #217<commit_after>package commands

import (
	"fmt"
	"github.com/spf13/cobra"

	"github.com/nanobox-io/nanobox/commands/steps"
	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/processors/env"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/display"
)

var (

	// DestroyCmd ...
	DestroyCmd = &cobra.Command{
		Use:   "destroy",
		Short: "Destroys the current project and removes it from Nanobox",
		Long: `
Destroys the current project and removes it from Nanobox, destroying
the filesystem mount, associated dns aliases, and local app data.
		`,
		PreRun: steps.Run("start"),
		Run:    destroyFunc,
	}
)

// destroyFunc ...
func destroyFunc(ccmd *cobra.Command, args []string) {
	envModel, err := models.FindEnvByID(config.EnvID())
	if err != nil {
		fmt.Println("This project doesn't exist on nanobox.")
		return
	}
	display.CommandErr(env.Destroy(envModel))
}
<|endoftext|>


<commit_before>package commands

import "os"

// DefaultConfig - sets config based on ENV variable or default config.yml
func defaultConfig() string {
	env := os.Getenv(configENV)
	if env == "" {
		return "config.yml"
	}
	return env
}
<commit_msg>added support for config.yaml files to be read by default if they exist<commit_after>package commands

import "os"

const (
	defaultconfigA = "config.yml"
	defaultconfigB = "config.yaml"
)

// DefaultConfig - sets config based on ENV variable or default config.yml
func defaultConfig() string {
	if env := os.Getenv(configENV); env != "" {
		return env
	}

	if _, err := os.Stat(defaultconfigB); err == nil {
		return defaultconfigB
	}

	return defaultconfigA

}
<|endoftext|>


<commit_before>package rpcman

import (
	"encoding/json"
	"errors"
	"log"
	"sync"
	"time"

	zmq "github.com/alecthomas/gozmq"
)

type RPCMan struct {
	Context  *zmq.Context
	ServAddr string
	Socket   *zmq.Socket
	mutex    *sync.Mutex
}

type Request struct {
	Method string
	Args   interface{}
}

type Response struct {
	Response interface{}
	Status   int
}

func Init(addr string) (*RPCMan, error) {
	context, _ := zmq.NewContext()

	socket, err := context.NewSocket(zmq.REQ)
	if err != nil {
		log.Println("could not set up socket to rpcman", err)
		return nil, err
	}
	err = socket.Connect(addr)
	if err != nil {
		log.Println("Could not connect to socket", err)
		return nil, err
	}

	// set timeout to 1s
	duration, _ := time.ParseDuration("1s")
	socket.SetRcvTimeout(duration)

	mutex := &sync.Mutex{}
	//cond := sync.NewCond(sync.Mutex{})

	rpc := RPCMan{
		Context:  context,
		ServAddr: addr,
		Socket:   socket,
		mutex:    mutex}

	return &rpc, nil

}

func (rpc RPCMan) Close() {
	rpc.Context.Close()
}

func (rpc RPCMan) Call(method string, args ...interface{}) (interface{}, error) {

	// exclusive access to socket
	//rpc.mutex.Lock()
	//defer rpc.mutex.Unlock()

	msg := Request{method, args}

	enc, err := json.Marshal(msg)
	if err != nil {
		log.Println("json error", err)
		return -1, err
	}

	rpc.Socket.Send(enc, 0)

	//rpc.Socket.Send(enc, 0)
	resp := new(Response)

	//reply, err := rpc.Socket.Recv(0)
	reply, err := rpc.Socket.Recv(0)
	if err != nil {
		log.Println("RPC recv failed:", err, method)
		return -1, err
	}

	err = json.Unmarshal(reply, resp)

	if err != nil {
		log.Println("json error", err)
		return -1, err
	}

	if resp.Status != 0 {
		return -1, errors.New("RPC Method not found:" + method)
	}

	// socket.Close()

	return resp.Response, nil

}
<commit_msg>support for multiple addr in connect<commit_after>package rpcman

import (
	"encoding/json"
	"errors"
	"log"
	"sync"
	"time"

	zmq "github.com/alecthomas/gozmq"
)

type RPCMan struct {
	Context  *zmq.Context
	ServAddr []string
	Socket   *zmq.Socket
	mutex    *sync.Mutex
}

type Request struct {
	Method string
	Args   interface{}
}

type Response struct {
	Response interface{}
	Status   int
}

func Init(addrs []string) (*RPCMan, error) {
	context, _ := zmq.NewContext()

	socket, err := context.NewSocket(zmq.REQ)
	if err != nil {
		log.Println("could not set up socket to rpcman", err)
		return nil, err
	}
	for _, addr := range addrs {
		err = socket.Connect(addr)
		if err != nil {
			log.Println("Could not connect to socket", err)
			return nil, err
		}
	}

	// set timeout to 1s
	duration, _ := time.ParseDuration("1s")
	socket.SetRcvTimeout(duration)

	mutex := &sync.Mutex{}
	//cond := sync.NewCond(sync.Mutex{})

	rpc := RPCMan{
		Context:  context,
		ServAddr: addrs,
		Socket:   socket,
		mutex:    mutex}

	return &rpc, nil

}

func (rpc RPCMan) Close() {
	rpc.Context.Close()
}

func (rpc RPCMan) Call(method string, args ...interface{}) (interface{}, error) {

	// exclusive access to socket
	//rpc.mutex.Lock()
	//defer rpc.mutex.Unlock()

	msg := Request{method, args}

	enc, err := json.Marshal(msg)
	if err != nil {
		log.Println("json error", err)
		return -1, err
	}

	rpc.Socket.Send(enc, 0)

	//rpc.Socket.Send(enc, 0)
	resp := new(Response)

	//reply, err := rpc.Socket.Recv(0)
	reply, err := rpc.Socket.Recv(0)
	if err != nil {
		log.Println("RPC recv failed:", err, method)
		return -1, err
	}

	err = json.Unmarshal(reply, resp)

	if err != nil {
		log.Println("json error", err)
		return -1, err
	}

	if resp.Status != 0 {
		return -1, errors.New("RPC Method not found:" + method)
	}

	// socket.Close()

	return resp.Response, nil

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016, Theodore Butler
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package dtrie

import (
	"fmt"
	"sync/atomic"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPopCount(t *testing.T) {
	b := []uint32{
		uint32(0x55555555), // 0x55555555 = 01010101 01010101 01010101 01010101
		uint32(0x33333333), // 0x33333333 = 00110011 00110011 00110011 00110011
		uint32(0x0F0F0F0F), // 0x0F0F0F0F = 00001111 00001111 00001111 00001111
		uint32(0x00FF00FF), // 0x00FF00FF = 00000000 11111111 00000000 11111111
		uint32(0x0000FFFF), // 0x0000FFFF = 00000000 00000000 11111111 11111111
	}
	for _, x := range b {
		assert.Equal(t, 16, popCount(x))
	}
}

func TestDefaultHasher(t *testing.T) {
	assert.Equal(t,
		defaultHasher(map[int]string{11234: "foo"}),
		defaultHasher(map[int]string{11234: "foo"}))
	assert.NotEqual(t, defaultHasher("foo"), defaultHasher("bar"))
}

type testEntry struct {
	hash  uint32
	key   int
	value int
}

func (e *testEntry) KeyHash() uint32 {
	return e.hash
}

func (e *testEntry) Key() interface{} {
	return e.key
}

func (e *testEntry) Value() interface{} {
	return e.value
}

func (e *testEntry) String() string {
	return fmt.Sprint(e.value)
}

func collisionHash(key interface{}) uint32 {
	return uint32(0xffffffff) // for testing collisions
}

func TestInsert(t *testing.T) {
	insertTest(t, defaultHasher, 10000)
	insertTest(t, collisionHash, 1000)
}

func insertTest(t *testing.T, hashfunc func(interface{}) uint32, count int) *node {
	n := emptyNode(0, 32)
	for i := 0; i < count; i++ {
		n = insert(n, &testEntry{hashfunc(i), i, i})
	}
	return n
}

func TestGet(t *testing.T) {
	getTest(t, defaultHasher, 10000)
	getTest(t, collisionHash, 1000)
}

func getTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		x := get(n, hashfunc(i), i)
		assert.Equal(t, i, x.Value())
	}
}

func TestRemove(t *testing.T) {
	removeTest(t, defaultHasher, 10000)
	removeTest(t, collisionHash, 1000)
}

func removeTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		n = remove(n, hashfunc(i), i)
	}
	for _, e := range n.entries {
		if e != nil {
			t.Fatal("final node is not empty")
		}
	}
}

func TestUpdate(t *testing.T) {
	updateTest(t, defaultHasher, 10000)
	updateTest(t, collisionHash, 1000)
}

func updateTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		n = insert(n, &testEntry{hashfunc(i), i, -i})
	}
}

func TestIterate(t *testing.T) {
	n := insertTest(t, defaultHasher, 10000)
	echan := iterate(n, nil)
	var c int64
	for range echan {
		c++
	}
	assert.Equal(t, int64(10000), c)
	// test with stop chan
	c = 0
	stop := make(chan struct{})
	echan = iterate(n, stop)
	go func() {
		for range echan {
			atomic.AddInt64(&c, 1)
		}
	}()
	for atomic.LoadInt64(&c) < 100 {
	}
	close(stop)
	assert.True(t, c > 99 && c < 1000)
	// test with collisions
	n = insertTest(t, collisionHash, 1000)
	c = 0
	echan = iterate(n, nil)
	for range echan {
		c++
	}
	assert.Equal(t, int64(1000), c)
}

func TestSize(t *testing.T) {
	n := insertTest(t, defaultHasher, 10000)
	d := &Dtrie{n, defaultHasher}
	assert.Equal(t, 10000, d.Size())
}

func BenchmarkInsert(b *testing.B) {
	b.ReportAllocs()
	n := emptyNode(0, 32)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = insert(n, &testEntry{defaultHasher(i), i, i})
	}
}

func BenchmarkGet(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		get(n, defaultHasher(i), i)
	}
}

func BenchmarkRemove(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = remove(n, defaultHasher(i), i)
	}
}

func BenchmarkUpdate(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = insert(n, &testEntry{defaultHasher(i), i, -i})
	}
}
<commit_msg>add blank identifier to more range statements<commit_after>/*
Copyright (c) 2016, Theodore Butler
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package dtrie

import (
	"fmt"
	"sync/atomic"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestPopCount(t *testing.T) {
	b := []uint32{
		uint32(0x55555555), // 0x55555555 = 01010101 01010101 01010101 01010101
		uint32(0x33333333), // 0x33333333 = 00110011 00110011 00110011 00110011
		uint32(0x0F0F0F0F), // 0x0F0F0F0F = 00001111 00001111 00001111 00001111
		uint32(0x00FF00FF), // 0x00FF00FF = 00000000 11111111 00000000 11111111
		uint32(0x0000FFFF), // 0x0000FFFF = 00000000 00000000 11111111 11111111
	}
	for _, x := range b {
		assert.Equal(t, 16, popCount(x))
	}
}

func TestDefaultHasher(t *testing.T) {
	assert.Equal(t,
		defaultHasher(map[int]string{11234: "foo"}),
		defaultHasher(map[int]string{11234: "foo"}))
	assert.NotEqual(t, defaultHasher("foo"), defaultHasher("bar"))
}

type testEntry struct {
	hash  uint32
	key   int
	value int
}

func (e *testEntry) KeyHash() uint32 {
	return e.hash
}

func (e *testEntry) Key() interface{} {
	return e.key
}

func (e *testEntry) Value() interface{} {
	return e.value
}

func (e *testEntry) String() string {
	return fmt.Sprint(e.value)
}

func collisionHash(key interface{}) uint32 {
	return uint32(0xffffffff) // for testing collisions
}

func TestInsert(t *testing.T) {
	insertTest(t, defaultHasher, 10000)
	insertTest(t, collisionHash, 1000)
}

func insertTest(t *testing.T, hashfunc func(interface{}) uint32, count int) *node {
	n := emptyNode(0, 32)
	for i := 0; i < count; i++ {
		n = insert(n, &testEntry{hashfunc(i), i, i})
	}
	return n
}

func TestGet(t *testing.T) {
	getTest(t, defaultHasher, 10000)
	getTest(t, collisionHash, 1000)
}

func getTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		x := get(n, hashfunc(i), i)
		assert.Equal(t, i, x.Value())
	}
}

func TestRemove(t *testing.T) {
	removeTest(t, defaultHasher, 10000)
	removeTest(t, collisionHash, 1000)
}

func removeTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		n = remove(n, hashfunc(i), i)
	}
	for _, e := range n.entries {
		if e != nil {
			t.Fatal("final node is not empty")
		}
	}
}

func TestUpdate(t *testing.T) {
	updateTest(t, defaultHasher, 10000)
	updateTest(t, collisionHash, 1000)
}

func updateTest(t *testing.T, hashfunc func(interface{}) uint32, count int) {
	n := insertTest(t, hashfunc, count)
	for i := 0; i < count; i++ {
		n = insert(n, &testEntry{hashfunc(i), i, -i})
	}
}

func TestIterate(t *testing.T) {
	n := insertTest(t, defaultHasher, 10000)
	echan := iterate(n, nil)
	var c int64
	for _ = range echan {
		c++
	}
	assert.Equal(t, int64(10000), c)
	// test with stop chan
	c = 0
	stop := make(chan struct{})
	echan = iterate(n, stop)
	go func() {
		for range echan {
			atomic.AddInt64(&c, 1)
		}
	}()
	for atomic.LoadInt64(&c) < 100 {
	}
	close(stop)
	assert.True(t, c > 99 && c < 1000)
	// test with collisions
	n = insertTest(t, collisionHash, 1000)
	c = 0
	echan = iterate(n, nil)
	for _ = range echan {
		c++
	}
	assert.Equal(t, int64(1000), c)
}

func TestSize(t *testing.T) {
	n := insertTest(t, defaultHasher, 10000)
	d := &Dtrie{n, defaultHasher}
	assert.Equal(t, 10000, d.Size())
}

func BenchmarkInsert(b *testing.B) {
	b.ReportAllocs()
	n := emptyNode(0, 32)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = insert(n, &testEntry{defaultHasher(i), i, i})
	}
}

func BenchmarkGet(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		get(n, defaultHasher(i), i)
	}
}

func BenchmarkRemove(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = remove(n, defaultHasher(i), i)
	}
}

func BenchmarkUpdate(b *testing.B) {
	b.ReportAllocs()
	n := insertTest(nil, defaultHasher, b.N)
	b.ResetTimer()
	for i := b.N; i > 0; i-- {
		n = insert(n, &testEntry{defaultHasher(i), i, -i})
	}
}
<|endoftext|>


<commit_before>package commands

import (
	"github.com/docker/machine/log"

	"github.com/codegangsta/cli"
)

func cmdRestart(c *cli.Context) {
	if err := runActionWithContext("restart", c); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Warning user that the active machine was restarted and may have a new IP<commit_after>package commands

import (
	"os"
	"strings"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/log"

	"github.com/codegangsta/cli"
)

func cmdRestart(c *cli.Context) {
	if err := runActionWithContext("restart", c); err != nil {
		log.Fatal(err)
	}

	warnIfActiveIPChanged(c)
}

func warnIfActiveIPChanged(c *cli.Context) {
	if activeInList(c.Args()) {
		activeURL := os.Getenv("DOCKER_HOST")
		log.Debugf("checking to see if active host's URL has changed from %s", activeURL)

		h := getActiveHost(c)
		u, err := h.GetURL()
		if err != nil {
			log.Fatal(err)
		}
		if activeURL != u {
			// TODO: hardcoded port here is a giant kludge...
			var swarmOpt string
			if strings.Contains(activeURL, ":3376") {
				swarmOpt = "--swarm "
			}
			log.Warnf("Active machine was restarted, and has a new IP address.\nRun 'eval \"$(docker-machine env %s%s)\"' again.", swarmOpt, h.Name)
		}
	}
}

func activeInList(machines []string) bool {
	active := os.Getenv("DOCKER_MACHINE_NAME")
	return active != "" && inArray(active, machines)
}

func getActiveHost(c *cli.Context) *libmachine.Host {
	certInfo := getCertPathInfo(c)
	store, err := getDefaultStore(
		c.GlobalString("storage-path"),
		certInfo.CaCertPath,
		certInfo.CaKeyPath,
	)
	if err != nil {
		log.Fatal(err)
	}
	active, err := store.GetActive()
	if err != nil {
		log.Fatal(err)
	}
	return active
}

func inArray(s string, a []string) bool {
	for _, cur := range a {
		if cur == s {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"

	"github.com/BurntSushi/toml"
	"github.com/spf13/cobra"
)

var (
	// Version is the current version of the devopsdays-cli tool. Unless set elsehwere, it is referred to as "master"
	Version = "master"
	// Build is the current build of the devopsdays-cli tool.
	// @todo The Build variable in cmd/version.go needs to be set somewhere.
	Build string
)

func init() {
	showCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of devopsdays-cli",
	Long:  `All software has versions. This is ours.`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("devopsdays-cli version: ", Version)
		fmt.Println("devopsdays-cli build: ", Build)
		fmt.Println("hugo version: ", getHugoVersion())
		fmt.Println("devopsdays-theme version: ", getThemeVersion())
	},
}

func getHugoVersion() (hugoVersion string) {
	out, err := exec.Command("hugo", "version").Output()
	if err != nil {
		log.Fatal(err)
	}
	s := string(out[:])
	re := regexp.MustCompile("v....")
	hugoVersion = re.FindString(s)
	return
}

func getThemeVersion() (themeVersion string) {
	var theme Theme
	themePath := filepath.Join(webdir, "themes", "devopsdays-theme", "theme.toml")
	if _, err := toml.DecodeFile(themePath, &theme); err != nil {
		fmt.Println(err)
		return
	}
	themeVersion = theme.Version
	return

}

// Theme represents the currently installed devopsdays-theme Hugo theme.
// The field Version represents the current version.
type Theme struct {
	Version string `toml:"theme_version"`
}
<commit_msg>Fix typo<commit_after>package commands

import (
	"fmt"
	"log"
	"os/exec"
	"path/filepath"
	"regexp"

	"github.com/BurntSushi/toml"
	"github.com/spf13/cobra"
)

var (
	// Version is the current version of the devopsdays-cli tool. Unless set elsewhere, it is referred to as "master"
	Version = "master"
	// Build is the current build of the devopsdays-cli tool.
	// @todo The Build variable in cmd/version.go needs to be set somewhere.
	Build string
)

func init() {
	showCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of devopsdays-cli",
	Long:  `All software has versions. This is ours.`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("devopsdays-cli version: ", Version)
		fmt.Println("devopsdays-cli build: ", Build)
		fmt.Println("hugo version: ", getHugoVersion())
		fmt.Println("devopsdays-theme version: ", getThemeVersion())
	},
}

func getHugoVersion() (hugoVersion string) {
	out, err := exec.Command("hugo", "version").Output()
	if err != nil {
		log.Fatal(err)
	}
	s := string(out[:])
	re := regexp.MustCompile("v....")
	hugoVersion = re.FindString(s)
	return
}

func getThemeVersion() (themeVersion string) {
	var theme Theme
	themePath := filepath.Join(webdir, "themes", "devopsdays-theme", "theme.toml")
	if _, err := toml.DecodeFile(themePath, &theme); err != nil {
		fmt.Println(err)
		return
	}
	themeVersion = theme.Version
	return

}

// Theme represents the currently installed devopsdays-theme Hugo theme.
// The field Version represents the current version.
type Theme struct {
	Version string `toml:"theme_version"`
}
<|endoftext|>


<commit_before>package commands

import (
	. "fmt"
)

const Version = "0.3.0"

type VersionCmdOpts struct { }

//Version command
func (opts *VersionCmdOpts) Execute(args []string) error {
	Println("docket version", Version)
	return nil
}
<commit_msg>Mark version 0.4.0<commit_after>package commands

import (
	. "fmt"
)

const Version = "0.4.0"

type VersionCmdOpts struct { }

//Version command
func (opts *VersionCmdOpts) Execute(args []string) error {
	Println("docket version", Version)
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 tsuru-client 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 installer

import (
	"fmt"
	"strconv"

	"github.com/docker/docker/api/types/swarm"
	"github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru-client/tsuru/installer/dm"
	"github.com/tsuru/tsuru/iaas/dockermachine"
)

var swarmPort = 2377

type ServiceCluster interface {
	GetManager() *dockermachine.Machine
	ServiceExec(string, []string, docker.StartExecOptions) error
	CreateService(docker.CreateServiceOptions) error
	ServicesInfo() ([]ServiceInfo, error)
	ClusterInfo() ([]NodeInfo, error)
}

type SwarmCluster struct {
	Managers []*dockermachine.Machine
	Workers  []*dockermachine.Machine
}

func (c *SwarmCluster) dockerClient() (*docker.Client, error) {
	return getDockerClient(c.GetManager())
}

func (c *SwarmCluster) GetManager() *dockermachine.Machine {
	return c.Managers[0]
}

// NewSwarmCluster creates a Swarm Cluster using the first machine as a manager
// and the rest as workers and also creates an overlay network between the nodes.
func NewSwarmCluster(machines []*dockermachine.Machine) (*SwarmCluster, error) {
	managerDockerClient, err := getDockerClient(machines[0])
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve machine %s docker client: %s", machines[0].Host.Name, err)
	}
	err = initSwarm(managerDockerClient, fmt.Sprintf("%s:%d", dm.GetPrivateIP(machines[0]), swarmPort))
	if err != nil {
		return nil, fmt.Errorf("failed to init swarm: %s", err)
	}
	var managers []*dockermachine.Machine
	for i, m := range machines {
		managers = append(managers, m)
		if i == 0 {
			continue
		}
		dockerClient, err := getDockerClient(m)
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve machine %s docker client: %s", m.Host.Name, err)
		}
		err = joinSwarm(managerDockerClient, dockerClient)
		if err != nil {
			return nil, fmt.Errorf("machine %s failed to join swarm: %s", m.Host.Name, err)
		}
	}
	return &SwarmCluster{
		Managers: managers,
		Workers:  machines,
	}, nil
}

func initSwarm(client *docker.Client, addr string) error {
	_, err := client.InitSwarm(docker.InitSwarmOptions{
		InitRequest: swarm.InitRequest{
			ListenAddr:    fmt.Sprintf("0.0.0.0:%d", swarmPort),
			AdvertiseAddr: addr,
		},
	})
	if err != nil && errors.Cause(err) != docker.ErrNodeAlreadyInSwarm {
		return errors.WithStack(err)
	}
	return nil
}

func joinSwarm(existingClient *docker.Client, newClient *docker.Client) error {
	swarmInfo, err := existingClient.InspectSwarm(nil)
	if err != nil {
		return errors.WithStack(err)
	}
	dockerInfo, err := existingClient.Info()
	if err != nil {
		return errors.WithStack(err)
	}
	if len(dockerInfo.Swarm.RemoteManagers) == 0 {
		return errors.Errorf("no remote managers found in node %#v", dockerInfo)
	}
	addrs := make([]string, len(dockerInfo.Swarm.RemoteManagers))
	for i, peer := range dockerInfo.Swarm.RemoteManagers {
		addrs[i] = peer.Addr
	}
	opts := docker.JoinSwarmOptions{
		JoinRequest: swarm.JoinRequest{
			ListenAddr:  fmt.Sprintf("0.0.0.0:%d", swarmPort),
			JoinToken:   swarmInfo.JoinTokens.Manager,
			RemoteAddrs: addrs,
		},
	}
	err = newClient.JoinSwarm(opts)
	if err != nil {
		if err == docker.ErrNodeAlreadyInSwarm {
			return nil
		}
		return errors.WithStack(err)
	}
	return nil
}

// ServiceExec finds a container running a service task and runs exec on it
func (c *SwarmCluster) ServiceExec(service string, cmd []string, startOpts docker.StartExecOptions) error {
	mClient, err := c.dockerClient()
	if err != nil {
		return fmt.Errorf("failed to retrive swarm docker client: %s", err)
	}
	tasks, err := mClient.ListTasks(docker.ListTasksOptions{
		Filters: map[string][]string{
			"service":       {service},
			"desired-state": {"running"},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to list tasks for service %s: %s", service, err)
	}
	if len(tasks) == 0 {
		return fmt.Errorf("no running task found for service %s", service)
	}
	node, err := mClient.InspectNode(tasks[0].NodeID)
	if err != nil {
		return fmt.Errorf("failed to inspect node %s: %s", tasks[0].NodeID, err)
	}
	nodeName := node.Description.Hostname
	var machine *dockermachine.Machine
	for _, m := range c.Workers {
		if m.Host.Name == nodeName {
			machine = m
			break
		}
	}
	if machine == nil {
		return fmt.Errorf("machine %s not found", nodeName)
	}
	client, err := getDockerClient(machine)
	if err != nil {
		return fmt.Errorf("failed to retrieve task node %s docker client: %s", machine.Host.Name, err)
	}
	container := tasks[0].Status.ContainerStatus.ContainerID
	exec, err := client.CreateExec(docker.CreateExecOptions{
		Cmd:          cmd,
		AttachStdout: true,
		AttachStderr: true,
		AttachStdin:  true,
		Container:    container,
	})
	if err != nil {
		return fmt.Errorf("failed to exec in task container %s: %s", container, err)
	}
	return client.StartExec(exec.ID, startOpts)
}

// CreateService creates a service on the swarm cluster
func (c *SwarmCluster) CreateService(opts docker.CreateServiceOptions) error {
	client, err := c.dockerClient()
	if err != nil {
		return err
	}
	_, err = client.CreateService(opts)
	return err
}

type NodeInfo struct {
	IP      string
	State   string
	Manager bool
}

func (c *SwarmCluster) ClusterInfo() ([]NodeInfo, error) {
	client, err := c.dockerClient()
	if err != nil {
		return nil, err
	}
	nodes, err := client.ListNodes(docker.ListNodesOptions{})
	if err != nil {
		return nil, err
	}
	var infos []NodeInfo
	for _, n := range nodes {
		var ip string
		m, err := c.GetMachine(n.Description.Hostname)
		if err != nil {
			ip = "???"
		} else {
			ip = m.Base.Address
		}
		infos = append(infos, NodeInfo{
			IP:      ip,
			State:   string(n.Status.State),
			Manager: n.ManagerStatus != nil,
		})
	}
	return infos, nil
}

// GetMachine retrieves a worker machine by its name
func (c *SwarmCluster) GetMachine(name string) (*dockermachine.Machine, error) {
	for _, m := range c.Workers {
		if m.Host.Name == name {
			return m, nil
		}
	}
	return nil, fmt.Errorf("machine %s not found", name)
}

type ServiceInfo struct {
	Name     string
	Replicas int
	Ports    []string
}

func (c *SwarmCluster) ServicesInfo() ([]ServiceInfo, error) {
	client, err := c.dockerClient()
	if err != nil {
		return nil, err
	}
	services, err := client.ListServices(docker.ListServicesOptions{})
	if err != nil {
		return nil, err
	}
	var infos []ServiceInfo
	for _, s := range services {
		var ports []string
		for _, p := range s.Endpoint.Ports {
			ports = append(ports, strconv.Itoa(int(p.PublishedPort)))
		}
		infos = append(infos, ServiceInfo{
			Name:     s.Spec.Name,
			Replicas: int(*s.Spec.Mode.Replicated.Replicas),
			Ports:    ports,
		})
	}
	return infos, nil
}

func getDockerClient(m *dockermachine.Machine) (*docker.Client, error) {
	return docker.NewTLSClientFromBytes(m.Base.FormatNodeAddress(),
		m.Base.ClientCert,
		m.Base.ClientKey,
		m.Base.CaCert,
	)
}
<commit_msg>tsuru/installer: fix metalinter warning about nil context<commit_after>// Copyright 2016 tsuru-client 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 installer

import (
	"context"
	"fmt"
	"strconv"

	"github.com/docker/docker/api/types/swarm"
	"github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru-client/tsuru/installer/dm"
	"github.com/tsuru/tsuru/iaas/dockermachine"
)

var swarmPort = 2377

type ServiceCluster interface {
	GetManager() *dockermachine.Machine
	ServiceExec(string, []string, docker.StartExecOptions) error
	CreateService(docker.CreateServiceOptions) error
	ServicesInfo() ([]ServiceInfo, error)
	ClusterInfo() ([]NodeInfo, error)
}

type SwarmCluster struct {
	Managers []*dockermachine.Machine
	Workers  []*dockermachine.Machine
}

func (c *SwarmCluster) dockerClient() (*docker.Client, error) {
	return getDockerClient(c.GetManager())
}

func (c *SwarmCluster) GetManager() *dockermachine.Machine {
	return c.Managers[0]
}

// NewSwarmCluster creates a Swarm Cluster using the first machine as a manager
// and the rest as workers and also creates an overlay network between the nodes.
func NewSwarmCluster(machines []*dockermachine.Machine) (*SwarmCluster, error) {
	managerDockerClient, err := getDockerClient(machines[0])
	if err != nil {
		return nil, fmt.Errorf("failed to retrieve machine %s docker client: %s", machines[0].Host.Name, err)
	}
	err = initSwarm(managerDockerClient, fmt.Sprintf("%s:%d", dm.GetPrivateIP(machines[0]), swarmPort))
	if err != nil {
		return nil, fmt.Errorf("failed to init swarm: %s", err)
	}
	var managers []*dockermachine.Machine
	for i, m := range machines {
		managers = append(managers, m)
		if i == 0 {
			continue
		}
		dockerClient, err := getDockerClient(m)
		if err != nil {
			return nil, fmt.Errorf("failed to retrieve machine %s docker client: %s", m.Host.Name, err)
		}
		err = joinSwarm(managerDockerClient, dockerClient)
		if err != nil {
			return nil, fmt.Errorf("machine %s failed to join swarm: %s", m.Host.Name, err)
		}
	}
	return &SwarmCluster{
		Managers: managers,
		Workers:  machines,
	}, nil
}

func initSwarm(client *docker.Client, addr string) error {
	_, err := client.InitSwarm(docker.InitSwarmOptions{
		InitRequest: swarm.InitRequest{
			ListenAddr:    fmt.Sprintf("0.0.0.0:%d", swarmPort),
			AdvertiseAddr: addr,
		},
	})
	if err != nil && errors.Cause(err) != docker.ErrNodeAlreadyInSwarm {
		return errors.WithStack(err)
	}
	return nil
}

func joinSwarm(existingClient *docker.Client, newClient *docker.Client) error {
	swarmInfo, err := existingClient.InspectSwarm(context.Background())
	if err != nil {
		return errors.WithStack(err)
	}
	dockerInfo, err := existingClient.Info()
	if err != nil {
		return errors.WithStack(err)
	}
	if len(dockerInfo.Swarm.RemoteManagers) == 0 {
		return errors.Errorf("no remote managers found in node %#v", dockerInfo)
	}
	addrs := make([]string, len(dockerInfo.Swarm.RemoteManagers))
	for i, peer := range dockerInfo.Swarm.RemoteManagers {
		addrs[i] = peer.Addr
	}
	opts := docker.JoinSwarmOptions{
		JoinRequest: swarm.JoinRequest{
			ListenAddr:  fmt.Sprintf("0.0.0.0:%d", swarmPort),
			JoinToken:   swarmInfo.JoinTokens.Manager,
			RemoteAddrs: addrs,
		},
	}
	err = newClient.JoinSwarm(opts)
	if err != nil {
		if err == docker.ErrNodeAlreadyInSwarm {
			return nil
		}
		return errors.WithStack(err)
	}
	return nil
}

// ServiceExec finds a container running a service task and runs exec on it
func (c *SwarmCluster) ServiceExec(service string, cmd []string, startOpts docker.StartExecOptions) error {
	mClient, err := c.dockerClient()
	if err != nil {
		return fmt.Errorf("failed to retrive swarm docker client: %s", err)
	}
	tasks, err := mClient.ListTasks(docker.ListTasksOptions{
		Filters: map[string][]string{
			"service":       {service},
			"desired-state": {"running"},
		},
	})
	if err != nil {
		return fmt.Errorf("failed to list tasks for service %s: %s", service, err)
	}
	if len(tasks) == 0 {
		return fmt.Errorf("no running task found for service %s", service)
	}
	node, err := mClient.InspectNode(tasks[0].NodeID)
	if err != nil {
		return fmt.Errorf("failed to inspect node %s: %s", tasks[0].NodeID, err)
	}
	nodeName := node.Description.Hostname
	var machine *dockermachine.Machine
	for _, m := range c.Workers {
		if m.Host.Name == nodeName {
			machine = m
			break
		}
	}
	if machine == nil {
		return fmt.Errorf("machine %s not found", nodeName)
	}
	client, err := getDockerClient(machine)
	if err != nil {
		return fmt.Errorf("failed to retrieve task node %s docker client: %s", machine.Host.Name, err)
	}
	container := tasks[0].Status.ContainerStatus.ContainerID
	exec, err := client.CreateExec(docker.CreateExecOptions{
		Cmd:          cmd,
		AttachStdout: true,
		AttachStderr: true,
		AttachStdin:  true,
		Container:    container,
	})
	if err != nil {
		return fmt.Errorf("failed to exec in task container %s: %s", container, err)
	}
	return client.StartExec(exec.ID, startOpts)
}

// CreateService creates a service on the swarm cluster
func (c *SwarmCluster) CreateService(opts docker.CreateServiceOptions) error {
	client, err := c.dockerClient()
	if err != nil {
		return err
	}
	_, err = client.CreateService(opts)
	return err
}

type NodeInfo struct {
	IP      string
	State   string
	Manager bool
}

func (c *SwarmCluster) ClusterInfo() ([]NodeInfo, error) {
	client, err := c.dockerClient()
	if err != nil {
		return nil, err
	}
	nodes, err := client.ListNodes(docker.ListNodesOptions{})
	if err != nil {
		return nil, err
	}
	var infos []NodeInfo
	for _, n := range nodes {
		var ip string
		m, err := c.GetMachine(n.Description.Hostname)
		if err != nil {
			ip = "???"
		} else {
			ip = m.Base.Address
		}
		infos = append(infos, NodeInfo{
			IP:      ip,
			State:   string(n.Status.State),
			Manager: n.ManagerStatus != nil,
		})
	}
	return infos, nil
}

// GetMachine retrieves a worker machine by its name
func (c *SwarmCluster) GetMachine(name string) (*dockermachine.Machine, error) {
	for _, m := range c.Workers {
		if m.Host.Name == name {
			return m, nil
		}
	}
	return nil, fmt.Errorf("machine %s not found", name)
}

type ServiceInfo struct {
	Name     string
	Replicas int
	Ports    []string
}

func (c *SwarmCluster) ServicesInfo() ([]ServiceInfo, error) {
	client, err := c.dockerClient()
	if err != nil {
		return nil, err
	}
	services, err := client.ListServices(docker.ListServicesOptions{})
	if err != nil {
		return nil, err
	}
	var infos []ServiceInfo
	for _, s := range services {
		var ports []string
		for _, p := range s.Endpoint.Ports {
			ports = append(ports, strconv.Itoa(int(p.PublishedPort)))
		}
		infos = append(infos, ServiceInfo{
			Name:     s.Spec.Name,
			Replicas: int(*s.Spec.Mode.Replicated.Replicas),
			Ports:    ports,
		})
	}
	return infos, nil
}

func getDockerClient(m *dockermachine.Machine) (*docker.Client, error) {
	return docker.NewTLSClientFromBytes(m.Base.FormatNodeAddress(),
		m.Base.ClientCert,
		m.Base.ClientKey,
		m.Base.CaCert,
	)
}
<|endoftext|>


<commit_before>package csv2lp

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// annotationComment describes CSV annotation
type annotationComment struct {
	// prefix in a CSV row that recognizes this annotation
	prefix string
	// flag is 0 to represent an annotation that is used for all data rows
	// or a unique bit (>0) between supported annotation prefixes
	flag uint8
	// setupColumn setups metadata that drives the way of how column data
	// are parsed, mandatory when flag > 0
	setupColumn func(column *CsvTableColumn, columnValue string)
	// setupColumn setups metadata that drives the way of how the table data
	// are parsed, mandatory when flag == 0
	setupTable func(table *CsvTable, row []string) error
}

// isTableAnnotation returns true for a table-wide annotation, false for column-based annotations
func (a annotationComment) isTableAnnotation() bool {
	return a.setupTable != nil
}

// matches tests whether an annotationComment can process the CSV comment row
func (a annotationComment) matches(comment string) bool {
	return strings.HasPrefix(strings.ToLower(comment), a.prefix)
}

// constantSetupTable setups the supplied CSV table from #constant annotation
func constantSetupTable(table *CsvTable, row []string) error {
	// adds a virtual column with contsant value to all data rows
	// supported types of constant annotation rows are:
	//  1. "#constant,datatype,label,defaultValue"
	//  2. "#constant,measurement,value"
	//  3. "#constant,dateTime,value"
	//  4. "#constant datatype,label,defaultValue"
	//  5. "#constant measurement,value"
	//  6. "#constant dateTime,value"
	// defaultValue is optional, additional columns are ignored
	col := CsvTableColumn{}
	col.Index = -1 // this is a virtual column that never extracts data from data rows
	// setup column data type
	col.setupDataType(row[0])
	var dataTypeIndex int
	if len(col.DataType) == 0 && col.LinePart == 0 {
		// type 1,2,3
		dataTypeIndex = 1
		if len(row) > 1 {
			col.setupDataType(row[1])
		}
	} else {
		// type 4,5,6
		dataTypeIndex = 0
	}
	// setup label if available
	if len(row) > dataTypeIndex+1 {
		col.Label = row[dataTypeIndex+1]
	}
	// setup defaultValue if available
	if len(row) > dataTypeIndex+2 {
		col.DefaultValue = row[dataTypeIndex+2]
	}
	// support type 2,3,5,6 syntax for measurement and timestamp
	if col.LinePart == linePartMeasurement || col.LinePart == linePartTime {
		if col.DefaultValue == "" && col.Label != "" {
			// type 2,3,5,6
			col.DefaultValue = col.Label
			col.Label = "#constant " + col.DataType
		} else if col.Label == "" {
			// setup a label if no label is supplied fo focused error messages
			col.Label = "#constant " + col.DataType
		}
	}
	// add a virtual column to the table
	table.extraColumns = append(table.extraColumns, &col)
	return nil
}

// supportedAnnotations contains all supported CSV annotations comments
var supportedAnnotations = []annotationComment{
	{
		prefix: "#group",
		flag:   1,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			if strings.HasSuffix(value, "true") {
				column.LinePart = linePartTag
			}
		},
	},
	{
		prefix: "#datatype",
		flag:   2,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			column.setupDataType(value)
		},
	},
	{
		prefix: "#default",
		flag:   4,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			column.DefaultValue = ignoreLeadingComment(value)
		},
	},
	{
		prefix:     "#constant",
		setupTable: constantSetupTable,
	},
	{
		prefix: "#timezone",
		setupTable: func(table *CsvTable, row []string) error {
			// setup timezone for parsing timestamps, UTC by default
			val := ignoreLeadingComment(row[0])
			if val == "" && len(row) > 1 {
				val = row[1] // #timezone,Local
			}
			tz, err := parseTimeZone(val)
			if err != nil {
				return fmt.Errorf("#timezone annotation: %v", err)
			}
			table.timeZone = tz
			return nil
		},
	},
}

// ignoreLeadingComment returns a value without '#anyComment ' prefix
func ignoreLeadingComment(value string) string {
	if len(value) > 0 && value[0] == '#' {
		pos := strings.Index(value, " ")
		if pos > 0 {
			return strings.TrimLeft(value[pos+1:], " ")
		}
		return ""
	}
	return value
}

// parseTimeZone parses the supplied timezone from a string into a time.Location
//
//  parseTimeZone("")      // time.UTC
//  parseTimeZone("local") // time.Local
//  parseTimeZone("-0500") // time.FixedZone(-5*3600 + 0*60)
//  parseTimeZone("+0200") // time.FixedZone(2*3600 + 0*60)
//  parseTimeZone("EST")   // time.LoadLocation("EST")
func parseTimeZone(val string) (*time.Location, error) {
	switch {
	case val == "":
		return time.UTC, nil
	case strings.ToLower(val) == "local":
		return time.Local, nil
	case val[0] == '-' || val[0] == '+':
		if matched, _ := regexp.MatchString("[+-][0-9][0-9][0-9][0-9]", val); !matched {
			return nil, fmt.Errorf("timezone '%s' is not  +hhmm or -hhmm", val)
		}
		intVal, _ := strconv.Atoi(val)
		offset := (intVal/100)*3600 + (intVal%100)*60
		return time.FixedZone(val, offset), nil
	default:
		return time.LoadLocation(val)
	}
}
<commit_msg>chore(pkg/csv2lp): repair doc<commit_after>package csv2lp

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// annotationComment describes CSV annotation
type annotationComment struct {
	// prefix in a CSV row that recognizes this annotation
	prefix string
	// flag is 0 to represent an annotation that is used for all data rows
	// or a unique bit (>0) between supported annotation prefixes
	flag uint8
	// setupColumn setups metadata that drives the way of how column data
	// are parsed, mandatory when flag > 0
	setupColumn func(column *CsvTableColumn, columnValue string)
	// setupTable setups metadata that drives the way of how the table data
	// are parsed, mandatory when flag == 0
	setupTable func(table *CsvTable, row []string) error
}

// isTableAnnotation returns true for a table-wide annotation, false for column-based annotations
func (a annotationComment) isTableAnnotation() bool {
	return a.setupTable != nil
}

// matches tests whether an annotationComment can process the CSV comment row
func (a annotationComment) matches(comment string) bool {
	return strings.HasPrefix(strings.ToLower(comment), a.prefix)
}

// constantSetupTable setups the supplied CSV table from #constant annotation
func constantSetupTable(table *CsvTable, row []string) error {
	// adds a virtual column with contsant value to all data rows
	// supported types of constant annotation rows are:
	//  1. "#constant,datatype,label,defaultValue"
	//  2. "#constant,measurement,value"
	//  3. "#constant,dateTime,value"
	//  4. "#constant datatype,label,defaultValue"
	//  5. "#constant measurement,value"
	//  6. "#constant dateTime,value"
	// defaultValue is optional, additional columns are ignored
	col := CsvTableColumn{}
	col.Index = -1 // this is a virtual column that never extracts data from data rows
	// setup column data type
	col.setupDataType(row[0])
	var dataTypeIndex int
	if len(col.DataType) == 0 && col.LinePart == 0 {
		// type 1,2,3
		dataTypeIndex = 1
		if len(row) > 1 {
			col.setupDataType(row[1])
		}
	} else {
		// type 4,5,6
		dataTypeIndex = 0
	}
	// setup label if available
	if len(row) > dataTypeIndex+1 {
		col.Label = row[dataTypeIndex+1]
	}
	// setup defaultValue if available
	if len(row) > dataTypeIndex+2 {
		col.DefaultValue = row[dataTypeIndex+2]
	}
	// support type 2,3,5,6 syntax for measurement and timestamp
	if col.LinePart == linePartMeasurement || col.LinePart == linePartTime {
		if col.DefaultValue == "" && col.Label != "" {
			// type 2,3,5,6
			col.DefaultValue = col.Label
			col.Label = "#constant " + col.DataType
		} else if col.Label == "" {
			// setup a label if no label is supplied fo focused error messages
			col.Label = "#constant " + col.DataType
		}
	}
	// add a virtual column to the table
	table.extraColumns = append(table.extraColumns, &col)
	return nil
}

// supportedAnnotations contains all supported CSV annotations comments
var supportedAnnotations = []annotationComment{
	{
		prefix: "#group",
		flag:   1,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			if strings.HasSuffix(value, "true") {
				column.LinePart = linePartTag
			}
		},
	},
	{
		prefix: "#datatype",
		flag:   2,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			column.setupDataType(value)
		},
	},
	{
		prefix: "#default",
		flag:   4,
		setupColumn: func(column *CsvTableColumn, value string) {
			// standard flux query result annotation
			column.DefaultValue = ignoreLeadingComment(value)
		},
	},
	{
		prefix:     "#constant",
		setupTable: constantSetupTable,
	},
	{
		prefix: "#timezone",
		setupTable: func(table *CsvTable, row []string) error {
			// setup timezone for parsing timestamps, UTC by default
			val := ignoreLeadingComment(row[0])
			if val == "" && len(row) > 1 {
				val = row[1] // #timezone,Local
			}
			tz, err := parseTimeZone(val)
			if err != nil {
				return fmt.Errorf("#timezone annotation: %v", err)
			}
			table.timeZone = tz
			return nil
		},
	},
}

// ignoreLeadingComment returns a value without '#anyComment ' prefix
func ignoreLeadingComment(value string) string {
	if len(value) > 0 && value[0] == '#' {
		pos := strings.Index(value, " ")
		if pos > 0 {
			return strings.TrimLeft(value[pos+1:], " ")
		}
		return ""
	}
	return value
}

// parseTimeZone parses the supplied timezone from a string into a time.Location
//
//  parseTimeZone("")      // time.UTC
//  parseTimeZone("local") // time.Local
//  parseTimeZone("-0500") // time.FixedZone(-5*3600 + 0*60)
//  parseTimeZone("+0200") // time.FixedZone(2*3600 + 0*60)
//  parseTimeZone("EST")   // time.LoadLocation("EST")
func parseTimeZone(val string) (*time.Location, error) {
	switch {
	case val == "":
		return time.UTC, nil
	case strings.ToLower(val) == "local":
		return time.Local, nil
	case val[0] == '-' || val[0] == '+':
		if matched, _ := regexp.MatchString("[+-][0-9][0-9][0-9][0-9]", val); !matched {
			return nil, fmt.Errorf("timezone '%s' is not  +hhmm or -hhmm", val)
		}
		intVal, _ := strconv.Atoi(val)
		offset := (intVal/100)*3600 + (intVal%100)*60
		return time.FixedZone(val, offset), nil
	default:
		return time.LoadLocation(val)
	}
}
<|endoftext|>