<commit_before>package ethchain

import (
	"bytes"
	"container/list"
	"fmt"
	"math/big"
	"sync"
	"time"

	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethlog"
	"github.com/ethereum/eth-go/ethreact"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
)

var statelogger = ethlog.NewLogger("STATE")

type BlockProcessor interface {
	ProcessBlock(block *Block)
}

type Peer interface {
	Inbound() bool
	LastSend() time.Time
	LastPong() int64
	Host() []byte
	Port() uint16
	Version() string
	PingTime() string
	Connected() *int32
}

type EthManager interface {
	StateManager() *StateManager
	BlockChain() *BlockChain
	TxPool() *TxPool
	Broadcast(msgType ethwire.MsgType, data []interface{})
	Reactor() *ethreact.ReactorEngine
	PeerCount() int
	IsMining() bool
	IsListening() bool
	Peers() *list.List
	KeyManager() *ethcrypto.KeyManager
	ClientIdentity() ethwire.ClientIdentity
	Db() ethutil.Database
}

type StateManager struct {
	// Mutex for locking the block processor. Blocks can only be handled one at a time
	mutex sync.Mutex
	// Canonical block chain
	bc *BlockChain
	// non-persistent key/value memory storage
	mem map[string]*big.Int
	// Proof of work used for validating
	Pow PoW
	// The ethereum manager interface
	Ethereum EthManager
	// The managed states
	// Transiently state. The trans state isn't ever saved, validated and
	// it could be used for setting account nonces without effecting
	// the main states.
	transState *ethstate.State
	// Mining state. The mining state is used purely and solely by the mining
	// operation.
	miningState *ethstate.State

	// The last attempted block is mainly used for debugging purposes
	// This does not have to be a valid block and will be set during
	// 'Process' & canonical validation.
	lastAttemptedBlock *Block
}

func NewStateManager(ethereum EthManager) *StateManager {
	sm := &StateManager{
		mem:      make(map[string]*big.Int),
		Pow:      &EasyPow{},
		Ethereum: ethereum,
		bc:       ethereum.BlockChain(),
	}
	sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy()
	sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy()

	return sm
}

func (sm *StateManager) CurrentState() *ethstate.State {
	return sm.Ethereum.BlockChain().CurrentBlock.State()
}

func (sm *StateManager) TransState() *ethstate.State {
	return sm.transState
}

func (sm *StateManager) MiningState() *ethstate.State {
	return sm.miningState
}

func (sm *StateManager) NewMiningState() *ethstate.State {
	sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy()

	return sm.miningState
}

func (sm *StateManager) BlockChain() *BlockChain {
	return sm.bc
}

func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) {
	var (
		receipts           Receipts
		handled, unhandled Transactions
		totalUsedGas       = big.NewInt(0)
		err                error
	)

done:
	for i, tx := range txs {
		txGas := new(big.Int).Set(tx.Gas)

		cb := state.GetStateObject(coinbase.Address())
		st := NewStateTransition(cb, tx, state, block)
		err = st.TransitionState()
		if err != nil {
			statelogger.Infoln(err)
			switch {
			case IsNonceErr(err):
				err = nil // ignore error
				continue
			case IsGasLimitErr(err):
				unhandled = txs[i:]

				break done
			default:
				statelogger.Infoln(err)
				err = nil
				//return nil, nil, nil, err
			}
		}

		// Notify all subscribers
		self.Ethereum.Reactor().Post("newTx:post", tx)

		// Update the state with pending changes
		state.Update()

		txGas.Sub(txGas, st.gas)
		accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
		receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}

		if i < len(block.Receipts()) {
			original := block.Receipts()[i]
			if !original.Cmp(receipt) {
				return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x  <=>  (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash())
			}
		}

		receipts = append(receipts, receipt)
		handled = append(handled, tx)

		if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
			state.CreateOutputForDiff()
		}
	}

	parent.GasUsed = totalUsedGas

	return receipts, handled, unhandled, err
}

func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
	// Processing a blocks may never happen simultaneously
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	if sm.bc.HasBlock(block.Hash()) {
		return nil
	}

	if !sm.bc.HasBlock(block.PrevHash) {
		return ParentError(block.PrevHash)
	}

	sm.lastAttemptedBlock = block

	var (
		parent = sm.bc.GetBlock(block.PrevHash)
		state  = parent.State()
	)

	// Defer the Undo on the Trie. If the block processing happened
	// we don't want to undo but since undo only happens on dirty
	// nodes this won't happen because Commit would have been called
	// before that.
	defer state.Reset()

	if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
		fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
	}

	receipts, err := sm.ApplyDiff(state, parent, block)
	if err != nil {
		return err
	}

	txSha := CreateTxSha(receipts)
	if bytes.Compare(txSha, block.TxSha) != 0 {
		return fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha)
	}

	// Block validation
	if err = sm.ValidateBlock(block); err != nil {
		statelogger.Errorln("Error validating block:", err)
		return err
	}

	// I'm not sure, but I don't know if there should be thrown
	// any errors at this time.
	if err = sm.AccumelateRewards(state, block); err != nil {
		statelogger.Errorln("Error accumulating reward", err)
		return err
	}

	if !block.State().Cmp(state) {
		err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis:  %x", block.State().Trie.Root, state.Trie.Root)
		return
	}

	// Calculate the new total difficulty and sync back to the db
	if sm.CalculateTD(block) {
		// Sync the current block's state to the database and cancelling out the deferred Undo
		state.Sync()

		// Add the block to the chain
		sm.bc.Add(block)

		// Create a bloom bin for this block
		filter := sm.createBloomFilter(state)
		// Persist the data
		fk := append([]byte("bloom"), block.Hash()...)
		sm.Ethereum.Db().Put(fk, filter.Bin())

		statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash())
		if dontReact == false {
			sm.Ethereum.Reactor().Post("newBlock", block)

			state.Manifest().Reset()
		}

		sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})

		sm.Ethereum.TxPool().RemoveInvalid(state)
	} else {
		statelogger.Errorln("total diff failed")
	}

	return nil
}

func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) {
	coinbase := state.GetOrNewStateObject(block.Coinbase)
	coinbase.SetGasPool(block.CalcGasLimit(parent))

	// Process the transactions on to current block
	receipts, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions())
	if err != nil {
		return nil, err
	}

	return receipts, nil
}

func (sm *StateManager) CalculateTD(block *Block) bool {
	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
	td := new(big.Int)
	td = td.Add(sm.bc.TD, uncleDiff)
	td = td.Add(td, block.Difficulty)

	// The new TD will only be accepted if the new difficulty is
	// is greater than the previous.
	if td.Cmp(sm.bc.TD) > 0 {
		// Set the new total difficulty back to the block chain
		sm.bc.SetTotalDifficulty(td)

		return true
	}

	return false
}

// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *StateManager) ValidateBlock(block *Block) error {
	// TODO
	// 2. Check if the difficulty is correct

	// Check each uncle's previous hash. In order for it to be valid
	// is if it has the same block hash as the current
	previousBlock := sm.bc.GetBlock(block.PrevHash)
	for _, uncle := range block.Uncles {
		if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 {
			return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash)
		}
	}

	diff := block.Time - previousBlock.Time
	if diff < 0 {
		return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time)
	}

	/* XXX
	// New blocks must be within the 15 minute range of the last block.
	if diff > int64(15*time.Minute) {
		return ValidationError("Block is too far in the future of last block (> 15 minutes)")
	}
	*/

	// Verify the nonce of the block. Return an error if it's not valid
	if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) {
		return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
	}

	return nil
}

func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
	base := new(big.Int)
	for i := 0; i < uncleLength; i++ {
		base.Add(base, UncleInclusionReward)
	}

	return base.Add(base, BlockReward)
}

func CalculateUncleReward(block *Block) *big.Int {
	return UncleReward
}

func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error {
	// Get the account associated with the coinbase
	account := state.GetAccount(block.Coinbase)
	// Reward amount of ether to the coinbase address
	account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))

	addr := make([]byte, len(block.Coinbase))
	copy(addr, block.Coinbase)
	state.UpdateStateObject(account)

	for _, uncle := range block.Uncles {
		uncleAccount := state.GetAccount(uncle.Coinbase)
		uncleAccount.AddAmount(CalculateUncleReward(uncle))

		state.UpdateStateObject(uncleAccount)
	}

	return nil
}

func (sm *StateManager) Stop() {
	sm.bc.Stop()
}

// Manifest will handle both creating notifications and generating bloom bin data
func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
	bloomf := NewBloomFilter(nil)

	/*
		for addr, stateObject := range state.Manifest().ObjectChanges {
			// Set the bloom filter's bin
			bloomf.Set([]byte(addr))

			sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
		}
	*/
	for _, msg := range state.Manifest().Messages {
		bloomf.Set(msg.To)
		bloomf.Set(msg.From)
	}

	sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages)

	/*
		for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
			for addr, value := range mappedObjects {
				// Set the bloom filter's bin
				bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr)))

				sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
			}
		}
	*/

	return bloomf
}

func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) {
	if !sm.bc.HasBlock(block.PrevHash) {
		return nil, ParentError(block.PrevHash)
	}

	sm.lastAttemptedBlock = block

	var (
		parent = sm.bc.GetBlock(block.PrevHash)
		state  = parent.State().Copy()
	)

	defer state.Reset()

	sm.ApplyDiff(state, parent, block)

	sm.AccumelateRewards(state, block)

	return state.Manifest().Messages, nil
}
<commit_msg>Reset the transient state when a new block's been found<commit_after>package ethchain

import (
	"bytes"
	"container/list"
	"fmt"
	"math/big"
	"sync"
	"time"

	"github.com/ethereum/eth-go/ethcrypto"
	"github.com/ethereum/eth-go/ethlog"
	"github.com/ethereum/eth-go/ethreact"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethwire"
)

var statelogger = ethlog.NewLogger("STATE")

type BlockProcessor interface {
	ProcessBlock(block *Block)
}

type Peer interface {
	Inbound() bool
	LastSend() time.Time
	LastPong() int64
	Host() []byte
	Port() uint16
	Version() string
	PingTime() string
	Connected() *int32
}

type EthManager interface {
	StateManager() *StateManager
	BlockChain() *BlockChain
	TxPool() *TxPool
	Broadcast(msgType ethwire.MsgType, data []interface{})
	Reactor() *ethreact.ReactorEngine
	PeerCount() int
	IsMining() bool
	IsListening() bool
	Peers() *list.List
	KeyManager() *ethcrypto.KeyManager
	ClientIdentity() ethwire.ClientIdentity
	Db() ethutil.Database
}

