<commit_before>// Copyright 2015 The Vanadium 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 flow defines interfaces for the management of authenticated bidirectional byte Flows.
// TODO(suharshs): This is a work in progress and can change without notice.
//
// A Flow represents a flow-controlled authenticated byte stream between two endpoints.
//
// A Manager manages the creation of Flows and the re-use of network connections.
// A Manager can Dial out to a specific remote end to receive a Flow to that end.
// A Manager can Listen on multiple protocols and addresses. Listening
// causes the Manager to accept flows from any of the specified protocols and addresses.
// Additionally a Manager will accept incoming Dialed out connections for their lifetime.
package flow

import (
	"io"

	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/security"
)

// Manager is the interface for managing the creation of Flows.
type Manager interface {
	// Listen causes the Manager to accept flows from the provided protocol and address.
	// Listen may be called muliple times.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Listen(ctx *context.T, protocol, address string) error

	// ListeningEndpoints returns the endpoints that the Manager has explicitly
	// listened on. The Manager will accept new flows on these endpoints.
	// Returned endpoints all have a RoutingID unique to the Acceptor.
	ListeningEndpoints() []naming.Endpoint

	// Accept blocks until a new Flow has been initiated by a remote process.
	// Flows are accepted from addresses that the Manager is listening on,
	// including outgoing dialed connections.
	//
	// For example:
	//   err := m.Listen(ctx, "tcp", ":0")
	//   for {
	//     flow, err := m.Accept(ctx)
	//     // process flow
	//   }
	//
	// can be used to accept Flows initiated by remote processes.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Accept(ctx *context.T) (Flow, error)

	// Dial creates a Flow to the provided remote endpoint, using 'fn' to
	// determine the blessings that will be sent to the remote end.
	//
	// To maximize re-use of connections, the Manager will also Listen on Dialed
	// connections for the lifetime of the connection.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Dial(ctx *context.T, remote naming.Endpoint, fn BlessingsForPeer) (Flow, error)

	// Closed returns a channel that remains open for the lifetime of the Manager
	// object. Once the channel is closed any operations on the Manager will
	// necessarily fail.
	Closed() <-chan struct{}
}

// BlessingsForPeer is the type of a callback used in performing security
// authorization.  The remote end reveals its blessings first in the
// authorization protocol, so the callback should first authorize the remote
// blessings in the call.  Once authorized, the callback should return the
// blessings that will be revealed to the remote end.
type BlessingsForPeer func(ctx *context.T, call security.Call) (security.Blessings, error)

// Conn represents the connection onto which this flow is multiplexed.
// Since this Conn may be shared between many flows it wouldn't be safe
// to read and write to it directly.  We just provide some metadata.
type Conn interface {
	// LocalEndpoint returns the local vanadium Endpoint
	LocalEndpoint() naming.Endpoint
	// RemoteEndpoint returns the remote vanadium Endpoint
	RemoteEndpoint() naming.Endpoint
	// Closed returns a channel that remains open until the connection has been closed.
	Closed() <-chan struct{}
}

// MsgWriter defines and interface for writing messages.
type MsgWriter interface {
	// WriteMsg is like Write, but allows writing more than one buffer at a time.
	// The data in each buffer is written sequentially onto the flow.  Returns the
	// number of bytes written.  WriteMsg must return a non-nil error if it writes
	// less than the total number of bytes from all buffers.
	WriteMsg(data ...[]byte) (int, error)
}

// MsgReader defines an interface for reading messages.
type MsgReader interface {
	// ReadMsg is like read, but it reads bytes in chunks.  Depending on the
	// implementation the batch boundaries might or might not be significant.
	ReadMsg() ([]byte, error)
}

// MsgReadWriter combines the MsgReader and MsgWriter interfaces
type MsgReadWriter interface {
	MsgWriter
	MsgReader
}

// Flow is the interface for a flow-controlled channel multiplexed over a Conn.
type Flow interface {
	io.ReadWriter
	MsgReadWriter

	// WriteVAndClose performs WriteMsg and then closes the flow.
	WriteMsgAndClose(data ...[]byte) (int, error)

	// SetContext sets the context associated with the flow.  Typically this is
	// used to set state that is only available after the flow is connected, such
	// as a more restricted flow timeout, or the language of the request.
	//
	// The flow.Manager associated with ctx must be the same flow.Manager that the
	// flow was dialed or accepted from, otherwise an error is returned.
	SetContext(ctx *context.T) error

	// LocalBlessings returns the blessings presented by the local end of the flow
	// during authentication.
	LocalBlessings() security.Blessings
	// RemoteBlessings returns the blessings presented by the remote end of the
	// flow during authentication.
	RemoteBlessings() security.Blessings
	// LocalDischarges returns the discharges presented by the local end of the
	// flow during authentication.
	//
	// Discharges are organized in a map keyed by the discharge-identifier.
	LocalDischarges() map[string]security.Discharge
	// RemoteDischarges returns the discharges presented by the remote end of the
	// flow during authentication.
	//
	// Discharges are organized in a map keyed by the discharge-identifier.
	RemoteDischarges() map[string]security.Discharge

	// Conn returns the connection the flow is multiplexed on.
	Conn() Conn

	// Closed returns a channel that remains open until the flow has been closed or
	// the ctx to the Dial or Accept call used to create the flow has been cancelled.
	Closed() <-chan struct{}
}
<commit_msg>TBR: Fix spelling.<commit_after>// Copyright 2015 The Vanadium 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 flow defines interfaces for the management of authenticated bidirectional byte Flows.
// TODO(suharshs): This is a work in progress and can change without notice.
//
// A Flow represents a flow-controlled authenticated byte stream between two endpoints.
//
// A Manager manages the creation of Flows and the re-use of network connections.
// A Manager can Dial out to a specific remote end to receive a Flow to that end.
// A Manager can Listen on multiple protocols and addresses. Listening
// causes the Manager to accept flows from any of the specified protocols and addresses.
// Additionally a Manager will accept incoming Dialed out connections for their lifetime.
package flow

import (
	"io"

	"v.io/v23/context"
	"v.io/v23/naming"
	"v.io/v23/security"
)

// Manager is the interface for managing the creation of Flows.
type Manager interface {
	// Listen causes the Manager to accept flows from the provided protocol and address.
	// Listen may be called muliple times.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Listen(ctx *context.T, protocol, address string) error

	// ListeningEndpoints returns the endpoints that the Manager has explicitly
	// listened on. The Manager will accept new flows on these endpoints.
	// Returned endpoints all have a RoutingID unique to the Acceptor.
	ListeningEndpoints() []naming.Endpoint

	// Accept blocks until a new Flow has been initiated by a remote process.
	// Flows are accepted from addresses that the Manager is listening on,
	// including outgoing dialed connections.
	//
	// For example:
	//   err := m.Listen(ctx, "tcp", ":0")
	//   for {
	//     flow, err := m.Accept(ctx)
	//     // process flow
	//   }
	//
	// can be used to accept Flows initiated by remote processes.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Accept(ctx *context.T) (Flow, error)

	// Dial creates a Flow to the provided remote endpoint, using 'fn' to
	// determine the blessings that will be sent to the remote end.
	//
	// To maximize re-use of connections, the Manager will also Listen on Dialed
	// connections for the lifetime of the connection.
	//
	// The flow.Manager associated with ctx must be the receiver of the method,
	// otherwise an error is returned.
	Dial(ctx *context.T, remote naming.Endpoint, fn BlessingsForPeer) (Flow, error)

	// Closed returns a channel that remains open for the lifetime of the Manager
	// object. Once the channel is closed any operations on the Manager will
	// necessarily fail.
	Closed() <-chan struct{}
}

// BlessingsForPeer is the type of a callback used in performing security
// authorization.  The remote end reveals its blessings first in the
// authorization protocol, so the callback should first authorize the remote
// blessings in the call.  Once authorized, the callback should return the
// blessings that will be revealed to the remote end.
type BlessingsForPeer func(ctx *context.T, call security.Call) (security.Blessings, error)

// Conn represents the connection onto which this flow is multiplexed.
// Since this Conn may be shared between many flows it wouldn't be safe
// to read and write to it directly.  We just provide some metadata.
type Conn interface {
	// LocalEndpoint returns the local vanadium Endpoint
	LocalEndpoint() naming.Endpoint
	// RemoteEndpoint returns the remote vanadium Endpoint
	RemoteEndpoint() naming.Endpoint
	// Closed returns a channel that remains open until the connection has been closed.
	Closed() <-chan struct{}
}

// MsgWriter defines and interface for writing messages.
type MsgWriter interface {
	// WriteMsg is like Write, but allows writing more than one buffer at a time.
	// The data in each buffer is written sequentially onto the flow.  Returns the
	// number of bytes written.  WriteMsg must return a non-nil error if it writes
	// less than the total number of bytes from all buffers.
	WriteMsg(data ...[]byte) (int, error)
}

// MsgReader defines an interface for reading messages.
type MsgReader interface {
	// ReadMsg is like read, but it reads bytes in chunks.  Depending on the
	// implementation the batch boundaries might or might not be significant.
	ReadMsg() ([]byte, error)
}

// MsgReadWriter combines the MsgReader and MsgWriter interfaces
type MsgReadWriter interface {
	MsgWriter
	MsgReader
}

// Flow is the interface for a flow-controlled channel multiplexed over a Conn.
type Flow interface {
	io.ReadWriter
	MsgReadWriter

	// WriteMsgAndClose performs WriteMsg and then closes the flow.
	WriteMsgAndClose(data ...[]byte) (int, error)

	// SetContext sets the context associated with the flow.  Typically this is
	// used to set state that is only available after the flow is connected, such
	// as a more restricted flow timeout, or the language of the request.
	//
	// The flow.Manager associated with ctx must be the same flow.Manager that the
	// flow was dialed or accepted from, otherwise an error is returned.
	SetContext(ctx *context.T) error

	// LocalBlessings returns the blessings presented by the local end of the flow
	// during authentication.
	LocalBlessings() security.Blessings
	// RemoteBlessings returns the blessings presented by the remote end of the
	// flow during authentication.
	RemoteBlessings() security.Blessings
	// LocalDischarges returns the discharges presented by the local end of the
	// flow during authentication.
	//
	// Discharges are organized in a map keyed by the discharge-identifier.
	LocalDischarges() map[string]security.Discharge
	// RemoteDischarges returns the discharges presented by the remote end of the
	// flow during authentication.
	//
	// Discharges are organized in a map keyed by the discharge-identifier.
	RemoteDischarges() map[string]security.Discharge

	// Conn returns the connection the flow is multiplexed on.
	Conn() Conn

	// Closed returns a channel that remains open until the flow has been closed or
	// the ctx to the Dial or Accept call used to create the flow has been cancelled.
	Closed() <-chan struct{}
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/ddnsmanager/domain/dnsdomain"
	"github.com/webx-top/echo"
)

// step1. config.Commit()
// step2. domains, err := ParseDomain(conf *config.Config)
// step3. err = domains.Update()
// - step1. err = updater.Init(settings, domains)
// - step2. updater.Update(`A`, newIPv4) / updater.Update(`AAAA`, newIPv6)

func New() *Config {
	return &Config{
		IPv4: NewNetIPConfig(),
		IPv6: NewNetIPConfig(),
		NotifyTemplate: map[string]string{
			"html":     "",
			"markdown": "",
		},
		Interval: 5 * time.Minute,
	}
}

const (
	NotifyDisabled = 0
	NotifyIfError  = 1
	NotifyAll      = 2
)

type Config struct {
	Closed         bool
	IPv4           *NetIPConfig
	IPv6           *NetIPConfig
	DNSServices    []*DNSService
	DNSResolver    string            // example: 8.8.8.8
	NotifyMode     int               // 0-关闭通知; 1-仅仅出错时发送通知；2-发送全部通知
	NotifyTemplate map[string]string // 通知模板{html:"",markdown:""}
	Webhooks       []*Webhook
	Interval       time.Duration
}

