<commit_before>package player

import (
	"time"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/objects/snake"
	"github.com/ivan1993spb/snake-server/world"
)

const countdown = 5

const chanMessageBuffer = 16

const chanErrorBuffer = 32

type Player struct {
	world  *world.World
	logger logrus.FieldLogger
}

func NewPlayer(logger logrus.FieldLogger, world *world.World) *Player {
	return &Player{
		logger: logger,
		world:  world,
	}
}

func (p *Player) Start(stop <-chan struct{}, chin <-chan string) <-chan Message {
	chout := make(chan Message, chanMessageBuffer)
	localStopper := make(chan struct{})

	go func() {
		<-stop
		close(localStopper)
	}()

	go func() {
		defer close(chout)

		chout <- NewMessageNotice("welcome to snake server!")
		chout <- NewMessageSize(p.world.Width(), p.world.Height())
		chout <- NewMessageObjects(p.world.GetObjects())

		for {
			chout <- NewMessageCountdown(countdown)

			timer := time.NewTimer(time.Second * countdown)
			select {
			case <-timer.C:
				timer.Stop()
			case <-localStopper:
				timer.Stop()
				return
			}

			chout <- NewMessageNotice("start")

			s, err := snake.NewSnake(p.world)
			if err != nil {
				chout <- NewMessageError("cannot create snake")
				p.logger.Errorln("cannot create snake to player:", err)
				continue
			}
			snakeStop := s.Run(localStopper)

			chout <- NewMessageSnake(s.GetUUID())

			p.processSnakeCommands(snakeStop, chin, s)

			select {
			case <-snakeStop:
			case <-localStopper:
				return
			}
		}
	}()

	return chout
}

func (p *Player) processSnakeCommands(stop <-chan struct{}, chin <-chan string, s *snake.Snake) <-chan error {
	errch := make(chan error, chanErrorBuffer)

	go func() {
		defer close(errch)
		for {
			select {
			case <-stop:
				return
			case command := <-chin:
				p.logger.WithField("command", command).Debug("received snake command")
				if err := s.Command(snake.Command(command)); err != nil {
					// TODO: Handle error and send it to channel with timeout!
					//errch <- err
				}
			}
		}
	}()

	return errch
}
<commit_msg>Handle error and send it to channel<commit_after>package player

import (
	"sync"
	"time"

	"github.com/sirupsen/logrus"

	"github.com/ivan1993spb/snake-server/objects/snake"
	"github.com/ivan1993spb/snake-server/world"
)

const countdown = 5

const chanMessageBuffer = 16

const chanErrorBuffer = 32

type Player struct {
	world  *world.World
	logger logrus.FieldLogger
}

func NewPlayer(logger logrus.FieldLogger, world *world.World) *Player {
	return &Player{
		logger: logger,
		world:  world,
	}
}

func (p *Player) Start(stop <-chan struct{}, chin <-chan string) <-chan Message {
	chout := make(chan Message, chanMessageBuffer)
	localStopper := make(chan struct{})

	wg := &sync.WaitGroup{}
	wg.Add(1)

	go func() {
		<-stop
		close(localStopper)

		wg.Wait()
		close(chout)
	}()

	go func() {
		defer wg.Done()

		chout <- NewMessageNotice("welcome to snake server!")
		chout <- NewMessageSize(p.world.Width(), p.world.Height())
		chout <- NewMessageObjects(p.world.GetObjects())

		for {
			chout <- NewMessageCountdown(countdown)

			timer := time.NewTimer(time.Second * countdown)
			select {
			case <-timer.C:
				timer.Stop()
			case <-localStopper:
				timer.Stop()
				return
			}

			chout <- NewMessageNotice("start")

			s, err := snake.NewSnake(p.world)
			if err != nil {
				chout <- NewMessageError("cannot create snake")
				p.logger.Errorln("cannot create snake to player:", err)
				continue
			}
			snakeStop := s.Run(localStopper)

			chout <- NewMessageSnake(s.GetUUID())

			wg.Add(1)
			go func() {
				defer wg.Done()
				errch := p.processSnakeCommands(snakeStop, chin, s)

				for {
					select {
					case <-snakeStop:
						return
					case err, ok := <-errch:
						if !ok {
							return
						}
						chout <- NewMessageError(err.Error())
					}
				}
			}()

			select {
			case <-snakeStop:
			case <-localStopper:
				return
			}
		}
	}()

	return chout
}

func (p *Player) processSnakeCommands(stop <-chan struct{}, chin <-chan string, s *snake.Snake) <-chan error {
	errch := make(chan error, chanErrorBuffer)

	go func() {
		defer close(errch)
		for {
			select {
			case <-stop:
				return
			case command := <-chin:
				p.logger.WithField("command", command).Debug("received snake command")
				if err := s.Command(snake.Command(command)); err != nil {
					errch <- err
				}
			}
		}
	}()

	return errch
}
<|endoftext|>


<commit_before>package deployment

import (
	"github.com/flynn/flynn/Godeps/_workspace/src/gopkg.in/inconshreveable/log15.v2"
	ct "github.com/flynn/flynn/controller/types"
	dd "github.com/flynn/flynn/discoverd/deployment"
)

// deployDiscoverMeta does a one-by-one deployment but uses discoverd.Deployment
// to wait for appropriate service metadata before stopping old jobs.
func (d *DeployJob) deployDiscoverdMeta() (err error) {
	log := d.logger.New("fn", "deployDiscoverdMeta")
	log.Info("starting discoverd-meta deployment")

	defer func() {
		if err != nil {
			// TODO: support rolling back
			err = ErrSkipRollback{err.Error()}
		}
	}()

	discDeploys := make(map[string]*dd.Deployment)

	for typ, serviceName := range d.serviceNames {
		discDeploy, err := dd.NewDeployment(serviceName)
		if err != nil {
			return err
		}
		discDeploys[typ] = discDeploy
		if err := discDeploy.Reset(); err != nil {
			return err
		}
		defer discDeploy.Close()
	}

	return d.deployOneByOneWithWaitFn(func(releaseID string, expected ct.JobEvents, log log15.Logger) error {
		for typ, events := range expected {
			if count, ok := events[ct.JobStateUp]; ok && count > 0 {
				if discDeploy, ok := discDeploys[typ]; ok {
					if err := discDeploy.Wait(count, 120, log); err != nil {
						return err
					}
					// clear up events for this type so we can safely
					// process job down events if needed
					expected[typ][ct.JobStateUp] = 0
				}
			}
		}
		return d.waitForJobEvents(releaseID, expected, log)
	})
}
<commit_msg>worker: Don't wait for empty events in discoverd-meta deploy<commit_after>package deployment

import (
	"github.com/flynn/flynn/Godeps/_workspace/src/gopkg.in/inconshreveable/log15.v2"
	ct "github.com/flynn/flynn/controller/types"
	dd "github.com/flynn/flynn/discoverd/deployment"
)

// deployDiscoverMeta does a one-by-one deployment but uses discoverd.Deployment
// to wait for appropriate service metadata before stopping old jobs.
func (d *DeployJob) deployDiscoverdMeta() (err error) {
	log := d.logger.New("fn", "deployDiscoverdMeta")
	log.Info("starting discoverd-meta deployment")

	defer func() {
		if err != nil {
			// TODO: support rolling back
			err = ErrSkipRollback{err.Error()}
		}
	}()

	discDeploys := make(map[string]*dd.Deployment)

	for typ, serviceName := range d.serviceNames {
		discDeploy, err := dd.NewDeployment(serviceName)
		if err != nil {
			return err
		}
		discDeploys[typ] = discDeploy
		if err := discDeploy.Reset(); err != nil {
			return err
		}
		defer discDeploy.Close()
	}

	return d.deployOneByOneWithWaitFn(func(releaseID string, expected ct.JobEvents, log log15.Logger) error {
		for typ, events := range expected {
			if count, ok := events[ct.JobStateUp]; ok && count > 0 {
				if discDeploy, ok := discDeploys[typ]; ok {
					if err := discDeploy.Wait(count, 120, log); err != nil {
						return err
					}
					// clear up events for this type so we can safely
					// process job down events if needed
					expected[typ][ct.JobStateUp] = 0
				}
			}
		}
		if expected.Count() == 0 {
			return nil
		}
		return d.waitForJobEvents(releaseID, expected, log)
	})
}
<|endoftext|>


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

SPDX-License-Identifier: Apache-2.0
*/

package txvalidator

import (
	"fmt"
	"sync"

	"github.com/hyperledger/fabric/common/cauthdsl"
	ledger2 "github.com/hyperledger/fabric/common/ledger"
	"github.com/hyperledger/fabric/core/handlers/validation/api"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/capabilities"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/identities"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/state"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/msp"
	"github.com/hyperledger/fabric/protos/common"
	"github.com/pkg/errors"
)

// MapBasedPluginMapper maps plugin names to their corresponding factories
type MapBasedPluginMapper map[string]validation.PluginFactory

// PluginFactoryByName returns a plugin factory for the given plugin name, or nil if not found
func (m MapBasedPluginMapper) PluginFactoryByName(name PluginName) validation.PluginFactory {
	return m[string(name)]
}

//go:generate mockery -dir . -name PluginMapper -case underscore -output mocks/
//go:generate mockery -dir ../../handlers/validation/api/ -name PluginFactory -case underscore -output mocks/
//go:generate mockery -dir ../../handlers/validation/api/ -name Plugin -case underscore -output mocks/

// PluginMapper maps plugin names to their corresponding factory instance.
// Returns nil if the name isn't associated to any plugin.
type PluginMapper interface {
	PluginFactoryByName(name PluginName) validation.PluginFactory
}

//go:generate mockery -dir . -name QueryExecutorCreator -case underscore -output mocks/

// QueryExecutorCreator creates new query executors
type QueryExecutorCreator interface {
	NewQueryExecutor() (ledger.QueryExecutor, error)
}

// Context defines information about a transaction
// that is being validated
type Context struct {
	Seq       int
	Envelope  []byte
	TxID      string
	Channel   string
	VSCCName  string
	Policy    []byte
	Namespace string
	Block     *common.Block
}

// String returns a string representation of this Context
func (c Context) String() string {
	return fmt.Sprintf("Tx %s, seq %d out of %d in block %d for channel %s with validation plugin %s", c.TxID, c.Seq, len(c.Block.Data.Data), c.Block.Header.Number, c.Channel, c.VSCCName)
}

// PluginValidator values transactions with validation plugins
type PluginValidator struct {
	sync.Mutex
	pluginChannelMapping map[PluginName]*pluginsByChannel
	PluginMapper
	QueryExecutorCreator
	msp.IdentityDeserializer
	capabilities Capabilities
}

//go:generate mockery -dir ../../handlers/validation/api/capabilities/ -name Capabilities -case underscore -output mocks/
//go:generate mockery -dir ../../../msp/ -name IdentityDeserializer -case underscore -output mocks/

// NewPluginValidator creates a new PluginValidator
func NewPluginValidator(pm PluginMapper, qec QueryExecutorCreator, deserializer msp.IdentityDeserializer, capabilities Capabilities) *PluginValidator {
	return &PluginValidator{
		capabilities:         capabilities,
		pluginChannelMapping: make(map[PluginName]*pluginsByChannel),
		PluginMapper:         pm,
		QueryExecutorCreator: qec,
		IdentityDeserializer: deserializer,
	}
}

func (pv *PluginValidator) ValidateWithPlugin(ctx *Context) error {
	plugin, err := pv.getOrCreatePlugin(ctx)
	if err != nil {
		return &validation.ExecutionFailureError{
			Reason: fmt.Sprintf("plugin with name %s couldn't be used: %v", ctx.VSCCName, err),
		}
	}
	err = plugin.Validate(ctx.Block, ctx.Namespace, ctx.Seq, 0, SerializedPolicy(ctx.Policy))
	validityStatus := "valid"
	if err != nil {
		validityStatus = fmt.Sprintf("invalid: %v", err)
	}
	logger.Debug("Transaction", ctx.TxID, "appears to be", validityStatus)
	return err
}

func (pv *PluginValidator) getOrCreatePlugin(ctx *Context) (validation.Plugin, error) {
	pluginFactory := pv.PluginFactoryByName(PluginName(ctx.VSCCName))
	if pluginFactory == nil {
		return nil, errors.Errorf("plugin with name %s wasn't found", ctx.VSCCName)
	}

	pluginsByChannel := pv.getOrCreatePluginChannelMapping(PluginName(ctx.VSCCName), pluginFactory)
	return pluginsByChannel.createPluginIfAbsent(ctx.Channel)

}

func (pv *PluginValidator) getOrCreatePluginChannelMapping(plugin PluginName, pf validation.PluginFactory) *pluginsByChannel {
	pv.Lock()
	defer pv.Unlock()
	endorserChannelMapping, exists := pv.pluginChannelMapping[PluginName(plugin)]
	if !exists {
		endorserChannelMapping = &pluginsByChannel{
			pluginFactory:    pf,
			channels2Plugins: make(map[string]validation.Plugin),
			pv:               pv,
		}
		pv.pluginChannelMapping[PluginName(plugin)] = endorserChannelMapping
	}
	return endorserChannelMapping
}

// PluginName defines the name of the plugin as it appears in the configuration
type PluginName string