type StateManager struct {
	// Mutex for locking the block processor. Blocks can only be handled one at a time
	mutex sync.Mutex
	// Canonical block chain
	bc *BlockChain
	// non-persistent key/value memory storage
	mem map[string]*big.Int
	// Proof of work used for validating
	Pow PoW
	// The ethereum manager interface
	Ethereum EthManager
	// The managed states
	// Transiently state. The trans state isn't ever saved, validated and
	// it could be used for setting account nonces without effecting
	// the main states.
	transState *ethstate.State
	// Mining state. The mining state is used purely and solely by the mining
	// operation.
	miningState *ethstate.State

	// The last attempted block is mainly used for debugging purposes
	// This does not have to be a valid block and will be set during
	// 'Process' & canonical validation.
	lastAttemptedBlock *Block
}

func NewStateManager(ethereum EthManager) *StateManager {
	sm := &StateManager{
		mem:      make(map[string]*big.Int),
		Pow:      &EasyPow{},
		Ethereum: ethereum,
		bc:       ethereum.BlockChain(),
	}
	sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy()
	sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy()

	return sm
}

func (sm *StateManager) CurrentState() *ethstate.State {
	return sm.Ethereum.BlockChain().CurrentBlock.State()
}

func (sm *StateManager) TransState() *ethstate.State {
	return sm.transState
}

func (sm *StateManager) MiningState() *ethstate.State {
	return sm.miningState
}

func (sm *StateManager) NewMiningState() *ethstate.State {
	sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy()

	return sm.miningState
}

func (sm *StateManager) BlockChain() *BlockChain {
	return sm.bc
}

func (self *StateManager) ProcessTransactions(coinbase *ethstate.StateObject, state *ethstate.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) {
	var (
		receipts           Receipts
		handled, unhandled Transactions
		totalUsedGas       = big.NewInt(0)
		err                error
	)

done:
	for i, tx := range txs {
		txGas := new(big.Int).Set(tx.Gas)

		cb := state.GetStateObject(coinbase.Address())
		st := NewStateTransition(cb, tx, state, block)
		err = st.TransitionState()
		if err != nil {
			statelogger.Infoln(err)
			switch {
			case IsNonceErr(err):
				err = nil // ignore error
				continue
			case IsGasLimitErr(err):
				unhandled = txs[i:]

				break done
			default:
				statelogger.Infoln(err)
				err = nil
				//return nil, nil, nil, err
			}
		}

		// Notify all subscribers
		self.Ethereum.Reactor().Post("newTx:post", tx)

		// Update the state with pending changes
		state.Update()

		txGas.Sub(txGas, st.gas)
		accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas))
		receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}

		if i < len(block.Receipts()) {
			original := block.Receipts()[i]
			if !original.Cmp(receipt) {
				return nil, nil, nil, fmt.Errorf("err diff #%d (r) %v ~ %x  <=>  (c) %v ~ %x (%x)\n", i+1, original.CumulativeGasUsed, original.PostState[0:4], receipt.CumulativeGasUsed, receipt.PostState[0:4], receipt.Tx.Hash())
			}
		}

		receipts = append(receipts, receipt)
		handled = append(handled, tx)

		if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
			state.CreateOutputForDiff()
		}
	}

	parent.GasUsed = totalUsedGas

	return receipts, handled, unhandled, err
}

func (sm *StateManager) Process(block *Block, dontReact bool) (err error) {
	// Processing a blocks may never happen simultaneously
	sm.mutex.Lock()
	defer sm.mutex.Unlock()

	if sm.bc.HasBlock(block.Hash()) {
		return nil
	}

	if !sm.bc.HasBlock(block.PrevHash) {
		return ParentError(block.PrevHash)
	}

	sm.lastAttemptedBlock = block

	var (
		parent = sm.bc.GetBlock(block.PrevHash)
		state  = parent.State()
	)

	// Defer the Undo on the Trie. If the block processing happened
	// we don't want to undo but since undo only happens on dirty
	// nodes this won't happen because Commit would have been called
	// before that.
	defer state.Reset()

	if ethutil.Config.Diff && ethutil.Config.DiffType == "all" {
		fmt.Printf("## %x %x ##\n", block.Hash(), block.Number)
	}

	receipts, err := sm.ApplyDiff(state, parent, block)
	if err != nil {
		return err
	}

	txSha := CreateTxSha(receipts)
	if bytes.Compare(txSha, block.TxSha) != 0 {
		return fmt.Errorf("Error validating tx sha. Received %x, got %x", block.TxSha, txSha)
	}

	// Block validation
	if err = sm.ValidateBlock(block); err != nil {
		statelogger.Errorln("Error validating block:", err)
		return err
	}

	// I'm not sure, but I don't know if there should be thrown
	// any errors at this time.
	if err = sm.AccumelateRewards(state, block); err != nil {
		statelogger.Errorln("Error accumulating reward", err)
		return err
	}

	if !block.State().Cmp(state) {
		err = fmt.Errorf("Invalid merkle root.\nrec: %x\nis:  %x", block.State().Trie.Root, state.Trie.Root)
		return
	}

	// Calculate the new total difficulty and sync back to the db
	if sm.CalculateTD(block) {
		// Sync the current block's state to the database and cancelling out the deferred Undo
		state.Sync()

		// Add the block to the chain
		sm.bc.Add(block)

		sm.transState = state.Copy()

		// Create a bloom bin for this block
		filter := sm.createBloomFilter(state)
		// Persist the data
		fk := append([]byte("bloom"), block.Hash()...)
		sm.Ethereum.Db().Put(fk, filter.Bin())

		statelogger.Infof("Added block #%d (%x)\n", block.Number, block.Hash())
		if dontReact == false {
			sm.Ethereum.Reactor().Post("newBlock", block)

			state.Manifest().Reset()
		}

		sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})

		sm.Ethereum.TxPool().RemoveInvalid(state)
	} else {
		statelogger.Errorln("total diff failed")
	}

	return nil
}

func (sm *StateManager) ApplyDiff(state *ethstate.State, parent, block *Block) (receipts Receipts, err error) {
	coinbase := state.GetOrNewStateObject(block.Coinbase)
	coinbase.SetGasPool(block.CalcGasLimit(parent))

	// Process the transactions on to current block
	receipts, _, _, err = sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions())
	if err != nil {
		return nil, err
	}

	return receipts, nil
}

func (sm *StateManager) CalculateTD(block *Block) bool {
	uncleDiff := new(big.Int)
	for _, uncle := range block.Uncles {
		uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
	}

	// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
	td := new(big.Int)
	td = td.Add(sm.bc.TD, uncleDiff)
	td = td.Add(td, block.Difficulty)

	// The new TD will only be accepted if the new difficulty is
	// is greater than the previous.
	if td.Cmp(sm.bc.TD) > 0 {
		// Set the new total difficulty back to the block chain
		sm.bc.SetTotalDifficulty(td)

		return true
	}

	return false
}

// Validates the current block. Returns an error if the block was invalid,
// an uncle or anything that isn't on the current block chain.
// Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *StateManager) ValidateBlock(block *Block) error {
	// TODO
	// 2. Check if the difficulty is correct

	// Check each uncle's previous hash. In order for it to be valid
	// is if it has the same block hash as the current
	previousBlock := sm.bc.GetBlock(block.PrevHash)
	for _, uncle := range block.Uncles {
		if bytes.Compare(uncle.PrevHash, previousBlock.PrevHash) != 0 {
			return ValidationError("Mismatch uncle's previous hash. Expected %x, got %x", previousBlock.PrevHash, uncle.PrevHash)
		}
	}

	diff := block.Time - previousBlock.Time
	if diff < 0 {
		return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time)
	}

	/* XXX
	// New blocks must be within the 15 minute range of the last block.
	if diff > int64(15*time.Minute) {
		return ValidationError("Block is too far in the future of last block (> 15 minutes)")
	}
	*/

	// Verify the nonce of the block. Return an error if it's not valid
	if !sm.Pow.Verify(block.HashNoNonce(), block.Difficulty, block.Nonce) {
		return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
	}

	return nil
}

func CalculateBlockReward(block *Block, uncleLength int) *big.Int {
	base := new(big.Int)
	for i := 0; i < uncleLength; i++ {
		base.Add(base, UncleInclusionReward)
	}

	return base.Add(base, BlockReward)
}

func CalculateUncleReward(block *Block) *big.Int {
	return UncleReward
}

func (sm *StateManager) AccumelateRewards(state *ethstate.State, block *Block) error {
	// Get the account associated with the coinbase
	account := state.GetAccount(block.Coinbase)
	// Reward amount of ether to the coinbase address
	account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))

	addr := make([]byte, len(block.Coinbase))
	copy(addr, block.Coinbase)
	state.UpdateStateObject(account)

	for _, uncle := range block.Uncles {
		uncleAccount := state.GetAccount(uncle.Coinbase)
		uncleAccount.AddAmount(CalculateUncleReward(uncle))

		state.UpdateStateObject(uncleAccount)
	}

	return nil
}

func (sm *StateManager) Stop() {
	sm.bc.Stop()
}

// Manifest will handle both creating notifications and generating bloom bin data
func (sm *StateManager) createBloomFilter(state *ethstate.State) *BloomFilter {
	bloomf := NewBloomFilter(nil)

	/*
		for addr, stateObject := range state.Manifest().ObjectChanges {
			// Set the bloom filter's bin
			bloomf.Set([]byte(addr))

			sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
		}
	*/
	for _, msg := range state.Manifest().Messages {
		bloomf.Set(msg.To)
		bloomf.Set(msg.From)
	}

	sm.Ethereum.Reactor().Post("messages", state.Manifest().Messages)

	/*
		for stateObjectAddr, mappedObjects := range state.Manifest().StorageChanges {
			for addr, value := range mappedObjects {
				// Set the bloom filter's bin
				bloomf.Set(ethcrypto.Sha3Bin([]byte(stateObjectAddr + addr)))

				sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &ethstate.StorageState{[]byte(stateObjectAddr), []byte(addr), value})
			}
		}
	*/

	return bloomf
}