var (
	_ echo.BinderKeyNormalizer = &Config{}
	_ echo.BeforeValidate      = &Config{}
	_ echo.AfterValidate       = &Config{}
)

func (c *Config) BinderKeyNormalizer(key string) string {
	return key
}

func (c *Config) BeforeValidate(ctx echo.Context) error {
	if c.IPv4.Enabled {
		switch c.IPv4.Type {
		case "netInterface":
			// if len(c.IPv4.NetInterface.Name) == 0 {
			// 	return errors.New(`请选择用于获取IPv4地址的网卡(如果没有出现选择项，说明不支持)`)
			// }
		case "cmd":
			if len(c.IPv4.CommandLine.Command) == 0 {
				return errors.New(`请输入用于获取IPv4地址的可执行命令`)
			}
		default:
			if len(c.IPv4.NetIPApiUrl) == 0 {
				return errors.New(`请输入用于获取IPv4地址的API接口网址`)
			}
		}
	}
	if c.IPv6.Enabled {
		switch c.IPv6.Type {
		case "netInterface":
			// if len(c.IPv6.NetInterface.Name) == 0 {
			// 	return errors.New(`请选择用于获取IPv6地址的网卡(如果没有出现选择项，说明不支持)`)
			// }
		case "cmd":
			if len(c.IPv6.CommandLine.Command) == 0 {
				return errors.New(`请输入用于获取IPv4地址的可执行命令`)
			}
		default:
			if len(c.IPv6.NetIPApiUrl) == 0 {
				return errors.New(`请输入用于获取IPv4地址的API接口网址`)
			}
		}
	}
	if !c.Closed {
		for _, dnsService := range c.DNSServices {
			if c.IPv4.Enabled {
				for _, domain := range dnsService.IPv4Domains {
					if domain == nil {
						continue
					}
					if len(domain.Domain) == 0 {
						return fmt.Errorf(`请设置“%s”的IPv4域名`, dnsService.Provider)
					}
				}
			}
			if c.IPv6.Enabled {
				for _, domain := range dnsService.IPv6Domains {
					if domain == nil {
						continue
					}
					if len(domain.Domain) == 0 {
						return fmt.Errorf(`请设置“%s”的IPv6域名`, dnsService.Provider)
					}
				}
			}
		}
	}
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		if err := webhook.validate(); err != nil {
			return err
		}
	}
	return nil
}

func (c *Config) AfterValidate(ctx echo.Context) error {
	return nil
}

func (c *Config) FindService(provider string) *DNSService {
	for _, dnsService := range c.DNSServices {
		if dnsService == nil {
			continue
		}
		if dnsService.Provider == provider {
			return dnsService
		}
	}
	return nil
}

func (c *Config) Commit() error {
	if err := c.IPv4.NetInterface.Filter.Init(); err != nil {
		return err
	}
	return c.IPv6.NetInterface.Filter.Init()
}

func (c *Config) IsValid() bool {
	if c.Closed {
		return false
	}
	if !c.IPv4.Enabled && !c.IPv6.Enabled {
		return false
	}
	for _, srv := range c.DNSServices {
		if srv == nil {
			continue
		}
		if srv.Enabled {
			if c.IPv4.Enabled && len(srv.IPv4Domains) > 0 {
				return true
			}
			if c.IPv6.Enabled && len(srv.IPv6Domains) > 0 {
				return true
			}
		}
	}
	return false
}

func (c *Config) HasWebhook() bool {
	if len(c.Webhooks) == 0 {
		return false
	}
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		return true
	}
	return false
}

func (c *Config) ExecWebhooks(tagValues *dnsdomain.TagValues) error {
	var retErr error
	var errs []string
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		err := webhook.Exec(tagValues)
		if err != nil {
			log.Error(err)
			errs = append(errs, err.Error())
		}
	}
	if len(errs) > 0 {
		retErr = errors.New(strings.Join(errs, "\n"))
	}
	return retErr
}
<commit_msg>update<commit_after>package config

import (
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/admpub/log"
	"github.com/admpub/nging/v3/application/library/ddnsmanager/domain/dnsdomain"
	"github.com/webx-top/echo"
)

// step1. config.Commit()
// step2. domains, err := ParseDomain(conf *config.Config)
// step3. err = domains.Update()
// - step1. err = updater.Init(settings, domains)
// - step2. updater.Update(`A`, newIPv4) / updater.Update(`AAAA`, newIPv6)

func New() *Config {
	return &Config{
		IPv4: NewNetIPConfig(),
		IPv6: NewNetIPConfig(),
		NotifyTemplate: map[string]string{
			"html":     "",
			"markdown": "",
		},
		Interval: 5 * time.Minute,
	}
}

const (
	NotifyDisabled = 0
	NotifyIfError  = 1
	NotifyAll      = 2
)

type Config struct {
	Closed         bool
	IPv4           *NetIPConfig
	IPv6           *NetIPConfig
	DNSServices    []*DNSService
	DNSResolver    string            // example: 8.8.8.8
	NotifyMode     int               // 0-关闭通知; 1-仅仅出错时发送通知；2-发送全部通知
	NotifyTemplate map[string]string // 通知模板{html:"",markdown:""}
	Webhooks       []*Webhook
	Interval       time.Duration
}

var (
	_ echo.BinderKeyNormalizer = &Config{}
	_ echo.BeforeValidate      = &Config{}
	_ echo.AfterValidate       = &Config{}
)

func (c *Config) BinderKeyNormalizer(key string) string {
	return key
}

func (c *Config) BeforeValidate(ctx echo.Context) error {
	if c.IPv4.Enabled {
		switch c.IPv4.Type {
		case "netInterface":
			if len(c.IPv4.NetInterface.Name) == 0 {
				return errors.New(`请选择用于获取IPv4地址的网卡(如果没有出现选择项，说明不支持)`)
			}
		case "cmd":
			if len(c.IPv4.CommandLine.Command) == 0 {
				return errors.New(`请输入用于获取IPv4地址的可执行命令`)
			}
		default:
			if len(c.IPv4.NetIPApiUrl) == 0 {
				return errors.New(`请输入用于获取IPv4地址的API接口网址`)
			}
		}
	}
	if c.IPv6.Enabled {
		switch c.IPv6.Type {
		case "netInterface":
			if len(c.IPv6.NetInterface.Name) == 0 {
				return errors.New(`请选择用于获取IPv6地址的网卡(如果没有出现选择项，说明不支持)`)
			}
		case "cmd":
			if len(c.IPv6.CommandLine.Command) == 0 {
				return errors.New(`请输入用于获取IPv4地址的可执行命令`)
			}
		default:
			if len(c.IPv6.NetIPApiUrl) == 0 {
				return errors.New(`请输入用于获取IPv4地址的API接口网址`)
			}
		}
	}
	if !c.Closed {
		for _, dnsService := range c.DNSServices {
			if c.IPv4.Enabled {
				for _, domain := range dnsService.IPv4Domains {
					if domain == nil {
						continue
					}
					if len(domain.Domain) == 0 {
						return fmt.Errorf(`请设置“%s”的IPv4域名`, dnsService.Provider)
					}
				}
			}
			if c.IPv6.Enabled {
				for _, domain := range dnsService.IPv6Domains {
					if domain == nil {
						continue
					}
					if len(domain.Domain) == 0 {
						return fmt.Errorf(`请设置“%s”的IPv6域名`, dnsService.Provider)
					}
				}
			}
		}
	}
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		if err := webhook.validate(); err != nil {
			return err
		}
	}
	return nil
}

func (c *Config) AfterValidate(ctx echo.Context) error {
	return nil
}

func (c *Config) FindService(provider string) *DNSService {
	for _, dnsService := range c.DNSServices {
		if dnsService == nil {
			continue
		}
		if dnsService.Provider == provider {
			return dnsService
		}
	}
	return nil
}

func (c *Config) Commit() error {
	if err := c.IPv4.NetInterface.Filter.Init(); err != nil {
		return err
	}
	return c.IPv6.NetInterface.Filter.Init()
}

func (c *Config) IsValid() bool {
	if c.Closed {
		return false
	}
	if !c.IPv4.Enabled && !c.IPv6.Enabled {
		return false
	}
	for _, srv := range c.DNSServices {
		if srv == nil {
			continue
		}
		if srv.Enabled {
			if c.IPv4.Enabled && len(srv.IPv4Domains) > 0 {
				return true
			}
			if c.IPv6.Enabled && len(srv.IPv6Domains) > 0 {
				return true
			}
		}
	}
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		if len(webhook.Url) > 0 {
			return true
		}
	}
	return false
}

func (c *Config) HasWebhook() bool {
	if len(c.Webhooks) == 0 {
		return false
	}
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		return true
	}
	return false
}

func (c *Config) ExecWebhooks(tagValues *dnsdomain.TagValues) error {
	var retErr error
	var errs []string
	for _, webhook := range c.Webhooks {
		if webhook == nil {
			continue
		}
		err := webhook.Exec(tagValues)
		if err != nil {
			log.Error(err)
			errs = append(errs, err.Error())
		}
	}
	if len(errs) > 0 {
		retErr = errors.New(strings.Join(errs, "\n"))
	}
	return retErr
}
<|endoftext|>


<commit_before>package fake

import (
	"errors"

	"github.com/pmorie/go-open-service-broker-client/v2"
)

// NewFakeClientFunc returns a v2.CreateFunc that returns a FakeClient with
// the given FakeClientConfiguration.  It is useful for injecting the
// FakeClient in code that uses the v2.CreateFunc interface.
func NewFakeClientFunc(config FakeClientConfiguration) v2.CreateFunc {
	return func(_ *v2.ClientConfiguration) (v2.Client, error) {
		return NewFakeClient(config), nil
	}
}

// ReturnFakeClientFunc returns a v2.CreateFunc that returns the given
// FakeClient.
func ReturnFakeClientFunc(c *FakeClient) v2.CreateFunc {
	return func(_ *v2.ClientConfiguration) (v2.Client, error) {
		return c, nil
	}
}

// NewFakeClient returns a new fake Client with the given
// FakeClientConfiguration.
func NewFakeClient(config FakeClientConfiguration) *FakeClient {
	return &FakeClient{
		CatalogReaction:           config.CatalogReaction,
		ProvisionReaction:         config.ProvisionReaction,
		UpdateInstanceReaction:    config.UpdateInstanceReaction,
		DeprovisionReaction:       config.DeprovisionReaction,
		PollLastOperationReaction: config.PollLastOperationReaction,
		BindReaction:              config.BindReaction,
		UnbindReaction:            config.UnbindReaction,
	}
}

// FakeClientConfiguration models the configuration of a FakeClient.
type FakeClientConfiguration struct {
	CatalogReaction           *CatalogReaction
	ProvisionReaction         *ProvisionReaction
	UpdateInstanceReaction    *UpdateInstanceReaction
	DeprovisionReaction       *DeprovisionReaction
	PollLastOperationReaction *PollLastOperationReaction
	BindReaction              *BindReaction
	UnbindReaction            *UnbindReaction
}

// FakeClient is a fake implementation of the v2.Client interface. It records
// the actions that are taken on it and runs the appropriate reaction to those
// actions. If an action for which there is no reaction specified occurs, it
// returns an error.
type FakeClient struct {
	CatalogReaction           *CatalogReaction
	ProvisionReaction         *ProvisionReaction
	UpdateInstanceReaction    *UpdateInstanceReaction
	DeprovisionReaction       *DeprovisionReaction
	PollLastOperationReaction *PollLastOperationReaction
	BindReaction              *BindReaction
	UnbindReaction            *UnbindReaction
	actions                   []Action
}

// Action is a record of a method call on the FakeClient.
type Action struct {
	Type    ActionType
	Request interface{}
}

// ActionType is a typedef over the set of actions that can be taken on a
// FakeClient.
type ActionType string