type pluginsByChannel struct {
	sync.RWMutex
	pluginFactory    validation.PluginFactory
	channels2Plugins map[string]validation.Plugin
	pv               *PluginValidator
}

func (pbc *pluginsByChannel) createPluginIfAbsent(channel string) (validation.Plugin, error) {
	pbc.RLock()
	plugin, exists := pbc.channels2Plugins[channel]
	pbc.RUnlock()
	if exists {
		return plugin, nil
	}

	pbc.Lock()
	defer pbc.Unlock()
	plugin, exists = pbc.channels2Plugins[channel]
	if exists {
		return plugin, nil
	}

	pluginInstance := pbc.pluginFactory.New()
	plugin, err := pbc.initPlugin(pluginInstance, channel)
	if err != nil {
		return nil, err
	}
	pbc.channels2Plugins[channel] = plugin
	return plugin, nil
}

func (pbc *pluginsByChannel) initPlugin(plugin validation.Plugin, channel string) (validation.Plugin, error) {
	pe := &PolicyEvaluator{IdentityDeserializer: pbc.pv.IdentityDeserializer}
	sf := &StateFetcherImpl{QueryExecutorCreator: pbc.pv}
	if err := plugin.Init(pe, sf, pbc.pv.capabilities); err != nil {
		return nil, errors.Wrap(err, "failed initializing plugin")
	}
	return plugin, nil
}

type PolicyEvaluator struct {
	msp.IdentityDeserializer
}

// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
func (id *PolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error {
	pp := cauthdsl.NewPolicyProvider(id.IdentityDeserializer)
	policy, _, err := pp.NewPolicy(policyBytes)
	if err != nil {
		return err
	}
	return policy.Evaluate(signatureSet)
}

// DeserializeIdentity unmarshals the given identity to msp.Identity
func (id *PolicyEvaluator) DeserializeIdentity(serializedIdentity []byte) (Identity, error) {
	mspIdentity, err := id.IdentityDeserializer.DeserializeIdentity(serializedIdentity)
	if err != nil {
		return nil, err
	}
	return &identity{Identity: mspIdentity}, nil
}

type identity struct {
	msp.Identity
}

func (i *identity) GetIdentityIdentifier() *IdentityIdentifier {
	identifier := i.Identity.GetIdentifier()
	return &IdentityIdentifier{
		Id:    identifier.Id,
		Mspid: identifier.Mspid,
	}
}

type StateFetcherImpl struct {
	QueryExecutorCreator
}

func (sf *StateFetcherImpl) FetchState() (State, error) {
	qe, err := sf.NewQueryExecutor()
	if err != nil {
		return nil, err
	}
	return &StateImpl{qe}, nil
}

type StateImpl struct {
	ledger.QueryExecutor
}

func (s *StateImpl) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error) {
	it, err := s.QueryExecutor.GetStateRangeScanIterator(namespace, startKey, endKey)
	if err != nil {
		return nil, err
	}
	return &ResultsIteratorImpl{ResultsIterator: it}, nil
}

type ResultsIteratorImpl struct {
	ledger2.ResultsIterator
}

func (it *ResultsIteratorImpl) Next() (QueryResult, error) {
	return it.Next()
}

// SerializedPolicy defines a marshaled policy
type SerializedPolicy []byte

// Bytes returns te bytes of the SerializedPolicy
func (sp SerializedPolicy) Bytes() []byte {
	return sp
}
<commit_msg>[FAB-12968] Fix bug of iterator in plugin_validator<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package txvalidator

import (
	"fmt"
	"sync"

	"github.com/hyperledger/fabric/common/cauthdsl"
	ledger2 "github.com/hyperledger/fabric/common/ledger"
	"github.com/hyperledger/fabric/core/handlers/validation/api"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/capabilities"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/identities"
	. "github.com/hyperledger/fabric/core/handlers/validation/api/state"
	"github.com/hyperledger/fabric/core/ledger"
	"github.com/hyperledger/fabric/msp"
	"github.com/hyperledger/fabric/protos/common"
	"github.com/pkg/errors"
)

// MapBasedPluginMapper maps plugin names to their corresponding factories
type MapBasedPluginMapper map[string]validation.PluginFactory

// PluginFactoryByName returns a plugin factory for the given plugin name, or nil if not found
func (m MapBasedPluginMapper) PluginFactoryByName(name PluginName) validation.PluginFactory {
	return m[string(name)]
}

//go:generate mockery -dir . -name PluginMapper -case underscore -output mocks/
//go:generate mockery -dir ../../handlers/validation/api/ -name PluginFactory -case underscore -output mocks/
//go:generate mockery -dir ../../handlers/validation/api/ -name Plugin -case underscore -output mocks/

// PluginMapper maps plugin names to their corresponding factory instance.
// Returns nil if the name isn't associated to any plugin.
type PluginMapper interface {
	PluginFactoryByName(name PluginName) validation.PluginFactory
}

//go:generate mockery -dir . -name QueryExecutorCreator -case underscore -output mocks/

// QueryExecutorCreator creates new query executors
type QueryExecutorCreator interface {
	NewQueryExecutor() (ledger.QueryExecutor, error)
}

// Context defines information about a transaction
// that is being validated
type Context struct {
	Seq       int
	Envelope  []byte
	TxID      string
	Channel   string
	VSCCName  string
	Policy    []byte
	Namespace string
	Block     *common.Block
}

// String returns a string representation of this Context
func (c Context) String() string {
	return fmt.Sprintf("Tx %s, seq %d out of %d in block %d for channel %s with validation plugin %s", c.TxID, c.Seq, len(c.Block.Data.Data), c.Block.Header.Number, c.Channel, c.VSCCName)
}

// PluginValidator values transactions with validation plugins
type PluginValidator struct {
	sync.Mutex
	pluginChannelMapping map[PluginName]*pluginsByChannel
	PluginMapper
	QueryExecutorCreator
	msp.IdentityDeserializer
	capabilities Capabilities
}

//go:generate mockery -dir ../../handlers/validation/api/capabilities/ -name Capabilities -case underscore -output mocks/
//go:generate mockery -dir ../../../msp/ -name IdentityDeserializer -case underscore -output mocks/

// NewPluginValidator creates a new PluginValidator
func NewPluginValidator(pm PluginMapper, qec QueryExecutorCreator, deserializer msp.IdentityDeserializer, capabilities Capabilities) *PluginValidator {
	return &PluginValidator{
		capabilities:         capabilities,
		pluginChannelMapping: make(map[PluginName]*pluginsByChannel),
		PluginMapper:         pm,
		QueryExecutorCreator: qec,
		IdentityDeserializer: deserializer,
	}
}

func (pv *PluginValidator) ValidateWithPlugin(ctx *Context) error {
	plugin, err := pv.getOrCreatePlugin(ctx)
	if err != nil {
		return &validation.ExecutionFailureError{
			Reason: fmt.Sprintf("plugin with name %s couldn't be used: %v", ctx.VSCCName, err),
		}
	}
	err = plugin.Validate(ctx.Block, ctx.Namespace, ctx.Seq, 0, SerializedPolicy(ctx.Policy))
	validityStatus := "valid"
	if err != nil {
		validityStatus = fmt.Sprintf("invalid: %v", err)
	}
	logger.Debug("Transaction", ctx.TxID, "appears to be", validityStatus)
	return err
}

func (pv *PluginValidator) getOrCreatePlugin(ctx *Context) (validation.Plugin, error) {
	pluginFactory := pv.PluginFactoryByName(PluginName(ctx.VSCCName))
	if pluginFactory == nil {
		return nil, errors.Errorf("plugin with name %s wasn't found", ctx.VSCCName)
	}

	pluginsByChannel := pv.getOrCreatePluginChannelMapping(PluginName(ctx.VSCCName), pluginFactory)
	return pluginsByChannel.createPluginIfAbsent(ctx.Channel)

}

func (pv *PluginValidator) getOrCreatePluginChannelMapping(plugin PluginName, pf validation.PluginFactory) *pluginsByChannel {
	pv.Lock()
	defer pv.Unlock()
	endorserChannelMapping, exists := pv.pluginChannelMapping[PluginName(plugin)]
	if !exists {
		endorserChannelMapping = &pluginsByChannel{
			pluginFactory:    pf,
			channels2Plugins: make(map[string]validation.Plugin),
			pv:               pv,
		}
		pv.pluginChannelMapping[PluginName(plugin)] = endorserChannelMapping
	}
	return endorserChannelMapping
}

// PluginName defines the name of the plugin as it appears in the configuration
type PluginName string

type pluginsByChannel struct {
	sync.RWMutex
	pluginFactory    validation.PluginFactory
	channels2Plugins map[string]validation.Plugin
	pv               *PluginValidator
}

func (pbc *pluginsByChannel) createPluginIfAbsent(channel string) (validation.Plugin, error) {
	pbc.RLock()
	plugin, exists := pbc.channels2Plugins[channel]
	pbc.RUnlock()
	if exists {
		return plugin, nil
	}

	pbc.Lock()
	defer pbc.Unlock()
	plugin, exists = pbc.channels2Plugins[channel]
	if exists {
		return plugin, nil
	}

	pluginInstance := pbc.pluginFactory.New()
	plugin, err := pbc.initPlugin(pluginInstance, channel)
	if err != nil {
		return nil, err
	}
	pbc.channels2Plugins[channel] = plugin
	return plugin, nil
}

func (pbc *pluginsByChannel) initPlugin(plugin validation.Plugin, channel string) (validation.Plugin, error) {
	pe := &PolicyEvaluator{IdentityDeserializer: pbc.pv.IdentityDeserializer}
	sf := &StateFetcherImpl{QueryExecutorCreator: pbc.pv}
	if err := plugin.Init(pe, sf, pbc.pv.capabilities); err != nil {
		return nil, errors.Wrap(err, "failed initializing plugin")
	}
	return plugin, nil
}

type PolicyEvaluator struct {
	msp.IdentityDeserializer
}

// Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies the policy
func (id *PolicyEvaluator) Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error {
	pp := cauthdsl.NewPolicyProvider(id.IdentityDeserializer)
	policy, _, err := pp.NewPolicy(policyBytes)
	if err != nil {
		return err
	}
	return policy.Evaluate(signatureSet)
}

// DeserializeIdentity unmarshals the given identity to msp.Identity
func (id *PolicyEvaluator) DeserializeIdentity(serializedIdentity []byte) (Identity, error) {
	mspIdentity, err := id.IdentityDeserializer.DeserializeIdentity(serializedIdentity)
	if err != nil {
		return nil, err
	}
	return &identity{Identity: mspIdentity}, nil
}

type identity struct {
	msp.Identity
}

func (i *identity) GetIdentityIdentifier() *IdentityIdentifier {
	identifier := i.Identity.GetIdentifier()
	return &IdentityIdentifier{
		Id:    identifier.Id,
		Mspid: identifier.Mspid,
	}
}

type StateFetcherImpl struct {
	QueryExecutorCreator
}

func (sf *StateFetcherImpl) FetchState() (State, error) {
	qe, err := sf.NewQueryExecutor()
	if err != nil {
		return nil, err
	}
	return &StateImpl{qe}, nil
}

type StateImpl struct {
	ledger.QueryExecutor
}

func (s *StateImpl) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error) {
	it, err := s.QueryExecutor.GetStateRangeScanIterator(namespace, startKey, endKey)
	if err != nil {
		return nil, err
	}
	return &ResultsIteratorImpl{ResultsIterator: it}, nil
}

type ResultsIteratorImpl struct {
	ledger2.ResultsIterator
}

func (it *ResultsIteratorImpl) Next() (QueryResult, error) {
	return it.ResultsIterator.Next()
}

// SerializedPolicy defines a marshaled policy
type SerializedPolicy []byte

// Bytes returns te bytes of the SerializedPolicy
func (sp SerializedPolicy) Bytes() []byte {
	return sp
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

type Executor struct {
	rules         map[string]*Rule
	implicitRules []*Rule
	suffixRules   map[string][]*Rule
	firstRule     *Rule
}

func newExecutor() *Executor {
	return &Executor{
		rules:       make(map[string]*Rule),
		suffixRules: make(map[string][]*Rule),
	}
}

// TODO(ukai): use time.Time?
func getTimestamp(filename string) int64 {
	st, err := os.Stat(filename)
	if err != nil {
		return -2
	}
	return st.ModTime().Unix()
}

func (ex *Executor) runCommands(cmds []string, output string) error {
Loop:
	for _, cmd := range cmds {
		echo := true
		ignoreErr := false
		for {
			if cmd == "" {
				continue Loop
			}
			switch cmd[0] {
			case '@':
				echo = false
				cmd = cmd[1:]
				continue
			case '-':
				ignoreErr = true
				cmd = cmd[1:]
				continue
			}
			break
		}
		if echo {
			fmt.Printf("%s\n", cmd)
		}
		if dryRunFlag {
			continue
		}

		args := []string{"/bin/sh", "-c", cmd}
		cmd := exec.Cmd{
			Path: args[0],
			Args: args,
		}
		out, err := cmd.CombinedOutput()
		exit := 0
		if err != nil {
			exit = 1
			if err, ok := err.(*exec.ExitError); ok {
				if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
					exit = w.ExitStatus()
				}
			} else {
				return err
			}
		}
		fmt.Printf("%s", out)
		if exit != 0 {
			if ignoreErr {
				fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
				continue
			}
			return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
		}
	}
	return nil
}