func (sm *StateManager) GetMessages(block *Block) (messages []*ethstate.Message, err error) {
	if !sm.bc.HasBlock(block.PrevHash) {
		return nil, ParentError(block.PrevHash)
	}

	sm.lastAttemptedBlock = block

	var (
		parent = sm.bc.GetBlock(block.PrevHash)
		state  = parent.State().Copy()
	)

	defer state.Reset()

	sm.ApplyDiff(state, parent, block)

	sm.AccumelateRewards(state, block)

	return state.Manifest().Messages, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=k8s.io/kubernetes/federation/apis/federation
// +k8s:openapi-gen=true
package v1beta1 // import "k8s.io/kubernetes/federation/apis/federation/v1beta1"
<commit_msg>Flag all packages as needing defaulters<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

// +k8s:deepcopy-gen=package,register
// +k8s:conversion-gen=k8s.io/kubernetes/federation/apis/federation
// +k8s:openapi-gen=true
// +k8s:defaulter-gen=TypeMeta
package v1beta1 // import "k8s.io/kubernetes/federation/apis/federation/v1beta1"
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

func fib_even_numbers(max int) int {
	a, b, sum := 1, 2, 2

	for {
		a, b = a + b + b, a + a + b + b + b

		if b >= max {
			return sum
		}

		sum += b
	}
}

func main() {
	start := time.Now()

	max := 4000000
	fmt.Println(fib_even_numbers(max))
	fmt.Println("Elapsed: ", time.Since(start))
}<commit_msg>Solution for problem 2 - Even Fibonacci Numbers<commit_after>package main

import (
	"fmt"
	"time"
)

func fib_even_numbers(max int) int {
	a, b, sum := 1, 2, 2

	for {
		a, b = a+2*b, 2*a+3*b

		if b >= max {
			return sum
		}

		sum += b
	}
}

func main() {
	start := time.Now()

	max := 4000000
	fmt.Println(fib_even_numbers(max))
	fmt.Println("Elapsed: ", time.Since(start))
}
<|endoftext|>


<commit_before>package blog

import (
	"log"
	"os"
	"testing"

	"github.com/acsellers/dr/migrate"
	_ "github.com/mattn/go-sqlite3"
)

func TestUserSave(t *testing.T) {
	c := openTestConn()

	u := User{
		Name:                "Andrew",
		Email:               "andrew@example.com",
		PermissionLevel:     2,
		CryptPassword:       []byte("helloworld"),
		ArticleCompensation: 4.5,
		TotalCompensation:   1234.45,
	}
	err := u.Save(c)
	if err != nil {
		t.Fatal("User Save", err)
	}
	if u.ID == 0 {
		t.Fatal("User didn't update ID from result")
	}

	if c.User.Count() == 0 {
		t.Log(u)
		t.Fatal("User wasn't saved")
	}

	u2, err := c.User.Find(u.ID)
	if err != nil {
		t.Fatal("User Find", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

	u2, err = c.User.Name().Eq(u.Name).Retrieve()
	if err != nil {
		t.Fatal("User Name Retrieve", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

	u2, err = c.User.Email().Eq(u.Email).Retrieve()
	if err != nil {
		t.Fatal("User Email Retrieve", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

}

func openTestConn() *Conn {
	c, err := Open("sqlite3", ":memory:")
	if err != nil {
		panic(err)
	}
	db := migrate.Database{
		DB:         c.DB,
		Schema:     Schema,
		Translator: NewAppConfig("sqlite3"),
		DBMS:       migrate.Sqlite,
		Log:        log.New(os.Stdout, "Migrate: ", 0),
	}
	err = db.Migrate()
	if err != nil {
		panic(err)
	}
	return c
}
<commit_msg>Add a bunch of scope tests<commit_after>package blog

import (
	"bytes"
	"log"
	"testing"

	"github.com/acsellers/dr/migrate"
	_ "github.com/mattn/go-sqlite3"
)

func TestUserSave(t *testing.T) {
	c := openTestConn()

	u := User{
		Name:                "Andrew",
		Email:               "andrew@example.com",
		PermissionLevel:     2,
		CryptPassword:       []byte("helloworld"),
		ArticleCompensation: 4.5,
		TotalCompensation:   1234.45,
	}
	err := u.Save(c)
	if err != nil {
		t.Fatal("User Save", err)
	}
	if u.ID == 0 {
		t.Fatal("User didn't update ID from result")
	}

	if c.User.Count() == 0 {
		t.Log(u)
		t.Fatal("User wasn't saved")
	}

	u2, err := c.User.Find(u.ID)
	if err != nil {
		t.Fatal("User Find", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

	u2, err = c.User.Name().Eq(u.Name).Retrieve()
	if err != nil {
		t.Fatal("User Name Retrieve", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

	u2, err = c.User.Email().Eq(u.Email).Retrieve()
	if err != nil {
		t.Fatal("User Email Retrieve", err)
	}
	if u2.Name != u.Name {
		t.Fatal("Name Compare", u.Name, u2.Name)
	}
	if u2.Email != u.Email {
		t.Fatal("Email Compare", u.Email, u2.Email)
	}
	if u2.PermissionLevel != u.PermissionLevel {
		t.Fatal("PermissionLevel Compare", u.PermissionLevel, u2.PermissionLevel)
	}
	if string(u2.CryptPassword) != string(u.CryptPassword) {
		t.Fatal("CryptPassword Compare", u.CryptPassword, u2.CryptPassword)
	}
	if u2.ArticleCompensation != u.ArticleCompensation {
		t.Fatal("ArticleCompensation Compare", u.ArticleCompensation, u2.ArticleCompensation)
	}
	if u2.TotalCompensation != u.TotalCompensation {
		t.Fatal("TotalCompensation Compare", u.TotalCompensation, u2.TotalCompensation)
	}

	c.Close()
}

func TestUserScopes(t *testing.T) {

	c := openTestConn()
	users := []User{
		User{
			Name:                "Hastur",
			Email:               "hastur@example.com",
			PermissionLevel:     1,
			CryptPassword:       []byte("asdf"),
			ArticleCompensation: 1.2,
			TotalCompensation:   2.4,
		},
		User{
			Name:                "Cthulhu",
			Email:               "cthulhu@example.com",
			PermissionLevel:     3,
			CryptPassword:       []byte("asdf"),
			ArticleCompensation: 1.8,
			TotalCompensation:   2.8,
		},
		User{
			Name:                "Yog-Sothoth",
			Email:               "yog-sothoth@example.com",
			PermissionLevel:     2,
			CryptPassword:       []byte("asdf"),
			ArticleCompensation: 1.8,
			TotalCompensation:   2.8,
		},
		User{
			Name:                "Tsathoggua",
			Email:               "tsathoggua@example.com",
			PermissionLevel:     2,
			CryptPassword:       []byte("asdf"),
			ArticleCompensation: 1.0,
			TotalCompensation:   2.0,
		},
		User{
			Name:                "Cthugha",
			Email:               "cthugha@example.com",
			PermissionLevel:     1,
			CryptPassword:       []byte("asdf"),
			ArticleCompensation: 1.2,
			TotalCompensation:   2.4,
		},
	}
	err := c.User.SaveAll(users)
	if err != nil {
		t.Fatal("User Save", err)
	}

	if c.User.Name().Eq("Cthulhu").Count() != 1 {
		t.Fatal("User not present")
	}

	if c.User.Name().Like("cthu%").Count() != 2 {
		t.Fatal("User.Like not working found:", c.User.Name().Like("cthu%").Count())
	}

	if c.User.Email().Like("%example.com").Count() != 5 {
		t.Fatal("Could not retrieve by email")
	}

	if c.User.PermissionLevel().Gt(1).Count() != 3 {
		t.Fatal("Could not find higher level users")
	}

	if c.User.ArticleCompensation().Gt(1).Count() != 4 {
		t.Fatal("Could not find highly compensated users")
	}
	if c.User.ArticleCompensation().Lte(1.21).Count() != 3 {
		t.Log(c.User.ArticleCompensation().Lte(1.21).QuerySQL())
		t.Fatal("Could not find cheaper users")
	}

	if c.User.TotalCompensation().Gt(2.5).Count() != 2 {
		t.Fatal("Could not find highly compensated users")
	}

	c.Close()
}

func openTestConn() *Conn {
	c, err := Open("sqlite3", ":memory:")
	if err != nil {
		panic(err)
	}
	db := migrate.Database{
		DB:         c.DB,
		Schema:     Schema,
		Translator: NewAppConfig("sqlite3"),
		DBMS:       migrate.Sqlite,
		Log:        log.New(&bytes.Buffer{}, "Migrate: ", 0),
	}
	err = db.Migrate()
	if err != nil {
		panic(err)
	}
	return c
}
<|endoftext|>


<commit_before>package mount

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/hanwen/go-fuse/v2/fuse"
	"time"
)

/**
 * Flush method
 *
 * This is called on each close() of the opened file.
 *
 * Since file descriptors can be duplicated (dup, dup2, fork), for
 * one open call there may be many flush calls.
 *
 * Filesystems shouldn't assume that flush will always be called
 * after some writes, or that if will be called at all.
 *
 * fi->fh will contain the value set by the open method, or will
 * be undefined if the open method didn't set any value.
 *
 * NOTE: the name of the method is misleading, since (unlike
 * fsync) the filesystem is not forced to flush pending writes.
 * One reason to flush data is if the filesystem wants to return
 * write errors during close.  However, such use is non-portable
 * because POSIX does not require [close] to wait for delayed I/O to
 * complete.
 *
 * If the filesystem supports file locking operations (setlk,
 * getlk) it should remove all locks belonging to 'fi->owner'.
 *
 * If this request is answered with an error code of ENOSYS,
 * this is treated as success and future calls to flush() will
 * succeed automatically without being send to the filesystem
 * process.
 *
 * Valid replies:
 *   fuse_reply_err
 *
 * @param req request handle
 * @param ino the inode number
 * @param fi file information
 *
 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
 */
func (wfs *WFS) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
	fh := wfs.GetHandle(FileHandleId(in.Fh))
	if fh == nil {
		return fuse.ENOENT
	}

	fh.Lock()
	defer fh.Unlock()

	return wfs.doFlush(fh, in.Uid, in.Gid)
}

/**
 * Synchronize file contents
 *
 * If the datasync parameter is non-zero, then only the user data
 * should be flushed, not the meta data.
 *
 * If this request is answered with an error code of ENOSYS,
 * this is treated as success and future calls to fsync() will
 * succeed automatically without being send to the filesystem
 * process.
 *
 * Valid replies:
 *   fuse_reply_err
 *
 * @param req request handle
 * @param ino the inode number
 * @param datasync flag indicating if only data should be flushed
 * @param fi file information
 */
func (wfs *WFS) Fsync(cancel <-chan struct{}, in *fuse.FsyncIn) (code fuse.Status) {

	fh := wfs.GetHandle(FileHandleId(in.Fh))
	if fh == nil {
		return fuse.ENOENT
	}

	fh.Lock()
	defer fh.Unlock()

	return wfs.doFlush(fh, in.Uid, in.Gid)

}

func (wfs *WFS) doFlush(fh *FileHandle, uid, gid uint32) fuse.Status {
	// flush works at fh level
	fileFullPath := fh.FullPath()
	dir, _ := fileFullPath.DirAndName()
	// send the data to the OS
	glog.V(4).Infof("doFlush %s fh %d", fileFullPath, fh.handle)

	if err := fh.dirtyPages.FlushData(); err != nil {
		glog.Errorf("%v doFlush: %v", fileFullPath, err)
		return fuse.EIO
	}

	if !fh.dirtyMetadata {
		return fuse.OK
	}

	err := wfs.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {

		entry := fh.entry
		if entry == nil {
			return nil
		}

		if entry.Attributes != nil {
			entry.Attributes.Mime = fh.contentType
			if entry.Attributes.Uid == 0 {
				entry.Attributes.Uid = uid
			}
			if entry.Attributes.Gid == 0 {
				entry.Attributes.Gid = gid
			}
			if entry.Attributes.Crtime == 0 {
				entry.Attributes.Crtime = time.Now().Unix()
			}
			entry.Attributes.Mtime = time.Now().Unix()
			entry.Attributes.Collection, entry.Attributes.Replication = fh.dirtyPages.GetStorageOptions()
		}

		request := &filer_pb.CreateEntryRequest{
			Directory:  string(dir),
			Entry:      entry,
			Signatures: []int32{wfs.signature},
		}

		glog.V(4).Infof("%s set chunks: %v", fileFullPath, len(entry.Chunks))
		for i, chunk := range entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fileFullPath, i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		manifestChunks, nonManifestChunks := filer.SeparateManifestChunks(entry.Chunks)

		chunks, _ := filer.CompactFileChunks(wfs.LookupFn(), nonManifestChunks)
		chunks, manifestErr := filer.MaybeManifestize(wfs.saveDataAsChunk(fileFullPath), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		entry.Chunks = append(chunks, manifestChunks...)

		wfs.mapPbIdFromLocalToFiler(request.Entry)
		defer wfs.mapPbIdFromFilerToLocal(request.Entry)

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fileFullPath, err)
			return fmt.Errorf("fh flush create %s: %v", fileFullPath, err)
		}

		wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry(request.Directory, request.Entry))

		return nil
	})

	if err == nil {
		fh.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fileFullPath, fh.handle, err)
		return fuse.EIO
	}

	return fuse.OK
}
<commit_msg>mount: fix fsync opened and renamed files<commit_after>package mount

import (
	"context"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/hanwen/go-fuse/v2/fuse"
	"time"
)

/**
 * Flush method
 *
 * This is called on each close() of the opened file.
 *
 * Since file descriptors can be duplicated (dup, dup2, fork), for
 * one open call there may be many flush calls.
 *
 * Filesystems shouldn't assume that flush will always be called
 * after some writes, or that if will be called at all.
 *
 * fi->fh will contain the value set by the open method, or will
 * be undefined if the open method didn't set any value.
 *
 * NOTE: the name of the method is misleading, since (unlike
 * fsync) the filesystem is not forced to flush pending writes.
 * One reason to flush data is if the filesystem wants to return
 * write errors during close.  However, such use is non-portable
 * because POSIX does not require [close] to wait for delayed I/O to
 * complete.
 *
 * If the filesystem supports file locking operations (setlk,
 * getlk) it should remove all locks belonging to 'fi->owner'.
 *
 * If this request is answered with an error code of ENOSYS,
 * this is treated as success and future calls to flush() will
 * succeed automatically without being send to the filesystem
 * process.
 *
 * Valid replies:
 *   fuse_reply_err
 *
 * @param req request handle
 * @param ino the inode number
 * @param fi file information
 *
 * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html
 */
func (wfs *WFS) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
	fh := wfs.GetHandle(FileHandleId(in.Fh))
	if fh == nil {
		return fuse.ENOENT
	}

	fh.Lock()
	defer fh.Unlock()

	return wfs.doFlush(fh, in.Uid, in.Gid)
}

/**
 * Synchronize file contents
 *
 * If the datasync parameter is non-zero, then only the user data
 * should be flushed, not the meta data.
 *
 * If this request is answered with an error code of ENOSYS,
 * this is treated as success and future calls to fsync() will
 * succeed automatically without being send to the filesystem
 * process.
 *
 * Valid replies:
 *   fuse_reply_err
 *
 * @param req request handle
 * @param ino the inode number
 * @param datasync flag indicating if only data should be flushed
 * @param fi file information
 */
func (wfs *WFS) Fsync(cancel <-chan struct{}, in *fuse.FsyncIn) (code fuse.Status) {

	fh := wfs.GetHandle(FileHandleId(in.Fh))
	if fh == nil {
		return fuse.ENOENT
	}

	fh.Lock()
	defer fh.Unlock()

	return wfs.doFlush(fh, in.Uid, in.Gid)

}

func (wfs *WFS) doFlush(fh *FileHandle, uid, gid uint32) fuse.Status {
	// flush works at fh level
	fileFullPath := fh.FullPath()
	dir, name := fileFullPath.DirAndName()
	// send the data to the OS
	glog.V(4).Infof("doFlush %s fh %d", fileFullPath, fh.handle)

	if err := fh.dirtyPages.FlushData(); err != nil {
		glog.Errorf("%v doFlush: %v", fileFullPath, err)
		return fuse.EIO
	}

	if !fh.dirtyMetadata {
		return fuse.OK
	}

	err := wfs.WithFilerClient(false, func(client filer_pb.SeaweedFilerClient) error {

		entry := fh.entry
		if entry == nil {
			return nil
		}
		entry.Name = name // this flush may be just after a rename operation

		if entry.Attributes != nil {
			entry.Attributes.Mime = fh.contentType
			if entry.Attributes.Uid == 0 {
				entry.Attributes.Uid = uid
			}
			if entry.Attributes.Gid == 0 {
				entry.Attributes.Gid = gid
			}
			if entry.Attributes.Crtime == 0 {
				entry.Attributes.Crtime = time.Now().Unix()
			}
			entry.Attributes.Mtime = time.Now().Unix()
			entry.Attributes.Collection, entry.Attributes.Replication = fh.dirtyPages.GetStorageOptions()
		}

		request := &filer_pb.CreateEntryRequest{
			Directory:  string(dir),
			Entry:      entry,
			Signatures: []int32{wfs.signature},
		}

		glog.V(4).Infof("%s set chunks: %v", fileFullPath, len(entry.Chunks))
		for i, chunk := range entry.Chunks {
			glog.V(4).Infof("%s chunks %d: %v [%d,%d)", fileFullPath, i, chunk.GetFileIdString(), chunk.Offset, chunk.Offset+int64(chunk.Size))
		}

		manifestChunks, nonManifestChunks := filer.SeparateManifestChunks(entry.Chunks)

		chunks, _ := filer.CompactFileChunks(wfs.LookupFn(), nonManifestChunks)
		chunks, manifestErr := filer.MaybeManifestize(wfs.saveDataAsChunk(fileFullPath), chunks)
		if manifestErr != nil {
			// not good, but should be ok
			glog.V(0).Infof("MaybeManifestize: %v", manifestErr)
		}
		entry.Chunks = append(chunks, manifestChunks...)

		wfs.mapPbIdFromLocalToFiler(request.Entry)
		defer wfs.mapPbIdFromFilerToLocal(request.Entry)

		if err := filer_pb.CreateEntry(client, request); err != nil {
			glog.Errorf("fh flush create %s: %v", fileFullPath, err)
			return fmt.Errorf("fh flush create %s: %v", fileFullPath, err)
		}

		wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry(request.Directory, request.Entry))

		return nil
	})

	if err == nil {
		fh.dirtyMetadata = false
	}

	if err != nil {
		glog.Errorf("%v fh %d flush: %v", fileFullPath, fh.handle, err)
		return fuse.EIO
	}

	return fuse.OK
}
<|endoftext|>


<commit_before>/*
Copyright 2017, 2018 Ankyra

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

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

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

package core

import (
	"fmt"
	"strings"
)

type ExecStage struct {

	// The command to run. Its arguments, if any, should be defined using the
	// "args" field.
	Cmd string `json:"cmd"`
	// Arguments to the command.
	Args []string `json:"args"`

	// An inline script, which will be executed using bash. It's an error to
	// specify both the "cmd" and "inline" fields.
	Inline string `json:"inline"`

	// Relative path to a script. If the "cmd" field is already populated
	// then this field will be ignored entirely.
	RelativeScript string `json:"script"`
}

func NewExecStageFromString(str string) *ExecStage {
	return &ExecStage{
		Cmd:  "bash",
		Args: []string{"-c", str},
	}

}

func NewExecStageForRelativeScript(script string) *ExecStage {
	return &ExecStage{
		RelativeScript: script,
	}
}

func (e *ExecStage) IsEmpty() bool {
	return e.Cmd == "" && e.RelativeScript == "" && e.Inline == ""
}

func (e *ExecStage) GetAsCommand() []string {
	if e.Cmd != "" {
		result := []string{e.Cmd}
		return append(result, e.Args...)
	} else if e.RelativeScript != "" {
		script := "./" + e.RelativeScript + " .escape/outputs.json"
		return []string{"bash", "-c", script}
	} else if e.Inline != "" {
		panic("not yet supported")
	}
	return []string{}
}

func (e *ExecStage) ValidateAndFix() error {
	fieldsSet := 0
	if e.Cmd != "" {
		fieldsSet += 1
	}
	if e.Inline != "" {
		fieldsSet += 1
	}
	if e.RelativeScript != "" {
		fieldsSet += 1
	}
	if fieldsSet > 1 {
		return fmt.Errorf("More than one field is set. Please specify only one of script, cmd or inline.")
	}
	return nil
}

func (e *ExecStage) String() string {
	if e.Cmd != "" {
		return fmt.Sprintf("%s %s", e.Cmd, strings.Join(e.Args, " "))
	} else {
		return e.Inline
	}
}
<commit_msg>Omit empty string on ExecStage json structure.<commit_after>/*
Copyright 2017, 2018 Ankyra

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

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

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

package core

import (
	"fmt"
	"strings"
)

type ExecStage struct {

	// The command to run. Its arguments, if any, should be defined using the
	// "args" field.
	Cmd string `json:"cmd,omitempty"`
	// Arguments to the command.
	Args []string `json:"args,omitempty"`

	// An inline script, which will be executed using bash. It's an error to
	// specify both the "cmd" and "inline" fields.
	Inline string `json:"inline,omitempty"`

	// Relative path to a script. If the "cmd" field is already populated
	// then this field will be ignored entirely.
	RelativeScript string `json:"script,omitempty"`
}

func NewExecStageFromString(str string) *ExecStage {
	return &ExecStage{
		Cmd:  "bash",
		Args: []string{"-c", str},
	}

}

func NewExecStageForRelativeScript(script string) *ExecStage {
	return &ExecStage{
		RelativeScript: script,
	}
}

func (e *ExecStage) IsEmpty() bool {
	return e.Cmd == "" && e.RelativeScript == "" && e.Inline == ""
}

func (e *ExecStage) GetAsCommand() []string {
	if e.Cmd != "" {
		result := []string{e.Cmd}
		return append(result, e.Args...)
	} else if e.RelativeScript != "" {
		script := "./" + e.RelativeScript + " .escape/outputs.json"
		return []string{"bash", "-c", script}
	} else if e.Inline != "" {
		panic("not yet supported")
	}
	return []string{}
}

func (e *ExecStage) ValidateAndFix() error {
	fieldsSet := 0
	if e.Cmd != "" {
		fieldsSet += 1
	}
	if e.Inline != "" {
		fieldsSet += 1
	}
	if e.RelativeScript != "" {
		fieldsSet += 1
	}
	if fieldsSet > 1 {
		return fmt.Errorf("More than one field is set. Please specify only one of script, cmd or inline.")
	}
	return nil
}

func (e *ExecStage) String() string {
	if e.Cmd != "" {
		return fmt.Sprintf("%s %s", e.Cmd, strings.Join(e.Args, " "))
	} else if e.RelativeScript != "" {
		return e.RelativeScript
	} else {
		return e.Inline
	}
}
<|endoftext|>


<commit_before>package expertview

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
)

const (
	DefaultEndpoint = "https://playground.expertview-live.com:443/ExpertWebservice-play/Webservice"
	DefaultVersion  = "2.5.0"
)

var (
	ErrAuthentication        = errors.New("authentication error")
	ErrUnexpected            = errors.New("unexpected error")
	ErrFirmwareNotSelectable = errors.New("firmware not selectable error")
	ErrNoSuchFile            = errors.New("no such file error")
)

type Credentials struct {
	Login    string
	Password string
}

func (c *Credentials) PasswordMD5Sum() string {
	hasher := md5.New()
	hasher.Write([]byte(c.Password))
	return hex.EncodeToString(hasher.Sum(nil))
}

type DeviceType struct {
	Description   string
	ProductNumber string
}

type RecordKind string

const (
	DCFKind      RecordKind = "DCF"
	FirmwareKind RecordKind = "Firmware"
)

type Record struct {
	Kind RecordKind
	Name string
	File string
}

type FileList struct {
	DeviceTypes []DeviceType
	Records     []Record
}

type InstallationRecord struct {
	SerialNumber string
	ID           string
	Telematic    string
	HardwareProf string
	SoftwareProf string
	DCF          string
	Firmware     string
	Key          string
	Username     string
}

// ExpertView is a client for the Squarell Expert View webservice.
type ExpertView struct {
	version     string
	cli         *soapCli
	credentials Credentials
}

// NewExpertView returns an *ExpertView, pointing to the given endpoint and using the specified API version and
// credentials. If no version or endpoint are given, the default values are used instead (DefaultEndpoint and
// DefaultVersion)
func NewExpertView(endpoint string, version string, credentials Credentials) (*ExpertView, error) {
	if endpoint == "" {
		endpoint = DefaultEndpoint
	}
	if version == "" {
		version = DefaultVersion
	}
	if credentials.Login == "" || credentials.Password == "" {
		return nil, errors.New("invalid credentials: login and password required")
	}
	ev := &ExpertView{
		version: version,
		cli: &soapCli{
			Endpoint:           endpoint,
			InsecureSkipVerify: true,
		},
		credentials: credentials,
	}
	return ev, nil
}

func (ev *ExpertView) GetFileList() (FileList, error) {
	doc, err := createGetFileList(ev.credentials, ev.version)
	if err != nil {
		return FileList{}, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return FileList{}, err
	}

	if len(resp) == 0 {
		return FileList{}, errors.New("empty response")
	}
	return parseGetFileList(resp)
}

func (ev *ExpertView) GetFile(filename string) ([]byte, error) {
	doc, err := createGetFile(ev.credentials, ev.version, filename)
	if err != nil {
		return nil, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return nil, err
	}

	if len(resp) == 0 {
		return nil, errors.New("empty response")
	}
	return parseGetFile(resp)
}

func (ev *ExpertView) GetInstallationRecords() ([]InstallationRecord, error) {
	doc, err := createGetInstallRecords(ev.credentials, ev.version)
	if err != nil {
		return nil, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return nil, err
	}

	if len(resp) == 0 {
		return nil, errors.New("empty response")
	}
	return parseGetInstallRecords(resp)
}
<commit_msg>Fixes default endpoint (should point to production ws)<commit_after>package expertview

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"strings"
)

const (
	DefaultEndpoint = "https://www.expertview-live.com:443/ExpertWebservice-prod/Webservice"
	DefaultVersion  = "2.5.0"
)

var (
	ErrAuthentication        = errors.New("authentication error")
	ErrUnexpected            = errors.New("unexpected error")
	ErrFirmwareNotSelectable = errors.New("firmware not selectable error")
	ErrNoSuchFile            = errors.New("no such file error")
)

type Credentials struct {
	Login    string
	Password string
}

func (c *Credentials) PasswordMD5Sum() string {
	hasher := md5.New()
	hasher.Write([]byte(c.Password))
	return hex.EncodeToString(hasher.Sum(nil))
}

type DeviceType struct {
	Description   string
	ProductNumber string
}

type RecordKind string

const (
	DCFKind      RecordKind = "DCF"
	FirmwareKind RecordKind = "Firmware"
)

type Record struct {
	Kind RecordKind
	Name string
	File string
}

type FileList struct {
	DeviceTypes []DeviceType
	Records     []Record
}

type InstallationRecord struct {
	SerialNumber string
	ID           string
	Telematic    string
	HardwareProf string
	SoftwareProf string
	DCF          string
	Firmware     string
	Key          string
	Username     string
}

// ExpertView is a client for the Squarell Expert View webservice.
type ExpertView struct {
	version     string
	cli         *soapCli
	credentials Credentials
}

// NewExpertView returns an *ExpertView, pointing to the given endpoint and using the specified API version and
// credentials. If no version or endpoint are given, the default values are used instead (DefaultEndpoint and
// DefaultVersion)
func NewExpertView(endpoint string, version string, credentials Credentials) (*ExpertView, error) {
	if endpoint == "" {
		endpoint = DefaultEndpoint
	}
	if version == "" {
		version = DefaultVersion
	}
	if credentials.Login == "" || credentials.Password == "" {
		return nil, errors.New("invalid credentials: login and password required")
	}
	ev := &ExpertView{
		version: version,
		cli: &soapCli{
			Endpoint:           endpoint,
			InsecureSkipVerify: true,
		},
		credentials: credentials,
	}
	return ev, nil
}

func (ev *ExpertView) GetFileList() (FileList, error) {
	doc, err := createGetFileList(ev.credentials, ev.version)
	if err != nil {
		return FileList{}, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return FileList{}, err
	}

	if len(resp) == 0 {
		return FileList{}, errors.New("empty response")
	}
	return parseGetFileList(resp)
}

func (ev *ExpertView) GetFile(filename string) ([]byte, error) {
	doc, err := createGetFile(ev.credentials, ev.version, filename)
	if err != nil {
		return nil, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return nil, err
	}

	if len(resp) == 0 {
		return nil, errors.New("empty response")
	}
	return parseGetFile(resp)
}

func (ev *ExpertView) GetInstallationRecords() ([]InstallationRecord, error) {
	doc, err := createGetInstallRecords(ev.credentials, ev.version)
	if err != nil {
		return nil, fmt.Errorf("error building xml request: %s", err)
	}

	reqBody := strings.NewReader(doc.String())
	resp, err := ev.cli.call(reqBody)
	if err != nil {
		return nil, err
	}

	if len(resp) == 0 {
		return nil, errors.New("empty response")
	}
	return parseGetInstallRecords(resp)
}
<|endoftext|>


<commit_before>// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sys

import "github.com/e-XpertSolutions/f5-rest-client/f5"

// LogConfigList holds a list of Log configuration.
type LogConfigList struct {
	Items    []LogConfig `json:"items"`
	Kind     string      `json:"kind"`
	SelfLink string      `json:"selflink"`
}

// LogConfig holds the configuration of a single Log.
type LogConfig struct {
}

// LogEndpoint represents the REST resource for managing Log.
const LogEndpoint = "/tm/sys/log"

// LogResource provides an API to manage Log configurations.
type LogResource struct {
	c f5.Client
}

// ListAll  lists all the Log configurations.
func (r *LogResource) ListAll() (*LogConfigList, error) {
	var list LogConfigList
	if err := r.c.ReadQuery(BasePath+LogEndpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

// Get a single Log configuration identified by id.
func (r *LogResource) Get(id string) (*LogConfig, error) {
	var item LogConfig
	if err := r.c.ReadQuery(BasePath+LogEndpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

// Create a new Log configuration.
func (r *LogResource) Create(item LogConfig) error {
	if err := r.c.ModQuery("POST", BasePath+LogEndpoint, item); err != nil {
		return err
	}
	return nil
}

// Edit a Log configuration identified by id.
func (r *LogResource) Edit(id string, item LogConfig) error {
	if err := r.c.ModQuery("PUT", BasePath+LogEndpoint+"/"+id, item); err != nil {
		return err
	}
	return nil
}

// Delete a single Log configuration identified by id.
func (r *LogResource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath+LogEndpoint+"/"+id, nil); err != nil {
		return err
	}
	return nil
}
<commit_msg>f5/sys: fix URI path for Log<commit_after>// Copyright e-Xpert Solutions SA. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sys

import "github.com/e-XpertSolutions/f5-rest-client/f5"

// LogConfigList holds a list of Log configuration.
type LogConfigList struct {
	Items    []LogConfig `json:"items"`
	Kind     string      `json:"kind"`
	SelfLink string      `json:"selflink"`
}

// LogConfig holds the configuration of a single Log.
type LogConfig struct {
}

// LogEndpoint represents the REST resource for managing Log.
const LogEndpoint = "/log"

// LogResource provides an API to manage Log configurations.
type LogResource struct {
	c f5.Client
}

// ListAll  lists all the Log configurations.
func (r *LogResource) ListAll() (*LogConfigList, error) {
	var list LogConfigList
	if err := r.c.ReadQuery(BasePath+LogEndpoint, &list); err != nil {
		return nil, err
	}
	return &list, nil
}

// Get a single Log configuration identified by id.
func (r *LogResource) Get(id string) (*LogConfig, error) {
	var item LogConfig
	if err := r.c.ReadQuery(BasePath+LogEndpoint, &item); err != nil {
		return nil, err
	}
	return &item, nil
}

// Create a new Log configuration.
func (r *LogResource) Create(item LogConfig) error {
	if err := r.c.ModQuery("POST", BasePath+LogEndpoint, item); err != nil {
		return err
	}
	return nil
}

// Edit a Log configuration identified by id.
func (r *LogResource) Edit(id string, item LogConfig) error {
	if err := r.c.ModQuery("PUT", BasePath+LogEndpoint+"/"+id, item); err != nil {
		return err
	}
	return nil
}

// Delete a single Log configuration identified by id.
func (r *LogResource) Delete(id string) error {
	if err := r.c.ModQuery("DELETE", BasePath+LogEndpoint+"/"+id, nil); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package rdirsync_test

import (
	"context"
	"crypto/rand"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"path/filepath"
	"testing"

	"github.com/hnakamur/rdirsync"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

func TestFetch(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "rdirsync_test")
	if err != nil {
		t.Fatalf("fail to create tempdir; %s", err)
	}
	defer os.RemoveAll(tempDir)

	srcDir := filepath.Join(tempDir, "src")
	destDir := filepath.Join(tempDir, "dest")

	buildSrcPath := func(names ...string) string {
		return filepath.Join(srcDir, filepath.Join(names...))
	}

	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		grpclog.Fatal(err)
	}

	grpcServer := grpc.NewServer()
	rdirsync.RegisterNewRDirSyncServer(grpcServer)
	go grpcServer.Serve(lis)
	defer grpcServer.Stop()

	// NOTE: We dial each time for Fetch to avoid the following error.
	// transport: http2Server.HandleStreams failed to read frame: read tcp 127.0.0.1:37025->127.0.0.1:38422: use of closed network connection
	runFetch := func() error {
		conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure())
		if err != nil {
			t.Fatal(err)
		}
		defer conn.Close()

		client, err := rdirsync.NewClient(conn,
			rdirsync.SetSyncModTime(true))
		if err != nil {
			t.Fatal(err)
		}

		ctx := context.Background()
		err = client.Fetch(ctx, srcDir, destDir)
		if err != nil {
			t.Fatal(err)
		}
		return nil
	}

	testCases := []struct {
		tree          testFileTreeNode
		modifications []modificationOp
	}{
		{
			tree: testFileTreeNode{
				name: "dir1", mode: os.ModeDir | 0775,
				children: []testFileTreeNode{
					{name: "file1-1", mode: 0666, size: 1024},
					{name: "file1-2", mode: 0660, size: 0},
					{name: "file1-3", mode: 0606, size: 5000 * 1000},
				},
			},
			modifications: []modificationOp{
				truncateOp(buildSrcPath("dir1", "file1-1"), 500),
				removeFileOp(buildSrcPath("dir1", "file1-2")),
				writeRandomOp(buildSrcPath("dir1", "file1-3"), 100, 300),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 3},
			modifications: []modificationOp{
				truncateOp(buildSrcPath("file1"), 0),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 0},
			modifications: []modificationOp{
				writeRandomOp(buildSrcPath("file1"), 0, 2000),
			},
		},
	}

	for _, testCase := range testCases {
		err = os.MkdirAll(srcDir, 0700)
		if err != nil {
			log.Fatal(err)
		}

		err = buildFileTree(srcDir, testCase.tree)
		if err != nil {
			log.Fatal(err)
		}

		err = runFetch()
		if err != nil {
			return
		}
		sameDirTreeContent(t, destDir, srcDir)

		for _, op := range testCase.modifications {
			err := op()
			if err != nil {
				t.Fatal(err)
			}
		}

		err = runFetch()
		if err != nil {
			return
		}
		sameDirTreeContent(t, destDir, srcDir)

		err = os.RemoveAll(srcDir)
		if err != nil {
			t.Fatal(err)
		}
		err = os.RemoveAll(destDir)
		if err != nil {
			t.Fatal(err)
		}
	}
}

type modificationOp func() error

func truncateOp(path string, size int64) modificationOp {
	return func() error {
		return os.Truncate(path, size)
	}
}

func writeRandomOp(path string, offset, length int64) modificationOp {
	return func() error {
		file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = file.Seek(offset, os.SEEK_SET)
		if err != nil {
			return err
		}
		_, err = io.CopyN(file, rand.Reader, length)
		return err
	}
}

func removeFileOp(path string) modificationOp {
	return func() error {
		return os.Remove(path)
	}
}

func removeDirOp(path string) modificationOp {
	return func() error {
		return os.RemoveAll(path)
	}
}
<commit_msg>Add more test cases to TestFetch<commit_after>package rdirsync_test

import (
	"context"
	"crypto/rand"
	"io"
	"io/ioutil"
	"log"
	"net"
	"os"
	"path/filepath"
	"testing"

	"github.com/hnakamur/rdirsync"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

func TestFetch(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "rdirsync_test")
	if err != nil {
		t.Fatalf("fail to create tempdir; %s", err)
	}
	defer os.RemoveAll(tempDir)

	srcDir := filepath.Join(tempDir, "src")
	destDir := filepath.Join(tempDir, "dest")

	buildSrcPath := func(names ...string) string {
		return filepath.Join(srcDir, filepath.Join(names...))
	}

	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		grpclog.Fatal(err)
	}

	grpcServer := grpc.NewServer()
	rdirsync.RegisterNewRDirSyncServer(grpcServer)
	go grpcServer.Serve(lis)
	defer grpcServer.Stop()

	// NOTE: We dial each time for Fetch to avoid the following error.
	// transport: http2Server.HandleStreams failed to read frame: read tcp 127.0.0.1:37025->127.0.0.1:38422: use of closed network connection
	runFetch := func() error {
		conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure())
		if err != nil {
			t.Fatal(err)
		}
		defer conn.Close()

		client, err := rdirsync.NewClient(conn,
			rdirsync.SetSyncModTime(true))
		if err != nil {
			t.Fatal(err)
		}

		ctx := context.Background()
		err = client.Fetch(ctx, srcDir, destDir)
		if err != nil {
			t.Fatal(err)
		}
		return nil
	}

	testCases := []struct {
		tree          testFileTreeNode
		modifications []modificationOp
	}{
		{
			tree: testFileTreeNode{
				name: "dir1", mode: os.ModeDir | 0775,
				children: []testFileTreeNode{
					{name: "file1-1", mode: 0666, size: 1024},
					{name: "file1-2", mode: 0660, size: 0},
					{name: "file1-3", mode: 0606, size: 5000 * 1000},
				},
			},
			modifications: []modificationOp{
				truncateOp(buildSrcPath("dir1", "file1-1"), 500),
				removeFileOp(buildSrcPath("dir1", "file1-2")),
				writeRandomOp(buildSrcPath("dir1", "file1-3"), 100, 300),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 3},
			modifications: []modificationOp{
				truncateOp(buildSrcPath("file1"), 0),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 1024 * 1024},
			modifications: []modificationOp{
				writeRandomOp(buildSrcPath("file1"), 1024*1024, 1024),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 16 * 1024 * 1024},
			modifications: []modificationOp{
				writeRandomOp(buildSrcPath("file1"), 16*1024*1024, 1024),
			},
		},
		{
			tree: testFileTreeNode{name: "file1", mode: 0600, size: 0},
			modifications: []modificationOp{
				writeRandomOp(buildSrcPath("file1"), 0, 2000),
			},
		},
	}

	for _, testCase := range testCases {
		err = os.MkdirAll(srcDir, 0700)
		if err != nil {
			log.Fatal(err)
		}

		err = buildFileTree(srcDir, testCase.tree)
		if err != nil {
			log.Fatal(err)
		}

		err = runFetch()
		if err != nil {
			return
		}
		sameDirTreeContent(t, destDir, srcDir)

		for _, op := range testCase.modifications {
			err := op()
			if err != nil {
				t.Fatal(err)
			}
		}

		err = runFetch()
		if err != nil {
			return
		}
		sameDirTreeContent(t, destDir, srcDir)

		err = os.RemoveAll(srcDir)
		if err != nil {
			t.Fatal(err)
		}
		err = os.RemoveAll(destDir)
		if err != nil {
			t.Fatal(err)
		}
	}
}

type modificationOp func() error

func truncateOp(path string, size int64) modificationOp {
	return func() error {
		return os.Truncate(path, size)
	}
}

func writeRandomOp(path string, offset, length int64) modificationOp {
	return func() error {
		file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
		if err != nil {
			return err
		}
		defer file.Close()

		_, err = file.Seek(offset, os.SEEK_SET)
		if err != nil {
			return err
		}
		_, err = io.CopyN(file, rand.Reader, length)
		return err
	}
}

func removeFileOp(path string) modificationOp {
	return func() error {
		return os.Remove(path)
	}
}

func removeDirOp(path string) modificationOp {
	return func() error {
		return os.RemoveAll(path)
	}
}
<|endoftext|>


<commit_before><commit_msg>Improved airing anime<commit_after><|endoftext|>


<commit_before>package horizon

import (
	"github.com/stellar/horizon/log"
)

// InitFn is a function that contributes to the initialization of an App struct
type InitFn func(*App)

type initializer struct {
	Name string
	Fn   InitFn
	Deps []string
}

type initializerSet []initializer

var appInit initializerSet

// Add adds a new initializer into the chain
func (is *initializerSet) Add(name string, fn InitFn, deps ...string) {
	*is = append(*is, initializer{
		Name: name,
		Fn:   fn,
		Deps: deps,
	})
}

// Run initializes the provided application, but running every Initializer
func (is *initializerSet) Run(app *App) {
	init := *is
	alreadyRun := make(map[string]bool)

	for {
		ranInitializer := false
		for _, i := range init {
			runnable := true

			// if we've already been run, skip
			if _, ok := alreadyRun[i.Name]; ok {
				runnable = false
			}

			// if any of our dependencies haven't been run, skip
			for _, d := range i.Deps {
				if _, ok := alreadyRun[d]; !ok {
					runnable = false
					break
				}
			}

			if !runnable {
				continue
			}

			log.Debugf("running init:%s", i.Name)
			i.Fn(app)
			alreadyRun[i.Name] = true
			ranInitializer = true
			log.Debugf("ran init:%s", i.Name)
		}
		// If, after a full loop through the initializers we ran nothing
		// we are done
		if !ranInitializer {
			break
		}
	}

	// if we didn't get to run all initializers, we have a cycle
	if len(alreadyRun) != len(init) {
		log.Panic("initializer cycle detected")
	}
}
<commit_msg>Simplify initializer logging<commit_after>package horizon

import (
	"github.com/stellar/horizon/log"
)

// InitFn is a function that contributes to the initialization of an App struct
type InitFn func(*App)

type initializer struct {
	Name string
	Fn   InitFn
	Deps []string
}

type initializerSet []initializer

var appInit initializerSet

// Add adds a new initializer into the chain
func (is *initializerSet) Add(name string, fn InitFn, deps ...string) {
	*is = append(*is, initializer{
		Name: name,
		Fn:   fn,
		Deps: deps,
	})
}

// Run initializes the provided application, but running every Initializer
func (is *initializerSet) Run(app *App) {
	init := *is
	alreadyRun := make(map[string]bool)

	for {
		ranInitializer := false
		for _, i := range init {
			runnable := true

			// if we've already been run, skip
			if _, ok := alreadyRun[i.Name]; ok {
				runnable = false
			}

			// if any of our dependencies haven't been run, skip
			for _, d := range i.Deps {
				if _, ok := alreadyRun[d]; !ok {
					runnable = false
					break
				}
			}

			if !runnable {
				continue
			}

			log.WithField("init_name", i.Name).Debug("running initializer")
			i.Fn(app)
			alreadyRun[i.Name] = true
			ranInitializer = true
		}
		// If, after a full loop through the initializers we ran nothing
		// we are done
		if !ranInitializer {
			break
		}
	}

	// if we didn't get to run all initializers, we have a cycle
	if len(alreadyRun) != len(init) {
		log.Panic("initializer cycle detected")
	}
}
<|endoftext|>


<commit_before>package app

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"net/http"
)

var SuperuserKey string = "su"
var AppMode string = "standard"

func DebugModeHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	md := vars["md"]
	if SuperuserKey != r.FormValue("authkey") {
		Error.Println(r.RemoteAddr, "POST /api/v1/layer [401]")
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	}
	if md == "debug" {
		js, err := json.Marshal(`{"status": "ok", "message": "debug mode on"}`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(true)
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	} else if md == "standard" {
		js, err := json.Marshal(`{"status": "ok", "message": "debug mode off"}`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(false)
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	}
}

// SUPERUSER
func NewCustomerHandler(w http.ResponseWriter, r *http.Request) {
	if SuperuserKey != r.FormValue("authkey") {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	} else {
		// new customer
		apikey := NewAPIKey(12)
		customer := Customer{Apikey: apikey}
		err := DB.insertCustomer(customer)
		if err != nil {
			Error.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// return results
		data := `{"status":"ok","apikey":"` + apikey + `", "result":"customer created"}`
		js, err := json.Marshal(data)
		if err != nil {
			Error.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(false)
		w.Header().Set("Content-Type", "application/json")
		// allow cross domain AJAX requests
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Write(js)
	}
}

/*=======================================*/
// Method: ShareLayerHandler
// Description:
//		Gives customer access to datasource
// @param apikey - customer to give access
// @param authkey
// @return json
/*=======================================*/
func ShareLayerHandler(w http.ResponseWriter, r *http.Request) {

	// Get params
	apikey := r.FormValue("apikey")
	authkey := r.FormValue("authkey")

	// Get ds from url path
	vars := mux.Vars(r)
	ds := vars["ds"]

	if SuperuserKey != r.FormValue("authkey") {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	} else {

		if apikey == "" {
			Error.Println(r.RemoteAddr, "PUT /api/v1/layer/{ds} [401]")
			http.Error(w, "bad request", http.StatusBadRequest)
			return
		}

		// Get customer from database
		customer, err := DB.getCustomer(apikey)
		if err != nil {
			Warning.Println(r.RemoteAddr, "PUT /api/v1/layer/{ds} [404]")
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}

		// Add datasource uuid to customer
		customer.Datasources = append(customer.Datasources, ds)
		DB.insertCustomer(customer)

		// Generate message
		data := `{"status":"ok","datasource":"` + ds + `"}`
		js, err := json.Marshal(data)
		if err != nil {
			Error.Println(r.RemoteAddr, "PUT /api/v1/layer [500]")
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Return results
		Info.Println(r.RemoteAddr, "PUT /api/v1/layer [200]")
		w.Header().Set("Content-Type", "application/json")
		// allow cross domain AJAX requests
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Write(js)

	}

}<commit_msg>share layers<commit_after>package app

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"net/http"
)

var SuperuserKey string = "su"
var AppMode string = "standard"

func DebugModeHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	md := vars["md"]
	if SuperuserKey != r.FormValue("authkey") {
		Error.Println(r.RemoteAddr, "POST /api/v1/layer [401]")
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	}
	if md == "debug" {
		js, err := json.Marshal(`{"status": "ok", "message": "debug mode on"}`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(true)
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	} else if md == "standard" {
		js, err := json.Marshal(`{"status": "ok", "message": "debug mode off"}`)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(false)
		w.Header().Set("Content-Type", "application/json")
		w.Write(js)
	}
}

// SUPERUSER
func NewCustomerHandler(w http.ResponseWriter, r *http.Request) {
	if SuperuserKey != r.FormValue("authkey") {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	} else {
		// new customer
		apikey := NewAPIKey(12)
		customer := Customer{Apikey: apikey}
		err := DB.insertCustomer(customer)
		if err != nil {
			Error.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		// return results
		data := `{"status":"ok","apikey":"` + apikey + `", "result":"customer created"}`
		js, err := json.Marshal(data)
		if err != nil {
			Error.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		DebugMode(false)
		w.Header().Set("Content-Type", "application/json")
		// allow cross domain AJAX requests
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Write(js)
	}
}

/*=======================================*/
// Method: ShareLayerHandler
// Description:
//		Gives customer access to datasource
// @param apikey - customer to give access
// @param authkey
// @return json
/*=======================================*/
func ShareLayerHandler(w http.ResponseWriter, r *http.Request) {

	// Get params
	apikey := r.FormValue("apikey")
	authkey := r.FormValue("authkey")

	// Get ds from url path
	vars := mux.Vars(r)
	ds := vars["ds"]

	// superuser access
	if SuperuserKey != r.FormValue("authkey") {
		http.Error(w, "unauthorized", http.StatusUnauthorized)
		return
	} else {

		if apikey == "" {
			Error.Println(r.RemoteAddr, "PUT /api/v1/layer/{ds} [401]")
			http.Error(w, "bad request", http.StatusBadRequest)
			return
		}

		// Get customer from database
		customer, err := DB.getCustomer(apikey)
		if err != nil {
			Warning.Println(r.RemoteAddr, "PUT /api/v1/layer/{ds} [404]")
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}

		// Add datasource uuid to customer
		customer.Datasources = append(customer.Datasources, ds)
		DB.insertCustomer(customer)

		// Generate message
		data := `{"status":"ok","datasource":"` + ds + `"}`
		js, err := json.Marshal(data)
		if err != nil {
			Error.Println(r.RemoteAddr, "PUT /api/v1/layer [500]")
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Return results
		Info.Println(r.RemoteAddr, "PUT /api/v1/layer [200]")
		w.Header().Set("Content-Type", "application/json")
		// allow cross domain AJAX requests
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Write(js)

	}

}<|endoftext|>


<commit_before>package prtagbuilder

import (
	"context"
	"fmt"
	"os"
	"regexp"
	"strconv"

	"github.com/google/go-github/v31/github"
	"github.com/sirupsen/logrus"
	"k8s.io/test-infra/prow/pod-utils/downwardapi"
)

const (
	ghProxyURL = "http://ghproxy/"
)

var (
	client *github.Client
	ctx    = context.Background()
)

// findPRNumber match commit message with regex to extract pull request number. By default github add pr number to the commit message.
func findPRNumber(commit *github.RepositoryCommit) string {
	re := regexp.MustCompile(`^.*\(#(?P<prNumber>\d*)\)\s*$`)
	matches := re.FindStringSubmatch(*commit.Commit.Message)
	if len(matches) != 2 {
		logrus.Fatalf("failed find PR number in commit message, found %d matched strings", len(matches))
	}
	return matches[1]
}

// verifyPR checks if pull request merge commit match provided commit SHA.
func verifyPR(pr *github.PullRequest, commitSHA string) bool {
	if *pr.Merged {
		if *pr.MergeCommitSHA != commitSHA {
			logrus.Fatalf("commit SHA and matched PR merge commit SHA doesn't match")
		}
	}
	return true
}

// BuildPrTag will extract PR number from commit message, search PR, validate if correct PR was found and print pr tag.
func BuildPrTag() {
	// check if prtagbuilder was called on presubmit, fail if true
	if _, present := os.LookupEnv("PULL_NUMBER"); present {
		logrus.Fatalf("prtagbuilder was called on presubmit, failing")
	}
	// get git base reference from postsubmit environment variables
	jobSpec, err := downwardapi.ResolveSpecFromEnv()
	if err != nil {
		logrus.WithError(err).Fatalf("failed to read JOB_SPEC prowjob env")
	}
	// create github client with ghproxy URL
	client, err = github.NewEnterpriseClient(ghProxyURL, ghProxyURL, nil)
	if err != nil {
		logrus.WithError(err).Fatalf("failed get new github client")
	}
	// get api meta data through ghproxy
	_, _, err = client.APIMeta(ctx)
	if err != nil {
		logrus.WithError(err).Warnf("failed connecting to ghproxy")
		// fallback to create github client with default public github URL because ghproxy didn't respond
		client = github.NewClient(nil)
	}
	// get commit details for base sha
	commit, _, err := client.Repositories.GetCommit(ctx, jobSpec.Refs.Org, jobSpec.Refs.Repo, jobSpec.Refs.BaseSHA)
	if err != nil {
		logrus.WithError(err).Fatalf("failed get commit %s", jobSpec.Refs.BaseSHA)
	}
	// extract pull request number from commit message
	prNumber, err := strconv.Atoi(findPRNumber(commit))
	if err != nil {
		logrus.WithError(err).Fatalf("failed convert PR number to integer")
	}
	// get pull request details for extracted pr
	pr, _, err := client.PullRequests.Get(ctx, jobSpec.Refs.Org, jobSpec.Refs.Repo, prNumber)
	if err != nil {
		logrus.WithError(err).Fatalf("failed get Pull Request number %d", prNumber)
	}
	// check if correct pr was found
	if verifyPR(pr, jobSpec.Refs.BaseSHA) {
		// print PR image tag
		fmt.Printf("PR-%d", prNumber)
	}
}
<commit_msg>Fixed matching regex (#2844)<commit_after>package prtagbuilder

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/google/go-github/v31/github"
	"github.com/sirupsen/logrus"
	"k8s.io/test-infra/prow/pod-utils/downwardapi"
)

var (
	client *github.Client
	ctx    = context.Background()
)

// findPRNumber match commit message with regex to extract pull request number. By default github add pr number to the commit message.
func findPRNumber(commit *github.RepositoryCommit) string {
	re := regexp.MustCompile(`(?s)^.*\(#(?P<prNumber>\d*)?\)\s*.*$`)
	messageReader := strings.NewReader(commit.Commit.GetMessage())
	scanner := bufio.NewScanner(messageReader)
	scanner.Scan()
	matches := re.FindStringSubmatch(scanner.Text())
	if len(matches) != 2 {
		logrus.Fatalf("failed find PR number in first line of commit message: %s, found %d matched strings", scanner.Text(), len(matches))
	}
	return matches[1]
}

// verifyPR checks if pull request merge commit match provided commit SHA.
func verifyPR(pr *github.PullRequest, commitSHA string) bool {
	if *pr.Merged {
		if *pr.MergeCommitSHA != commitSHA {
			logrus.Fatalf("commit SHA and matched PR merge commit SHA doesn't match")
		}
	}
	return true
}

// BuildPrTag will extract PR number from commit message, search PR, validate if correct PR was found and print pr tag.
func BuildPrTag() {
	// check if prtagbuilder was called on presubmit, fail if true
	if _, present := os.LookupEnv("PULL_NUMBER"); present {
		logrus.Fatalf("prtagbuilder was called on presubmit, failing")
	}
	// get git base reference from postsubmit environment variables
	jobSpec, err := downwardapi.ResolveSpecFromEnv()
	if err != nil {
		logrus.WithError(err).Fatalf("failed to read JOB_SPEC prowjob env")
	}
	// create github client
	client = github.NewClient(nil)

	// get commit details for base sha
	commit, _, err := client.Repositories.GetCommit(ctx, jobSpec.Refs.Org, jobSpec.Refs.Repo, jobSpec.Refs.BaseSHA)
	if err != nil {
		logrus.WithError(err).Fatalf("failed get commit %s", jobSpec.Refs.BaseSHA)
	}
	// extract pull request number from commit message
	prNumber, err := strconv.Atoi(findPRNumber(commit))
	if err != nil {
		logrus.WithError(err).Fatalf("failed convert PR number to integer")
	}
	// get pull request details for extracted pr
	pr, _, err := client.PullRequests.Get(ctx, jobSpec.Refs.Org, jobSpec.Refs.Repo, prNumber)
	if err != nil {
		logrus.WithError(err).Fatalf("failed get Pull Request number %d", prNumber)
	}
	// check if correct pr was found
	if verifyPR(pr, jobSpec.Refs.BaseSHA) {
		// print PR image tag
		fmt.Printf("PR-%d", prNumber)
	}
}
<|endoftext|>


<commit_before><commit_msg>encoding/json: add Decoder.InputOffset for offset access<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker/decls"
	celext "github.com/google/cel-go/ext"
	"github.com/spf13/cobra"
	triggerscel "github.com/tektoncd/triggers/pkg/interceptors/cel"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/labels"
	corev1lister "k8s.io/client-go/listers/core/v1"
)

var (
	rootCmd = &cobra.Command{
		Use:   "cel-eval",
		Short: "Tekton CEL interceptor evaluator",
		Run:   rootRun,
	}

	expressionPath string
	httpPath       string
)

func init() {
	rootCmd.Flags().StringVarP(&expressionPath, "expression", "e", "", "Expression to evaluate")
	rootCmd.Flags().StringVarP(&httpPath, "http-request", "r", "", "Path to HTTP request")
	if err := rootCmd.MarkFlagRequired("expression"); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	if err := rootCmd.MarkFlagRequired("http-request"); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func rootRun(cmd *cobra.Command, args []string) {
	if err := evalCEL(os.Stdout, expressionPath, httpPath); err != nil {
		log.Fatal(err)
	}
}

type secretLister struct{}

func (sl secretLister) List(selector labels.Selector) (ret []*v1.Secret, err error) {
	return nil, nil
}

func (sl secretLister) Secrets(namespace string) corev1lister.SecretNamespaceLister {
	return secretLister{}
}

func (sl secretLister) Get(name string) (*v1.Secret, error) {
	return nil, nil
}

func evalCEL(w io.Writer, expressionPath, httpPath string) error {
	// Read expression
	expression, err := readExpression(expressionPath)
	if err != nil {
		return fmt.Errorf("error reading HTTP file: %w", err)
	}

	// Read HTTP request.
	r, body, err := readHTTP(httpPath)
	if err != nil {
		return fmt.Errorf("error reading HTTP file: %w", err)
	}

	evalContext, err := makeEvalContext(body, r.Header, r.URL.String(), map[string]interface{}{})
	if err != nil {
		return fmt.Errorf("error making eval context: %w", err)
	}

	mapStrDyn := decls.NewMapType(decls.String, decls.Dyn)
	env, err := cel.NewEnv(
		triggerscel.Triggers("default", secretLister{}),
		celext.Strings(),
		celext.Encoders(),
		cel.Declarations(
			decls.NewVar("body", mapStrDyn),
			decls.NewVar("header", mapStrDyn),
			decls.NewVar("extensions", mapStrDyn),
			decls.NewVar("requestURL", decls.String),
		))
	if err != nil {
		log.Fatal(err)
	}

	parsed, issues := env.Parse(expression)
	if issues != nil && issues.Err() != nil {
		return fmt.Errorf("failed to parse expression %#v: %w", expression, issues.Err())
	}

	checked, issues := env.Check(parsed)
	if issues != nil && issues.Err() != nil {
		return fmt.Errorf("expression %#v check failed: %w", expression, issues.Err())
	}

	prg, err := env.Program(checked)
	if err != nil {
		return fmt.Errorf("expression %#v failed to create a Program: %w", expression, err)
	}

	out, _, err := prg.Eval(evalContext)
	if err != nil {
		return fmt.Errorf("expression %#v failed to evaluate: %w", expression, err)
	}

	fmt.Fprint(w, out)

	return nil
}

func readExpression(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("error opening file: %w", err)
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		return "", fmt.Errorf("error reading from file: %w", err)
	}

	return string(data), nil
}

func readHTTP(path string) (*http.Request, []byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil, fmt.Errorf("error opening file: %w", err)
	}
	defer f.Close()

	req, err := http.ReadRequest(bufio.NewReader(f))
	if err != nil {
		return nil, nil, fmt.Errorf("error reading request: %w", err)
	}
	defer req.Body.Close()
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return nil, nil, fmt.Errorf("error reading HTTP body: %w", err)
	}
	return req, body, nil
}

func makeEvalContext(body []byte, h http.Header, url string, extensions map[string]interface{}) (map[string]interface{}, error) {
	var jsonMap map[string]interface{}
	err := json.Unmarshal(body, &jsonMap)
	if err != nil {
		return nil, fmt.Errorf("failed to parse the body as JSON: %w", err)
	}
	return map[string]interface{}{
		"body":       jsonMap,
		"header":     h,
		"requestURL": url,
		"extensions": extensions,
	}, nil
}

// Execute runs the command.
func Execute() error {
	return rootCmd.Execute()
}
<commit_msg>Fix cel-eval for interceptor's secretgetter<commit_after>package cmd

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"

	"github.com/google/cel-go/cel"
	"github.com/google/cel-go/checker/decls"
	celext "github.com/google/cel-go/ext"
	"github.com/spf13/cobra"
	triggersv1beta1 "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
	triggerscel "github.com/tektoncd/triggers/pkg/interceptors/cel"
)

var (
	rootCmd = &cobra.Command{
		Use:   "cel-eval",
		Short: "Tekton CEL interceptor evaluator",
		Run:   rootRun,
	}

	expressionPath string
	httpPath       string
)

func init() {
	rootCmd.Flags().StringVarP(&expressionPath, "expression", "e", "", "Expression to evaluate")
	rootCmd.Flags().StringVarP(&httpPath, "http-request", "r", "", "Path to HTTP request")
	if err := rootCmd.MarkFlagRequired("expression"); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
	if err := rootCmd.MarkFlagRequired("http-request"); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func rootRun(cmd *cobra.Command, args []string) {
	if err := evalCEL(os.Stdout, expressionPath, httpPath); err != nil {
		log.Fatal(err)
	}
}

type secretGetter struct{}

func (sg secretGetter) Get(ctx context.Context, triggerNS string, sr *triggersv1beta1.SecretRef) ([]byte, error) {
	return nil, nil
}

func evalCEL(w io.Writer, expressionPath, httpPath string) error {
	// Read expression
	expression, err := readExpression(expressionPath)
	if err != nil {
		return fmt.Errorf("error reading HTTP file: %w", err)
	}

	// Read HTTP request.
	r, body, err := readHTTP(httpPath)
	if err != nil {
		return fmt.Errorf("error reading HTTP file: %w", err)
	}

	evalContext, err := makeEvalContext(body, r.Header, r.URL.String(), map[string]interface{}{})
	if err != nil {
		return fmt.Errorf("error making eval context: %w", err)
	}

	mapStrDyn := decls.NewMapType(decls.String, decls.Dyn)
	env, err := cel.NewEnv(
		triggerscel.Triggers(context.Background(), "default", secretGetter{}),
		celext.Strings(),
		celext.Encoders(),
		cel.Declarations(
			decls.NewVar("body", mapStrDyn),
			decls.NewVar("header", mapStrDyn),
			decls.NewVar("extensions", mapStrDyn),
			decls.NewVar("requestURL", decls.String),
		))
	if err != nil {
		log.Fatal(err)
	}

	parsed, issues := env.Parse(expression)
	if issues != nil && issues.Err() != nil {
		return fmt.Errorf("failed to parse expression %#v: %w", expression, issues.Err())
	}

	checked, issues := env.Check(parsed)
	if issues != nil && issues.Err() != nil {
		return fmt.Errorf("expression %#v check failed: %w", expression, issues.Err())
	}

	prg, err := env.Program(checked)
	if err != nil {
		return fmt.Errorf("expression %#v failed to create a Program: %w", expression, err)
	}

	out, _, err := prg.Eval(evalContext)
	if err != nil {
		return fmt.Errorf("expression %#v failed to evaluate: %w", expression, err)
	}

	fmt.Fprint(w, out)

	return nil
}

func readExpression(path string) (string, error) {
	f, err := os.Open(path)
	if err != nil {
		return "", fmt.Errorf("error opening file: %w", err)
	}
	defer f.Close()

	data, err := ioutil.ReadAll(f)
	if err != nil {
		return "", fmt.Errorf("error reading from file: %w", err)
	}

	return string(data), nil
}

func readHTTP(path string) (*http.Request, []byte, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, nil, fmt.Errorf("error opening file: %w", err)
	}
	defer f.Close()

	req, err := http.ReadRequest(bufio.NewReader(f))
	if err != nil {
		return nil, nil, fmt.Errorf("error reading request: %w", err)
	}
	defer req.Body.Close()
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		return nil, nil, fmt.Errorf("error reading HTTP body: %w", err)
	}
	return req, body, nil
}

func makeEvalContext(body []byte, h http.Header, url string, extensions map[string]interface{}) (map[string]interface{}, error) {
	var jsonMap map[string]interface{}
	err := json.Unmarshal(body, &jsonMap)
	if err != nil {
		return nil, fmt.Errorf("failed to parse the body as JSON: %w", err)
	}
	return map[string]interface{}{
		"body":       jsonMap,
		"header":     h,
		"requestURL": url,
		"extensions": extensions,
	}, nil
}

// Execute runs the command.
func Execute() error {
	return rootCmd.Execute()
}
<|endoftext|>