const (
	GetCatalog          ActionType = "GetCatalog"
	ProvisionInstance   ActionType = "ProvisionInstance"
	UpdateInstance      ActionType = "UpdateInstance"
	DeprovisionInstance ActionType = "DeprovisionInstance"
	PollLastOperation   ActionType = "PollLastOperation"
	Bind                ActionType = "Bind"
	Unbind              ActionType = "Unbind"
)

var _ v2.Client = &FakeClient{}

func (c *FakeClient) Actions() []Action {
	return c.actions
}

func (c *FakeClient) GetCatalog() (*v2.CatalogResponse, error) {
	c.actions = append(c.actions, Action{Type: GetCatalog})

	if c.CatalogReaction != nil {
		return c.CatalogReaction.Response, c.CatalogReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) ProvisionInstance(r *v2.ProvisionRequest) (*v2.ProvisionResponse, error) {
	c.actions = append(c.actions, Action{ProvisionInstance, r})

	if c.ProvisionReaction != nil {
		return c.ProvisionReaction.Response, c.ProvisionReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) UpdateInstance(r *v2.UpdateInstanceRequest) (*v2.UpdateInstanceResponse, error) {
	c.actions = append(c.actions, Action{UpdateInstance, r})

	if c.UpdateInstanceReaction != nil {
		return c.UpdateInstanceReaction.Response, c.UpdateInstanceReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) DeprovisionInstance(r *v2.DeprovisionRequest) (*v2.DeprovisionResponse, error) {
	c.actions = append(c.actions, Action{DeprovisionInstance, r})

	if c.DeprovisionReaction != nil {
		return c.DeprovisionReaction.Response, c.DeprovisionReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) PollLastOperation(r *v2.LastOperationRequest) (*v2.LastOperationResponse, error) {
	c.actions = append(c.actions, Action{PollLastOperation, r})

	if c.PollLastOperationReaction != nil {
		return c.PollLastOperationReaction.Response, c.PollLastOperationReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) Bind(r *v2.BindRequest) (*v2.BindResponse, error) {
	c.actions = append(c.actions, Action{Bind, r})

	if c.BindReaction != nil {
		return c.BindReaction.Response, c.BindReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) Unbind(r *v2.UnbindRequest) (*v2.UnbindResponse, error) {
	c.actions = append(c.actions, Action{Unbind, r})

	if c.UnbindReaction != nil {
		return c.UnbindReaction.Response, c.UnbindReaction.Error
	}

	return nil, UnexpectedActionError()
}

func UnexpectedActionError() error {
	return errors.New("Unexpected action")
}

type CatalogReaction struct {
	Response *v2.CatalogResponse
	Error    error
}

type ProvisionReaction struct {
	Response *v2.ProvisionResponse
	Error    error
}

type UpdateInstanceReaction struct {
	Response *v2.UpdateInstanceResponse
	Error    error
}

type DeprovisionReaction struct {
	Response *v2.DeprovisionResponse
	Error    error
}

type PollLastOperationReaction struct {
	Response *v2.LastOperationResponse
	Error    error
}

type BindReaction struct {
	Response *v2.BindResponse
	Error    error
}

type UnbindReaction struct {
	Response *v2.UnbindResponse
	Error    error
}
<commit_msg>Make fake client thread-safe (#35)<commit_after>package fake

import (
	"errors"
	"sync"

	"github.com/pmorie/go-open-service-broker-client/v2"
)

// NewFakeClientFunc returns a v2.CreateFunc that returns a FakeClient with
// the given FakeClientConfiguration.  It is useful for injecting the
// FakeClient in code that uses the v2.CreateFunc interface.
func NewFakeClientFunc(config FakeClientConfiguration) v2.CreateFunc {
	return func(_ *v2.ClientConfiguration) (v2.Client, error) {
		return NewFakeClient(config), nil
	}
}

// ReturnFakeClientFunc returns a v2.CreateFunc that returns the given
// FakeClient.
func ReturnFakeClientFunc(c *FakeClient) v2.CreateFunc {
	return func(_ *v2.ClientConfiguration) (v2.Client, error) {
		return c, nil
	}
}

// NewFakeClient returns a new fake Client with the given
// FakeClientConfiguration.
func NewFakeClient(config FakeClientConfiguration) *FakeClient {
	return &FakeClient{
		CatalogReaction:           config.CatalogReaction,
		ProvisionReaction:         config.ProvisionReaction,
		UpdateInstanceReaction:    config.UpdateInstanceReaction,
		DeprovisionReaction:       config.DeprovisionReaction,
		PollLastOperationReaction: config.PollLastOperationReaction,
		BindReaction:              config.BindReaction,
		UnbindReaction:            config.UnbindReaction,
	}
}

// FakeClientConfiguration models the configuration of a FakeClient.
type FakeClientConfiguration struct {
	CatalogReaction           *CatalogReaction
	ProvisionReaction         *ProvisionReaction
	UpdateInstanceReaction    *UpdateInstanceReaction
	DeprovisionReaction       *DeprovisionReaction
	PollLastOperationReaction *PollLastOperationReaction
	BindReaction              *BindReaction
	UnbindReaction            *UnbindReaction
}

// Action is a record of a method call on the FakeClient.
type Action struct {
	Type    ActionType
	Request interface{}
}

// ActionType is a typedef over the set of actions that can be taken on a
// FakeClient.
type ActionType string

const (
	GetCatalog          ActionType = "GetCatalog"
	ProvisionInstance   ActionType = "ProvisionInstance"
	UpdateInstance      ActionType = "UpdateInstance"
	DeprovisionInstance ActionType = "DeprovisionInstance"
	PollLastOperation   ActionType = "PollLastOperation"
	Bind                ActionType = "Bind"
	Unbind              ActionType = "Unbind"
)

// FakeClient is a fake implementation of the v2.Client interface. It records
// the actions that are taken on it and runs the appropriate reaction to those
// actions. If an action for which there is no reaction specified occurs, it
// returns an error.  FakeClient is threadsafe.
type FakeClient struct {
	CatalogReaction           *CatalogReaction
	ProvisionReaction         *ProvisionReaction
	UpdateInstanceReaction    *UpdateInstanceReaction
	DeprovisionReaction       *DeprovisionReaction
	PollLastOperationReaction *PollLastOperationReaction
	BindReaction              *BindReaction
	UnbindReaction            *UnbindReaction

	sync.Mutex
	actions []Action
}

var _ v2.Client = &FakeClient{}

func (c *FakeClient) Actions() []Action {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	return c.actions
}

func (c *FakeClient) GetCatalog() (*v2.CatalogResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{Type: GetCatalog})

	if c.CatalogReaction != nil {
		return c.CatalogReaction.Response, c.CatalogReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) ProvisionInstance(r *v2.ProvisionRequest) (*v2.ProvisionResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{ProvisionInstance, r})

	if c.ProvisionReaction != nil {
		return c.ProvisionReaction.Response, c.ProvisionReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) UpdateInstance(r *v2.UpdateInstanceRequest) (*v2.UpdateInstanceResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{UpdateInstance, r})

	if c.UpdateInstanceReaction != nil {
		return c.UpdateInstanceReaction.Response, c.UpdateInstanceReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) DeprovisionInstance(r *v2.DeprovisionRequest) (*v2.DeprovisionResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{DeprovisionInstance, r})

	if c.DeprovisionReaction != nil {
		return c.DeprovisionReaction.Response, c.DeprovisionReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) PollLastOperation(r *v2.LastOperationRequest) (*v2.LastOperationResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{PollLastOperation, r})

	if c.PollLastOperationReaction != nil {
		return c.PollLastOperationReaction.Response, c.PollLastOperationReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) Bind(r *v2.BindRequest) (*v2.BindResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{Bind, r})

	if c.BindReaction != nil {
		return c.BindReaction.Response, c.BindReaction.Error
	}

	return nil, UnexpectedActionError()
}

func (c *FakeClient) Unbind(r *v2.UnbindRequest) (*v2.UnbindResponse, error) {
	c.Mutex.Lock()
	defer c.Mutex.Unlock()

	c.actions = append(c.actions, Action{Unbind, r})

	if c.UnbindReaction != nil {
		return c.UnbindReaction.Response, c.UnbindReaction.Error
	}

	return nil, UnexpectedActionError()
}

func UnexpectedActionError() error {
	return errors.New("Unexpected action")
}

type CatalogReaction struct {
	Response *v2.CatalogResponse
	Error    error
}

type ProvisionReaction struct {
	Response *v2.ProvisionResponse
	Error    error
}

type UpdateInstanceReaction struct {
	Response *v2.UpdateInstanceResponse
	Error    error
}

type DeprovisionReaction struct {
	Response *v2.DeprovisionResponse
	Error    error
}

type PollLastOperationReaction struct {
	Response *v2.LastOperationResponse
	Error    error
}

type BindReaction struct {
	Response *v2.BindResponse
	Error    error
}

type UnbindReaction struct {
	Response *v2.UnbindResponse
	Error    error
}
<|endoftext|>


<commit_before>package frame

import (
	cv "github.com/glycerine/goconvey/convey"
	"testing"
	"time"
)

func TestParsingTMFRAME(t *testing.T) {
	cv.Convey("Given that we have a timestamp and a string message, we should be able to assemble and parse the TMFRAME message.", t, func() {

		tm := time.Now()
		msg := []byte("fake msg")
		pti := PtiUDE
		utyp := Utf8
		frame := NewFrame(tm, pti, utyp, 0, 0, msg)

		nano := tm.UnixNano()
		low3 := nano % 8

		cv.So(frame.Tm, cv.ShouldEqual, nano-low3)
		cv.So(string(frame.Data), cv.ShouldEqual, string(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(frame.Data))
		cv.So(frame.IsUser, cv.ShouldEqual, false)
		cv.So(frame.Pti, cv.ShouldEqual, PtiUDE)
		cv.So(frame.Prim, cv.ShouldEqual, frame.Tm|int64(pti))
		by, err := frame.Marshal(nil)
		panicOn(err)
		Q("by = '%v'", string(by))

		var frame2 Frame
		frame2.Unmarshal(by)
		cv.So(&frame2, cv.ShouldResemble, frame)

	})

	cv.Convey("We should be able to marshal and unmarshal User typed messages (q-bit == 1; type numbers < 0)", t, func() {

		tm := time.Now()
		msg := []byte("fake msg")
		pti := PtiUDE
		utyp := Evtnum(-34)
		frame := NewFrame(tm, pti, utyp, 0, 0, msg)

		nano := tm.UnixNano()
		low3 := nano % 8

		cv.So(frame.Tm, cv.ShouldEqual, nano-low3)
		cv.So(string(frame.Data), cv.ShouldEqual, string(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(frame.Data))
		cv.So(frame.IsUser, cv.ShouldEqual, true)
		cv.So(frame.Pti, cv.ShouldEqual, PtiUDE)
		cv.So(frame.Prim, cv.ShouldEqual, frame.Tm|int64(pti))
		by, err := frame.Marshal(nil)
		panicOn(err)
		Q("by = '%v'", string(by))

		var frame2 Frame
		frame2.Unmarshal(by)
		cv.So(&frame2, cv.ShouldResemble, frame)

	})

}
<commit_msg>atg. update test var names<commit_after>package frame

import (
	cv "github.com/glycerine/goconvey/convey"
	"testing"
	"time"
)

func TestParsingTMFRAME(t *testing.T) {
	cv.Convey("Given that we have a timestamp and a string message, we should be able to assemble and parse the TMFRAME message.", t, func() {

		tm := time.Now()
		msg := []byte("fake msg")
		pti := PtiUDE
		utyp := Utf8
		frame := NewFrame(tm, pti, utyp, 0, 0, msg)

		nano := tm.UnixNano()
		low3 := nano % 8

		cv.So(frame.Tm, cv.ShouldEqual, nano-low3)
		cv.So(string(frame.Data), cv.ShouldEqual, string(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(frame.Data))
		cv.So(frame.IsUser, cv.ShouldEqual, false)
		cv.So(frame.Pti, cv.ShouldEqual, PtiUDE)
		cv.So(frame.Prim, cv.ShouldEqual, frame.Tm|int64(pti))
		by, err := frame.Marshal(nil)
		panicOn(err)
		Q("by = '%v'", string(by))

		var frame2 Frame
		frame2.Unmarshal(by)
		cv.So(&frame2, cv.ShouldResemble, frame)

	})

	cv.Convey("We should be able to marshal and unmarshal User typed messages (q-bit == 1; with evnnum < 0)", t, func() {

		tm := time.Now()
		msg := []byte("fake msg")
		pti := PtiUDE
		evnum := Evtnum(-34)
		frame := NewFrame(tm, pti, evnum, 0, 0, msg)

		nano := tm.UnixNano()
		low3 := nano % 8

		cv.So(frame.Tm, cv.ShouldEqual, nano-low3)
		cv.So(string(frame.Data), cv.ShouldEqual, string(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(msg))
		cv.So(frame.Ulen, cv.ShouldEqual, len(frame.Data))
		cv.So(frame.IsUser, cv.ShouldEqual, true)
		cv.So(frame.Pti, cv.ShouldEqual, PtiUDE)
		cv.So(frame.Prim, cv.ShouldEqual, frame.Tm|int64(pti))
		by, err := frame.Marshal(nil)
		panicOn(err)
		Q("by = '%v'", string(by))

		var frame2 Frame
		frame2.Unmarshal(by)
		cv.So(&frame2, cv.ShouldResemble, frame)
		cv.So(frame2.Evnum, cv.ShouldEqual, -34)
		Q("frame2.Tm = %v", time.Unix(0, frame2.Tm))
		Q("tm = %v", tm)
	})

}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"
)

func LogInfo(msgid string, msgs ...interface{}) {
	logPrefix := time.Now().UTC().Format(time.RFC3339Nano) + " [" + msgid + "]"
	msgs = append([]interface{}{logPrefix}, msgs...)
	fmt.Println(msgs...)
}

func getStringFromEnv(key string) (string, error) {
	str := os.Getenv(envPrefix + key)
	if len(str) == 0 {
		return "", errors.New("Please add " + envPrefix + key + " to your environment")
	}
	return str, nil
}

func getBytesFromEnv(key string) ([]byte, error) {
	str, err := getStringFromEnv(key)
	if err != nil {
		return nil, err
	}
	return []byte(str), nil
}

func getIntFromEnv(key string) (int, error) {
	str, err := getStringFromEnv(key)
	if err != nil {
		return 0, err
	}
	i, err := strconv.Atoi(str)
	if err != nil {
		return 0, errors.New("Environment key " + envPrefix + key + " is not parseable as integer")
	}
	return i, nil
}

func getTranslation(language string, templateName string, key string) (string, error) {
	var foundLang, foundTemplate, foundKey bool
	if lang, foundLang := Translations[language]; foundLang {
		if tpl, foundTemplate := lang.(map[string]interface{})[templateName]; foundTemplate {
			if value, foundKey := tpl.(map[string]interface{})[key]; foundKey {
				return value.(string), nil
			}
		}
	}
	if foundKey == false {
		return "", errors.New("could not find key " + key + " in template " + templateName + " in language " + language)
	}
	if foundTemplate == false {
		return "", errors.New("could not find template " + templateName + " in language " + language)
	}
	if foundLang == false {
		return "", errors.New("could not find language " + language)
	}

	return "", errors.New("Unexpected exception")
}
<commit_msg>reorder error reporting<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"
)

func LogInfo(msgid string, msgs ...interface{}) {
	logPrefix := time.Now().UTC().Format(time.RFC3339Nano) + " [" + msgid + "]"
	msgs = append([]interface{}{logPrefix}, msgs...)
	fmt.Println(msgs...)
}

func getStringFromEnv(key string) (string, error) {
	str := os.Getenv(envPrefix + key)
	if len(str) == 0 {
		return "", errors.New("Please add " + envPrefix + key + " to your environment")
	}
	return str, nil
}

func getBytesFromEnv(key string) ([]byte, error) {
	str, err := getStringFromEnv(key)
	if err != nil {
		return nil, err
	}
	return []byte(str), nil
}

func getIntFromEnv(key string) (int, error) {
	str, err := getStringFromEnv(key)
	if err != nil {
		return 0, err
	}
	i, err := strconv.Atoi(str)
	if err != nil {
		return 0, errors.New("Environment key " + envPrefix + key + " is not parseable as integer")
	}
	return i, nil
}

func getTranslation(language string, templateName string, key string) (string, error) {
	var foundLang, foundTemplate, foundKey bool
	if lang, foundLang := Translations[language]; foundLang {
		if tpl, foundTemplate := lang.(map[string]interface{})[templateName]; foundTemplate {
			if value, foundKey := tpl.(map[string]interface{})[key]; foundKey {
				return value.(string), nil
			}
		}
	}
	if foundTemplate == false {
		return "", errors.New("could not find template " + templateName + " in language " + language)
	}
	if foundLang == false {
		return "", errors.New("could not find language " + language)
	}
	if foundKey == false {
		return "", errors.New("could not find key " + key + " in template " + templateName + " in language " + language)
	}

	return "", errors.New("Unexpected exception")
}
<|endoftext|>


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

package binary

import (
	"bytes"
	"os"
	"testing"
)

func testConstant(t *testing.T, w uint, max int) {
	var buf [MaxVarintLen64]byte
	n := PutUvarint(buf[:], 1<<w-1)
	if n != max {
		t.Errorf("MaxVarintLen%d = %d; want %d", w, max, n)
	}
}

func TestConstants(t *testing.T) {
	testConstant(t, 16, MaxVarintLen16)
	testConstant(t, 32, MaxVarintLen32)
	testConstant(t, 64, MaxVarintLen64)
}

func testVarint(t *testing.T, x int64) {
	var buf1 [10]byte
	n := PutVarint(buf1[:], x)
	y, m := Varint(buf1[0:n])
	if x != y {
		t.Errorf("Varint(%d): got %d", x, y)
	}
	if n != m {
		t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
	}

	var buf2 bytes.Buffer
	err := WriteVarint(&buf2, x)
	if err != nil {
		t.Errorf("WriteVarint(%d): %s", x, err)
	}
	if n != buf2.Len() {
		t.Errorf("WriteVarint(%d): got n = %d; want %d", x, buf2.Len(), n)
	}
	y, err = ReadVarint(&buf2)
	if err != nil {
		t.Errorf("ReadVarint(%d): %s", x, err)
	}
	if x != y {
		t.Errorf("ReadVarint(%d): got %d", x, y)
	}
}

func testUvarint(t *testing.T, x uint64) {
	var buf1 [10]byte
	n := PutUvarint(buf1[:], x)
	y, m := Uvarint(buf1[0:n])
	if x != y {
		t.Errorf("Uvarint(%d): got %d", x, y)
	}
	if n != m {
		t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
	}

	var buf2 bytes.Buffer
	err := WriteUvarint(&buf2, x)
	if err != nil {
		t.Errorf("WriteUvarint(%d): %s", x, err)
	}
	if n != buf2.Len() {
		t.Errorf("WriteUvarint(%d): got n = %d; want %d", x, buf2.Len(), n)
	}
	y, err = ReadUvarint(&buf2)
	if err != nil {
		t.Errorf("ReadUvarint(%d): %s", x, err)
	}
	if x != y {
		t.Errorf("ReadUvarint(%d): got %d", x, y)
	}
}

var tests = []int64{
	-1 << 63,
	-1<<63 + 1,
	-1,
	0,
	1,
	2,
	10,
	20,
	63,
	64,
	65,
	127,
	128,
	129,
	255,
	256,
	257,
	1<<63 - 1,
}

func TestVarint(t *testing.T) {
	for _, x := range tests {
		testVarint(t, x)
		testVarint(t, -x)
	}
	for x := int64(0x7); x != 0; x <<= 1 {
		testVarint(t, x)
		testVarint(t, -x)
	}
}

func TestUvarint(t *testing.T) {
	for _, x := range tests {
		testUvarint(t, uint64(x))
	}
	for x := uint64(0x7); x != 0; x <<= 1 {
		testUvarint(t, x)
	}
}

func TestBufferTooSmall(t *testing.T) {
	buf := []byte{0x80, 0x80, 0x80, 0x80}
	for i := 0; i <= len(buf); i++ {
		buf := buf[0:i]
		x, n := Uvarint(buf)
		if x != 0 || n != 0 {
			t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
		}

		x, err := ReadUvarint(bytes.NewBuffer(buf))
		if x != 0 || err != os.EOF {
			t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
		}
	}
}

func testOverflow(t *testing.T, buf []byte, n0 int, err0 os.Error) {
	x, n := Uvarint(buf)
	if x != 0 || n != n0 {
		t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
	}

	x, err := ReadUvarint(bytes.NewBuffer(buf))
	if x != 0 || err != err0 {
		t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
	}
}

func TestOverflow(t *testing.T) {
	testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, -10, overflow)
	testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, -13, overflow)
}

func TestNonCanonicalZero(t *testing.T) {
	buf := []byte{0x80, 0x80, 0x80, 0}
	x, n := Uvarint(buf)
	if x != 0 || n != 4 {
		t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, 4", buf, x, n)

	}
}
<commit_msg>encoding/binary: added benchmarks<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package binary

import (
	"bytes"
	"os"
	"testing"
)

func testConstant(t *testing.T, w uint, max int) {
	buf := make([]byte, MaxVarintLen64)
	n := PutUvarint(buf, 1<<w-1)
	if n != max {
		t.Errorf("MaxVarintLen%d = %d; want %d", w, max, n)
	}
}

func TestConstants(t *testing.T) {
	testConstant(t, 16, MaxVarintLen16)
	testConstant(t, 32, MaxVarintLen32)
	testConstant(t, 64, MaxVarintLen64)
}

func testVarint(t *testing.T, x int64) {
	buf1 := make([]byte, MaxVarintLen64)
	n := PutVarint(buf1[:], x)
	y, m := Varint(buf1[0:n])
	if x != y {
		t.Errorf("Varint(%d): got %d", x, y)
	}
	if n != m {
		t.Errorf("Varint(%d): got n = %d; want %d", x, m, n)
	}

	var buf2 bytes.Buffer
	err := WriteVarint(&buf2, x)
	if err != nil {
		t.Errorf("WriteVarint(%d): %s", x, err)
	}
	if n != buf2.Len() {
		t.Errorf("WriteVarint(%d): got n = %d; want %d", x, buf2.Len(), n)
	}
	y, err = ReadVarint(&buf2)
	if err != nil {
		t.Errorf("ReadVarint(%d): %s", x, err)
	}
	if x != y {
		t.Errorf("ReadVarint(%d): got %d", x, y)
	}
}

func testUvarint(t *testing.T, x uint64) {
	buf1 := make([]byte, MaxVarintLen64)
	n := PutUvarint(buf1[:], x)
	y, m := Uvarint(buf1[0:n])
	if x != y {
		t.Errorf("Uvarint(%d): got %d", x, y)
	}
	if n != m {
		t.Errorf("Uvarint(%d): got n = %d; want %d", x, m, n)
	}

	var buf2 bytes.Buffer
	err := WriteUvarint(&buf2, x)
	if err != nil {
		t.Errorf("WriteUvarint(%d): %s", x, err)
	}
	if n != buf2.Len() {
		t.Errorf("WriteUvarint(%d): got n = %d; want %d", x, buf2.Len(), n)
	}
	y, err = ReadUvarint(&buf2)
	if err != nil {
		t.Errorf("ReadUvarint(%d): %s", x, err)
	}
	if x != y {
		t.Errorf("ReadUvarint(%d): got %d", x, y)
	}
}

var tests = []int64{
	-1 << 63,
	-1<<63 + 1,
	-1,
	0,
	1,
	2,
	10,
	20,
	63,
	64,
	65,
	127,
	128,
	129,
	255,
	256,
	257,
	1<<63 - 1,
}

func TestVarint(t *testing.T) {
	for _, x := range tests {
		testVarint(t, x)
		testVarint(t, -x)
	}
	for x := int64(0x7); x != 0; x <<= 1 {
		testVarint(t, x)
		testVarint(t, -x)
	}
}

func TestUvarint(t *testing.T) {
	for _, x := range tests {
		testUvarint(t, uint64(x))
	}
	for x := uint64(0x7); x != 0; x <<= 1 {
		testUvarint(t, x)
	}
}

func TestBufferTooSmall(t *testing.T) {
	buf := []byte{0x80, 0x80, 0x80, 0x80}
	for i := 0; i <= len(buf); i++ {
		buf := buf[0:i]
		x, n := Uvarint(buf)
		if x != 0 || n != 0 {
			t.Errorf("Uvarint(%v): got x = %d, n = %d", buf, x, n)
		}

		x, err := ReadUvarint(bytes.NewBuffer(buf))
		if x != 0 || err != os.EOF {
			t.Errorf("ReadUvarint(%v): got x = %d, err = %s", buf, x, err)
		}
	}
}

func testOverflow(t *testing.T, buf []byte, n0 int, err0 os.Error) {
	x, n := Uvarint(buf)
	if x != 0 || n != n0 {
		t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, %d", buf, x, n, n0)
	}

	x, err := ReadUvarint(bytes.NewBuffer(buf))
	if x != 0 || err != err0 {
		t.Errorf("ReadUvarint(%v): got x = %d, err = %s; want 0, %s", buf, x, err, err0)
	}
}

func TestOverflow(t *testing.T) {
	testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x2}, -10, overflow)
	testOverflow(t, []byte{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1, 0, 0}, -13, overflow)
}

func TestNonCanonicalZero(t *testing.T) {
	buf := []byte{0x80, 0x80, 0x80, 0}
	x, n := Uvarint(buf)
	if x != 0 || n != 4 {
		t.Errorf("Uvarint(%v): got x = %d, n = %d; want 0, 4", buf, x, n)

	}
}

func BenchmarkPutUvarint32(b *testing.B) {
	buf := make([]byte, MaxVarintLen32)
	for i := 0; i < b.N; i++ {
		for j := uint(0); j < MaxVarintLen32; j++ {
			PutUvarint(buf, 1<<(j*7))
		}
	}
}

func BenchmarkPutUvarint64(b *testing.B) {
	buf := make([]byte, MaxVarintLen64)
	for i := 0; i < b.N; i++ {
		for j := uint(0); j < MaxVarintLen64; j++ {
			PutUvarint(buf, 1<<(j*7))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/PomeloCloud/BFTRaft4go/server"
	"github.com/PomeloCloud/BFTRaft4go/utils"
	"os"
	"time"
	"log"
)

func initDB(dbPath string) {
	if err := os.MkdirAll(dbPath, os.ModePerm); err != nil {
		panic(err)
	}
	server.InitDatabase(dbPath)
}

func getServer(dbPath string, addr string, bootstraps []string) *server.BFTRaftServer {
	initDB(dbPath)
	s, err := server.GetServer(server.Options{
		DBPath:           dbPath,
		Address:          addr,
		Bootstrap:        bootstraps,
		ConsensusTimeout: 1 * time.Minute,
	})

	if err != nil {
		panic(err)
	}
	return s
}

func main() {
	print("testing")
	args := os.Args
	cfgPath := args[1]
	log.Println(cfgPath)
	cfg := server.ReadConfigFile(cfgPath)
	os.RemoveAll(cfg.Db)
	defer os.RemoveAll(cfg.Db)
	println("start server", cfg.Address)
	s := getServer(cfg.Db, cfg.Address, cfg.Bootstraps)
	time.Sleep(1 * time.Second)
	s.StartServer()
	if len(cfg.Bootstraps) > 0 {
		time.Sleep(1 * time.Second)
		s.NodeJoin(utils.ALPHA_GROUP)
	}
	<-time.After(1 * time.Hour)
}
<commit_msg>stablize<commit_after>package main

import (
	"github.com/PomeloCloud/BFTRaft4go/server"
	"github.com/PomeloCloud/BFTRaft4go/utils"
	"os"
	"time"
	"log"
)

func initDB(dbPath string) {
	if err := os.MkdirAll(dbPath, os.ModePerm); err != nil {
		panic(err)
	}
	server.InitDatabase(dbPath)
}

func getServer(dbPath string, addr string, bootstraps []string) *server.BFTRaftServer {
	initDB(dbPath)
	s, err := server.GetServer(server.Options{
		DBPath:           dbPath,
		Address:          addr,
		Bootstrap:        bootstraps,
		ConsensusTimeout: 5 * time.Second,
	})

	if err != nil {
		panic(err)
	}
	return s
}

func main() {
	print("testing")
	args := os.Args
	cfgPath := args[1]
	log.Println(cfgPath)
	cfg := server.ReadConfigFile(cfgPath)
	os.RemoveAll(cfg.Db)
	defer os.RemoveAll(cfg.Db)
	println("start server", cfg.Address)
	s := getServer(cfg.Db, cfg.Address, cfg.Bootstraps)
	time.Sleep(1 * time.Second)
	s.StartServer()
	if len(cfg.Bootstraps) > 0 {
		time.Sleep(1 * time.Second)
		s.NodeJoin(utils.ALPHA_GROUP)
	}
	<-time.After(1 * time.Hour)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"winston"
)

type Index struct {
	Data map[string][]*winston.Winston
}

func (i *Index) update(w *winston.Winston) {
	for _, gram := range w.Grams {
		if i.Data[gram] == nil {
			i.Data[gram] = make([]*winston.Winston, 0)
		}

		index.Data[gram] = append(index.Data[gram], w)
	}
}

func add(website string) {
	var w winston.Winston
	w.Location = website
	w.FetchUrl(website)
	w.CalcGrams()
	winstons = append(winstons, w)

	index.update(&w)
}

func AddHandler(rw http.ResponseWriter, r *http.Request) {
	err := r.ParseForm()
	winston.CheckError(err)

	fmt.Println(r.Form)

	go add(r.Form["website"][0])

	http.Redirect(rw, r, "/", http.StatusFound)
}

type tv struct {
	Location string
	GramsLen int
}

type stv struct {
	Location string
	Score    int
}

func SearchHandler(rw http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/layout.html", "templates/search.html")
	winston.CheckError(err)

	stvs := make([]stv, 0)

	for k, v := range index.Data {
		if k == r.FormValue("query") {
			for _, w := range v {
				stvs = append(stvs, stv{w.Location, 1})
			}
		}
	}

	t.Execute(rw, stvs)
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/layout.html", "templates/index.html")
	winston.CheckError(err)

	tvs := make([]tv, 0)
	tvs = append(tvs, tv{"Index", len(index.Data)})

	for i := 0; i < len(winstons); i++ {
		tvs = append(tvs, tv{winstons[i].Location, len(winstons[i].Grams)})
	}

	t.Execute(w, tvs)
}

var winstons []winston.Winston
var index Index

func main() {
	winstons = make([]winston.Winston, 0)
	index.Data = make(map[string][]*winston.Winston)

	wd, err := os.Getwd()

	winston.CheckError(err)

	http.HandleFunc("/", IndexHandler)
	http.HandleFunc("/add", AddHandler)
	http.HandleFunc("/search", SearchHandler)
	http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir(wd+`/public`))))

	err = http.ListenAndServe(":9090", nil)
	winston.CheckError(err)
}
<commit_msg>moving things around<commit_after>package main

import (
	"html/template"
	"net/http"
	"os"
	"sir"
	"winston"
)

type tv struct {
	Location string
	GramsLen int
}

type stv struct {
	Location string
	Score    int
}

func AddHandler(w http.ResponseWriter, r *http.Request) {
	go winston.Add(r.FormValue("website"))
	http.Redirect(w, r, "/", http.StatusFound)
}

func SearchHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/layout.html", "templates/search.html")
	sir.CheckError(err)

	stvs := make([]stv, 0)

	for index, location := range winston.Query(r.FormValue("query")) {
		stvs = append(stvs, stv{location, index})
	}

	t.Execute(w, stvs)
}

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	t, err := template.ParseFiles("templates/layout.html", "templates/index.html")
	sir.CheckError(err)

	tvs := make([]tv, 0)
	tvs = append(tvs, tv{"Index", winston.IndexDataLen()})
	/*
		for i := 0; i < len(winston.Documents); i++ {
			tvs = append(tvs, tv{winstons[i].Location, len(winstons[i].Grams)})
		}
	*/
	t.Execute(w, tvs)
}

func main() {
	wd, err := os.Getwd()

	sir.CheckError(err)

	http.HandleFunc("/", IndexHandler)
	http.HandleFunc("/add", AddHandler)
	http.HandleFunc("/search", SearchHandler)
	http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir(wd+`/public`))))

	err = http.ListenAndServe(":9090", nil)
	sir.CheckError(err)
}
<|endoftext|>