func replaceSuffix(s string, newsuf string) string {
	// TODO: Factor out the logic around suffix rules and use
	// it from substitution references.
	// http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
	return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
}

func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
	outputPattern := rule.outputPatterns[0]
	if !matchPattern(outputPattern, output) {
		return false
	}
	for _, input := range rule.inputs {
		input = substPattern(outputPattern, input, output)
		if !exists(input) {
			return false
		}
	}
	return true
}

func (ex *Executor) pickRule(output string) (*Rule, bool) {
	rule, present := ex.rules[output]
	if present {
		return rule, true
	}

	for _, rule := range ex.implicitRules {
		if ex.canPickImplicitRule(rule, output) {
			return rule, true
		}
	}

	outputSuffix := filepath.Ext(output)
	if len(outputSuffix) > 0 && outputSuffix[0] == '.' {
		rules, present := ex.suffixRules[outputSuffix[1:]]
		if present {
			for _, rule := range rules {
				if len(rule.inputs) != 1 {
					panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(rule.inputs)))
				}
				if exists(replaceSuffix(output, rule.inputs[0])) {
					return rule, true
				}
			}
		}
	}

	return nil, false
}

func (ex *Executor) build(vars *VarTab, output string) (int64, error) {
	Log("Building: %s", output)
	outputTs := getTimestamp(output)

	rule, present := ex.pickRule(output)
	if !present {
		if outputTs >= 0 {
			return outputTs, nil
		}
		return outputTs, fmt.Errorf("no rule to make target %q", output)
	}
	if rule.vars != nil {
		vars = NewVarTab(vars)
		for k, v := range rule.vars.m {
			vars.Assign(k, v)
		}
	}

	latest := int64(-1)
	var actualInputs []string
	for _, input := range rule.inputs {
		if len(rule.outputPatterns) > 0 {
			if len(rule.outputPatterns) > 1 {
				panic("TODO: multiple output pattern is not supported yet")
			}
			input = substPattern(rule.outputPatterns[0], input, output)
		} else if rule.isSuffixRule {
			input = replaceSuffix(output, input)
		}
		actualInputs = append(actualInputs, input)

		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	for _, input := range rule.orderOnlyInputs {
		if exists(input) {
			continue
		}
		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	if outputTs >= latest {
		return outputTs, nil
	}

	localVars := NewVarTab(vars)
	// automatic variables.
	localVars.Assign("@", SimpleVar{value: output, origin: "automatic"})
	if len(actualInputs) > 0 {
		localVars.Assign("<", SimpleVar{
			value:  actualInputs[0],
			origin: "automatic",
		})
		localVars.Assign("^", SimpleVar{
			value:  strings.Join(actualInputs, " "),
			origin: "automatic",
		})
	}
	ev := newEvaluator(localVars)
	ev.filename = rule.filename
	ev.lineno = rule.cmdLineno
	var cmds []string
	for _, cmd := range rule.cmds {
		if strings.IndexByte(cmd, '$') < 0 {
			// fast path.
			cmds = append(cmds, cmd)
			continue
		}
		ecmd := ev.evalExpr(cmd)
		Log("build eval:%q => %q", cmd, ecmd)
		cmds = append(cmds, strings.Split(ecmd, "\n")...)
	}

	err := ex.runCommands(cmds, output)
	if err != nil {
		return outputTs, err
	}

	outputTs = getTimestamp(output)
	if outputTs < 0 {
		outputTs = time.Now().Unix()
	}
	return outputTs, nil
}

func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
	if len(output) == 0 || output[0] != '.' {
		return false
	}
	rest := output[1:]
	dotIndex := strings.IndexByte(rest, '.')
	// If there is only a single dot or the third dot, this is not a
	// suffix rule.
	if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
		return false
	}

	// This is a suffix rule.
	inputSuffix := rest[:dotIndex]
	outputSuffix := rest[dotIndex+1:]
	r := &Rule{}
	*r = *rule
	r.inputs = []string{inputSuffix}
	r.isSuffixRule = true
	ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
	return true
}

func (ex *Executor) populateExplicitRule(rule *Rule) {
	for _, output := range rule.outputs {
		isSuffixRule := ex.populateSuffixRule(rule, output)

		if oldRule, present := ex.rules[output]; present {
			if oldRule.vars != nil || rule.vars != nil {
				oldRule.isDoubleColon = rule.isDoubleColon
				switch {
				case rule.vars == nil && oldRule.vars != nil:
					rule.vars = oldRule.vars
				case rule.vars != nil && oldRule.vars == nil:
				case rule.vars != nil && oldRule.vars != nil:
					// parent would be the same vars?
					for k, v := range rule.vars.m {
						oldRule.vars.m[k] = v
					}
					rule.vars = oldRule.vars
				}
			}
			if oldRule.isDoubleColon != rule.isDoubleColon {
				Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
			}
			if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
				Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
				Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
			}
			r := &Rule{}
			*r = *rule
			if rule.isDoubleColon {
				r.cmds = append(oldRule.cmds, r.cmds...)
			}
			r.inputs = append(r.inputs, oldRule.inputs...)
			ex.rules[output] = r
		} else {
			ex.rules[output] = rule
			if ex.firstRule == nil && !isSuffixRule {
				ex.firstRule = rule
			}
		}
	}
}

func (ex *Executor) populateImplicitRule(rule *Rule) {
	for _, outputPattern := range rule.outputPatterns {
		r := &Rule{}
		*r = *rule
		r.outputPatterns = []string{outputPattern}
		ex.implicitRules = append(ex.implicitRules, r)
	}
}

func (ex *Executor) populateRules(er *EvalResult) {
	for _, rule := range er.rules {
		ex.populateExplicitRule(rule)

		if len(rule.outputs) == 0 {
			ex.populateImplicitRule(rule)
		}
	}

	// Reverse the implicit rule for easier lookup.
	for i, r := range ex.implicitRules {
		if i >= len(ex.implicitRules)/2 {
			break
		}
		j := len(ex.implicitRules) - i - 1
		ex.implicitRules[i] = ex.implicitRules[j]
		ex.implicitRules[j] = r
	}
}

func (ex *Executor) exec(er *EvalResult, targets []string) error {
	ex.populateRules(er)

	if len(targets) == 0 {
		if ex.firstRule == nil {
			ErrorNoLocation("*** No targets.")
		}
		targets = append(targets, ex.firstRule.outputs[0])
	}

	for _, target := range targets {
		_, err := ex.build(er.vars, target)
		if err != nil {
			return err
		}
	}
	return nil
}

func Exec(er *EvalResult, targets []string) error {
	ex := newExecutor()
	return ex.exec(er, targets)
}
<commit_msg>fix runCommand. ignore left whiespaces.<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

type Executor struct {
	rules         map[string]*Rule
	implicitRules []*Rule
	suffixRules   map[string][]*Rule
	firstRule     *Rule
}

func newExecutor() *Executor {
	return &Executor{
		rules:       make(map[string]*Rule),
		suffixRules: make(map[string][]*Rule),
	}
}

// TODO(ukai): use time.Time?
func getTimestamp(filename string) int64 {
	st, err := os.Stat(filename)
	if err != nil {
		return -2
	}
	return st.ModTime().Unix()
}

func (ex *Executor) runCommands(cmds []string, output string) error {
Loop:
	for _, cmd := range cmds {
		echo := true
		ignoreErr := false
		for {
			cmd = strings.TrimLeft(cmd, " \t")
			if cmd == "" {
				continue Loop
			}
			switch cmd[0] {
			case '@':
				echo = false
				cmd = cmd[1:]
				continue
			case '-':
				ignoreErr = true
				cmd = cmd[1:]
				continue
			}
			break
		}
		if echo {
			fmt.Printf("%s\n", cmd)
		}
		if dryRunFlag {
			continue
		}

		args := []string{"/bin/sh", "-c", cmd}
		cmd := exec.Cmd{
			Path: args[0],
			Args: args,
		}
		out, err := cmd.CombinedOutput()
		exit := 0
		if err != nil {
			exit = 1
			if err, ok := err.(*exec.ExitError); ok {
				if w, ok := err.ProcessState.Sys().(syscall.WaitStatus); ok {
					exit = w.ExitStatus()
				}
			} else {
				return err
			}
		}
		fmt.Printf("%s", out)
		if exit != 0 {
			if ignoreErr {
				fmt.Printf("[%s] Error %d (ignored)\n", output, exit)
				continue
			}
			return fmt.Errorf("command failed: %q. Error %d", cmd, exit)
		}
	}
	return nil
}

func replaceSuffix(s string, newsuf string) string {
	// TODO: Factor out the logic around suffix rules and use
	// it from substitution references.
	// http://www.gnu.org/software/make/manual/make.html#Substitution-Refs
	return fmt.Sprintf("%s.%s", stripExt(s), newsuf)
}

func (ex *Executor) canPickImplicitRule(rule *Rule, output string) bool {
	outputPattern := rule.outputPatterns[0]
	if !matchPattern(outputPattern, output) {
		return false
	}
	for _, input := range rule.inputs {
		input = substPattern(outputPattern, input, output)
		if !exists(input) {
			return false
		}
	}
	return true
}

func (ex *Executor) pickRule(output string) (*Rule, bool) {
	rule, present := ex.rules[output]
	if present {
		return rule, true
	}

	for _, rule := range ex.implicitRules {
		if ex.canPickImplicitRule(rule, output) {
			return rule, true
		}
	}

	outputSuffix := filepath.Ext(output)
	if len(outputSuffix) > 0 && outputSuffix[0] == '.' {
		rules, present := ex.suffixRules[outputSuffix[1:]]
		if present {
			for _, rule := range rules {
				if len(rule.inputs) != 1 {
					panic(fmt.Sprintf("unexpected number of input for a suffix rule (%d)", len(rule.inputs)))
				}
				if exists(replaceSuffix(output, rule.inputs[0])) {
					return rule, true
				}
			}
		}
	}

	return nil, false
}