<commit_before>package pigae

import (
	"fmt"
	"net/http"
	"strings"

	. "github.com/Deleplace/programming-idioms/pig"

	"github.com/gorilla/mux"

	"appengine"
)

//
// This file is about full text search of idioms and implementations.
//

// SearchResultsFacade is the facade for the Search Results page.
type SearchResultsFacade struct {
	PageMeta    PageMeta
	UserProfile UserProfile
	Q           string
	Results     []*Idiom
}

// User types terms, but it's important to recognize when a term is a language name.
func separateLangKeywords(terms []string) (words, langs []string) {
	words = make([]string, 0, len(terms))
	for _, term := range terms {
		lang := normLang(term)
		if lang == "" {
			words = append(words, term)
		} else {
			langs = append(langs, lang)
		}
	}
	return words, langs
}

// This is a "word by word" search, not a rdbms "like" filter
func search(w http.ResponseWriter, r *http.Request) error {
	vars := mux.Vars(r)

	userProfile := readUserProfile(r)

	c := appengine.NewContext(r)
	q := vars["q"]

	// This is a premature hack. TODO find a graceful way to handle "c++",
	// and stop confounding spaces and pluses.
	q = strings.Replace(q, "c++", "cpp", -1)
	q = strings.Replace(q, "C++", "cpp", -1)
	// TODO find a graceful way to handle "c#".

	terms := SplitForSearching(q, true)

	if len(terms) == 0 {
		// Search query is empty or illegible...
		redirURL := hostPrefix() + "/about#about-block-all-idioms"
		http.Redirect(w, r, redirURL, http.StatusFound)
		return nil
	}

	words, typedLangs := separateLangKeywords(terms)

	words = FilterStrings(words, func(chunk string) bool {
		// Small terms (1 or 2 chars) must be discarded,
		// because they weren't indexed in the first place.
		// (Words only, not language names.)
		return len(chunk) >= 3 || RegexpDigitsOnly.MatchString(chunk)
	})

	if len(words) == 0 {
		words, typedLangs = typedLangs, nil
	}

	numberMaxResults := 20
	hits, err := dao.searchIdiomsByWordsWithFavorites(c, words, typedLangs, userProfile.FavoriteLanguages, userProfile.SeeNonFavorite, numberMaxResults)
	if err != nil {
		return err
	}

	typedLangsSet := make(map[string]bool, len(typedLangs))
	for _, lang := range typedLangs {
		typedLangsSet[lang] = true
	}

	// Highlight matching impls :)
	matchingImplIDs, err := dao.searchImplIDs(c, words, typedLangs)
	if err != nil {
		return err
	}
	for _, idiom := range hits {
		implFavoriteLanguagesFirstWithOrder(idiom, userProfile.FavoriteLanguages, "", userProfile.SeeNonFavorite)
		for i := range idiom.Implementations {
			impl := &idiom.Implementations[i]
			implIDStr := fmt.Sprintf("%d", impl.Id)
			if matchingImplIDs[implIDStr] {
				impl.Deco.Matching = true
			}
			if typedLangsSet[impl.LanguageName] {
				impl.Deco.SearchedLang = true
			}
		}
	}

	normalizedQ := strings.Join(terms, " ")
	return listResults(w, r, normalizedQ, hits)
}