func (ex *Executor) build(vars *VarTab, output string) (int64, error) {
	Log("Building: %s", output)
	outputTs := getTimestamp(output)

	rule, present := ex.pickRule(output)
	if !present {
		if outputTs >= 0 {
			return outputTs, nil
		}
		return outputTs, fmt.Errorf("no rule to make target %q", output)
	}
	if rule.vars != nil {
		vars = NewVarTab(vars)
		for k, v := range rule.vars.m {
			vars.Assign(k, v)
		}
	}

	latest := int64(-1)
	var actualInputs []string
	for _, input := range rule.inputs {
		if len(rule.outputPatterns) > 0 {
			if len(rule.outputPatterns) > 1 {
				panic("TODO: multiple output pattern is not supported yet")
			}
			input = substPattern(rule.outputPatterns[0], input, output)
		} else if rule.isSuffixRule {
			input = replaceSuffix(output, input)
		}
		actualInputs = append(actualInputs, input)

		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	for _, input := range rule.orderOnlyInputs {
		if exists(input) {
			continue
		}
		ts, err := ex.build(vars, input)
		if err != nil {
			return outputTs, err
		}
		if latest < ts {
			latest = ts
		}
	}

	if outputTs >= latest {
		return outputTs, nil
	}

	localVars := NewVarTab(vars)
	// automatic variables.
	localVars.Assign("@", SimpleVar{value: output, origin: "automatic"})
	if len(actualInputs) > 0 {
		localVars.Assign("<", SimpleVar{
			value:  actualInputs[0],
			origin: "automatic",
		})
		localVars.Assign("^", SimpleVar{
			value:  strings.Join(actualInputs, " "),
			origin: "automatic",
		})
	}
	ev := newEvaluator(localVars)
	ev.filename = rule.filename
	ev.lineno = rule.cmdLineno
	var cmds []string
	for _, cmd := range rule.cmds {
		if strings.IndexByte(cmd, '$') < 0 {
			// fast path.
			cmds = append(cmds, cmd)
			continue
		}
		ecmd := ev.evalExpr(cmd)
		Log("build eval:%q => %q", cmd, ecmd)
		cmds = append(cmds, strings.Split(ecmd, "\n")...)
	}

	err := ex.runCommands(cmds, output)
	if err != nil {
		return outputTs, err
	}

	outputTs = getTimestamp(output)
	if outputTs < 0 {
		outputTs = time.Now().Unix()
	}
	return outputTs, nil
}

func (ex *Executor) populateSuffixRule(rule *Rule, output string) bool {
	if len(output) == 0 || output[0] != '.' {
		return false
	}
	rest := output[1:]
	dotIndex := strings.IndexByte(rest, '.')
	// If there is only a single dot or the third dot, this is not a
	// suffix rule.
	if dotIndex < 0 || strings.IndexByte(rest[dotIndex+1:], '.') >= 0 {
		return false
	}

	// This is a suffix rule.
	inputSuffix := rest[:dotIndex]
	outputSuffix := rest[dotIndex+1:]
	r := &Rule{}
	*r = *rule
	r.inputs = []string{inputSuffix}
	r.isSuffixRule = true
	ex.suffixRules[outputSuffix] = append([]*Rule{r}, ex.suffixRules[outputSuffix]...)
	return true
}

func (ex *Executor) populateExplicitRule(rule *Rule) {
	for _, output := range rule.outputs {
		isSuffixRule := ex.populateSuffixRule(rule, output)

		if oldRule, present := ex.rules[output]; present {
			if oldRule.vars != nil || rule.vars != nil {
				oldRule.isDoubleColon = rule.isDoubleColon
				switch {
				case rule.vars == nil && oldRule.vars != nil:
					rule.vars = oldRule.vars
				case rule.vars != nil && oldRule.vars == nil:
				case rule.vars != nil && oldRule.vars != nil:
					// parent would be the same vars?
					for k, v := range rule.vars.m {
						oldRule.vars.m[k] = v
					}
					rule.vars = oldRule.vars
				}
			}
			if oldRule.isDoubleColon != rule.isDoubleColon {
				Error(rule.filename, rule.lineno, "*** target file %q has both : and :: entries.", output)
			}
			if len(oldRule.cmds) > 0 && len(rule.cmds) > 0 && !isSuffixRule && !rule.isDoubleColon {
				Warn(rule.filename, rule.cmdLineno, "overriding commands for target %q", output)
				Warn(oldRule.filename, oldRule.cmdLineno, "ignoring old commands for target %q", output)
			}
			r := &Rule{}
			*r = *rule
			if rule.isDoubleColon {
				r.cmds = append(oldRule.cmds, r.cmds...)
			}
			r.inputs = append(r.inputs, oldRule.inputs...)
			ex.rules[output] = r
		} else {
			ex.rules[output] = rule
			if ex.firstRule == nil && !isSuffixRule {
				ex.firstRule = rule
			}
		}
	}
}

func (ex *Executor) populateImplicitRule(rule *Rule) {
	for _, outputPattern := range rule.outputPatterns {
		r := &Rule{}
		*r = *rule
		r.outputPatterns = []string{outputPattern}
		ex.implicitRules = append(ex.implicitRules, r)
	}
}

func (ex *Executor) populateRules(er *EvalResult) {
	for _, rule := range er.rules {
		ex.populateExplicitRule(rule)

		if len(rule.outputs) == 0 {
			ex.populateImplicitRule(rule)
		}
	}

	// Reverse the implicit rule for easier lookup.
	for i, r := range ex.implicitRules {
		if i >= len(ex.implicitRules)/2 {
			break
		}
		j := len(ex.implicitRules) - i - 1
		ex.implicitRules[i] = ex.implicitRules[j]
		ex.implicitRules[j] = r
	}
}

func (ex *Executor) exec(er *EvalResult, targets []string) error {
	ex.populateRules(er)

	if len(targets) == 0 {
		if ex.firstRule == nil {
			ErrorNoLocation("*** No targets.")
		}
		targets = append(targets, ex.firstRule.outputs[0])
	}

	for _, target := range targets {
		_, err := ex.build(er.vars, target)
		if err != nil {
			return err
		}
	}
	return nil
}

func Exec(er *EvalResult, targets []string) error {
	ex := newExecutor()
	return ex.exec(er, targets)
}
<|endoftext|>


<commit_before>package main

type OperandType int

const (
	OpConstant OperandType = iota
	OpCellRef
	OpRangeRef
	OpFunction
)

type Operand interface {
	Value(doc *Document) float64
	Type() OperandType
}

type Expr struct {
	expression []Operand
}

func ParseExpression(text string) (*Expr, error) {
	return nil, nil
}

func (e *Expr) String() string {
	return "="
}

func (e *Expr) Evaluate(doc *Document) (float64, error) {
	argStack := make([]Operand, 0, len(e.expression)/2)

	for _, op := range e.expression {
		switch op.Type() {
		case OpConstant:
		case OpCellRef:
		case OpRangeRef:
			argStack = append(argStack, op)
		case OpFunction:
			//f := op.(*Function)
		}
	}

	return 0.0, nil
}

type Constant struct {
	value float64
}

func NewConstant(value float64) *Constant {
	return &Constant{value: value}
}

func (c *Constant) Value(doc *Document) float64 {
	return c.value
}

func (c *Constant) Type() OperandType {
	return OpConstant
}

type CellRef struct {
	index Index
}

func NewCellRef(idx Index) *CellRef {
	return &CellRef{index: idx}
}

func (c *CellRef) Value(doc *Document) float64 {
	cell, err := doc.GetCell(c.index)
	if err != nil {
		return 0.0
	}

	value, err := cell.Eval(doc)
	if err != nil {
		return 0.0
	}

	return value
}

func (c *CellRef) Type() OperandType {
	return OpConstant
}

type RangeRef struct {
	start Index
	end   Index
}

func NewRangeRef(start, end Index) *RangeRef {
	return &RangeRef{start: start, end: end}
}

func (r *RangeRef) Value(doc *Document) float64 {
	return 0.0
}

func (r *RangeRef) Type() OperandType {
	return OpRangeRef
}

type Function struct {
}

func (f *Function) Value(doc *Document) float64 {
	return 0.0
}

func (f *Function) Type() OperandType {
	return OpFunction
}
<commit_msg>Finished expression evaluation, and started to work on the parser side.<commit_after>package main

import (
	"errors"
	//	"go/scanner"
	"go/token"
	//	"strconv"
)

type OperandType int

const (
	ConstantSymbol OperandType = iota
	CellSymbol
	RangeSymbol
	FunctionSymbol
)

type Symbol interface {
	Value(doc *Document) float64
	Type() OperandType
}

type SymbolFunc func(*Document, []Symbol) []Symbol

type Expr struct {
	expression []Symbol
}

type operatorPair struct {
	tok token.Token
	lit string
}

func ParseExpression(text string) (*Expr, error) {
	/*
		output := make([]Symbol)
		operatorStack := make([]operatorPair, 0, 10)

		var s scanner.Scanner

		fileSet := token.NewFileSet()
		file := fileSet.AddFile("", fileSet.Base(), len(text))
		s.Init(file, []byte(text), nil, scanner.ScanComments)

		for {
			_, tok, lit := s.Scan()

			switch tok {
			case token.INT:
				number, err := strconv.ParseFloat(lit, 64)
				if err != nil {
					return nil, err
				}
				output = append(output, NewConstant(number))

			case token.FLOAT:
				number, err := strconv.ParseFloat(lit, 64)
				if err != nil {
					return nil, err
				}
				output = append(output, NewConstant(number))

			case token.IDENT:
			}

			if tok == token.EOF {
				break
			}
		}

		return output, nil
	*/
	return nil, nil
}

func (e *Expr) String() string {
	return ""
}

func (e *Expr) Evaluate(doc *Document) (float64, error) {
	argStack := make([]Symbol, 0, len(e.expression)/2)

	for _, symbol := range e.expression {
		switch symbol.Type() {
		case ConstantSymbol:
		case CellSymbol:
		case RangeSymbol:
			argStack = append(argStack, symbol)
		case FunctionSymbol:
			f := symbol.(*Function)
			argStack = f.cmd(doc, argStack)
		}
	}

	if len(argStack) != 0 {
		return 0.0, errors.New("error while evaluating expression '" + e.String() + "'")
	}

	return argStack[0].Value(doc), nil
}

type Constant struct {
	value float64
}

func NewConstant(value float64) *Constant {

	return &Constant{value: value}
}

func (c *Constant) Value(doc *Document) float64 {
	return c.value
}

func (c *Constant) Type() OperandType {
	return ConstantSymbol
}

type CellRef struct {
	index Index
}

func NewCellRef(idx Index) *CellRef {
	return &CellRef{index: idx}
}

func (c *CellRef) Value(doc *Document) float64 {
	cell, err := doc.GetCell(c.index)
	if err != nil {
		return 0.0
	}

	value, err := cell.Eval(doc)
	if err != nil {
		return 0.0
	}

	return value
}

func (c *CellRef) Type() OperandType {
	return ConstantSymbol
}

type RangeRef struct {
	start Index
	end   Index
}

func NewRangeRef(start, end Index) *RangeRef {
	return &RangeRef{start: start, end: end}
}

func (r *RangeRef) Value(doc *Document) float64 {
	return 0.0
}

func (r *RangeRef) Type() OperandType {
	return RangeSymbol
}

type Function struct {
	cmd SymbolFunc
}

func (f *Function) Value(doc *Document) float64 {
	return 0.0
}

func (f *Function) Type() OperandType {
	return FunctionSymbol
}
<|endoftext|>


<commit_before>package plugin

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/alecthomas/template"
)

var HELM_BIN = "/bin/helm"
var KUBECONFIG = "/root/.kube/kubeconfig"

type (
	// Config maps the params we need to run Helm
	Config struct {
		APIServer          string   `json:"api_server"`
		Token              string   `json:"token"`
		Certificate        string   `json:"certificate"`
		ServiceAccount     string   `json:"service_account"`
		KubeConfig         string   `json:"kube_config"`
		HelmCommand        string   `json:"helm_command"`
		SkipTLSVerify      bool     `json:"tls_skip_verify"`
		Namespace          string   `json:"namespace"`
		Release            string   `json:"release"`
		Chart              string   `json:"chart"`
		Version            string   `json:"version"`
		Values             string   `json:"values"`
		ValuesFiles        string   `json:"values_files"`
		Debug              bool     `json:"debug"`
		DryRun             bool     `json:"dry_run"`
		Secrets            []string `json:"secrets"`
		Prefix             string   `json:"prefix"`
		TillerNs           string   `json:"tiller_ns"`
		Wait               bool     `json:"wait"`
		RecreatePods       bool     `json:"recreate_pods"`
		Upgrade            bool     `json:"upgrade"`
		CanaryImage        bool     `json:"canary_image"`
		ClientOnly         bool     `json:"client_only"`
		ReuseValues        bool     `json:"reuse_values"`
		Timeout            string   `json:"timeout"`
		Force              bool     `json:"force"`
		HelmRepos          []string `json:"helm_repos"`
		Purge              bool     `json:"purge"`
		UpdateDependencies bool     `json:"update_dependencies"`
	}
	// Plugin default
	Plugin struct {
		Config  Config
		command []string
	}
)

func setHelpCommand(p *Plugin) {
	p.command = []string{""}
}
func setDeleteCommand(p *Plugin) {
	delete := make([]string, 2)
	delete[0] = "delete"
	delete[1] = p.Config.Release

	if p.Config.TillerNs != "" {
		delete = append(delete, "--tiller-namespace")
		delete = append(delete, p.Config.TillerNs)
	}
	if p.Config.DryRun {
		delete = append(delete, "--dry-run")
	}
	if p.Config.Purge {
		delete = append(delete, "--purge")
	}

	p.command = delete
}

func setUpgradeCommand(p *Plugin) {
	upgrade := make([]string, 2)
	upgrade[0] = "upgrade"
	upgrade[1] = "--install"

	if p.Config.Release != "" {
		upgrade = append(upgrade, p.Config.Release)
	}
	upgrade = append(upgrade, p.Config.Chart)
	if p.Config.Version != "" {
		upgrade = append(upgrade, "--version")
		upgrade = append(upgrade, p.Config.Version)
	}
	if p.Config.Values != "" {
		upgrade = append(upgrade, "--set")
		upgrade = append(upgrade, unQuote(p.Config.Values))
	}
	if p.Config.ValuesFiles != "" {
		for _, valuesFile := range strings.Split(p.Config.ValuesFiles, ",") {
			upgrade = append(upgrade, "--values")
			upgrade = append(upgrade, valuesFile)
		}
	}
	if p.Config.Namespace != "" {
		upgrade = append(upgrade, "--namespace")
		upgrade = append(upgrade, p.Config.Namespace)
	}
	if p.Config.TillerNs != "" {
		upgrade = append(upgrade, "--tiller-namespace")
		upgrade = append(upgrade, p.Config.TillerNs)
	}
	if p.Config.DryRun {
		upgrade = append(upgrade, "--dry-run")
	}
	if p.Config.Debug {
		upgrade = append(upgrade, "--debug")
	}
	if p.Config.Wait {
		upgrade = append(upgrade, "--wait")
	}
	if p.Config.RecreatePods {
		upgrade = append(upgrade, "--recreate-pods")
	}
	if p.Config.ReuseValues {
		upgrade = append(upgrade, "--reuse-values")
	}
	if p.Config.Timeout != "" {
		upgrade = append(upgrade, "--timeout")
		upgrade = append(upgrade, p.Config.Timeout)
	}
	if p.Config.Force {
		upgrade = append(upgrade, "--force")
	}
	p.command = upgrade

}

func setHelmCommand(p *Plugin) {

	switch p.Config.HelmCommand {
	case "upgrade":
		setUpgradeCommand(p)
	case "delete":
		setDeleteCommand(p)
	default:
		switch os.Getenv("DRONE_BUILD_EVENT") {
		case "push", "tag", "deployment", "pull_request":
			setUpgradeCommand(p)
		case "delete":
			setDeleteCommand(p)
		default:
			setHelpCommand(p)
		}
	}

}

var repoExp = regexp.MustCompile(`^(?P<name>[\w-]+)=(?P<url>(http|https)://[\w-./:]+)`)

// parseRepo returns map of regex capture groups (name, url)
func parseRepo(repo string) (map[string]string, error) {
	matches := repoExp.FindStringSubmatch(repo)
	if len(matches) < 1 {
		return nil, fmt.Errorf("Invalid repo definition: %s", repo)
	}
	result := make(map[string]string)
	for i, name := range repoExp.SubexpNames() {
		if i != 0 {
			result[name] = matches[i]
		}
	}
	return result, nil
}

func doHelmRepoAdd(repo string) ([]string, error) {
	repoMap, err := parseRepo(unQuote(repo))
	if err != nil {
		return nil, err
	}
	repoAdd := []string{
		"repo",
		"add",
		repoMap["name"],
		repoMap["url"],
	}
	return repoAdd, nil
}

func doHelmInit(p *Plugin) []string {
	init := make([]string, 1)
	init[0] = "init"
	if p.Config.TillerNs != "" {
		init = append(init, "--tiller-namespace")
		init = append(init, p.Config.TillerNs)
	}
	if p.Config.ClientOnly {
		init = append(init, "--client-only")
	}
	if p.Config.Upgrade {
		init = append(init, "--upgrade")
	}
	if p.Config.CanaryImage {
		init = append(init, "--canary-image")
	}

	return init

}

func doDependencyUpdate(chart string) []string {
	dependencyUpdate := []string{
		"dependency",
		"update",
		chart,
	}

	return dependencyUpdate
}

// Exec default method
func (p *Plugin) Exec() error {
	if p.Config.Debug {
		p.debugEnv()
	}

	// create /root/.kube/config file if not exists
	if _, err := os.Stat(p.Config.KubeConfig); os.IsNotExist(err) {
		resolveSecrets(p)
		if p.Config.APIServer == "" {
			return fmt.Errorf("Error: API Server is needed to deploy.")
		}
		if p.Config.Token == "" {
			return fmt.Errorf("Error: Token is needed to deploy.")
		}
		if p.Config.SkipTLSVerify == false && p.Config.Certificate == "" {
			return fmt.Errorf("Error: Certificate is needed to deploy when SKIP_TLS_VERIFY is false.")
		}
		initialiseKubeconfig(&p.Config, KUBECONFIG, p.Config.KubeConfig)
	}

	if p.Config.Debug {
		p.debug()
	}

	init := doHelmInit(p)
	err := runCommand(init)
	if err != nil {
		return fmt.Errorf("Error running helm command: " + strings.Join(init[:], " "))
	}

	if len(p.Config.HelmRepos) > 0 {
		for _, repo := range p.Config.HelmRepos {
			repoAdd, err := doHelmRepoAdd(repo)
			if err == nil {
				if p.Config.Debug {
					log.Println("adding helm repo: " + strings.Join(repoAdd[:], " "))
				}

				if err = runCommand(repoAdd); err != nil {
					return fmt.Errorf("Error adding helm repo: " + err.Error())
				}
			} else {
				return err
			}
		}
	}

	if p.Config.UpdateDependencies {
		if err = runCommand(doDependencyUpdate(p.Config.Chart)); err != nil {
			return fmt.Errorf("Error updating dependencies: " + err.Error())
		}
	}

	setHelmCommand(p)

	if p.Config.Debug {
		log.Println("helm command: " + strings.Join(p.command, " "))
	}

	err = runCommand(p.command)
	if err != nil {
		return fmt.Errorf("Error running helm command: " + strings.Join(p.command[:], " "))
	}

	return nil
}

func initialiseKubeconfig(params *Config, source string, target string) error {
	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()
	// parse template
	t, _ := template.ParseFiles(source)
	// execute template
	return t.Execute(f, params)
}

func runCommand(params []string) error {
	cmd := new(exec.Cmd)
	cmd = exec.Command(HELM_BIN, params...)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	return err
}

func resolveSecrets(p *Plugin) {
	p.Config.Values = resolveEnvVar(p.Config.Values, p.Config.Prefix, p.Config.Debug)
	if p.Config.APIServer == "" {
		p.Config.APIServer = resolveEnvVar("${API_SERVER}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.Token == "" {
		p.Config.Token = resolveEnvVar("${KUBERNETES_TOKEN}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.Certificate == "" {
		p.Config.Certificate = resolveEnvVar("${KUBERNETES_CERTIFICATE}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.ServiceAccount == "" {
		p.Config.ServiceAccount = resolveEnvVar("${SERVICE_ACCOUNT}", p.Config.Prefix, p.Config.Debug)
		if p.Config.ServiceAccount == "" {
			p.Config.ServiceAccount = "helm"
		}
	}
}

// getEnvVars will return [${TAG} {TAG} TAG]
func getEnvVars(envvars string) [][]string {
	re := regexp.MustCompile(`\$(\{?(\w+)\}?)\.?`)
	extracted := re.FindAllStringSubmatch(envvars, -1)
	return extracted
}

func resolveEnvVar(key string, prefix string, debug bool) string {
	envvars := getEnvVars(key)
	return replaceEnvvars(envvars, prefix, key, debug)
}

func replaceEnvvars(envvars [][]string, prefix string, s string, debug bool) string {
	for _, envvar := range envvars {
		envvarName := envvar[0]
		envvarKey := envvar[2]
		prefixedKey := strings.ToUpper(prefix + "_" + envvarKey)
		envval := os.Getenv(prefixedKey)
		if debug {
			fmt.Printf("-ReplVar: %s => %s-- %s\n", prefixedKey, envvarKey, envval)
		}

		if envval == "" {
			envval = os.Getenv(envvarKey)
		}

		if strings.Contains(s, envvarName) {
			s = strings.Replace(s, envvarName, envval, -1)
		}
	}

	return s
}

// unQuote removes quotes if present
func unQuote(s string) string {
	unquoted, err := strconv.Unquote(s)
	if err != nil {
		// ignore error and return original string
		return s
	}
	return unquoted
}

func (p *Plugin) debugEnv() {
	// debug env vars
	for _, e := range os.Environ() {
		fmt.Println("-Var:--", e)
	}
}

func (p *Plugin) debug() {
	fmt.Println(p)
	// debug plugin obj
	fmt.Printf("Api server: %s \n", p.Config.APIServer)
	fmt.Printf("Values: %s \n", p.Config.Values)
	fmt.Printf("Secrets: %s \n", p.Config.Secrets)
	fmt.Printf("Helm Repos: %s \n", p.Config.HelmRepos)
	fmt.Printf("ValuesFiles: %s \n", p.Config.ValuesFiles)
	kubeconfig, err := ioutil.ReadFile(KUBECONFIG)
	if err == nil {
		fmt.Println(string(kubeconfig))
	}

	config, err := ioutil.ReadFile(p.Config.KubeConfig)
	if err == nil {
		fmt.Println(string(config))
	}
}
<commit_msg>the server might have a valid cert that does not need a ca. this should not stop trying<commit_after>package plugin

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"

	"github.com/alecthomas/template"
)

var HELM_BIN = "/bin/helm"
var KUBECONFIG = "/root/.kube/kubeconfig"

type (
	// Config maps the params we need to run Helm
	Config struct {
		APIServer          string   `json:"api_server"`
		Token              string   `json:"token"`
		Certificate        string   `json:"certificate"`
		ServiceAccount     string   `json:"service_account"`
		KubeConfig         string   `json:"kube_config"`
		HelmCommand        string   `json:"helm_command"`
		SkipTLSVerify      bool     `json:"tls_skip_verify"`
		Namespace          string   `json:"namespace"`
		Release            string   `json:"release"`
		Chart              string   `json:"chart"`
		Version            string   `json:"version"`
		Values             string   `json:"values"`
		ValuesFiles        string   `json:"values_files"`
		Debug              bool     `json:"debug"`
		DryRun             bool     `json:"dry_run"`
		Secrets            []string `json:"secrets"`
		Prefix             string   `json:"prefix"`
		TillerNs           string   `json:"tiller_ns"`
		Wait               bool     `json:"wait"`
		RecreatePods       bool     `json:"recreate_pods"`
		Upgrade            bool     `json:"upgrade"`
		CanaryImage        bool     `json:"canary_image"`
		ClientOnly         bool     `json:"client_only"`
		ReuseValues        bool     `json:"reuse_values"`
		Timeout            string   `json:"timeout"`
		Force              bool     `json:"force"`
		HelmRepos          []string `json:"helm_repos"`
		Purge              bool     `json:"purge"`
		UpdateDependencies bool     `json:"update_dependencies"`
	}
	// Plugin default
	Plugin struct {
		Config  Config
		command []string
	}
)

func setHelpCommand(p *Plugin) {
	p.command = []string{""}
}
func setDeleteCommand(p *Plugin) {
	delete := make([]string, 2)
	delete[0] = "delete"
	delete[1] = p.Config.Release

	if p.Config.TillerNs != "" {
		delete = append(delete, "--tiller-namespace")
		delete = append(delete, p.Config.TillerNs)
	}
	if p.Config.DryRun {
		delete = append(delete, "--dry-run")
	}
	if p.Config.Purge {
		delete = append(delete, "--purge")
	}

	p.command = delete
}

func setUpgradeCommand(p *Plugin) {
	upgrade := make([]string, 2)
	upgrade[0] = "upgrade"
	upgrade[1] = "--install"

	if p.Config.Release != "" {
		upgrade = append(upgrade, p.Config.Release)
	}
	upgrade = append(upgrade, p.Config.Chart)
	if p.Config.Version != "" {
		upgrade = append(upgrade, "--version")
		upgrade = append(upgrade, p.Config.Version)
	}
	if p.Config.Values != "" {
		upgrade = append(upgrade, "--set")
		upgrade = append(upgrade, unQuote(p.Config.Values))
	}
	if p.Config.ValuesFiles != "" {
		for _, valuesFile := range strings.Split(p.Config.ValuesFiles, ",") {
			upgrade = append(upgrade, "--values")
			upgrade = append(upgrade, valuesFile)
		}
	}
	if p.Config.Namespace != "" {
		upgrade = append(upgrade, "--namespace")
		upgrade = append(upgrade, p.Config.Namespace)
	}
	if p.Config.TillerNs != "" {
		upgrade = append(upgrade, "--tiller-namespace")
		upgrade = append(upgrade, p.Config.TillerNs)
	}
	if p.Config.DryRun {
		upgrade = append(upgrade, "--dry-run")
	}
	if p.Config.Debug {
		upgrade = append(upgrade, "--debug")
	}
	if p.Config.Wait {
		upgrade = append(upgrade, "--wait")
	}
	if p.Config.RecreatePods {
		upgrade = append(upgrade, "--recreate-pods")
	}
	if p.Config.ReuseValues {
		upgrade = append(upgrade, "--reuse-values")
	}
	if p.Config.Timeout != "" {
		upgrade = append(upgrade, "--timeout")
		upgrade = append(upgrade, p.Config.Timeout)
	}
	if p.Config.Force {
		upgrade = append(upgrade, "--force")
	}
	p.command = upgrade

}

func setHelmCommand(p *Plugin) {

	switch p.Config.HelmCommand {
	case "upgrade":
		setUpgradeCommand(p)
	case "delete":
		setDeleteCommand(p)
	default:
		switch os.Getenv("DRONE_BUILD_EVENT") {
		case "push", "tag", "deployment", "pull_request":
			setUpgradeCommand(p)
		case "delete":
			setDeleteCommand(p)
		default:
			setHelpCommand(p)
		}
	}

}

var repoExp = regexp.MustCompile(`^(?P<name>[\w-]+)=(?P<url>(http|https)://[\w-./:]+)`)

// parseRepo returns map of regex capture groups (name, url)
func parseRepo(repo string) (map[string]string, error) {
	matches := repoExp.FindStringSubmatch(repo)
	if len(matches) < 1 {
		return nil, fmt.Errorf("Invalid repo definition: %s", repo)
	}
	result := make(map[string]string)
	for i, name := range repoExp.SubexpNames() {
		if i != 0 {
			result[name] = matches[i]
		}
	}
	return result, nil
}

func doHelmRepoAdd(repo string) ([]string, error) {
	repoMap, err := parseRepo(unQuote(repo))
	if err != nil {
		return nil, err
	}
	repoAdd := []string{
		"repo",
		"add",
		repoMap["name"],
		repoMap["url"],
	}
	return repoAdd, nil
}

func doHelmInit(p *Plugin) []string {
	init := make([]string, 1)
	init[0] = "init"
	if p.Config.TillerNs != "" {
		init = append(init, "--tiller-namespace")
		init = append(init, p.Config.TillerNs)
	}
	if p.Config.ClientOnly {
		init = append(init, "--client-only")
	}
	if p.Config.Upgrade {
		init = append(init, "--upgrade")
	}
	if p.Config.CanaryImage {
		init = append(init, "--canary-image")
	}

	return init

}

func doDependencyUpdate(chart string) []string {
	dependencyUpdate := []string{
		"dependency",
		"update",
		chart,
	}

	return dependencyUpdate
}

// Exec default method
func (p *Plugin) Exec() error {
	if p.Config.Debug {
		p.debugEnv()
	}

	// create /root/.kube/config file if not exists
	if _, err := os.Stat(p.Config.KubeConfig); os.IsNotExist(err) {
		resolveSecrets(p)
		if p.Config.APIServer == "" {
			return fmt.Errorf("Error: API Server is needed to deploy.")
		}
		if p.Config.Token == "" {
			return fmt.Errorf("Error: Token is needed to deploy.")
		}
		initialiseKubeconfig(&p.Config, KUBECONFIG, p.Config.KubeConfig)
	}

	if p.Config.Debug {
		p.debug()
	}

	init := doHelmInit(p)
	err := runCommand(init)
	if err != nil {
		return fmt.Errorf("Error running helm command: " + strings.Join(init[:], " "))
	}

	if len(p.Config.HelmRepos) > 0 {
		for _, repo := range p.Config.HelmRepos {
			repoAdd, err := doHelmRepoAdd(repo)
			if err == nil {
				if p.Config.Debug {
					log.Println("adding helm repo: " + strings.Join(repoAdd[:], " "))
				}

				if err = runCommand(repoAdd); err != nil {
					return fmt.Errorf("Error adding helm repo: " + err.Error())
				}
			} else {
				return err
			}
		}
	}

	if p.Config.UpdateDependencies {
		if err = runCommand(doDependencyUpdate(p.Config.Chart)); err != nil {
			return fmt.Errorf("Error updating dependencies: " + err.Error())
		}
	}

	setHelmCommand(p)

	if p.Config.Debug {
		log.Println("helm command: " + strings.Join(p.command, " "))
	}

	err = runCommand(p.command)
	if err != nil {
		return fmt.Errorf("Error running helm command: " + strings.Join(p.command[:], " "))
	}

	return nil
}

func initialiseKubeconfig(params *Config, source string, target string) error {
	f, err := os.Create(target)
	if err != nil {
		return err
	}
	defer f.Close()
	// parse template
	t, _ := template.ParseFiles(source)
	// execute template
	return t.Execute(f, params)
}

func runCommand(params []string) error {
	cmd := new(exec.Cmd)
	cmd = exec.Command(HELM_BIN, params...)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	return err
}

func resolveSecrets(p *Plugin) {
	p.Config.Values = resolveEnvVar(p.Config.Values, p.Config.Prefix, p.Config.Debug)
	if p.Config.APIServer == "" {
		p.Config.APIServer = resolveEnvVar("${API_SERVER}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.Token == "" {
		p.Config.Token = resolveEnvVar("${KUBERNETES_TOKEN}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.Certificate == "" {
		p.Config.Certificate = resolveEnvVar("${KUBERNETES_CERTIFICATE}", p.Config.Prefix, p.Config.Debug)
	}
	if p.Config.ServiceAccount == "" {
		p.Config.ServiceAccount = resolveEnvVar("${SERVICE_ACCOUNT}", p.Config.Prefix, p.Config.Debug)
		if p.Config.ServiceAccount == "" {
			p.Config.ServiceAccount = "helm"
		}
	}
}

// getEnvVars will return [${TAG} {TAG} TAG]
func getEnvVars(envvars string) [][]string {
	re := regexp.MustCompile(`\$(\{?(\w+)\}?)\.?`)
	extracted := re.FindAllStringSubmatch(envvars, -1)
	return extracted
}

func resolveEnvVar(key string, prefix string, debug bool) string {
	envvars := getEnvVars(key)
	return replaceEnvvars(envvars, prefix, key, debug)
}

func replaceEnvvars(envvars [][]string, prefix string, s string, debug bool) string {
	for _, envvar := range envvars {
		envvarName := envvar[0]
		envvarKey := envvar[2]
		prefixedKey := strings.ToUpper(prefix + "_" + envvarKey)
		envval := os.Getenv(prefixedKey)
		if debug {
			fmt.Printf("-ReplVar: %s => %s-- %s\n", prefixedKey, envvarKey, envval)
		}

		if envval == "" {
			envval = os.Getenv(envvarKey)
		}

		if strings.Contains(s, envvarName) {
			s = strings.Replace(s, envvarName, envval, -1)
		}
	}

	return s
}

// unQuote removes quotes if present
func unQuote(s string) string {
	unquoted, err := strconv.Unquote(s)
	if err != nil {
		// ignore error and return original string
		return s
	}
	return unquoted
}

func (p *Plugin) debugEnv() {
	// debug env vars
	for _, e := range os.Environ() {
		fmt.Println("-Var:--", e)
	}
}

func (p *Plugin) debug() {
	fmt.Println(p)
	// debug plugin obj
	fmt.Printf("Api server: %s \n", p.Config.APIServer)
	fmt.Printf("Values: %s \n", p.Config.Values)
	fmt.Printf("Secrets: %s \n", p.Config.Secrets)
	fmt.Printf("Helm Repos: %s \n", p.Config.HelmRepos)
	fmt.Printf("ValuesFiles: %s \n", p.Config.ValuesFiles)
	kubeconfig, err := ioutil.ReadFile(KUBECONFIG)
	if err == nil {
		fmt.Println(string(kubeconfig))
	}

	config, err := ioutil.ReadFile(p.Config.KubeConfig)
	if err == nil {
		fmt.Println(string(config))
	}
}
<|endoftext|>


<commit_before>package stats_api

import (
	"encoding/json"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"sync"
	"time"
)

type Stats struct {
	Time int64 `json:"time"`
	// runtime
	GoVersion    string `json:"go_version"`
	GoOs         string `json:"go_os"`
	GoArch       string `json:"go_arch"`
	CpuNum       int    `json:"cpu_num"`
	GoroutineNum int    `json:"goroutine_num"`
	Gomaxprocs   int    `json:"gomaxprocs"`
	CgoCallNum   int64  `json:"cgo_call_num"`
	// memory
	MemoryAlloc      uint64 `json:"memory_alloc"`
	MemoryTotalAlloc uint64 `json:"memory_total_alloc"`
	MemorySys        uint64 `json:"memory_sys"`
	MemoryLookups    uint64 `json:"memory_lookups"`
	MemoryMallocs    uint64 `json:"memory_mallocs"`
	MemoryFrees      uint64 `json:"memory_frees"`
	// stack
	StackInUse uint64 `json:"memory_stack"`
	// heap
	HeapAlloc    uint64 `json:"heap_alloc"`
	HeapSys      uint64 `json:"heap_sys"`
	HeapIdle     uint64 `json:"heap_idle"`
	HeapInuse    uint64 `json:"heap_inuse"`
	HeapReleased uint64 `json:"heap_released"`
	HeapObjects  uint64 `json:"heap_objects"`
	// garbage collection
	GcNext           uint64    `json:"gc_next"`
	GcLast           uint64    `json:"gc_last"`
	GcNum            uint32    `json:"gc_num"`
	GcPerSecond      float64   `json:"gc_per_second"`
	GcPausePerSecond float64   `json:"gc_pause_per_second"`
	GcPause          []float64 `json:"gc_pause"`
}

var lastSampleTime time.Time
var lastPauseNs uint64 = 0
var lastNumGc uint32 = 0

var nsInMs float64 = float64(time.Millisecond)

var statsMux sync.Mutex

func GetStats() *Stats {
	statsMux.Lock()
	defer statsMux.Unlock()

	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)

	now := time.Now()

	var gcPausePerSecond float64

	if lastPauseNs > 0 {
		pauseSinceLastSample := mem.PauseTotalNs - lastPauseNs
		gcPausePerSecond = float64(pauseSinceLastSample) / nsInMs
	}

	lastPauseNs = mem.PauseTotalNs

	countGc := int(mem.NumGC - lastNumGc)

	var gcPerSecond float64

	if lastNumGc > 0 {
		diff := float64(countGc)
		diffTime := now.Sub(lastSampleTime).Seconds()
		gcPerSecond = diff / diffTime
	}

	gcPause := make([]float64, countGc)

	if countGc > 0 {
		if countGc > 256 {
			// lagging GC pause times
			countGc = 256
		}

		for i := 0; i < countGc; i++ {
			idx := int((mem.NumGC-uint32(i))+255) % 256
			pause := float64(mem.PauseNs[idx])
			gcPause[i] = pause / nsInMs
		}
	}

	lastNumGc = mem.NumGC
	lastSampleTime = time.Now()

	return &Stats{
		Time:         now.UnixNano(),
		GoVersion:    runtime.Version(),
		GoOs:         runtime.GOOS,
		GoArch:       runtime.GOARCH,
		CpuNum:       runtime.NumCPU(),
		GoroutineNum: runtime.NumGoroutine(),
		Gomaxprocs:   runtime.GOMAXPROCS(0),
		CgoCallNum:   runtime.NumCgoCall(),
		// memory
		MemoryAlloc:      mem.Alloc,
		MemoryTotalAlloc: mem.TotalAlloc,
		MemorySys:        mem.Sys,
		MemoryLookups:    mem.Lookups,
		MemoryMallocs:    mem.Mallocs,
		MemoryFrees:      mem.Frees,
		// stack
		StackInUse: mem.StackInuse,
		// heap
		HeapAlloc:    mem.HeapAlloc,
		HeapSys:      mem.HeapSys,
		HeapIdle:     mem.HeapIdle,
		HeapInuse:    mem.HeapInuse,
		HeapReleased: mem.HeapReleased,
		HeapObjects:  mem.HeapObjects,
		// garbage collection
		GcNext:           mem.NextGC,
		GcLast:           mem.LastGC,
		GcNum:            mem.NumGC,
		GcPerSecond:      gcPerSecond,
		GcPausePerSecond: gcPausePerSecond,
		GcPause:          gcPause,
	}
}

var newLineTerm bool = false
var prettyPrint bool = false

func NewLineTermEnabled() {
	newLineTerm = true
}

func NewLineTermDisabled() {
	newLineTerm = false
}

func PrettyPrintEnabled() {
	prettyPrint = true
}

func PrettyPrintDisabled() {
	prettyPrint = false
}

func Handler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)

	var jsonBytes []byte
	var jsonErr error
	if prettyPrint {
		jsonBytes, jsonErr = json.MarshalIndent(GetStats(), "", "  ")
	} else {
		jsonBytes, jsonErr = json.Marshal(GetStats())
	}
	var body string
	if jsonErr != nil {
		body = jsonErr.Error()
	} else {
		body = string(jsonBytes)
	}

	if newLineTerm {
		body += "\n"
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"
	headers["Content-Length"] = strconv.Itoa(len(body))
	for name, value := range headers {
		w.Header().Set(name, value)
	}

	if jsonErr != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusOK)
	}

	io.WriteString(w, body)
}
<commit_msg>mod gc_pause<commit_after>package stats_api