func listResults(w http.ResponseWriter, r *http.Request, q string, idioms []*Idiom) error {
	data := &SearchResultsFacade{
		PageMeta: PageMeta{
			PageTitle:   "Idioms for \"" + q + "\"",
			Toggles:     toggles,
			SearchQuery: q,
		},
		UserProfile: readUserProfile(r),
		Q:           q,
		Results:     idioms,
	}

	return templates.ExecuteTemplate(w, "page-list-results", data)
}

func searchRedirect(w http.ResponseWriter, r *http.Request) error {
	q := r.FormValue("q")
	if q == "" {
		// Small hack for own convenience: empty search -> homepage
		http.Redirect(w, r, "/", 301)
		return nil
	}
	q = strings.Replace(q, " ", "+", -1)

	http.Redirect(w, r, hostPrefix()+"/search/"+q, http.StatusMovedPermanently)
	return nil
}

func listByLanguage(w http.ResponseWriter, r *http.Request) error {
	vars := mux.Vars(r)

	userProfile := readUserProfile(r)

	c := appengine.NewContext(r)
	langsStr := vars["langs"]
	langs := strings.Split(langsStr, "_")
	langs = MapStrings(langs, normLang)
	langs = RemoveEmptyStrings(langs)

	numberMaxResults := 20
	hits, err := dao.searchIdiomsByLangs(c, langs, numberMaxResults)
	if err != nil {
		return err
	}

	for _, idiom := range hits {
		implFavoriteLanguagesFirstWithOrder(idiom, userProfile.FavoriteLanguages, "", userProfile.SeeNonFavorite)
	}

	niceLangs := MapStrings(langs, printNiceLang)
	return listResults(w, r, fmt.Sprintf("Language=%v", niceLangs), hits)
}
<commit_msg>Fix search: crash with too short terms.<commit_after>package pigae