import (
	"encoding/json"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"sync"
	"time"
)

type Stats struct {
	Time int64 `json:"time"`
	// runtime
	GoVersion    string `json:"go_version"`
	GoOs         string `json:"go_os"`
	GoArch       string `json:"go_arch"`
	CpuNum       int    `json:"cpu_num"`
	GoroutineNum int    `json:"goroutine_num"`
	Gomaxprocs   int    `json:"gomaxprocs"`
	CgoCallNum   int64  `json:"cgo_call_num"`
	// memory
	MemoryAlloc      uint64 `json:"memory_alloc"`
	MemoryTotalAlloc uint64 `json:"memory_total_alloc"`
	MemorySys        uint64 `json:"memory_sys"`
	MemoryLookups    uint64 `json:"memory_lookups"`
	MemoryMallocs    uint64 `json:"memory_mallocs"`
	MemoryFrees      uint64 `json:"memory_frees"`
	// stack
	StackInUse uint64 `json:"memory_stack"`
	// heap
	HeapAlloc    uint64 `json:"heap_alloc"`
	HeapSys      uint64 `json:"heap_sys"`
	HeapIdle     uint64 `json:"heap_idle"`
	HeapInuse    uint64 `json:"heap_inuse"`
	HeapReleased uint64 `json:"heap_released"`
	HeapObjects  uint64 `json:"heap_objects"`
	// garbage collection
	GcNext           uint64    `json:"gc_next"`
	GcLast           uint64    `json:"gc_last"`
	GcNum            uint32    `json:"gc_num"`
	GcPerSecond      float64   `json:"gc_per_second"`
	GcPausePerSecond float64   `json:"gc_pause_per_second"`
	GcPause          []float64 `json:"gc_pause"`
}

var lastSampleTime time.Time
var lastPauseNs uint64 = 0
var lastNumGc uint32 = 0

var nsInMs float64 = float64(time.Millisecond)

var statsMux sync.Mutex

func GetStats() *Stats {
	statsMux.Lock()
	defer statsMux.Unlock()

	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)

	now := time.Now()

	var gcPausePerSecond float64

	if lastPauseNs > 0 {
		pauseSinceLastSample := mem.PauseTotalNs - lastPauseNs
		gcPausePerSecond = float64(pauseSinceLastSample) / nsInMs
	}

	lastPauseNs = mem.PauseTotalNs

	countGc := int(mem.NumGC - lastNumGc)

	var gcPerSecond float64

	if lastNumGc > 0 {
		diff := float64(countGc)
		diffTime := now.Sub(lastSampleTime).Seconds()
		gcPerSecond = diff / diffTime
	}

	if countGc > 256 {
		// lagging GC pause times
		countGc = 256
	}

	gcPause := make([]float64, countGc)

	if countGc > 0 {

		for i := 0; i < countGc; i++ {
			idx := int((mem.NumGC-uint32(i))+255) % 256
			pause := float64(mem.PauseNs[idx])
			gcPause[i] = pause / nsInMs
		}
	}

	lastNumGc = mem.NumGC
	lastSampleTime = time.Now()

	return &Stats{
		Time:         now.UnixNano(),
		GoVersion:    runtime.Version(),
		GoOs:         runtime.GOOS,
		GoArch:       runtime.GOARCH,
		CpuNum:       runtime.NumCPU(),
		GoroutineNum: runtime.NumGoroutine(),
		Gomaxprocs:   runtime.GOMAXPROCS(0),
		CgoCallNum:   runtime.NumCgoCall(),
		// memory
		MemoryAlloc:      mem.Alloc,
		MemoryTotalAlloc: mem.TotalAlloc,
		MemorySys:        mem.Sys,
		MemoryLookups:    mem.Lookups,
		MemoryMallocs:    mem.Mallocs,
		MemoryFrees:      mem.Frees,
		// stack
		StackInUse: mem.StackInuse,
		// heap
		HeapAlloc:    mem.HeapAlloc,
		HeapSys:      mem.HeapSys,
		HeapIdle:     mem.HeapIdle,
		HeapInuse:    mem.HeapInuse,
		HeapReleased: mem.HeapReleased,
		HeapObjects:  mem.HeapObjects,
		// garbage collection
		GcNext:           mem.NextGC,
		GcLast:           mem.LastGC,
		GcNum:            mem.NumGC,
		GcPerSecond:      gcPerSecond,
		GcPausePerSecond: gcPausePerSecond,
		GcPause:          gcPause,
	}
}