import (
	"fmt"
	"net/http"
	"strings"

	. "github.com/Deleplace/programming-idioms/pig"

	"github.com/gorilla/mux"

	"appengine"
)

//
// This file is about full text search of idioms and implementations.
//

// SearchResultsFacade is the facade for the Search Results page.
type SearchResultsFacade struct {
	PageMeta    PageMeta
	UserProfile UserProfile
	Q           string
	Results     []*Idiom
}

// User types terms, but it's important to recognize when a term is a language name.
func separateLangKeywords(terms []string) (words, langs []string) {
	words = make([]string, 0, len(terms))
	for _, term := range terms {
		lang := normLang(term)
		if lang == "" {
			words = append(words, term)
		} else {
			langs = append(langs, lang)
		}
	}
	return words, langs
}

// This is a "word by word" search, not a rdbms "like" filter
func search(w http.ResponseWriter, r *http.Request) error {
	vars := mux.Vars(r)

	userProfile := readUserProfile(r)

	c := appengine.NewContext(r)
	q := vars["q"]

	// This is a premature hack. TODO find a graceful way to handle "c++",
	// and stop confounding spaces and pluses.
	q = strings.Replace(q, "c++", "cpp", -1)
	q = strings.Replace(q, "C++", "cpp", -1)
	// TODO find a graceful way to handle "c#".

	terms := SplitForSearching(q, true)

	words, typedLangs := separateLangKeywords(terms)

	words = FilterStrings(words, func(chunk string) bool {
		// Small terms (1 or 2 chars) must be discarded,
		// because they weren't indexed in the first place.
		// (Words only, not language names.)
		return len(chunk) >= 3 || RegexpDigitsOnly.MatchString(chunk)
	})

	if len(words)+len(typedLangs) == 0 {
		// Search query is empty or illegible...
		redirURL := hostPrefix() + "/about#about-block-all-idioms"
		http.Redirect(w, r, redirURL, http.StatusFound)
		return nil
	}

	if len(words) == 0 {
		words, typedLangs = typedLangs, nil
	}

	numberMaxResults := 20
	hits, err := dao.searchIdiomsByWordsWithFavorites(c, words, typedLangs, userProfile.FavoriteLanguages, userProfile.SeeNonFavorite, numberMaxResults)
	if err != nil {
		return err
	}

	typedLangsSet := make(map[string]bool, len(typedLangs))
	for _, lang := range typedLangs {
		typedLangsSet[lang] = true
	}

	// Highlight matching impls :)
	matchingImplIDs, err := dao.searchImplIDs(c, words, typedLangs)
	if err != nil {
		return err
	}
	for _, idiom := range hits {
		implFavoriteLanguagesFirstWithOrder(idiom, userProfile.FavoriteLanguages, "", userProfile.SeeNonFavorite)
		for i := range idiom.Implementations {
			impl := &idiom.Implementations[i]
			implIDStr := fmt.Sprintf("%d", impl.Id)
			if matchingImplIDs[implIDStr] {
				impl.Deco.Matching = true
			}
			if typedLangsSet[impl.LanguageName] {
				impl.Deco.SearchedLang = true
			}
		}
	}

	normalizedQ := strings.Join(terms, " ")
	return listResults(w, r, normalizedQ, hits)
}

func listResults(w http.ResponseWriter, r *http.Request, q string, idioms []*Idiom) error {
	data := &SearchResultsFacade{
		PageMeta: PageMeta{
			PageTitle:   "Idioms for \"" + q + "\"",
			Toggles:     toggles,
			SearchQuery: q,
		},
		UserProfile: readUserProfile(r),
		Q:           q,
		Results:     idioms,
	}

	return templates.ExecuteTemplate(w, "page-list-results", data)
}

func searchRedirect(w http.ResponseWriter, r *http.Request) error {
	q := r.FormValue("q")
	if q == "" {
		// Small hack for own convenience: empty search -> homepage
		http.Redirect(w, r, "/", 301)
		return nil
	}
	q = strings.Replace(q, " ", "+", -1)

	http.Redirect(w, r, hostPrefix()+"/search/"+q, http.StatusMovedPermanently)
	return nil
}

func listByLanguage(w http.ResponseWriter, r *http.Request) error {
	vars := mux.Vars(r)

	userProfile := readUserProfile(r)

	c := appengine.NewContext(r)
	langsStr := vars["langs"]
	langs := strings.Split(langsStr, "_")
	langs = MapStrings(langs, normLang)
	langs = RemoveEmptyStrings(langs)

	numberMaxResults := 20
	hits, err := dao.searchIdiomsByLangs(c, langs, numberMaxResults)
	if err != nil {
		return err
	}

	for _, idiom := range hits {
		implFavoriteLanguagesFirstWithOrder(idiom, userProfile.FavoriteLanguages, "", userProfile.SeeNonFavorite)
	}

	niceLangs := MapStrings(langs, printNiceLang)
	return listResults(w, r, fmt.Sprintf("Language=%v", niceLangs), hits)
}
<|endoftext|>


<commit_before>// Copyright 2018 Istio Authors. 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 checker

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
)

// IgnoreTestLinterData skips over unit tests
var IgnoreTestLinterData = true

// Check checks the list of files, and write to the given Report.
func Check(paths []string, factory RulesFactory, allowlist *Allowlist, report *Report) error {
	// Empty paths means current dir.
	if len(paths) == 0 {
		paths = []string{"."}
	}

	for _, path := range paths {
		if !filepath.IsAbs(path) {
			path, _ = filepath.Abs(path)
		}
		err := filepath.Walk(path, func(fpath string, info os.FileInfo, err error) error {
			if err != nil {
				return fmt.Errorf("pervent panic by handling failure accessing a path %q: %v", fpath, err)
			}
			rules := factory.GetRules(fpath, info)
			if len(rules) > 0 {
				fileCheck(fpath, rules, allowlist, report)
			}
			return nil
		})
		if err != nil {
			return fmt.Errorf("error visiting the path %q: %v", path, err)
		}
	}
	return nil
}

// fileCheck checks a file using the given rules, and write to the given Report.
func fileCheck(path string, rules []Rule, allowlist *Allowlist, report *Report) {
	// TODO: skip over linter tests in a principled manner for all linters
	if IgnoreTestLinterData && strings.Contains(path, "testlinter/testdata") {
		return
	}

	fs := token.NewFileSet()
	astFile, err := parser.ParseFile(fs, path, nil, parser.Mode(0))
	if err != nil {
		report.AddString(fmt.Sprintf("%v", err))
		return
	}
	v := FileVisitor{
		path:      path,
		rules:     rules,
		allowlist: allowlist,
		fileset:   fs,
		report:    report,
	}
	// Walk through the files
	ast.Walk(&v, astFile)
}

// FileVisitor visits the go file syntax tree and applies the given rules.
type FileVisitor struct {
	path      string
	rules     []Rule     // rules to check
	allowlist *Allowlist // rules to skip
	fileset   *token.FileSet
	report    *Report // report for linting process
}

// Visit checks each node and runs the applicable checks.
func (fv *FileVisitor) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		return nil
	}

	// ApplyRules applies rules to node and generate lint report.
	for _, rule := range fv.rules {
		if !fv.allowlist.Apply(fv.path, rule) {
			rule.Check(node, fv.fileset, fv.report)
		}
	}
	return fv
}
<commit_msg>Allow skipping envvarlinter for specific files (#1572)<commit_after>// Copyright 2018 Istio Authors. 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 checker

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"path/filepath"
	"strings"
)

// IgnoreTestLinterData skips over unit tests
var IgnoreTestLinterData = true

// Check checks the list of files, and write to the given Report.
func Check(paths []string, factory RulesFactory, allowlist *Allowlist, report *Report) error {
	// Empty paths means current dir.
	if len(paths) == 0 {
		paths = []string{"."}
	}

	for _, path := range paths {
		if !filepath.IsAbs(path) {
			path, _ = filepath.Abs(path)
		}
		err := filepath.Walk(path, func(fpath string, info os.FileInfo, err error) error {
			if err != nil {
				return fmt.Errorf("pervent panic by handling failure accessing a path %q: %v", fpath, err)
			}
			rules := factory.GetRules(fpath, info)
			if len(rules) > 0 {
				fileCheck(fpath, rules, allowlist, report)
			}
			return nil
		})
		if err != nil {
			return fmt.Errorf("error visiting the path %q: %v", path, err)
		}
	}
	return nil
}

// fileCheck checks a file using the given rules, and write to the given Report.
func fileCheck(path string, rules []Rule, allowlist *Allowlist, report *Report) {
	// TODO: skip over linter tests in a principled manner for all linters
	if IgnoreTestLinterData && strings.Contains(path, "testlinter/testdata") {
		return
	}

	fs := token.NewFileSet()
	astFile, err := parser.ParseFile(fs, path, nil, parser.ParseComments)
	if err != nil {
		report.AddString(fmt.Sprintf("%v", err))
		return
	}
	if skipFile(astFile) {
		return
	}
	v := FileVisitor{
		path:      path,
		rules:     rules,
		allowlist: allowlist,
		fileset:   fs,
		report:    report,
	}
	// Walk through the files
	ast.Walk(&v, astFile)
}

func skipFile(f *ast.File) bool {
	for _, c := range f.Comments {
		if strings.Contains(c.Text(), "nolint") && strings.Contains(c.Text(), "envvarlint") {
			return true
		}
	}
	return false
}

// FileVisitor visits the go file syntax tree and applies the given rules.
type FileVisitor struct {
	path      string
	rules     []Rule     // rules to check
	allowlist *Allowlist // rules to skip
	fileset   *token.FileSet
	report    *Report // report for linting process
}

// Visit checks each node and runs the applicable checks.
func (fv *FileVisitor) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		return nil
	}

	// ApplyRules applies rules to node and generate lint report.
	for _, rule := range fv.rules {
		if !fv.allowlist.Apply(fv.path, rule) {
			rule.Check(node, fv.fileset, fv.report)
		}
	}
	return fv
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package taint

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/spf13/cobra"
	"k8s.io/klog"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

// TaintOptions have the data required to perform the taint operation
type TaintOptions struct {
	PrintFlags *genericclioptions.PrintFlags
	ToPrinter  func(string) (printers.ResourcePrinter, error)

	resources      []string
	taintsToAdd    []v1.Taint
	taintsToRemove []v1.Taint
	builder        *resource.Builder
	selector       string
	overwrite      bool
	all            bool

	ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)

	genericclioptions.IOStreams
}

var (
	taintLong = templates.LongDesc(i18n.T(`
		Update the taints on one or more nodes.

		* A taint consists of a key, value, and effect. As an argument here, it is expressed as key=value:effect.
		* The key must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[1]d characters.
		* Optionally, the key can begin with a DNS subdomain prefix and a single '/', like example.com/my-app
		* The value is optional. If given, it must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[2]d characters.
		* The effect must be NoSchedule, PreferNoSchedule or NoExecute.
		* Currently taint can only apply to node.`))

	taintExample = templates.Examples(i18n.T(`
		# Update node 'foo' with a taint with key 'dedicated' and value 'special-user' and effect 'NoSchedule'.
		# If a taint with that key and effect already exists, its value is replaced as specified.
		kubectl taint nodes foo dedicated=special-user:NoSchedule

		# Remove from node 'foo' the taint with key 'dedicated' and effect 'NoSchedule' if one exists.
		kubectl taint nodes foo dedicated:NoSchedule-

		# Remove from node 'foo' all the taints with key 'dedicated'
		kubectl taint nodes foo dedicated-

		# Add a taint with key 'dedicated' on nodes having label mylabel=X
		kubectl taint node -l myLabel=X  dedicated=foo:PreferNoSchedule

		# Add to node 'foo' a taint with key 'bar' and no value
		kubectl taint nodes foo bar:NoSchedule`))
)

func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	options := &TaintOptions{
		PrintFlags: genericclioptions.NewPrintFlags("tainted").WithTypeSetter(scheme.Scheme),
		IOStreams:  streams,
	}

	validArgs := []string{"node"}

	cmd := &cobra.Command{
		Use:                   "taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Update the taints on one or more nodes"),
		Long:                  fmt.Sprintf(taintLong, validation.DNS1123SubdomainMaxLength, validation.LabelValueMaxLength),
		Example:               taintExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.Complete(f, cmd, args))
			cmdutil.CheckErr(options.Validate())
			cmdutil.CheckErr(options.RunTaint())
		},
		ValidArgs: validArgs,
	}

	options.PrintFlags.AddFlags(cmd)

	cmdutil.AddValidateFlags(cmd)
	cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
	cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.")
	cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all nodes in the cluster")
	return cmd
}

// Complete adapts from the command line args and factory to the data required.
func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
	namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	// retrieves resource and taint args from args
	// also checks args to verify that all resources are specified before taints
	taintArgs := []string{}
	metTaintArg := false
	for _, s := range args {
		isTaint := strings.Contains(s, "=") || strings.HasSuffix(s, "-")
		switch {
		case !metTaintArg && isTaint:
			metTaintArg = true
			fallthrough
		case metTaintArg && isTaint:
			taintArgs = append(taintArgs, s)
		case !metTaintArg && !isTaint:
			o.resources = append(o.resources, s)
		case metTaintArg && !isTaint:
			return fmt.Errorf("all resources must be specified before taint changes: %s", s)
		}
	}

	o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
		o.PrintFlags.NamePrintFlags.Operation = operation
		return o.PrintFlags.ToPrinter()
	}

	if len(o.resources) < 1 {
		return fmt.Errorf("one or more resources must be specified as <resource> <name>")
	}
	if len(taintArgs) < 1 {
		return fmt.Errorf("at least one taint update is required")
	}

	if o.taintsToAdd, o.taintsToRemove, err = parseTaints(taintArgs); err != nil {
		return cmdutil.UsageErrorf(cmd, err.Error())
	}
	o.builder = f.NewBuilder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace()
	if o.selector != "" {
		o.builder = o.builder.LabelSelectorParam(o.selector).ResourceTypes("node")
	}
	if o.all {
		o.builder = o.builder.SelectAllParam(o.all).ResourceTypes("node").Flatten().Latest()
	}
	if !o.all && o.selector == "" && len(o.resources) >= 2 {
		o.builder = o.builder.ResourceNames("node", o.resources[1:]...)
	}
	o.builder = o.builder.LabelSelectorParam(o.selector).
		Flatten().
		Latest()

	o.ClientForMapping = f.ClientForMapping
	return nil
}

// validateFlags checks for the validation of flags for kubectl taints.
func (o TaintOptions) validateFlags() error {
	// Cannot have a non-empty selector and all flag set. They are mutually exclusive.
	if o.all && o.selector != "" {
		return fmt.Errorf("setting 'all' parameter with a non empty selector is prohibited")
	}
	// If both selector and all are not set.
	if !o.all && o.selector == "" {
		if len(o.resources) < 2 {
			return fmt.Errorf("at least one resource name must be specified since 'all' parameter is not set")
		} else {
			return nil
		}
	}
	return nil
}

// Validate checks to the TaintOptions to see if there is sufficient information run the command.
func (o TaintOptions) Validate() error {
	resourceType := strings.ToLower(o.resources[0])
	validResources, isValidResource := []string{"node", "nodes"}, false
	for _, validResource := range validResources {
		if resourceType == validResource {
			isValidResource = true
			break
		}
	}
	if !isValidResource {
		return fmt.Errorf("invalid resource type %s, only %q are supported", o.resources[0], validResources)
	}

	// check the format of taint args and checks removed taints aren't in the new taints list
	var conflictTaints []string
	for _, taintAdd := range o.taintsToAdd {
		for _, taintRemove := range o.taintsToRemove {
			if taintAdd.Key != taintRemove.Key {
				continue
			}
			if len(taintRemove.Effect) == 0 || taintAdd.Effect == taintRemove.Effect {
				conflictTaint := fmt.Sprintf("{\"%s\":\"%s\"}", taintRemove.Key, taintRemove.Effect)
				conflictTaints = append(conflictTaints, conflictTaint)
			}
		}
	}
	if len(conflictTaints) > 0 {
		return fmt.Errorf("can not both modify and remove the following taint(s) in the same command: %s", strings.Join(conflictTaints, ", "))
	}
	return o.validateFlags()
}

// RunTaint does the work
func (o TaintOptions) RunTaint() error {
	r := o.builder.Do()
	if err := r.Err(); err != nil {
		return err
	}

	return r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		obj := info.Object
		name, namespace := info.Name, info.Namespace
		oldData, err := json.Marshal(obj)
		if err != nil {
			return err
		}
		operation, err := o.updateTaints(obj)
		if err != nil {
			return err
		}
		newData, err := json.Marshal(obj)
		if err != nil {
			return err
		}
		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
		createdPatch := err == nil
		if err != nil {
			klog.V(2).Infof("couldn't compute patch: %v", err)
		}

		mapping := info.ResourceMapping()
		client, err := o.ClientForMapping(mapping)
		if err != nil {
			return err
		}
		helper := resource.NewHelper(client, mapping)

		var outputObj runtime.Object
		if createdPatch {
			outputObj, err = helper.Patch(namespace, name, types.StrategicMergePatchType, patchBytes, nil)
		} else {
			outputObj, err = helper.Replace(namespace, name, false, obj)
		}
		if err != nil {
			return err
		}

		printer, err := o.ToPrinter(operation)
		if err != nil {
			return err
		}
		return printer.PrintObj(outputObj, o.Out)
	})
}

// updateTaints applies a taint option(o) to a node in cluster after computing the net effect of operation(i.e. does it result in an overwrite?), it reports back the end result in a way that user can easily interpret.
func (o TaintOptions) updateTaints(obj runtime.Object) (string, error) {
	node, ok := obj.(*v1.Node)
	if !ok {
		return "", fmt.Errorf("unexpected type %T, expected Node", obj)
	}
	if !o.overwrite {
		if exists := checkIfTaintsAlreadyExists(node.Spec.Taints, o.taintsToAdd); len(exists) != 0 {
			return "", fmt.Errorf("node %s already has %v taint(s) with same effect(s) and --overwrite is false", node.Name, exists)
		}
	}
	operation, newTaints, err := reorganizeTaints(node, o.overwrite, o.taintsToAdd, o.taintsToRemove)
	if err != nil {
		return "", err
	}
	node.Spec.Taints = newTaints
	return operation, nil
}
<commit_msg>Fix kubectl taint's Complete parsing<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package taint

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/spf13/cobra"
	"k8s.io/klog"

	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/meta"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/apimachinery/pkg/util/validation"
	"k8s.io/cli-runtime/pkg/genericclioptions"
	"k8s.io/cli-runtime/pkg/printers"
	"k8s.io/cli-runtime/pkg/resource"
	cmdutil "k8s.io/kubectl/pkg/cmd/util"
	"k8s.io/kubectl/pkg/scheme"
	"k8s.io/kubectl/pkg/util/i18n"
	"k8s.io/kubectl/pkg/util/templates"
)

// TaintOptions have the data required to perform the taint operation
type TaintOptions struct {
	PrintFlags *genericclioptions.PrintFlags
	ToPrinter  func(string) (printers.ResourcePrinter, error)

	resources      []string
	taintsToAdd    []v1.Taint
	taintsToRemove []v1.Taint
	builder        *resource.Builder
	selector       string
	overwrite      bool
	all            bool

	ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)

	genericclioptions.IOStreams
}

var (
	taintLong = templates.LongDesc(i18n.T(`
		Update the taints on one or more nodes.

		* A taint consists of a key, value, and effect. As an argument here, it is expressed as key=value:effect.
		* The key must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[1]d characters.
		* Optionally, the key can begin with a DNS subdomain prefix and a single '/', like example.com/my-app
		* The value is optional. If given, it must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to %[2]d characters.
		* The effect must be NoSchedule, PreferNoSchedule or NoExecute.
		* Currently taint can only apply to node.`))

	taintExample = templates.Examples(i18n.T(`
		# Update node 'foo' with a taint with key 'dedicated' and value 'special-user' and effect 'NoSchedule'.
		# If a taint with that key and effect already exists, its value is replaced as specified.
		kubectl taint nodes foo dedicated=special-user:NoSchedule

		# Remove from node 'foo' the taint with key 'dedicated' and effect 'NoSchedule' if one exists.
		kubectl taint nodes foo dedicated:NoSchedule-

		# Remove from node 'foo' all the taints with key 'dedicated'
		kubectl taint nodes foo dedicated-

		# Add a taint with key 'dedicated' on nodes having label mylabel=X
		kubectl taint node -l myLabel=X  dedicated=foo:PreferNoSchedule

		# Add to node 'foo' a taint with key 'bar' and no value
		kubectl taint nodes foo bar:NoSchedule`))
)

func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	options := &TaintOptions{
		PrintFlags: genericclioptions.NewPrintFlags("tainted").WithTypeSetter(scheme.Scheme),
		IOStreams:  streams,
	}

	validArgs := []string{"node"}

	cmd := &cobra.Command{
		Use:                   "taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Update the taints on one or more nodes"),
		Long:                  fmt.Sprintf(taintLong, validation.DNS1123SubdomainMaxLength, validation.LabelValueMaxLength),
		Example:               taintExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(options.Complete(f, cmd, args))
			cmdutil.CheckErr(options.Validate())
			cmdutil.CheckErr(options.RunTaint())
		},
		ValidArgs: validArgs,
	}

	options.PrintFlags.AddFlags(cmd)

	cmdutil.AddValidateFlags(cmd)
	cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
	cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.")
	cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all nodes in the cluster")
	return cmd
}