var newLineTerm bool = false
var prettyPrint bool = false

func NewLineTermEnabled() {
	newLineTerm = true
}

func NewLineTermDisabled() {
	newLineTerm = false
}

func PrettyPrintEnabled() {
	prettyPrint = true
}

func PrettyPrintDisabled() {
	prettyPrint = false
}

func Handler(w http.ResponseWriter, r *http.Request) {
	var mem runtime.MemStats
	runtime.ReadMemStats(&mem)

	var jsonBytes []byte
	var jsonErr error
	if prettyPrint {
		jsonBytes, jsonErr = json.MarshalIndent(GetStats(), "", "  ")
	} else {
		jsonBytes, jsonErr = json.Marshal(GetStats())
	}
	var body string
	if jsonErr != nil {
		body = jsonErr.Error()
	} else {
		body = string(jsonBytes)
	}

	if newLineTerm {
		body += "\n"
	}

	headers := make(map[string]string)
	headers["Content-Type"] = "application/json"
	headers["Content-Length"] = strconv.Itoa(len(body))
	for name, value := range headers {
		w.Header().Set(name, value)
	}

	if jsonErr != nil {
		w.WriteHeader(http.StatusInternalServerError)
	} else {
		w.WriteHeader(http.StatusOK)
	}

	io.WriteString(w, body)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/syndtr/goleveldb/leveldb"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"
)

// A Mark is a JSON-unmarshalable, structure that specifes the bone and meat of
// a fact. The format is [[boneStr], terms, kinds]. The boneStr is a
// JSON-flattened nested-string-array with the quotes removed (the nodes of
// this tree cannot contain commas or brackets). Best not to try to interact
// with a Mark's contents directly; use the methods.  Marks should be considered
// immutable.

type Mark struct {
	list  [][]string
	flat  string
	hash  string
	Index int
}

// Given a mark's hash, and the pointers to the subst pair, there is only one
// answer for rewrite -- we memorize it.
type MarkBind struct {
	mark  int
	terms *Subst
	kinds *Subst
}

var (
	// TODO: will need to sync these
	memo        map[MarkBind]Mark
	markIndices map[string]int
	MaxMark     int
)

func (this *Mark) Hash() string {
	if len(this.hash) == 0 {
		this.hash = this.list[0][0] + "\x01" +
			strings.Join(this.list[1], "\x00") + "\x01" +
			strings.Join(this.list[2], "\x00")
		if markIndices == nil {
			markIndices = make(map[string]int)
		}
		index, ok := markIndices[this.hash]
		if !ok {
			index = len(markIndices)
			markIndices[this.hash] = index
		}
		this.Index = index
		if index >= MaxMark {
			MaxMark = MaxMark*2 + 400
		}
	}
	return this.hash
}

func (this *Mark) String() string {
	if len(this.flat) == 0 {
		str := this.list[0][0] + ";["
		for j := 1; j < len(this.list); j++ {
			if j > 1 {
				str += ","
			}
			str += "["
			for i, k := range this.list[j] {
				k = strings.Replace(k, "\\", "\\\\", -1)
				k = strings.Replace(k, "\"", "\\\"", -1)
				if i > 0 {
					str += ","
				}
				str += "\"" + k + "\""
			}
			str += "]"
		}
		str += "]"
		this.flat = str
		return str
	} else {
		return this.flat
	}

}

//BoneKey gives the prefix-string to use in a database query for bones like this
//mark.
func (this Mark) BoneKey() string {
	return this.list[0][0]
}

// Rewrite takes two maps to rewrite the terms and kinds of the mark. The bone
// parts are unchanged. If the output would be the same as the input, the input
// is simply returned.
func (this Mark) Rewrite(bind Bind) Mark {
	if memo == nil {
		memo = make(map[MarkBind]Mark)
	}
	keyMarkBind := MarkBind{this.Index, bind.terms, bind.kinds}
	if m, ok := memo[keyMarkBind]; ok {
		return m
	}
	var that Mark
	that.list = make([][]string, 3)
	that.list[0] = make([]string, 1)
	that.list[0][0] = this.list[0][0]
	// TODO: duplicate code in Bind
	mapStuff := func(j int, stuff *Subst) bool {
		workDone := false
		that.list[j] = make([]string, len(this.list[j]))
		for i, oldw := range this.list[j] {
			var ok bool
			that.list[j][i], ok = stuff.Get(oldw)
			if ok {
				workDone = true
			}
		}
		return workDone
	}
	tChange, kChange := true, true
	if bind.terms.Len() == 0 || !mapStuff(1, bind.terms) {
		that.list[1] = this.list[1]
		tChange = false
	}
	if bind.kinds.Len() == 0 || !mapStuff(2, bind.kinds) {
		that.list[2] = this.list[2]
		kChange = false
	}
	if !tChange && !kChange {
		that = this
	}
	// Force precompute these
	that.Hash()
	that.String()
	memo[keyMarkBind] = that
	return that
}

// A fact represents a stmt, thm, or defthm. This struct is designed to be
// unmarshalled into by the json package. Anything that is listed as interface{}
// in this struct is a nested list of strings.
type Fact struct {
	Bone struct {
		Stmt interface{}
		Hyps []interface{}
		Free [][]string
	}
	Meat struct {
		Terms []string
		Kinds []string
	}
	Skin struct {
		Name       string
		License    string
		HypNames   []string
		Delimiters []string
		DepNames   []string
		V          [][]string
		T          [][]string
	}
	Tree struct {
		Cmd      string
		Deps     [][][]string
		depMarks []Mark // wrapped around the [][]string
		Proof    []interface{}
		Dkind    int
		Dsig     []interface{}
		Terms    []string
		Kinds    []string
	}
}

func (this *Fact) Deps() []Mark {
	if this.Tree.depMarks == nil {
		this.Tree.depMarks = make([]Mark, len(this.Tree.Deps))
		for i, m := range this.Tree.Deps {
			var mm Mark
			mm.list = m
			// Force precompute these
			mm.Hash()
			mm.String()
			this.Tree.depMarks[i] = mm
		}
	}
	return this.Tree.depMarks
}

// An Entry is a database entry containing a Fact and its Key. The Key is the
// Fact's Mark, optionally followed by ! and a sha1sum.
type Entry struct {
	Key  string
	Fact Fact
	mark *Mark
}

// BonePrefix returns that prefix of a Key or MarkStr which only pertains to the fact's Bone,
// not its Meat.
func BonePrefix(key string) string {
	return key[0:strings.Index(key, ";")]
}

// MarkStr returns that prefix of an entry's Key which only pertains to the fact's Bone and Meat, not its sha1.
func (this *Entry) MarkStr() string {
	return this.Key[0:strings.LastIndex(this.Key, ";")]
}

func (this *Entry) Mark() Mark {
	if this.mark == nil {
		m := new(Mark)
		m.list = [][]string{[]string{BonePrefix(this.Key), this.MarkStr()},
			this.Fact.Meat.Terms, this.Fact.Meat.Kinds}
		this.mark = m
		// Force precompute these
		m.Hash()
		m.String()
	}
	return *this.mark
}

var dbCache map[string][]*Entry

func GetFactsByPrefix(db *leveldb.DB, pfix string, out chan<- *Entry) {
	if dbCache == nil {
		dbCache = make(map[string][]*Entry)
	}
	if es, ok := dbCache[pfix]; ok {
		for _, e := range es {
			out <- e
		}
		close(out)
		return
	}
	es := make([]*Entry, 0)
	start := []byte(pfix)
	iter := db.NewIterator(nil)
	defer iter.Release()
	end := append(start, byte(0xff))
	iter.Seek(start)
	found := false
	for {
		key := iter.Key()
		if bytes.Compare(key, end) > 0 {
			break
		}
		value := iter.Value()
		keyFact := new(Entry)
		keyFact.Key = string(key)
		err := json.Unmarshal(value, &keyFact.Fact)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\nPfix:%v\nKey:%s\nValue: %s\n",
				err, pfix, key, value)
			panic("JSON Error")
		} else {
			found = true
			out <- keyFact
			es = append(es, keyFact)
		}
		if DEBUG {
			fmt.Fprintf(os.Stderr, "Found: %s is %s\n", keyFact.Key, keyFact.Fact.Skin.Name)
		}
		if !iter.Next() {
			break
		}
	}
	if !found {
		fmt.Fprintf(os.Stderr, "Pfix Not Found: %s\n", pfix)
	}
	dbCache[pfix] = es
	close(out)
}

// makes a ghilbert-parsable string from a parsed-json sexp
func (this *Fact) sexpToString(sexp interface{}, bind Bind) string {
	if s, ok := sexp.(string); ok {
		fields := strings.Split(s, ".")
		if len(fields) != 2 {
			panic("Bad var string fields " + s)
		}
		num, err := strconv.Atoi(fields[1])
		if err != nil {
			panic("Bad num " + s)
		}
		switch fields[0] {
		case "Deps":
			return this.Skin.DepNames[num]
		case "Hyps":
			return this.Skin.HypNames[num]
		default: // TN or VN
			var names [][]string
			switch fields[0][0] {
			case 'T':
				names = this.Skin.T
			case 'V':
				names = this.Skin.V
			default:
				panic("Bad var string " + s)
			}
			kindNum, err := strconv.Atoi(fields[0][1:])
			if err != nil {
				panic("Bad var kind num " + s)
			}
			return names[kindNum][num]
		}
	} else if s, ok := sexp.(float64); ok {
		return bind.Term(this.Tree.Terms[int(s)])
	} else {
		v := reflect.ValueOf(sexp)
		l := v.Len()
		out := "("
		for i := 0; i < l; i++ {
			if i > 0 {
				out += " "
			}
			out += this.sexpToString(v.Index(i).Interface(), bind)
		}
		out += ")"
		return out
	}
}

// Extract the vars and tvars used in this fact into the given maps.
func (this *Fact) getVarNames(varDecs, tvarDecs map[string]map[string]bool,
	bind Bind) {
	for ki, vs := range this.Skin.V {
		if len(vs) == 0 {
			continue
		}
		kind := bind.Kind(this.Tree.Kinds[ki])
		vd, ok := varDecs[kind]
		if !ok {
			vd = make(map[string]bool)
			varDecs[kind] = vd
		}
		for _, v := range vs {
			vd[v] = true
		}
	}
	for ki, vs := range this.Skin.T {
		if len(vs) == 0 {
			continue
		}
		kind := bind.Kind(this.Tree.Kinds[ki])
		vd, ok := tvarDecs[kind]
		if !ok {
			vd = make(map[string]bool)
			tvarDecs[kind] = vd
		}
		for _, v := range vs {
			vd[v] = true
		}
	}
}

func WriteProofs(out io.Writer, list []*Entry, exports map[string]*Entry,
	bind Bind) (n int, err error) {
	// Step 1: scan through the list. Set aside axioms. Pull out all var names
	// to predeclare. Rename exports to match interface.
	depNames := make(map[string]string)
	varDecs := make(map[string]map[string]bool)
	tvarDecs := make(map[string]map[string]bool)
	axioms := make([]*Fact, 0)
	rev := make([]*Fact, len(list))
	j := len(list) - 1
	for _, e := range list {
		f := &e.Fact
		mark := e.Mark().Rewrite(bind)
		markStr := mark.String()
		if exp, ok := exports[markStr]; ok {
			f.Skin.Name = exp.Fact.Skin.Name
		}
		depNames[markStr] = f.Skin.Name
		if len(f.Deps()) > 0 {
			rev[j], j = f, j-1
			f.getVarNames(varDecs, tvarDecs, bind)
		} else {
			axioms = append(axioms, f)
			// TODO: use these
		}
	}
	rev = rev[j+1:]
	write := func(s string) {
		nn, err := io.WriteString(out, s)
		if err != nil {
			panic(err)
		}
		n += nn
	}

	// Step 2: write var and tvar decs for each kind
	for k, vs := range varDecs {
		write("var (")
		write(k)
		write(" ")
		for v := range vs {
			write(v)
			write(" ")
		}
		write(")\n")
	}
	for k, vs := range tvarDecs {
		write("tvar (")
		write(k)
		write(" ")
		for v := range vs {
			write(v)
			write(" ")
		}
		write(")\n")
	}

	// Step 3: write each of the proofs.
	for _, f := range rev {
		for i, mark := range f.Deps() {
			newMark := bind.Rewrite(mark)
			markStr := newMark.String()
			newDep, ok := depNames[markStr]
			if !ok {
				panic("Can't find dep for " + markStr)
			}
			// TODO: oughtn't mutate
			f.Skin.DepNames[i] = newDep
		}
		if f.Tree.Dsig != nil {
			write("def")
		}
		write("thm (")
		write(f.Skin.Name)
		write(" ")
		if f.Tree.Dsig != nil {
			write(bind.Kind(f.Tree.Kinds[f.Tree.Dkind]))
			write(" ")
			write(f.sexpToString(f.Tree.Dsig, bind))
			write(" ")
		}
		write(f.sexpToString(f.Bone.Free, bind))
		write("\n   (")
		for i, s := range f.Bone.Hyps {
			write(f.Skin.HypNames[i])
			write(" ")
			write(f.sexpToString(s, bind))
			write("\n   ")
		}
		write(")\n   ")
		write(f.sexpToString(f.Bone.Stmt, bind))
		write("\n")
		for _, s := range f.Tree.Proof {
			write(f.sexpToString(s, bind))
			write("  ")
		}
		write("\n)\n\n")
	}
	return
}
<commit_msg>use new leveldb iterator api<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/util"
	"io"
	"os"
	"reflect"
	"strconv"
	"strings"
)