// Complete adapts from the command line args and factory to the data required.
func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) (err error) {
	namespace, _, err := f.ToRawKubeConfigLoader().Namespace()
	if err != nil {
		return err
	}

	// retrieves resource and taint args from args
	// also checks args to verify that all resources are specified before taints
	taintArgs := []string{}
	metTaintArg := false
	for _, s := range args {
		isTaint := strings.Contains(s, "=") || strings.Contains(s, ":") || strings.HasSuffix(s, "-")
		switch {
		case !metTaintArg && isTaint:
			metTaintArg = true
			fallthrough
		case metTaintArg && isTaint:
			taintArgs = append(taintArgs, s)
		case !metTaintArg && !isTaint:
			o.resources = append(o.resources, s)
		case metTaintArg && !isTaint:
			return fmt.Errorf("all resources must be specified before taint changes: %s", s)
		}
	}

	o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
		o.PrintFlags.NamePrintFlags.Operation = operation
		return o.PrintFlags.ToPrinter()
	}

	if len(o.resources) < 1 {
		return fmt.Errorf("one or more resources must be specified as <resource> <name>")
	}
	if len(taintArgs) < 1 {
		return fmt.Errorf("at least one taint update is required")
	}

	if o.taintsToAdd, o.taintsToRemove, err = parseTaints(taintArgs); err != nil {
		return cmdutil.UsageErrorf(cmd, err.Error())
	}
	o.builder = f.NewBuilder().
		WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
		ContinueOnError().
		NamespaceParam(namespace).DefaultNamespace()
	if o.selector != "" {
		o.builder = o.builder.LabelSelectorParam(o.selector).ResourceTypes("node")
	}
	if o.all {
		o.builder = o.builder.SelectAllParam(o.all).ResourceTypes("node").Flatten().Latest()
	}
	if !o.all && o.selector == "" && len(o.resources) >= 2 {
		o.builder = o.builder.ResourceNames("node", o.resources[1:]...)
	}
	o.builder = o.builder.LabelSelectorParam(o.selector).
		Flatten().
		Latest()

	o.ClientForMapping = f.ClientForMapping
	return nil
}

// validateFlags checks for the validation of flags for kubectl taints.
func (o TaintOptions) validateFlags() error {
	// Cannot have a non-empty selector and all flag set. They are mutually exclusive.
	if o.all && o.selector != "" {
		return fmt.Errorf("setting 'all' parameter with a non empty selector is prohibited")
	}
	// If both selector and all are not set.
	if !o.all && o.selector == "" {
		if len(o.resources) < 2 {
			return fmt.Errorf("at least one resource name must be specified since 'all' parameter is not set")
		} else {
			return nil
		}
	}
	return nil
}

// Validate checks to the TaintOptions to see if there is sufficient information run the command.
func (o TaintOptions) Validate() error {
	resourceType := strings.ToLower(o.resources[0])
	validResources, isValidResource := []string{"node", "nodes"}, false
	for _, validResource := range validResources {
		if resourceType == validResource {
			isValidResource = true
			break
		}
	}
	if !isValidResource {
		return fmt.Errorf("invalid resource type %s, only %q are supported", o.resources[0], validResources)
	}

	// check the format of taint args and checks removed taints aren't in the new taints list
	var conflictTaints []string
	for _, taintAdd := range o.taintsToAdd {
		for _, taintRemove := range o.taintsToRemove {
			if taintAdd.Key != taintRemove.Key {
				continue
			}
			if len(taintRemove.Effect) == 0 || taintAdd.Effect == taintRemove.Effect {
				conflictTaint := fmt.Sprintf("{\"%s\":\"%s\"}", taintRemove.Key, taintRemove.Effect)
				conflictTaints = append(conflictTaints, conflictTaint)
			}
		}
	}
	if len(conflictTaints) > 0 {
		return fmt.Errorf("can not both modify and remove the following taint(s) in the same command: %s", strings.Join(conflictTaints, ", "))
	}
	return o.validateFlags()
}

// RunTaint does the work
func (o TaintOptions) RunTaint() error {
	r := o.builder.Do()
	if err := r.Err(); err != nil {
		return err
	}

	return r.Visit(func(info *resource.Info, err error) error {
		if err != nil {
			return err
		}

		obj := info.Object
		name, namespace := info.Name, info.Namespace
		oldData, err := json.Marshal(obj)
		if err != nil {
			return err
		}
		operation, err := o.updateTaints(obj)
		if err != nil {
			return err
		}
		newData, err := json.Marshal(obj)
		if err != nil {
			return err
		}
		patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
		createdPatch := err == nil
		if err != nil {
			klog.V(2).Infof("couldn't compute patch: %v", err)
		}

		mapping := info.ResourceMapping()
		client, err := o.ClientForMapping(mapping)
		if err != nil {
			return err
		}
		helper := resource.NewHelper(client, mapping)

		var outputObj runtime.Object
		if createdPatch {
			outputObj, err = helper.Patch(namespace, name, types.StrategicMergePatchType, patchBytes, nil)
		} else {
			outputObj, err = helper.Replace(namespace, name, false, obj)
		}
		if err != nil {
			return err
		}

		printer, err := o.ToPrinter(operation)
		if err != nil {
			return err
		}
		return printer.PrintObj(outputObj, o.Out)
	})
}

// updateTaints applies a taint option(o) to a node in cluster after computing the net effect of operation(i.e. does it result in an overwrite?), it reports back the end result in a way that user can easily interpret.
func (o TaintOptions) updateTaints(obj runtime.Object) (string, error) {
	node, ok := obj.(*v1.Node)
	if !ok {
		return "", fmt.Errorf("unexpected type %T, expected Node", obj)
	}
	if !o.overwrite {
		if exists := checkIfTaintsAlreadyExists(node.Spec.Taints, o.taintsToAdd); len(exists) != 0 {
			return "", fmt.Errorf("node %s already has %v taint(s) with same effect(s) and --overwrite is false", node.Name, exists)
		}
	}
	operation, newTaints, err := reorganizeTaints(node, o.overwrite, o.taintsToAdd, o.taintsToRemove)
	if err != nil {
		return "", err
	}
	node.Spec.Taints = newTaints
	return operation, nil
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os/exec"
	"sync"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
)

var wgAll sync.WaitGroup

// WaitAll waits for all Commands to finish
func WaitAll() {
	wgAll.Wait()
}

type (
	// Command defines the interface for all shellouts
	Command interface {
		Stdout() io.Reader
		Stderr() io.Reader
		Stdin() io.Writer

		// Finish closes the Span
		//  Note, run this is you never get to Wait() (e.g. on `return err`)
		Finish()
		Wait() error
	}

	command struct {
		cmd    *exec.Cmd
		stdout io.ReadCloser
		stderr io.ReadCloser
		stdin  io.WriteCloser
		span   opentracing.Span
	}

	Option func(*command) error
)

// NewSimple is for when you would usually exec.Cmd.Run() something
func NewSimple(ctx context.Context, dir, name string, args ...string) (string, error) {
	buf := &bytes.Buffer{}
	cmd, err := New(ctx, dir, name, args, StdoutWriter(buf), StderrWriter(buf))
	if err != nil {
		return "", err
	}
	err = cmd.Wait()
	return buf.String(), err
}

// New creates a new Command
//  The caller is required to call Wait() or Finish() for the tracing to work
func New(ctx context.Context, dir, name string, args []string, opts ...Option) (Command, error) {
	// NOTE: This span is Finish()ed in Wait() or Finish()...
	span, ctx := opentracing.StartSpanFromContext(ctx, "command.New")
	span.SetTag("name", name)
	span.SetTag("args", fmt.Sprintf("%q", args))
	span.SetTag("dir", dir)
	cmd := &command{
		cmd: exec.CommandContext(ctx, name, args...),
	}
	cmd.cmd.Dir = dir
	// NOTE: GIT_DIR requires abolute paths, and `dir` can be relative for now...
	//cmd.cmd.Env = append(cmd.cmd.Env, fmt.Sprintf("GIT_DIR=%s", dir))

	for _, opt := range opts {
		if err := opt(cmd); err != nil {
			span.SetTag("error", true)
			span.LogKV("error", err)
			span.Finish()
			return nil, errors.Wrap(err, "StdoutPipe")
		}
	}

	wgAll.Add(1)
	cmd.span = span
	return cmd, cmd.cmd.Start()
}

func (c *command) Stdout() io.Reader {
	return c.stdout
}

func (c *command) Stderr() io.Reader {
	return c.stderr
}

func (c *command) Stdin() io.Writer {
	return c.stdin
}

// Finish ...
//  is idempotent
func (c *command) Finish() {
	if c.span == nil {
		return
	}
	c.span.Finish()
	wgAll.Done()
	c.span = nil
}

func (c *command) Wait() error {
	defer c.Finish()

	err := c.cmd.Wait()
	if err != nil {
		c.span.SetTag("error", true)
		c.span.LogKV("error", err)
	}
	return err
}
<commit_msg>document command.WaitAll()<commit_after>package command

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os/exec"
	"sync"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
)

var wgAll sync.WaitGroup

// WaitAll waits for all Commands to finish
// TODO: This waits for all commands to run to completion
//   This is so we don't kill any stray "git merge" or other
//   writing commands, which could leave things corrupt
func WaitAll() {
	wgAll.Wait()
}

type (
	// Command defines the interface for all shellouts
	Command interface {
		Stdout() io.Reader
		Stderr() io.Reader
		Stdin() io.Writer

		// Finish closes the Span
		//  Note, run this is you never get to Wait() (e.g. on `return err`)
		Finish()
		Wait() error
	}

	command struct {
		cmd    *exec.Cmd
		stdout io.ReadCloser
		stderr io.ReadCloser
		stdin  io.WriteCloser
		span   opentracing.Span
	}

	// Option ...
	Option func(*command) error
)

// NewSimple is for when you would usually exec.Cmd.Run() something
func NewSimple(ctx context.Context, dir, name string, args ...string) (string, error) {
	buf := &bytes.Buffer{}
	cmd, err := New(ctx, dir, name, args, StdoutWriter(buf), StderrWriter(buf))
	if err != nil {
		return "", err
	}
	err = cmd.Wait()
	return buf.String(), err
}

// New creates a new Command
//  The caller is required to call Wait() or Finish() for the tracing to work
func New(ctx context.Context, dir, name string, args []string, opts ...Option) (Command, error) {
	// NOTE: This span is Finish()ed in Wait() or Finish()...
	span, ctx := opentracing.StartSpanFromContext(ctx, "command.New")
	span.SetTag("name", name)
	span.SetTag("args", fmt.Sprintf("%q", args))
	span.SetTag("dir", dir)
	cmd := &command{
		cmd: exec.CommandContext(ctx, name, args...),
	}
	cmd.cmd.Dir = dir
	// NOTE: GIT_DIR requires abolute paths, and `dir` can be relative for now...
	//cmd.cmd.Env = append(cmd.cmd.Env, fmt.Sprintf("GIT_DIR=%s", dir))

	for _, opt := range opts {
		if err := opt(cmd); err != nil {
			span.SetTag("error", true)
			span.LogKV("error", err)
			span.Finish()
			return nil, errors.Wrap(err, "StdoutPipe")
		}
	}

	wgAll.Add(1)
	cmd.span = span
	return cmd, cmd.cmd.Start()
}

func (c *command) Stdout() io.Reader {
	return c.stdout
}

func (c *command) Stderr() io.Reader {
	return c.stderr
}

func (c *command) Stdin() io.Writer {
	return c.stdin
}

// Finish ...
//  is idempotent
func (c *command) Finish() {
	if c.span == nil {
		return
	}
	c.span.Finish()
	wgAll.Done()
	c.span = nil
}

func (c *command) Wait() error {
	defer c.Finish()

	err := c.cmd.Wait()
	if err != nil {
		c.span.SetTag("error", true)
		c.span.LogKV("error", err)
	}
	return err
}
<|endoftext|>