// A Mark is a JSON-unmarshalable, structure that specifes the bone and meat of
// a fact. The format is [[boneStr], terms, kinds]. The boneStr is a
// JSON-flattened nested-string-array with the quotes removed (the nodes of
// this tree cannot contain commas or brackets). Best not to try to interact
// with a Mark's contents directly; use the methods.  Marks should be considered
// immutable.

type Mark struct {
	list  [][]string
	flat  string
	hash  string
	Index int
}

// Given a mark's hash, and the pointers to the subst pair, there is only one
// answer for rewrite -- we memorize it.
type MarkBind struct {
	mark  int
	terms *Subst
	kinds *Subst
}

var (
	// TODO: will need to sync these
	memo        map[MarkBind]Mark
	markIndices map[string]int
	MaxMark     int
)

func (this *Mark) Hash() string {
	if len(this.hash) == 0 {
		this.hash = this.list[0][0] + "\x01" +
			strings.Join(this.list[1], "\x00") + "\x01" +
			strings.Join(this.list[2], "\x00")
		if markIndices == nil {
			markIndices = make(map[string]int)
		}
		index, ok := markIndices[this.hash]
		if !ok {
			index = len(markIndices)
			markIndices[this.hash] = index
		}
		this.Index = index
		if index >= MaxMark {
			MaxMark = MaxMark*2 + 400
		}
	}
	return this.hash
}

func (this *Mark) String() string {
	if len(this.flat) == 0 {
		str := this.list[0][0] + ";["
		for j := 1; j < len(this.list); j++ {
			if j > 1 {
				str += ","
			}
			str += "["
			for i, k := range this.list[j] {
				k = strings.Replace(k, "\\", "\\\\", -1)
				k = strings.Replace(k, "\"", "\\\"", -1)
				if i > 0 {
					str += ","
				}
				str += "\"" + k + "\""
			}
			str += "]"
		}
		str += "]"
		this.flat = str
		return str
	} else {
		return this.flat
	}

}

//BoneKey gives the prefix-string to use in a database query for bones like this
//mark.
func (this Mark) BoneKey() string {
	return this.list[0][0]
}

// Rewrite takes two maps to rewrite the terms and kinds of the mark. The bone
// parts are unchanged. If the output would be the same as the input, the input
// is simply returned.
func (this Mark) Rewrite(bind Bind) Mark {
	if memo == nil {
		memo = make(map[MarkBind]Mark)
	}
	keyMarkBind := MarkBind{this.Index, bind.terms, bind.kinds}
	if m, ok := memo[keyMarkBind]; ok {
		return m
	}
	var that Mark
	that.list = make([][]string, 3)
	that.list[0] = make([]string, 1)
	that.list[0][0] = this.list[0][0]
	// TODO: duplicate code in Bind
	mapStuff := func(j int, stuff *Subst) bool {
		workDone := false
		that.list[j] = make([]string, len(this.list[j]))
		for i, oldw := range this.list[j] {
			var ok bool
			that.list[j][i], ok = stuff.Get(oldw)
			if ok {
				workDone = true
			}
		}
		return workDone
	}
	tChange, kChange := true, true
	if bind.terms.Len() == 0 || !mapStuff(1, bind.terms) {
		that.list[1] = this.list[1]
		tChange = false
	}
	if bind.kinds.Len() == 0 || !mapStuff(2, bind.kinds) {
		that.list[2] = this.list[2]
		kChange = false
	}
	if !tChange && !kChange {
		that = this
	}
	// Force precompute these
	that.Hash()
	that.String()
	memo[keyMarkBind] = that
	return that
}

// A fact represents a stmt, thm, or defthm. This struct is designed to be
// unmarshalled into by the json package. Anything that is listed as interface{}
// in this struct is a nested list of strings.
type Fact struct {
	Bone struct {
		Stmt interface{}
		Hyps []interface{}
		Free [][]string
	}
	Meat struct {
		Terms []string
		Kinds []string
	}
	Skin struct {
		Name       string
		License    string
		HypNames   []string
		Delimiters []string
		DepNames   []string
		V          [][]string
		T          [][]string
	}
	Tree struct {
		Cmd      string
		Deps     [][][]string
		depMarks []Mark // wrapped around the [][]string
		Proof    []interface{}
		Dkind    int
		Dsig     []interface{}
		Terms    []string
		Kinds    []string
	}
}

func (this *Fact) Deps() []Mark {
	if this.Tree.depMarks == nil {
		this.Tree.depMarks = make([]Mark, len(this.Tree.Deps))
		for i, m := range this.Tree.Deps {
			var mm Mark
			mm.list = m
			// Force precompute these
			mm.Hash()
			mm.String()
			this.Tree.depMarks[i] = mm
		}
	}
	return this.Tree.depMarks
}

// An Entry is a database entry containing a Fact and its Key. The Key is the
// Fact's Mark, optionally followed by ! and a sha1sum.
type Entry struct {
	Key  string
	Fact Fact
	mark *Mark
}

// BonePrefix returns that prefix of a Key or MarkStr which only pertains to the fact's Bone,
// not its Meat.
func BonePrefix(key string) string {
	return key[0:strings.Index(key, ";")]
}

// MarkStr returns that prefix of an entry's Key which only pertains to the fact's Bone and Meat, not its sha1.
func (this *Entry) MarkStr() string {
	return this.Key[0:strings.LastIndex(this.Key, ";")]
}

func (this *Entry) Mark() Mark {
	if this.mark == nil {
		m := new(Mark)
		m.list = [][]string{[]string{BonePrefix(this.Key), this.MarkStr()},
			this.Fact.Meat.Terms, this.Fact.Meat.Kinds}
		this.mark = m
		// Force precompute these
		m.Hash()
		m.String()
	}
	return *this.mark
}

var dbCache map[string][]*Entry

func GetFactsByPrefix(db *leveldb.DB, pfix string, out chan<- *Entry) {
	if dbCache == nil {
		dbCache = make(map[string][]*Entry)
	}
	if es, ok := dbCache[pfix]; ok {
		for _, e := range es {
			out <- e
		}
		close(out)
		return
	}
	es := make([]*Entry, 0)
	var rang util.Range
	rang.Start = []byte(pfix)
	rang.Limit = append(rang.Start, byte(0xff))
	iter := db.NewIterator(&rang, nil)
	defer iter.Release()
	found := false
	for iter.Next() {
		key := iter.Key()
		value := iter.Value()
		keyFact := new(Entry)
		keyFact.Key = string(key)
		err := json.Unmarshal(value, &keyFact.Fact)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\nPfix:%v\nKey:%s\nValue: %s\n",
				err, pfix, key, value)
			panic("JSON Error")
		} else {
			found = true
			out <- keyFact
			es = append(es, keyFact)
		}
		if DEBUG {
			fmt.Fprintf(os.Stderr, "Found: %s is %s\n", keyFact.Key, keyFact.Fact.Skin.Name)
		}
	}
	if !found {
		fmt.Fprintf(os.Stderr, "Pfix Not Found: %s\n", pfix)
	}
	dbCache[pfix] = es
	close(out)
}

// makes a ghilbert-parsable string from a parsed-json sexp
func (this *Fact) sexpToString(sexp interface{}, bind Bind) string {
	if s, ok := sexp.(string); ok {
		fields := strings.Split(s, ".")
		if len(fields) != 2 {
			panic("Bad var string fields " + s)
		}
		num, err := strconv.Atoi(fields[1])
		if err != nil {
			panic("Bad num " + s)
		}
		switch fields[0] {
		case "Deps":
			return this.Skin.DepNames[num]
		case "Hyps":
			return this.Skin.HypNames[num]
		default: // TN or VN
			var names [][]string
			switch fields[0][0] {
			case 'T':
				names = this.Skin.T
			case 'V':
				names = this.Skin.V
			default:
				panic("Bad var string " + s)
			}
			kindNum, err := strconv.Atoi(fields[0][1:])
			if err != nil {
				panic("Bad var kind num " + s)
			}
			return names[kindNum][num]
		}
	} else if s, ok := sexp.(float64); ok {
		return bind.Term(this.Tree.Terms[int(s)])
	} else {
		v := reflect.ValueOf(sexp)
		l := v.Len()
		out := "("
		for i := 0; i < l; i++ {
			if i > 0 {
				out += " "
			}
			out += this.sexpToString(v.Index(i).Interface(), bind)
		}
		out += ")"
		return out
	}
}

// Extract the vars and tvars used in this fact into the given maps.
func (this *Fact) getVarNames(varDecs, tvarDecs map[string]map[string]bool,
	bind Bind) {
	for ki, vs := range this.Skin.V {
		if len(vs) == 0 {
			continue
		}
		kind := bind.Kind(this.Tree.Kinds[ki])
		vd, ok := varDecs[kind]
		if !ok {
			vd = make(map[string]bool)
			varDecs[kind] = vd
		}
		for _, v := range vs {
			vd[v] = true
		}
	}
	for ki, vs := range this.Skin.T {
		if len(vs) == 0 {
			continue
		}
		kind := bind.Kind(this.Tree.Kinds[ki])
		vd, ok := tvarDecs[kind]
		if !ok {
			vd = make(map[string]bool)
			tvarDecs[kind] = vd
		}
		for _, v := range vs {
			vd[v] = true
		}
	}
}

func WriteProofs(out io.Writer, list []*Entry, exports map[string]*Entry,
	bind Bind) (n int, err error) {
	// Step 1: scan through the list. Set aside axioms. Pull out all var names
	// to predeclare. Rename exports to match interface.
	depNames := make(map[string]string)
	varDecs := make(map[string]map[string]bool)
	tvarDecs := make(map[string]map[string]bool)
	axioms := make([]*Fact, 0)
	rev := make([]*Fact, len(list))
	j := len(list) - 1
	for _, e := range list {
		f := &e.Fact
		mark := e.Mark().Rewrite(bind)
		markStr := mark.String()
		if exp, ok := exports[markStr]; ok {
			f.Skin.Name = exp.Fact.Skin.Name
		}
		depNames[markStr] = f.Skin.Name
		if len(f.Deps()) > 0 {
			rev[j], j = f, j-1
			f.getVarNames(varDecs, tvarDecs, bind)
		} else {
			axioms = append(axioms, f)
			// TODO: use these
		}
	}
	rev = rev[j+1:]
	write := func(s string) {
		nn, err := io.WriteString(out, s)
		if err != nil {
			panic(err)
		}
		n += nn
	}

	// Step 2: write var and tvar decs for each kind
	for k, vs := range varDecs {
		write("var (")
		write(k)
		write(" ")
		for v := range vs {
			write(v)
			write(" ")
		}
		write(")\n")
	}
	for k, vs := range tvarDecs {
		write("tvar (")
		write(k)
		write(" ")
		for v := range vs {
			write(v)
			write(" ")
		}
		write(")\n")
	}

	// Step 3: write each of the proofs.
	for _, f := range rev {
		for i, mark := range f.Deps() {
			newMark := bind.Rewrite(mark)
			markStr := newMark.String()
			newDep, ok := depNames[markStr]
			if !ok {
				panic("Can't find dep for " + markStr)
			}
			// TODO: oughtn't mutate
			f.Skin.DepNames[i] = newDep
		}
		if f.Tree.Dsig != nil {
			write("def")
		}
		write("thm (")
		write(f.Skin.Name)
		write(" ")
		if f.Tree.Dsig != nil {
			write(bind.Kind(f.Tree.Kinds[f.Tree.Dkind]))
			write(" ")
			write(f.sexpToString(f.Tree.Dsig, bind))
			write(" ")
		}
		write(f.sexpToString(f.Bone.Free, bind))
		write("\n   (")
		for i, s := range f.Bone.Hyps {
			write(f.Skin.HypNames[i])
			write(" ")
			write(f.sexpToString(s, bind))
			write("\n   ")
		}
		write(")\n   ")
		write(f.sexpToString(f.Bone.Stmt, bind))
		write("\n")
		for _, s := range f.Tree.Proof {
			write(f.sexpToString(s, bind))
			write("  ")
		}
		write("\n)\n\n")
	}
	return
}
<|endoftext|>