<commit_before>package host

// TODO: Need to check that 'RevisionConfirmed' is sensitive to whether or not
// it was the *most recent* revision that got confirmed.

import (
	"encoding/binary"
	"encoding/json"
	"sync"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/bolt"
)

// initRescan is a helper function of initConsensusSubscribe, and is called when
// the host and the consensus set have become desynchronized. Desynchronization
// typically happens if the user is replacing or altering the persistent files
// in the consensus set or the host.
func (h *Host) initRescan() error {
	// Reset all of the variables that have relevance to the consensus set.
	var allObligations []storageObligation
	// Reset all of the consensus-relevant variables in the host.
	h.blockHeight = 0

	// Reset all of the storage obligations.
	err := h.db.Update(func(tx *bolt.Tx) error {
		bsu := tx.Bucket(bucketStorageObligations)
		c := bsu.Cursor()
		for k, soBytes := c.First(); soBytes != nil; k, soBytes = c.Next() {
			var so storageObligation
			err := json.Unmarshal(soBytes, &so)
			if err != nil {
				return err
			}
			so.OriginConfirmed = false
			so.RevisionConfirmed = false
			so.ProofConfirmed = false
			allObligations = append(allObligations, so)
			soBytes, err = json.Marshal(so)
			if err != nil {
				return err
			}
			err = bsu.Put(k, soBytes)
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Subscribe to the consensus set. This is a blocking call that will not
	// return until the host has fully caught up to the current block.
	//
	// Convention dictates that the host should not make external calls while
	// under lock, but this function happens at startup while blocking. Because
	// it happens while blocking, and because there is no actual host lock held
	// at this time, none of the host external functions are exposed, so it is
	// save to make the exported call.
	err = h.cs.ConsensusSetSubscribe(h, modules.ConsensusChangeBeginning)
	if err != nil {
		return err
	}
	h.tg.OnStop(func() {
		h.cs.Unsubscribe(h)
	})

	// Re-queue all of the action items for the storage obligations.
	for _, so := range allObligations {
		soid := so.id()
		err0 := h.tpool.AcceptTransactionSet(so.OriginTransactionSet)
		err1 := h.queueActionItem(h.blockHeight+resubmissionTimeout, soid)
		err2 := h.queueActionItem(so.expiration()-revisionSubmissionBuffer, soid)
		err3 := h.queueActionItem(so.expiration()+resubmissionTimeout, soid)
		err = composeErrors(err0, err1, err2, err3)
		if err != nil {
			h.log.Println("dropping storage obligation during rescan, id", so.id())
			return composeErrors(err, h.removeStorageObligation(so, obligationRejected))
		}
	}
	return nil
}

// initConsensusSubscription subscribes the host to the consensus set.
func (h *Host) initConsensusSubscription() error {
	// Convention dictates that the host should not make external calls while
	// under lock, but this function happens at startup while blocking. Because
	// it happens while blocking, and because there is no actual host lock held
	// at this time, none of the host external functions are exposed, so it is
	// save to make the exported call.
	err := h.cs.ConsensusSetSubscribe(h, h.recentChange)
	if err == modules.ErrInvalidConsensusChangeID {
		// Perform a rescan of the consensus set if the change id that the host
		// has is unrecognized by the consensus set. This will typically only
		// happen if the user has been replacing files inside the Sia folder
		// structure.
		return h.initRescan()
	}
	if err != nil {
		return err
	}
	h.tg.OnStop(func() {
		h.cs.Unsubscribe(h)
	})
	return nil
}

// ProcessConsensusChange will be called by the consensus set every time there
// is a change to the blockchain.
func (h *Host) ProcessConsensusChange(cc modules.ConsensusChange) {
	// ProcessConsensusChange spawns multiple threads which will wait until
	// storage obligations are unlocked and then submit storage proofs to
	// blockchain for those obligations. The ThreadGroup needs to wait for
	// these threads to terminate. These threads also require a host lock,
	//
	// We use a local sync.WaitGroup to track the progress of these threads.
	// Because these threads require a host lock, wg.Wait() should not be
	// called until after the host lock has been released. And then tg.Done()
	// should not be called until wg.Wait() returns.
	//
	// Because the host lock is released in a defer statement, wg.Wait() must
	// be called in a defer statement that comes before the deferred
	// h.mu.Unlock(). This is why the code for finishing the wait group is
	// declared far above the place where threads are added to the wait group.
	err := h.tg.Add()
	if err != nil {
		return
	}
	wg := new(sync.WaitGroup)
	defer func() {
		wg.Wait()
		h.tg.Done()
	}()

	// Host needs to unlock before wg.Wait() is called, so that the other
	// threads may access the host lock.
	lockID := h.mu.Lock()
	defer h.mu.Unlock(lockID)

	// Wrap the whole parsing into a single large database tx to keep things
	// efficient.
	var actionItems []types.FileContractID
	err = h.db.Update(func(tx *bolt.Tx) error {
		for _, block := range cc.RevertedBlocks {
			// Look for transactions relevant to open storage obligations.
			for _, txn := range block.Transactions {
				// Check for file contracts.
				if len(txn.FileContracts) > 0 {
					for j := range txn.FileContracts {
						fcid := txn.FileContractID(uint64(j))
						so, err := getStorageObligation(tx, fcid)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.OriginConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for file contract revisions.
				if len(txn.FileContractRevisions) > 0 {
					for _, fcr := range txn.FileContractRevisions {
						so, err := getStorageObligation(tx, fcr.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.RevisionConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for storage proofs.
				if len(txn.StorageProofs) > 0 {
					for _, sp := range txn.StorageProofs {
						// Check database for relevant storage proofs.
						so, err := getStorageObligation(tx, sp.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.ProofConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}
			}

			// Height is not adjusted when dealing with the genesis block because
			// the default height is 0 and the genesis block height is 0. If
			// removing the genesis block, height will already be at height 0 and
			// should not update, lest an underflow occur.
			if block.ID() != types.GenesisID {
				h.blockHeight--
			}
		}
		for _, block := range cc.AppliedBlocks {
			// Look for transactions relevant to open storage obligations.
			for _, txn := range block.Transactions {
				// Check for file contracts.
				if len(txn.FileContracts) > 0 {
					for i := range txn.FileContracts {
						fcid := txn.FileContractID(uint64(i))
						so, err := getStorageObligation(tx, fcid)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.OriginConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for file contract revisions.
				if len(txn.FileContractRevisions) > 0 {
					for _, fcr := range txn.FileContractRevisions {
						so, err := getStorageObligation(tx, fcr.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.RevisionConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for storage proofs.
				if len(txn.StorageProofs) > 0 {
					for _, sp := range txn.StorageProofs {
						so, err := getStorageObligation(tx, sp.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.ProofConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}
			}

			// Height is not adjusted when dealing with the genesis block because
			// the default height is 0 and the genesis block height is 0. If adding
			// the genesis block, height will already be at height 0 and should not
			// update.
			if block.ID() != types.GenesisID {
				h.blockHeight++
			}

			// Handle any action items relevant to the current height.
			bai := tx.Bucket(bucketActionItems)
			heightBytes := make([]byte, 8)
			binary.BigEndian.PutUint64(heightBytes, uint64(h.blockHeight)) // BigEndian used so bolt will keep things sorted automatically.
			existingItems := bai.Get(heightBytes)

			// From the existing items, pull out a storage obligation.
			knownActionItems := make(map[types.FileContractID]struct{})
			obligationIDs := make([]types.FileContractID, len(existingItems)/crypto.HashSize)
			for i := 0; i < len(existingItems); i += crypto.HashSize {
				copy(obligationIDs[i/crypto.HashSize][:], existingItems[i:i+crypto.HashSize])
			}
			for _, soid := range obligationIDs {
				_, exists := knownActionItems[soid]
				if !exists {
					actionItems = append(actionItems, soid)
					knownActionItems[soid] = struct{}{}
				}
			}
		}
		return nil
	})
	if err != nil {
		h.log.Println(err)
	}

	// Handle the list of action items.
	for i := range actionItems {
		// Add the action item to the wait group outside of the threaded call.
		// The call to wg.Done() was established at the beginning of the
		// function in a defer statement.
		wg.Add(1)
		go h.threadedHandleActionItem(actionItems[i], wg)
	}

	// Update the host's recent change pointer to point to the most recent
	// change.
	h.recentChange = cc.ID

	// Save the host.
	err = h.save()
	if err != nil {
		h.log.Println("ERROR: could not save during ProcessConsensusChange:", err)
	}
}
<commit_msg>fix deadlock error in modules/host/update.go<commit_after>package host

// TODO: Need to check that 'RevisionConfirmed' is sensitive to whether or not
// it was the *most recent* revision that got confirmed.

import (
	"encoding/binary"
	"encoding/json"
	"sync"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"

	"github.com/NebulousLabs/bolt"
)

// initRescan is a helper function of initConsensusSubscribe, and is called when
// the host and the consensus set have become desynchronized. Desynchronization
// typically happens if the user is replacing or altering the persistent files
// in the consensus set or the host.
func (h *Host) initRescan() error {
	// Reset all of the variables that have relevance to the consensus set.
	var allObligations []storageObligation
	// Reset all of the consensus-relevant variables in the host.
	h.blockHeight = 0

	// Reset all of the storage obligations.
	err := h.db.Update(func(tx *bolt.Tx) error {
		bsu := tx.Bucket(bucketStorageObligations)
		c := bsu.Cursor()
		for k, soBytes := c.First(); soBytes != nil; k, soBytes = c.Next() {
			var so storageObligation
			err := json.Unmarshal(soBytes, &so)
			if err != nil {
				return err
			}
			so.OriginConfirmed = false
			so.RevisionConfirmed = false
			so.ProofConfirmed = false
			allObligations = append(allObligations, so)
			soBytes, err = json.Marshal(so)
			if err != nil {
				return err
			}
			err = bsu.Put(k, soBytes)
			if err != nil {
				return err
			}
		}
		return nil
	})
	if err != nil {
		return err
	}

	// Subscribe to the consensus set. This is a blocking call that will not
	// return until the host has fully caught up to the current block.
	//
	// Convention dictates that the host should not make external calls while
	// under lock, but this function happens at startup while blocking. Because
	// it happens while blocking, and because there is no actual host lock held
	// at this time, none of the host external functions are exposed, so it is
	// save to make the exported call.
	err = h.cs.ConsensusSetSubscribe(h, modules.ConsensusChangeBeginning)
	if err != nil {
		return err
	}
	h.tg.OnStop(func() {
		h.cs.Unsubscribe(h)
	})

	// Re-queue all of the action items for the storage obligations.
	for _, so := range allObligations {
		soid := so.id()
		err0 := h.tpool.AcceptTransactionSet(so.OriginTransactionSet)
		err1 := h.queueActionItem(h.blockHeight+resubmissionTimeout, soid)
		err2 := h.queueActionItem(so.expiration()-revisionSubmissionBuffer, soid)
		err3 := h.queueActionItem(so.expiration()+resubmissionTimeout, soid)
		err = composeErrors(err0, err1, err2, err3)
		if err != nil {
			h.log.Println("dropping storage obligation during rescan, id", so.id())
			return composeErrors(err, h.removeStorageObligation(so, obligationRejected))
		}
	}
	return nil
}

// initConsensusSubscription subscribes the host to the consensus set.
func (h *Host) initConsensusSubscription() error {
	// Convention dictates that the host should not make external calls while
	// under lock, but this function happens at startup while blocking. Because
	// it happens while blocking, and because there is no actual host lock held
	// at this time, none of the host external functions are exposed, so it is
	// save to make the exported call.
	err := h.cs.ConsensusSetSubscribe(h, h.recentChange)
	if err == modules.ErrInvalidConsensusChangeID {
		// Perform a rescan of the consensus set if the change id that the host
		// has is unrecognized by the consensus set. This will typically only
		// happen if the user has been replacing files inside the Sia folder
		// structure.
		return h.initRescan()
	}
	if err != nil {
		return err
	}
	h.tg.OnStop(func() {
		h.cs.Unsubscribe(h)
	})
	return nil
}

// ProcessConsensusChange will be called by the consensus set every time there
// is a change to the blockchain.
func (h *Host) ProcessConsensusChange(cc modules.ConsensusChange) {
	// Add is called at the beginning of the function, but Done cannot be
	// called until all of the threads spawned by this function have also
	// terminated. This function should not block while these threads wait to
	// terminate.
	err := h.tg.Add()
	if err != nil {
		return
	}
	lockID := h.mu.Lock()
	defer h.mu.Unlock(lockID)

	// Wrap the whole parsing into a single large database tx to keep things
	// efficient.
	var actionItems []types.FileContractID
	err = h.db.Update(func(tx *bolt.Tx) error {
		for _, block := range cc.RevertedBlocks {
			// Look for transactions relevant to open storage obligations.
			for _, txn := range block.Transactions {
				// Check for file contracts.
				if len(txn.FileContracts) > 0 {
					for j := range txn.FileContracts {
						fcid := txn.FileContractID(uint64(j))
						so, err := getStorageObligation(tx, fcid)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.OriginConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for file contract revisions.
				if len(txn.FileContractRevisions) > 0 {
					for _, fcr := range txn.FileContractRevisions {
						so, err := getStorageObligation(tx, fcr.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.RevisionConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for storage proofs.
				if len(txn.StorageProofs) > 0 {
					for _, sp := range txn.StorageProofs {
						// Check database for relevant storage proofs.
						so, err := getStorageObligation(tx, sp.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.ProofConfirmed = false
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}
			}

			// Height is not adjusted when dealing with the genesis block because
			// the default height is 0 and the genesis block height is 0. If
			// removing the genesis block, height will already be at height 0 and
			// should not update, lest an underflow occur.
			if block.ID() != types.GenesisID {
				h.blockHeight--
			}
		}
		for _, block := range cc.AppliedBlocks {
			// Look for transactions relevant to open storage obligations.
			for _, txn := range block.Transactions {
				// Check for file contracts.
				if len(txn.FileContracts) > 0 {
					for i := range txn.FileContracts {
						fcid := txn.FileContractID(uint64(i))
						so, err := getStorageObligation(tx, fcid)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.OriginConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for file contract revisions.
				if len(txn.FileContractRevisions) > 0 {
					for _, fcr := range txn.FileContractRevisions {
						so, err := getStorageObligation(tx, fcr.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.RevisionConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}

				// Check for storage proofs.
				if len(txn.StorageProofs) > 0 {
					for _, sp := range txn.StorageProofs {
						so, err := getStorageObligation(tx, sp.ParentID)
						if err != nil {
							// The storage folder may not exist, or the disk
							// may be having trouble. Either way, we ignore the
							// problem. If the disk is having trouble, the user
							// will have to perform a rescan.
							continue
						}
						so.ProofConfirmed = true
						err = putStorageObligation(tx, so)
						if err != nil {
							continue
						}
					}
				}
			}

			// Height is not adjusted when dealing with the genesis block because
			// the default height is 0 and the genesis block height is 0. If adding
			// the genesis block, height will already be at height 0 and should not
			// update.
			if block.ID() != types.GenesisID {
				h.blockHeight++
			}

			// Handle any action items relevant to the current height.
			bai := tx.Bucket(bucketActionItems)
			heightBytes := make([]byte, 8)
			binary.BigEndian.PutUint64(heightBytes, uint64(h.blockHeight)) // BigEndian used so bolt will keep things sorted automatically.
			existingItems := bai.Get(heightBytes)

			// From the existing items, pull out a storage obligation.
			knownActionItems := make(map[types.FileContractID]struct{})
			obligationIDs := make([]types.FileContractID, len(existingItems)/crypto.HashSize)
			for i := 0; i < len(existingItems); i += crypto.HashSize {
				copy(obligationIDs[i/crypto.HashSize][:], existingItems[i:i+crypto.HashSize])
			}
			for _, soid := range obligationIDs {
				_, exists := knownActionItems[soid]
				if !exists {
					actionItems = append(actionItems, soid)
					knownActionItems[soid] = struct{}{}
				}
			}
		}
		return nil
	})
	if err != nil {
		h.log.Println(err)
	}

	// Handle the list of action items. Action items require host locks and
	// potentially require waiting for long periods of time while various
	// network communications finish. To prevent the host lock from being held
	// while the network I/O is blocking the action item execution, the action
	// items are handled in their own thread. A wait group is used to prevent
	// the host from releasing ThreadGroup control until all threads that this
	// function have spawned have completed.
	wg := new(sync.WaitGroup)
	// The host should not release thread group control until all spawned
	// threads have completed execution, though waiting for them should not
	// block this function. The host should also not release thread group
	// control until this function has terminated, hence the use of 'defer
	// func() { go func() }' to coordinate waiting and done-ing.
	defer func() {
		go func() {
			wg.Wait()
			h.tg.Done()
		}()
	}()
	for i := range actionItems {
		// Add the action item to the wait group outside of the threaded call.
		// The call to wg.Done() was established at the beginning of the
		// function in a defer statement.
		wg.Add(1)
		go h.threadedHandleActionItem(actionItems[i], wg)
	}

	// Update the host's recent change pointer to point to the most recent
	// change.
	h.recentChange = cc.ID

	// Save the host.
	err = h.save()
	if err != nil {
		h.log.Println("ERROR: could not save during ProcessConsensusChange:", err)
	}
}
<|endoftext|>


<commit_before>package main

// This is a simple example package that uses a template!

import (
	"fmt"
	ints "./slice_int"
	stringtest "./test_string"
	inttest "./test_int"
	list "./list_int"
	sort "./sort_float64"
)

func main() {
	ss := []string{"hello","world"}
	is := []int{5,4,3,2,1}
	fmt.Println("Head(ss)", stringtest.Head(ss))
	fmt.Println("Tail(is)", inttest.Tail(is))
	// Doesn't the following give you nightmares of lisp?
	fmt.Println(list.Cdr(list.Cons(1,list.Cons(2,list.Cons(3,nil)))))

	ints.Map(func (a int) int { return a*2 }, is)
	fmt.Println("is are now doubled: ", is)
	ls := []list.List{ *list.Cons(1,nil), *list.Cons(2,nil) }
	ls = lists.Append(ls, *list.Cons(3,nil))
	fmt.Println("I like lists: ", ls)

	tosort := []float64{5,4,3,2,1}
	sort.SortArray(tosort)
	if sort.AreSorted(tosort) { fmt.Println("The array is sorted!") }
}
<commit_msg>Remove usage of lists pkg.<commit_after>package main

// This is a simple example package that uses a template!

import (
	"fmt"
	ints "./slice_int"
	stringtest "./test_string"
	inttest "./test_int"
	list "./list_int"
	sort "./sort_float64"
)

func main() {
	ss := []string{"hello","world"}
	is := []int{5,4,3,2,1}
	fmt.Println("Head(ss)", stringtest.Head(ss))
	fmt.Println("Tail(is)", inttest.Tail(is))
	// Doesn't the following give you nightmares of lisp?
	fmt.Println(list.Cdr(list.Cons(1,list.Cons(2,list.Cons(3,nil)))))

	ints.Map(func (a int) int { return a*2 }, is)
	fmt.Println("is are now doubled: ", is)
	ls := []list.List{ *list.Cons(1,nil), *list.Cons(2,nil) }
	fmt.Println("I like lists: ", ls)

	tosort := []float64{5,4,3,2,1}
	sort.SortArray(tosort)
	if sort.AreSorted(tosort) { fmt.Println("The array is sorted!") }
}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package syntax

import (
	"go/ast"
	"go/parser"
	"go/token"

	"github.com/nelsam/gxui"
)

func zeroBasedPos(pos token.Pos) uint64 {
	if pos < 1 {
		panic("Positions of 0 are not valid positions")
	}
	return uint64(pos) - 1
}

func nodeLayer(node ast.Node, colors ...gxui.Color) *gxui.CodeSyntaxLayer {
	return layer(node.Pos(), int(node.End()-node.Pos()), colors...)
}

func layer(pos token.Pos, length int, colors ...gxui.Color) *gxui.CodeSyntaxLayer {
	if length == 0 {
		return nil
	}
	if len(colors) == 0 {
		panic("No colors passed to layer()")
	}
	if len(colors) > 2 {
		panic("Only two colors (text and background) are currently supported")
	}
	layer := gxui.CreateCodeSyntaxLayer()
	layer.Add(int(zeroBasedPos(pos)), length)
	layer.SetColor(colors[0])
	if len(colors) > 1 {
		layer.SetBackgroundColor(colors[1])
	}
	return layer
}

// TODO: highlight matching parenthesis/braces/brackets
func Layers(filename, text string) (gxui.CodeSyntaxLayers, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, text, 0)
	layers := make(gxui.CodeSyntaxLayers, 0, 100)
	if f.Doc != nil {
		layers = append(layers, nodeLayer(f.Doc, commentColor))
	}
	if f.Package.IsValid() {
		layers = append(layers, layer(f.Package, len("package"), keywordColor))
	}
	for _, importSpec := range f.Imports {
		layers = append(layers, nodeLayer(importSpec, stringColor))
	}
	for _, comment := range f.Comments {
		layers = append(layers, nodeLayer(comment, commentColor))
	}
	for _, decl := range f.Decls {
		layers = append(layers, handleDecl(decl)...)
	}
	for _, unresolved := range f.Unresolved {
		layers = append(layers, handleUnresolved(unresolved)...)
	}
	return layers, err
}
<commit_msg>Remove resolved TODO<commit_after>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package syntax

import (
	"go/ast"
	"go/parser"
	"go/token"

	"github.com/nelsam/gxui"
)

func zeroBasedPos(pos token.Pos) uint64 {
	if pos < 1 {
		panic("Positions of 0 are not valid positions")
	}
	return uint64(pos) - 1
}

func nodeLayer(node ast.Node, colors ...gxui.Color) *gxui.CodeSyntaxLayer {
	return layer(node.Pos(), int(node.End()-node.Pos()), colors...)
}

func layer(pos token.Pos, length int, colors ...gxui.Color) *gxui.CodeSyntaxLayer {
	if length == 0 {
		return nil
	}
	if len(colors) == 0 {
		panic("No colors passed to layer()")
	}
	if len(colors) > 2 {
		panic("Only two colors (text and background) are currently supported")
	}
	layer := gxui.CreateCodeSyntaxLayer()
	layer.Add(int(zeroBasedPos(pos)), length)
	layer.SetColor(colors[0])
	if len(colors) > 1 {
		layer.SetBackgroundColor(colors[1])
	}
	return layer
}

func Layers(filename, text string) (gxui.CodeSyntaxLayers, error) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, text, 0)
	layers := make(gxui.CodeSyntaxLayers, 0, 100)
	if f.Doc != nil {
		layers = append(layers, nodeLayer(f.Doc, commentColor))
	}
	if f.Package.IsValid() {
		layers = append(layers, layer(f.Package, len("package"), keywordColor))
	}
	for _, importSpec := range f.Imports {
		layers = append(layers, nodeLayer(importSpec, stringColor))
	}
	for _, comment := range f.Comments {
		layers = append(layers, nodeLayer(comment, commentColor))
	}
	for _, decl := range f.Decls {
		layers = append(layers, handleDecl(decl)...)
	}
	for _, unresolved := range f.Unresolved {
		layers = append(layers, handleUnresolved(unresolved)...)
	}
	return layers, err
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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 main

import (
	"bytes"
	"fmt"
	"html"
	"io"
	"net"
	"net/http"
	"strconv"
)

func taskList(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	p := writerf(w)
	p("<title>runsit</title>")
	p("
runsit Admin UI

running tasks

\n")
	for _, t := range GetTasks() {
		p("
%s: %s
\n", t.Name, t.Name,
			html.EscapeString(t.Status()))
	}
	p("
\n")
	p("
runsit log

%s
\n", html.EscapeString(logBuf.String()))
	p("\n")
}

func killTask(w http.ResponseWriter, r *http.Request, t *Task) {
	w.Header().Set("Content-Type", "text/html")
	in, ok := t.RunningInstance()
	if !ok {
		http.Error(w, "task not running", 500)
		return
	}
	pid, _ := strconv.Atoi(r.FormValue("pid"))
	if in.Pid() != pid || pid == 0 {
		http.Error(w, "active task pid doesn't match pid parameter", 500)
		return
	}
	in.cmd.Process.Kill()
	p := writerf(w)
	p("killed pid %d.
back to %s status", pid, t.Name, t.Name)
}

func taskView(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	taskName := path[len("/task/"):]
	t, ok := GetTask(taskName)
	if !ok {
		http.NotFound(w, r)
		return
	}
	mode := r.FormValue("mode")
	switch mode {
	case "kill":
		killTask(w, r, t)
		return
	default:
		http.Error(w, "unknown mode", 400)
		return
	case "":
	}

	// Buffer to memory so we never block writing to a slow client
	// while holding the TaskOutput mutex.
	var buf bytes.Buffer
	p := writerf(&buf)
	defer io.Copy(w, &buf)

	p("<title>runsit; task %q</title>", t.Name)
	p("
[runsit status]

%v
\n", t.Name)
	p("
status: %v
", html.EscapeString(t.Status()))

	in, ok := t.RunningInstance()
	if ok {
		if pid := in.Pid(); pid != 0 {
			p("
running instance: pid=%d ", pid)
			p("[kill] ", taskName, pid)
			p("
")
		}
		out := &in.output
		out.mu.Lock()
		defer out.mu.Unlock()
		for e := out.lines.Front(); e != nil; e = e.Next() {
			ol := e.Value.(*outputLine)
			p("
%v: %s: %s
\n", ol.t, ol.name, html.EscapeString(ol.data))
		}
	}

	p("\n")
}

func writerf(w io.Writer) func(string, ...interface{}) {
	return func(format string, args ...interface{}) {
		fmt.Fprintf(w, format, args...)
	}
}

func runWebServer(ln net.Listener) {
	mux := http.NewServeMux()
	// TODO: wrap mux in auth handler, making it available only to
	// TCP connections from localhost and owned by the uid/gid of
	// the running process.
	mux.HandleFunc("/", taskList)
	mux.HandleFunc("/task/", taskView)
	s := &http.Server{
		Handler: mux,
	}
	err := s.Serve(ln)
	if err != nil {
		logger.Fatalf("webserver exiting: %v", err)
	}
}
<commit_msg>prettier output / css / js<commit_after>/*
Copyright 2011 Google Inc.

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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 main

import (
	"bytes"
	"fmt"
	"html"
	"io"
	"net"
	"net/http"
	"strconv"
)

func taskList(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	p := writerf(w)
	p("<title>runsit</title>")
	p("
runsit Admin UI

running tasks

\n")
	for _, t := range GetTasks() {
		p("
%s: %s
\n", t.Name, t.Name,
			html.EscapeString(t.Status()))
	}
	p("
\n")
	p("
runsit log

%s
\n", html.EscapeString(logBuf.String()))
	p("\n")
}

func killTask(w http.ResponseWriter, r *http.Request, t *Task) {
	w.Header().Set("Content-Type", "text/html")
	in, ok := t.RunningInstance()
	if !ok {
		http.Error(w, "task not running", 500)
		return
	}
	pid, _ := strconv.Atoi(r.FormValue("pid"))
	if in.Pid() != pid || pid == 0 {
		http.Error(w, "active task pid doesn't match pid parameter", 500)
		return
	}
	in.cmd.Process.Kill()
	p := writerf(w)
	p("killed pid %d.
back to %s status", pid, t.Name, t.Name)
}

func taskView(w http.ResponseWriter, r *http.Request) {
	path := r.URL.Path
	taskName := path[len("/task/"):]
	t, ok := GetTask(taskName)
	if !ok {
		http.NotFound(w, r)
		return
	}
	mode := r.FormValue("mode")
	switch mode {
	case "kill":
		killTask(w, r, t)
		return
	default:
		http.Error(w, "unknown mode", 400)
		return
	case "":
	}

	// Buffer to memory so we never block writing to a slow client
	// while holding the TaskOutput mutex.
	var buf bytes.Buffer
	p := writerf(&buf)
	defer io.Copy(w, &buf)

	p("<title>runsit; task %q</title>", t.Name)
	p("\n", css)
	p("\n", js)
	p("")
	p("
[runsit status]

%v
\n", t.Name)
	p("
status: %v
", html.EscapeString(t.Status()))

	in, ok := t.RunningInstance()
	if ok {
		if pid := in.Pid(); pid != 0 {
			p("
running instance: pid=%d ", pid)
			p("[kill] ", taskName, pid)
			p("
")
		}
		out := &in.output
		out.mu.Lock()
		defer out.mu.Unlock()
		p("
")
		for e := out.lines.Front(); e != nil; e = e.Next() {
			ol := e.Value.(*outputLine)
			p("
%s
\n", ol.name, ol.t, html.EscapeString(ol.data))
		}
		p("
\n")
	}

	p("\n")
}

func writerf(w io.Writer) func(string, ...interface{}) {
	return func(format string, args ...interface{}) {
		fmt.Fprintf(w, format, args...)
	}
}

func runWebServer(ln net.Listener) {
	mux := http.NewServeMux()
	// TODO: wrap mux in auth handler, making it available only to
	// TCP connections from localhost and owned by the uid/gid of
	// the running process.
	mux.HandleFunc("/", taskList)
	mux.HandleFunc("/task/", taskView)
	s := &http.Server{
		Handler: mux,
	}
	err := s.Serve(ln)
	if err != nil {
		logger.Fatalf("webserver exiting: %v", err)
	}
}

var css = `
#output {
   font-family: monospace;
   font-size: 10pt;
   border: 2px solid gray;
   padding: 0.5em;
   overflow: scroll;
   max-height: 25em;
}

#output div.stderr {
   color: #c00;
}

`

var js = `
window.addEventListener("load", function() {
   var d = document.getElementById("output");
   if (d) {
     d.scrollTop = d.scrollHeight;
   }
});

`<|endoftext|>


<commit_before>package middleware

import (
	"github.com/gin-gonic/gin"
	"strings"

	"github.com/eirka/eirka-libs/redis"
)

var (
	RedisKeyIndex = make(map[string]RedisKey)
	RedisKeys     = []RedisKey{
		{base: "index", fieldcount: 1, hash: true, expire: false},
		{base: "thread", fieldcount: 2, hash: true, expire: false},
		{base: "tag", fieldcount: 2, hash: true, expire: true},
		{base: "image", fieldcount: 1, hash: true, expire: false},
		{base: "post", fieldcount: 2, hash: true, expire: false},
		{base: "tags", fieldcount: 1, hash: true, expire: false},
		{base: "directory", fieldcount: 1, hash: true, expire: false},
		{base: "new", fieldcount: 1, hash: false, expire: true},
		{base: "popular", fieldcount: 1, hash: false, expire: true},
		{base: "favorited", fieldcount: 1, hash: false, expire: true},
		{base: "tagtypes", fieldcount: 0, hash: false, expire: false},
		{base: "imageboards", fieldcount: 0, hash: false, expire: true},
	}
)

func init() {
	// key index map
	for _, key := range RedisKeys {
		RedisKeyIndex[key.base] = key
	}
}

// Cache will check for the key in Redis and serve it. If not found, it will
// take the marshalled JSON from the controller and set it in Redis
func Cache() gin.HandlerFunc {
	return func(c *gin.Context) {

		// bool for analytics middleware
		c.Set("cached", false)

		// break cache if there is a query
		if c.Request.URL.RawQuery != "" {
			c.Next()
			return
		}

		// Trim leading / from path and split
		params := strings.Split(strings.Trim(c.Request.URL.Path, "/"), "/")

		// get the keyname
		key, ok := RedisKeyIndex[params[0]]
		if !ok {
			c.Next()
			return
		}

		// set the key minus the base
		key.SetKey(params[1:]...)

		// check the cache
		result, err := key.Get()
		if result == nil {
			// go to the controller if it wasnt found
			c.Next()

			// Check if there was an error from the controller
			_, controllerError := c.Get("controllerError")
			if controllerError {
				c.Abort()
				return
			}

			// set the data returned from the controller
			err = key.Set(c.MustGet("data").([]byte))
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

		}
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// if we made it this far then the page was cached
		c.Set("cached", true)

		c.Writer.Header().Set("Content-Type", "application/json")
		c.Writer.Write(result)
		c.Abort()
		return
	}

}

type RedisKey struct {
	base       string
	fieldcount int
	hash       bool
	expire     bool
	key        string
	hashid     string
}

func (r *RedisKey) SetKey(ids ...string) {

	if r.fieldcount == 0 {
		r.key = r.base
		return
	}

	// create our key
	r.key = strings.Join([]string{r.base, strings.Join(ids[:r.fieldcount], ":")}, ":")

	// get our hash id
	if r.hash {
		r.hashid = strings.Join(ids[r.fieldcount:], "")
	}

	return
}

func (r *RedisKey) Get() (result []byte, err error) {

	if r.hash {
		return redis.RedisCache.HGet(r.key, r.hashid)
	} else {
		return redis.RedisCache.Get(r.key)
	}

	return
}

func (r *RedisKey) Set(data []byte) (err error) {

	if r.hash {
		err = redis.RedisCache.HMSet(r.key, r.hashid, data)
	} else {
		err = redis.RedisCache.Set(r.key, data)
	}
	if err != nil {
		return
	}

	if r.expire {
		return redis.RedisCache.Expire(r.key, 600)
	}

	return
}
<commit_msg>fix up redis lib<commit_after>package middleware

import (
	"github.com/gin-gonic/gin"
	"strings"

	"github.com/eirka/eirka-libs/redis"
)

// Cache will check for the key in Redis and serve it. If not found, it will
// take the marshalled JSON from the controller and set it in Redis
func Cache() gin.HandlerFunc {
	return func(c *gin.Context) {

		// bool for analytics middleware
		c.Set("cached", false)

		// break cache if there is a query
		if c.Request.URL.RawQuery != "" {
			c.Next()
			return
		}

		// Trim leading / from path and split
		params := strings.Split(strings.Trim(c.Request.URL.Path, "/"), "/")

		// get the keyname
		key, ok := redis.RedisKeyIndex[params[0]]
		if !ok {
			c.Next()
			return
		}

		// set the key minus the base
		key.SetKey(params[1:]...)

		// check the cache
		result, err := key.Get()
		if result == nil {
			// go to the controller if it wasnt found
			c.Next()

			// Check if there was an error from the controller
			_, controllerError := c.Get("controllerError")
			if controllerError {
				c.Abort()
				return
			}

			// set the data returned from the controller
			err = key.Set(c.MustGet("data").([]byte))
			if err != nil {
				c.Error(err)
				c.Abort()
				return
			}

		}
		if err != nil {
			c.Error(err)
			c.Abort()
			return
		}

		// if we made it this far then the page was cached
		c.Set("cached", true)

		c.Writer.Header().Set("Content-Type", "application/json")
		c.Writer.Write(result)
		c.Abort()
		return
	}

}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package stacks

import "errors"

// ErrType indicates that a value is no of the expected type.
var ErrType = errors.New("stacks: unexpected type")

// Stack interface define a basic stack operations.
type Stack interface {

	// Push adds e on top of the stack. An error is returned if e was not added.
	Push(e interface{}) error

	// Remove and return last added element from this stack.
	Pop() interface{}

	// Length of the stack.
	Len() int
}

// IntStack is an implementation of the Stack interface for integer values.
type IntStack []int

// Push adds e on top of the stack. An error is returned if e is not of type int.
// The time complexity is O(1)
func (s *IntStack) Push(e interface{}) error {
	v, ok := e.(int)
	if !ok {
		return ErrType
	}
	*s = append(*s, v)
	return nil
}

// Pop removes and returns the last added integer element from this stack.
// The time complexity is O(1)
func (s *IntStack) Pop() (e interface{}) {
	if s.Len() == 0 {
		return nil
	}
	e, *s = (*s)[len(*s)-1], (*s)[:len(*s)-1]
	return e
}

// Len returns the length of this stack.
func (s *IntStack) Len() int {
	return len(*s)
}
<commit_msg>Remove unnecessary blank line<commit_after>// Copyright (c) 2015, Peter Mrekaj. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE.txt file.

package stacks

import "errors"

// ErrType indicates that a value is no of the expected type.
var ErrType = errors.New("stacks: unexpected type")

// Stack interface define a basic stack operations.
type Stack interface {
	// Push adds e on top of the stack. An error is returned if e was not added.
	Push(e interface{}) error

	// Remove and return last added element from this stack.
	Pop() interface{}

	// Length of the stack.
	Len() int
}

// IntStack is an implementation of the Stack interface for integer values.
type IntStack []int

// Push adds e on top of the stack. An error is returned if e is not of type int.
// The time complexity is O(1)
func (s *IntStack) Push(e interface{}) error {
	v, ok := e.(int)
	if !ok {
		return ErrType
	}
	*s = append(*s, v)
	return nil
}

// Pop removes and returns the last added integer element from this stack.
// The time complexity is O(1)
func (s *IntStack) Pop() (e interface{}) {
	if s.Len() == 0 {
		return nil
	}
	e, *s = (*s)[len(*s)-1], (*s)[:len(*s)-1]
	return e
}

// Len returns the length of this stack.
func (s *IntStack) Len() int {
	return len(*s)
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 oem

import (
	"fmt"

	"github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/internal/providers"
	"github.com/coreos/ignition/internal/providers/azure"
	"github.com/coreos/ignition/internal/providers/digitalocean"
	"github.com/coreos/ignition/internal/providers/ec2"
	"github.com/coreos/ignition/internal/providers/file"
	"github.com/coreos/ignition/internal/providers/gce"
	"github.com/coreos/ignition/internal/providers/noop"
	"github.com/coreos/ignition/internal/providers/openstack"
	"github.com/coreos/ignition/internal/providers/packet"
	"github.com/coreos/ignition/internal/providers/qemu"
	"github.com/coreos/ignition/internal/providers/vmware"
	"github.com/coreos/ignition/internal/registry"

	"github.com/vincent-petithory/dataurl"
)

// Config represents a set of options that map to a particular OEM.
type Config struct {
	name              string
	fetch             providers.FuncFetchConfig
	baseConfig        types.Config
	defaultUserConfig types.Config
}

func (c Config) Name() string {
	return c.name
}

func (c Config) FetchFunc() providers.FuncFetchConfig {
	return c.fetch
}

func (c Config) BaseConfig() types.Config {
	return c.baseConfig
}

func (c Config) DefaultUserConfig() types.Config {
	return c.defaultUserConfig
}

var configs = registry.Create("oem configs")

func init() {
	configs.Register(Config{
		name:  "azure",
		fetch: azure.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudsigma",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudstack",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "digitalocean",
		fetch: digitalocean.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
		defaultUserConfig: types.Config{Systemd: types.Systemd{Units: []types.SystemdUnit{userCloudInit("DigitalOcean", "digitalocean")}}},
	})
	configs.Register(Config{
		name:  "brightbox",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "openstack",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "ec2",
		fetch: ec2.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
	})
	configs.Register(Config{
		name:  "exoscale",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "gce",
		fetch: gce.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{
					{Enable: true, Name: "coreos-metadata-sshkeys@.service"},
					{Enable: true, Name: "oem-gce.service"},
				},
			},
			Storage: types.Storage{
				Files: []types.File{
					serviceFromOem("oem-gce.service"),
					{
						Node: types.Node{
							Filesystem: "root",
							Path:       "/etc/hosts",
							Mode:       0444,
						},
						Contents: contentsFromString("169.254.169.254 metadata\n127.0.0.1 localhost\n"),
					},
					{
						Node: types.Node{
							Filesystem: "root",
							Path:       "/etc/profile.d/google-cloud-sdk.sh",
							Mode:       0444,
						},
						Contents: contentsFromString(`#!/bin/sh
alias gcloud="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config -v /var/run/docker.sock:/var/run/doker.sock google/cloud-sdk gcloud"
alias gcutil="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config google/cloud-sdk gcutil"
alias gsutil="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config google/cloud-sdk gsutil"
`),
					},
				},
			},
		},
		defaultUserConfig: types.Config{Systemd: types.Systemd{Units: []types.SystemdUnit{userCloudInit("GCE", "gce")}}},
	})
	configs.Register(Config{
		name:  "hyperv",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "niftycloud",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "packet",
		fetch: packet.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
	})
	configs.Register(Config{
		name:  "pxe",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace-onmetal",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vagrant",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vmware",
		fetch: vmware.FetchConfig,
	})
	configs.Register(Config{
		name:  "xendom0",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "interoute",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "qemu",
		fetch: qemu.FetchConfig,
	})
	configs.Register(Config{
		name:  "file",
		fetch: file.FetchConfig,
	})
}

func Get(name string) (config Config, ok bool) {
	config, ok = configs.Get(name).(Config)
	return
}

func MustGet(name string) Config {
	if config, ok := Get(name); ok {
		return config
	} else {
		panic(fmt.Sprintf("invalid OEM name %q provided", name))
	}
}

func Names() (names []string) {
	return configs.Names()
}

func contentsFromString(data string) types.FileContents {
	return types.FileContents{
		Source: types.Url{
			Scheme: "data",
			Opaque: "," + dataurl.EscapeString(data),
		},
	}
}

func contentsFromOem(path string) types.FileContents {
	return types.FileContents{
		Source: types.Url{
			Scheme: "oem",
			Path:   path,
		},
	}
}

func userCloudInit(name string, oem string) types.SystemdUnit {
	contents := `[Unit]
Description=Cloudinit from %s metadata

[Service]
Type=oneshot
ExecStart=/usr/bin/coreos-cloudinit --oem=%s

[Install]
WantedBy=multi-user.target
`

	return types.SystemdUnit{
		Name:     "oem-cloudinit.service",
		Enable:   true,
		Contents: fmt.Sprintf(contents, name, oem),
	}
}

func serviceFromOem(unit string) types.File {
	return types.File{
		Node: types.Node{
			Filesystem: "root",
			Path:       types.Path("/etc/systemd/system/" + unit),
			Mode:       0444,
		},
		Contents: contentsFromOem("/units/" + unit),
	}
}
<commit_msg>oem: fix gce gcloud alias<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 oem

import (
	"fmt"

	"github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/internal/providers"
	"github.com/coreos/ignition/internal/providers/azure"
	"github.com/coreos/ignition/internal/providers/digitalocean"
	"github.com/coreos/ignition/internal/providers/ec2"
	"github.com/coreos/ignition/internal/providers/file"
	"github.com/coreos/ignition/internal/providers/gce"
	"github.com/coreos/ignition/internal/providers/noop"
	"github.com/coreos/ignition/internal/providers/openstack"
	"github.com/coreos/ignition/internal/providers/packet"
	"github.com/coreos/ignition/internal/providers/qemu"
	"github.com/coreos/ignition/internal/providers/vmware"
	"github.com/coreos/ignition/internal/registry"

	"github.com/vincent-petithory/dataurl"
)

// Config represents a set of options that map to a particular OEM.
type Config struct {
	name              string
	fetch             providers.FuncFetchConfig
	baseConfig        types.Config
	defaultUserConfig types.Config
}

func (c Config) Name() string {
	return c.name
}

func (c Config) FetchFunc() providers.FuncFetchConfig {
	return c.fetch
}

func (c Config) BaseConfig() types.Config {
	return c.baseConfig
}

func (c Config) DefaultUserConfig() types.Config {
	return c.defaultUserConfig
}

var configs = registry.Create("oem configs")

func init() {
	configs.Register(Config{
		name:  "azure",
		fetch: azure.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudsigma",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "cloudstack",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "digitalocean",
		fetch: digitalocean.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
		defaultUserConfig: types.Config{Systemd: types.Systemd{Units: []types.SystemdUnit{userCloudInit("DigitalOcean", "digitalocean")}}},
	})
	configs.Register(Config{
		name:  "brightbox",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "openstack",
		fetch: openstack.FetchConfig,
	})
	configs.Register(Config{
		name:  "ec2",
		fetch: ec2.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
	})
	configs.Register(Config{
		name:  "exoscale",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "gce",
		fetch: gce.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{
					{Enable: true, Name: "coreos-metadata-sshkeys@.service"},
					{Enable: true, Name: "oem-gce.service"},
				},
			},
			Storage: types.Storage{
				Files: []types.File{
					serviceFromOem("oem-gce.service"),
					{
						Node: types.Node{
							Filesystem: "root",
							Path:       "/etc/hosts",
							Mode:       0444,
						},
						Contents: contentsFromString("169.254.169.254 metadata\n127.0.0.1 localhost\n"),
					},
					{
						Node: types.Node{
							Filesystem: "root",
							Path:       "/etc/profile.d/google-cloud-sdk.sh",
							Mode:       0444,
						},
						Contents: contentsFromString(`#!/bin/sh
alias gcloud="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config -v /var/run/docker.sock:/var/run/doker.sock -v /usr/bin/docker:/usr/bin/docker google/cloud-sdk gcloud"
alias gcutil="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config google/cloud-sdk gcutil"
alias gsutil="(docker images google/cloud-sdk || docker pull google/cloud-sdk) > /dev/null;docker run -t -i --net="host" -v $HOME/.config:/.config google/cloud-sdk gsutil"
`),
					},
				},
			},
		},
		defaultUserConfig: types.Config{Systemd: types.Systemd{Units: []types.SystemdUnit{userCloudInit("GCE", "gce")}}},
	})
	configs.Register(Config{
		name:  "hyperv",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "niftycloud",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "packet",
		fetch: packet.FetchConfig,
		baseConfig: types.Config{
			Systemd: types.Systemd{
				Units: []types.SystemdUnit{{Enable: true, Name: "coreos-metadata-sshkeys@.service"}},
			},
		},
	})
	configs.Register(Config{
		name:  "pxe",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "rackspace-onmetal",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vagrant",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "vmware",
		fetch: vmware.FetchConfig,
	})
	configs.Register(Config{
		name:  "xendom0",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "interoute",
		fetch: noop.FetchConfig,
	})
	configs.Register(Config{
		name:  "qemu",
		fetch: qemu.FetchConfig,
	})
	configs.Register(Config{
		name:  "file",
		fetch: file.FetchConfig,
	})
}

func Get(name string) (config Config, ok bool) {
	config, ok = configs.Get(name).(Config)
	return
}

func MustGet(name string) Config {
	if config, ok := Get(name); ok {
		return config
	} else {
		panic(fmt.Sprintf("invalid OEM name %q provided", name))
	}
}

func Names() (names []string) {
	return configs.Names()
}

func contentsFromString(data string) types.FileContents {
	return types.FileContents{
		Source: types.Url{
			Scheme: "data",
			Opaque: "," + dataurl.EscapeString(data),
		},
	}
}

func contentsFromOem(path string) types.FileContents {
	return types.FileContents{
		Source: types.Url{
			Scheme: "oem",
			Path:   path,
		},
	}
}

func userCloudInit(name string, oem string) types.SystemdUnit {
	contents := `[Unit]
Description=Cloudinit from %s metadata

[Service]
Type=oneshot
ExecStart=/usr/bin/coreos-cloudinit --oem=%s

[Install]
WantedBy=multi-user.target
`

	return types.SystemdUnit{
		Name:     "oem-cloudinit.service",
		Enable:   true,
		Contents: fmt.Sprintf(contents, name, oem),
	}
}

func serviceFromOem(unit string) types.File {
	return types.File{
		Node: types.Node{
			Filesystem: "root",
			Path:       types.Path("/etc/systemd/system/" + unit),
			Mode:       0444,
		},
		Contents: contentsFromOem("/units/" + unit),
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	if tidb.IsQuery(txnLine) {
		start := time.Now()
		rows, err := tx.Query(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: last insert id
		start := time.Now()
		res, err := tx.Exec(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0:
			fmt.Printf("Query OK, 0 row affected")
		case 1:
			fmt.Printf("Query OK, 1 row affected")
		default:
			fmt.Printf("Query OK, %v rows affected", cnt)
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
	}
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<commit_msg>interpreter: Tiny clean up<commit_after>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"database/sql"
	"flag"
	"fmt"
	"io"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/peterh/liner"
	"github.com/pingcap/tidb"
	"github.com/pingcap/tidb/util/errors2"
	"github.com/pingcap/tidb/util/printer"
)

var (
	logLevel = flag.String("L", "error", "log level")
	store    = flag.String("store", "goleveldb", "the name for the registered storage, e.g. memory, goleveldb, boltdb")
	dbPath   = flag.String("dbpath", "test/test", "db path")

	line        *liner.State
	historyPath = "/tmp/tidb_interpreter"
)

func openHistory() {
	if f, err := os.Open(historyPath); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
}

func saveHistory() {
	if f, err := os.Create(historyPath); err == nil {
		line.WriteHistory(f)
		f.Close()
	}
}

func executeLine(tx *sql.Tx, txnLine string) error {
	start := time.Now()
	if tidb.IsQuery(txnLine) {
		rows, err := tx.Query(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		defer rows.Close()
		cols, err := rows.Columns()
		if err != nil {
			return errors.Trace(err)
		}

		values := make([][]byte, len(cols))
		scanArgs := make([]interface{}, len(values))
		for i := range values {
			scanArgs[i] = &values[i]
		}

		var datas [][]string
		for rows.Next() {
			err := rows.Scan(scanArgs...)
			if err != nil {
				return errors.Trace(err)
			}

			data := make([]string, len(cols))
			for i, value := range values {
				if value == nil {
					data[i] = "NULL"
				} else {
					data[i] = string(value)
				}
			}

			datas = append(datas, data)
		}

		// For `cols` and `datas[i]` always has the same length,
		// no need to check return validity.
		result, _ := printer.GetPrintResult(cols, datas)
		fmt.Printf("%s", result)

		switch len(datas) {
		case 0:
			fmt.Printf("Empty set")
		case 1:
			fmt.Printf("1 row in set")
		default:
			fmt.Printf("%v rows in set", len(datas))
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
		if err := rows.Err(); err != nil {
			return errors.Trace(err)
		}
	} else {
		// TODO: last insert id
		res, err := tx.Exec(txnLine)
		elapsed := time.Since(start).Seconds()
		if err != nil {
			return errors.Trace(err)
		}
		cnt, err := res.RowsAffected()
		if err != nil {
			return errors.Trace(err)
		}
		switch cnt {
		case 0:
			fmt.Printf("Query OK, 0 row affected")
		case 1:
			fmt.Printf("Query OK, 1 row affected")
		default:
			fmt.Printf("Query OK, %v rows affected", cnt)
		}
		fmt.Printf(" (%.2f sec)\n", elapsed)
	}
	return nil
}

func mayExit(err error, l string) bool {
	if errors2.ErrorEqual(err, liner.ErrPromptAborted) || errors2.ErrorEqual(err, io.EOF) {
		fmt.Println("\nBye")
		saveHistory()
		return true
	}
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}
	return false
}

func readStatement(prompt string) (string, error) {
	var ret string
	for {
		l, err := line.Prompt(prompt)
		if err != nil {
			return "", err
		}
		if strings.HasSuffix(l, ";") == false {
			ret += l + "\n"
			prompt = "   -> "
			continue
		}
		return ret + l, nil
	}
}

func main() {
	printer.PrintTiDBInfo()

	flag.Parse()
	log.SetLevelByString(*logLevel)
	// support for signal notify
	runtime.GOMAXPROCS(runtime.NumCPU())

	line = liner.NewLiner()
	defer line.Close()

	line.SetCtrlCAborts(true)
	openHistory()

	mdb, err := sql.Open(tidb.DriverName, *store+"://"+*dbPath)
	if err != nil {
		log.Fatal(errors.ErrorStack(err))
	}

	for {
		l, err := readStatement("tidb> ")
		if mayExit(err, l) {
			return
		}
		line.AppendHistory(l)

		// if we're in transaction
		if strings.HasPrefix(l, "BEGIN") || strings.HasPrefix(l, "begin") {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			for {
				txnLine, err := readStatement(">> ")
				if mayExit(err, txnLine) {
					return
				}
				line.AppendHistory(txnLine)

				if !strings.HasSuffix(txnLine, ";") {
					txnLine += ";"
				}

				if strings.HasPrefix(txnLine, "COMMIT") || strings.HasPrefix(txnLine, "commit") {
					err := tx.Commit()
					if err != nil {
						log.Error(errors.ErrorStack(err))
						tx.Rollback()
					}
					break
				}
				// normal sql statement
				err = executeLine(tx, txnLine)
				if err != nil {
					log.Error(errors.ErrorStack(err))
					tx.Rollback()
					break
				}
			}
		} else {
			tx, err := mdb.Begin()
			if err != nil {
				log.Error(errors.ErrorStack(err))
				continue
			}
			err = executeLine(tx, l)
			if err != nil {
				log.Error(errors.ErrorStack(err))
				tx.Rollback()
			} else {
				tx.Commit()
			}
		}
	}
}
<|endoftext|>


<commit_before>package models

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	"github.com/go-openapi/spec"

	"github.com/Clever/wag/swagger"
	"github.com/Clever/wag/templates"
	"github.com/Clever/wag/utils"

	"github.com/go-swagger/go-swagger/generator"
)

// Generate writes the files to the client directories
func Generate(packageName string, s spec.Swagger) error {

	tmpFile, err := swagger.WriteToFile(&s)
	if err != nil {
		return err
	}
	defer os.Remove(tmpFile)

	// generate models with go-swagger
	if err := generator.GenerateServer("", []string{}, []string{}, &generator.GenOpts{
		Spec:           tmpFile,
		ModelPackage:   "models",
		Target:         fmt.Sprintf("%s/src/%s/", os.Getenv("GOPATH"), packageName),
		IncludeModel:   true,
		IncludeHandler: false,
		IncludeSupport: false,
	}); err != nil {
		return fmt.Errorf("error generating go-swagger models: %s", err)
	}

	if err := generateOutputs(packageName, s); err != nil {
		return fmt.Errorf("error generating outputs: %s", err)
	}
	if err := generateInputs(packageName, s.Paths); err != nil {
		return fmt.Errorf("error generating inputs: %s", err)
	}
	return nil
}

func generateInputs(packageName string, paths *spec.Paths) error {

	g := swagger.Generator{PackageName: packageName}

	g.Printf(`
package models

import(
		"encoding/json"
		"strconv"

		"github.com/go-openapi/validate"
		"github.com/go-openapi/strfmt"
)

// These imports may not be used depending on the input parameters
var _ = json.Marshal
var _ = strconv.FormatInt
var _ = validate.Maximum
var _ = strfmt.NewFormats
`)

	for _, pathKey := range swagger.SortedPathItemKeys(paths.Paths) {
		path := paths.Paths[pathKey]
		pathItemOps := swagger.PathItemOperations(path)
		for _, opKey := range swagger.SortedOperationsKeys(pathItemOps) {
			op := pathItemOps[opKey]
			// Do not generate an input struct + validation for an
			// operation that has a single, schema'd input.
			// The input to these will be the model generated for
			// the schema.
			if singleSchemaedBodyParameter, _ := swagger.SingleSchemaedBodyParameter(op); singleSchemaedBodyParameter {
				continue
			}
			if err := printInputStruct(&g, op); err != nil {
				return err
			}
			if err := printInputValidation(&g, op); err != nil {
				return err
			}
		}
	}

	return g.WriteFile("models/inputs.go")
}

func printInputStruct(g *swagger.Generator, op *spec.Operation) error {
	capOpID := swagger.Capitalize(op.ID)
	g.Printf("// %sInput holds the input parameters for a %s operation.\n", capOpID, op.ID)
	g.Printf("type %sInput struct {\n", capOpID)

	for _, param := range op.Parameters {
		if param.In == "formData" {
			return fmt.Errorf("input parameters with 'In' formData are not supported")
		}

		var typeName string
		var err error
		if param.In != "body" {
			typeName, err = swagger.ParamToType(param, true)
			if err != nil {
				return err
			}
		} else {
			typeName, err = swagger.TypeFromSchema(param.Schema, false)
			if err != nil {
				return err
			}
			// All schema types are pointers
			typeName = "*" + typeName
		}

		g.Printf("\t%s %s\n", swagger.StructParamName(param), typeName)
	}
	g.Printf("}\n\n")

	return nil
}

func printInputValidation(g *swagger.Generator, op *spec.Operation) error {
	singleStringPathParameter, paramName := swagger.SingleStringPathParameter(op)
	if singleStringPathParameter {
		capOpID := swagger.Capitalize(op.ID)
		g.Printf("// Validate%sInput returns an error if the input parameter doesn't\n",
			capOpID)
		g.Printf("// satisfy the requirements in the swagger yml file.\n")
		g.Printf("func Validate%sInput(%s string) error{\n", capOpID, paramName)
	} else {
		capOpID := swagger.Capitalize(op.ID)
		g.Printf("// Validate returns an error if any of the %sInput parameters don't satisfy the\n",
			capOpID)
		g.Printf("// requirements from the swagger yml file.\n")
		g.Printf("func (i %sInput) Validate() error{\n", capOpID)
	}

	for _, param := range op.Parameters {
		if param.In == "body" {
			g.Printf("\tif err := i.%s.Validate(nil); err != nil {\n", swagger.StructParamName(param))
			g.Printf("\t\treturn err\n")
			g.Printf("\t}\n\n")
		}

		validations, err := swagger.ParamToValidationCode(param)
		if err != nil {
			return err
		}
		for _, validation := range validations {
			if param.Required {
				if singleStringPathParameter {
					// replace i.<Param> with <param>
					validation = strings.Replace(validation,
						fmt.Sprintf("i.%s", utils.CamelCase(param.Name, true)),
						paramName, -1)
				}
				g.Printf(errCheck(validation))
			} else {
				g.Printf("\tif i.%s != nil {\n", swagger.StructParamName(param))
				g.Printf(errCheck(validation))
				g.Printf("\t}\n")
			}
		}
	}
	g.Printf("\treturn nil\n")
	g.Printf("}\n\n")

	return nil
}

// errCheck returns an if err := ifCondition; err != nil { return err } function
func errCheck(ifCondition string) string {
	return fmt.Sprintf(
		`	if err := %s; err != nil {
		return err
	}
`, ifCondition)
}

func generateOutputs(packageName string, s spec.Swagger) error {
	g := swagger.Generator{PackageName: packageName}

	g.Printf("package models\n\n")

	for _, pathKey := range swagger.SortedPathItemKeys(s.Paths.Paths) {
		path := s.Paths.Paths[pathKey]
		pathItemOps := swagger.PathItemOperations(path)
		for _, opKey := range swagger.SortedOperationsKeys(pathItemOps) {
			op := pathItemOps[opKey]
			capOpID := swagger.Capitalize(op.ID)

			// We classify response keys into three types:
			// 1. 200-399 - these are "success" responses and implement the Output interface
			// 	defined above
			// 2. 400-599 - these are "failure" responses and implement the error interface
			// 3. Default - this is defined as a 500
			successTypes, err := generateSuccessTypes(capOpID, op.Responses.StatusCodeResponses)
			if err != nil {
				return err
			}
			g.Printf(successTypes)
		}
	}
	return g.WriteFile("models/outputs.go")
}

func generateSuccessTypes(capOpID string, responses map[int]spec.Response) (string, error) {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("// %sOutput defines the success output interface for %s.\n",
		capOpID, capOpID))
	buf.WriteString(fmt.Sprintf("type %sOutput interface {\n", capOpID))
	buf.WriteString(fmt.Sprintf("\t%sStatusCode() int\n", capOpID))
	buf.WriteString(fmt.Sprintf("}\n\n"))

	var successStatusCodes []int
	for _, statusCode := range swagger.SortedStatusCodeKeys(responses) {
		if statusCode >= 400 {
			continue
		}
		successStatusCodes = append(successStatusCodes, statusCode)
	}

	// We don't need to generate any success types if there is one or less success responses. In that
	// case we can just use the raw type
	if len(successStatusCodes) < 2 {
		return "", nil
	}

	for _, statusCode := range successStatusCodes {
		typeString, err := generateType(capOpID, statusCode, responses[statusCode])
		if err != nil {
			return "", err
		}
		buf.WriteString(typeString)
	}
	return buf.String(), nil
}

func generateType(capOpID string, statusCode int, response spec.Response) (string, error) {
	outputName := fmt.Sprintf("%s%dOutput", capOpID, statusCode)
	typeName, err := swagger.TypeFromSchema(response.Schema, false)
	if err != nil {
		return "", err
	}

	fields := typeTemplateFields{
		Output:     outputName,
		StatusCode: statusCode,
		OpName:     capOpID,
		Type:       typeName,
		ErrorType:  statusCode >= 400,
	}
	return templates.WriteTemplate(typeTemplate, fields)
}

type typeTemplateFields struct {
	Output     string
	StatusCode int
	OpName     string
	Type       string
	ErrorType  bool
}

var typeTemplate = `
	// {{.Output}} defines the {{.StatusCode}} status code response for {{.OpName}}.
	type {{.Output}} {{.Type}}

	// {{.OpName}}StatusCode returns the status code for the operation.
	func (o {{.Output}}) {{.OpName}}StatusCode() int {
		return {{.StatusCode}}
	}
`
<commit_msg>Generate error methods<commit_after>package models

import (
	"bytes"
	"fmt"
	"os"
	"sort"
	"strings"

	"github.com/go-openapi/spec"

	"github.com/Clever/go-utils/stringset"
	"github.com/Clever/wag/swagger"
	"github.com/Clever/wag/templates"
	"github.com/Clever/wag/utils"

	"github.com/go-swagger/go-swagger/generator"
)

// Generate writes the files to the client directories
func Generate(packageName string, s spec.Swagger) error {

	tmpFile, err := swagger.WriteToFile(&s)
	if err != nil {
		return err
	}
	defer os.Remove(tmpFile)

	// generate models with go-swagger
	if err := generator.GenerateServer("", []string{}, []string{}, &generator.GenOpts{
		Spec:           tmpFile,
		ModelPackage:   "models",
		Target:         fmt.Sprintf("%s/src/%s/", os.Getenv("GOPATH"), packageName),
		IncludeModel:   true,
		IncludeHandler: false,
		IncludeSupport: false,
	}); err != nil {
		return fmt.Errorf("error generating go-swagger models: %s", err)
	}

	if err := generateOutputs(packageName, s); err != nil {
		return fmt.Errorf("error generating outputs: %s", err)
	}
	if err := generateInputs(packageName, s.Paths); err != nil {
		return fmt.Errorf("error generating inputs: %s", err)
	}
	return nil
}

func generateInputs(packageName string, paths *spec.Paths) error {

	g := swagger.Generator{PackageName: packageName}

	g.Printf(`
package models

import(
		"encoding/json"
		"strconv"

		"github.com/go-openapi/validate"
		"github.com/go-openapi/strfmt"
)

// These imports may not be used depending on the input parameters
var _ = json.Marshal
var _ = strconv.FormatInt
var _ = validate.Maximum
var _ = strfmt.NewFormats
`)

	for _, pathKey := range swagger.SortedPathItemKeys(paths.Paths) {
		path := paths.Paths[pathKey]
		pathItemOps := swagger.PathItemOperations(path)
		for _, opKey := range swagger.SortedOperationsKeys(pathItemOps) {
			op := pathItemOps[opKey]
			// Do not generate an input struct + validation for an
			// operation that has a single, schema'd input.
			// The input to these will be the model generated for
			// the schema.
			if singleSchemaedBodyParameter, _ := swagger.SingleSchemaedBodyParameter(op); singleSchemaedBodyParameter {
				continue
			}
			if err := printInputStruct(&g, op); err != nil {
				return err
			}
			if err := printInputValidation(&g, op); err != nil {
				return err
			}
		}
	}

	return g.WriteFile("models/inputs.go")
}

func printInputStruct(g *swagger.Generator, op *spec.Operation) error {
	capOpID := swagger.Capitalize(op.ID)
	g.Printf("// %sInput holds the input parameters for a %s operation.\n", capOpID, op.ID)
	g.Printf("type %sInput struct {\n", capOpID)

	for _, param := range op.Parameters {
		if param.In == "formData" {
			return fmt.Errorf("input parameters with 'In' formData are not supported")
		}

		var typeName string
		var err error
		if param.In != "body" {
			typeName, err = swagger.ParamToType(param, true)
			if err != nil {
				return err
			}
		} else {
			typeName, err = swagger.TypeFromSchema(param.Schema, false)
			if err != nil {
				return err
			}
			// All schema types are pointers
			typeName = "*" + typeName
		}

		g.Printf("\t%s %s\n", swagger.StructParamName(param), typeName)
	}
	g.Printf("}\n\n")

	return nil
}

func printInputValidation(g *swagger.Generator, op *spec.Operation) error {
	singleStringPathParameter, paramName := swagger.SingleStringPathParameter(op)
	if singleStringPathParameter {
		capOpID := swagger.Capitalize(op.ID)
		g.Printf("// Validate%sInput returns an error if the input parameter doesn't\n",
			capOpID)
		g.Printf("// satisfy the requirements in the swagger yml file.\n")
		g.Printf("func Validate%sInput(%s string) error{\n", capOpID, paramName)
	} else {
		capOpID := swagger.Capitalize(op.ID)
		g.Printf("// Validate returns an error if any of the %sInput parameters don't satisfy the\n",
			capOpID)
		g.Printf("// requirements from the swagger yml file.\n")
		g.Printf("func (i %sInput) Validate() error{\n", capOpID)
	}

	for _, param := range op.Parameters {
		if param.In == "body" {
			g.Printf("\tif err := i.%s.Validate(nil); err != nil {\n", swagger.StructParamName(param))
			g.Printf("\t\treturn err\n")
			g.Printf("\t}\n\n")
		}

		validations, err := swagger.ParamToValidationCode(param)
		if err != nil {
			return err
		}
		for _, validation := range validations {
			if param.Required {
				if singleStringPathParameter {
					// replace i.<Param> with <param>
					validation = strings.Replace(validation,
						fmt.Sprintf("i.%s", utils.CamelCase(param.Name, true)),
						paramName, -1)
				}
				g.Printf(errCheck(validation))
			} else {
				g.Printf("\tif i.%s != nil {\n", swagger.StructParamName(param))
				g.Printf(errCheck(validation))
				g.Printf("\t}\n")
			}
		}
	}
	g.Printf("\treturn nil\n")
	g.Printf("}\n\n")

	return nil
}

// errCheck returns an if err := ifCondition; err != nil { return err } function
func errCheck(ifCondition string) string {
	return fmt.Sprintf(
		`	if err := %s; err != nil {
		return err
	}
`, ifCondition)
}

func generateOutputs(packageName string, s spec.Swagger) error {
	g := swagger.Generator{PackageName: packageName}

	g.Printf("package models\n\n")

	// It's a bit wonky that we're writing these into output.go instead of the file
	// defining each of the types, but I think that's okay for now. We can clean this
	// up if it becomes confusing.
	errorMethodCode, err := generateErrorMethods(&s)
	if err != nil {
		return err
	}
	g.Printf(errorMethodCode)

	for _, pathKey := range swagger.SortedPathItemKeys(s.Paths.Paths) {
		path := s.Paths.Paths[pathKey]
		pathItemOps := swagger.PathItemOperations(path)
		for _, opKey := range swagger.SortedOperationsKeys(pathItemOps) {
			op := pathItemOps[opKey]
			capOpID := swagger.Capitalize(op.ID)

			// We classify response keys into three types:
			// 1. 200-399 - these are "success" responses and implement the Output interface
			// 	defined above
			// 2. 400-599 - these are "failure" responses and implement the error interface
			// 3. Default - this is defined as a 500
			successTypes, err := generateSuccessTypes(capOpID, op.Responses.StatusCodeResponses)
			if err != nil {
				return err
			}
			g.Printf(successTypes)

		}
	}
	return g.WriteFile("models/outputs.go")
}

func generateSuccessTypes(capOpID string, responses map[int]spec.Response) (string, error) {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("// %sOutput defines the success output interface for %s.\n",
		capOpID, capOpID))
	buf.WriteString(fmt.Sprintf("type %sOutput interface {\n", capOpID))
	buf.WriteString(fmt.Sprintf("\t%sStatusCode() int\n", capOpID))
	buf.WriteString(fmt.Sprintf("}\n\n"))

	var successStatusCodes []int
	for _, statusCode := range swagger.SortedStatusCodeKeys(responses) {
		if statusCode >= 400 {
			continue
		}
		successStatusCodes = append(successStatusCodes, statusCode)
	}

	// We don't need to generate any success types if there is one or less success responses. In that
	// case we can just use the raw type
	if len(successStatusCodes) < 2 {
		return "", nil
	}

	for _, statusCode := range successStatusCodes {
		typeString, err := generateType(capOpID, statusCode, responses[statusCode])
		if err != nil {
			return "", err
		}
		buf.WriteString(typeString)
	}
	return buf.String(), nil
}

func generateType(capOpID string, statusCode int, response spec.Response) (string, error) {
	outputName := fmt.Sprintf("%s%dOutput", capOpID, statusCode)
	typeName, err := swagger.TypeFromSchema(response.Schema, false)
	if err != nil {
		return "", err
	}

	fields := typeTemplateFields{
		Output:     outputName,
		StatusCode: statusCode,
		OpName:     capOpID,
		Type:       typeName,
		ErrorType:  statusCode >= 400,
	}
	return templates.WriteTemplate(typeTemplate, fields)
}

type typeTemplateFields struct {
	Output     string
	StatusCode int
	OpName     string
	Type       string
	ErrorType  bool
}

var typeTemplate = `
	// {{.Output}} defines the {{.StatusCode}} status code response for {{.OpName}}.
	type {{.Output}} {{.Type}}

	// {{.OpName}}StatusCode returns the status code for the operation.
	func (o {{.Output}}) {{.OpName}}StatusCode() int {
		return {{.StatusCode}}
	}
`

// generateErrorMethods finds all responses all error responses and generates an error
// method for them.
func generateErrorMethods(s *spec.Swagger) (string, error) {
	errorTypes := stringset.New()

	for _, pathKey := range swagger.SortedPathItemKeys(s.Paths.Paths) {
		path := s.Paths.Paths[pathKey]
		pathItemOps := swagger.PathItemOperations(path)
		for _, opKey := range swagger.SortedOperationsKeys(pathItemOps) {
			op := pathItemOps[opKey]
			for _, statusCode := range swagger.SortedStatusCodeKeys(op.Responses.StatusCodeResponses) {

				if statusCode < 400 {
					continue
				}

				typeName, _ := swagger.OutputType(s, op, statusCode)
				if strings.HasPrefix(typeName, "models.") {
					typeName = typeName[7:]
				}
				errorTypes.Add(typeName)
			}
		}
	}

	sortedErrors := errorTypes.ToList()
	sort.Strings(sortedErrors)

	var buf bytes.Buffer
	for _, errorType := range sortedErrors {
		buf.WriteString(fmt.Sprintf(`
func (o %s) Error() string {
	return o.Msg
}

`, errorType))
	}

	return buf.String(), nil

}
<|endoftext|>


<commit_before>package models

import (
	"fmt"
	"strings"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/validate"
)

// TagSearchModel holds the parameters from the request and also the key for the cache
type TagSearchModel struct {
	Ib     uint
	Term   string
	Result TagSearchType
}

// TagSearchType is the top level of the JSON response
type TagSearchType struct {
	Body []Tags `json:"tagsearch"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *TagSearchModel) Get() (err error) {

	// Initialize response header
	response := TagSearchType{}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	tags := []Tags{}

	// Validate tag input
	if i.Term != "" {
		tag := validate.Validate{Input: i.Term, Max: config.Settings.Limits.TagMaxLength, Min: config.Settings.Limits.TagMinLength}
		if tag.MinLength() {
			return e.ErrInvalidParam
		} else if tag.MaxLength() {
			return e.ErrInvalidParam
		}
	}

	// split search term
	terms := strings.Split(strings.TrimSpace(i.Term), " ")

	var searchterm string

	// add wildcards to the terms
	for i, term := range terms {
		// if not the first index then add a space before
		if i > 0 {
			searchterm += " "
		}
		// add a plus to the front of the term
		if len(term) > 0 && term != "" {
			searchterm += fmt.Sprintf("+%s", term)
		}
	}

	// add a wildcard to the end of the term
	searchterm += "*"

	rows, err := dbase.Query(`SELECT count,tag_id,tag_name,tagtype_id
	FROM (SELECT count(image_id) as count,ib_id,tags.tag_id,tag_name,tagtype_id
	FROM tags
	LEFT JOIN tagmap on tags.tag_id = tagmap.tag_id
	WHERE ib_id = ? AND MATCH(tag_name) AGAINST (? IN BOOLEAN MODE)
	group by tag_id) as a`, i.Ib, searchterm)
	if err != nil {
		return
	}

	for rows.Next() {
		// Initialize posts struct
		tag := Tags{}
		// Scan rows and place column into struct
		err := rows.Scan(&tag.Total, &tag.Id, &tag.Tag, &tag.Type)
		if err != nil {
			return err
		}

		// Append rows to info struct
		tags = append(tags, tag)
	}
	err = rows.Err()
	if err != nil {
		return
	}

	// Add pagedresponse to the response struct
	response.Body = tags

	// This is the data we will serialize
	i.Result = response

	return

}
<commit_msg>improve search terms<commit_after>package models

import (
	"fmt"
	"strings"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
	"github.com/eirka/eirka-libs/validate"
)

// TagSearchModel holds the parameters from the request and also the key for the cache
type TagSearchModel struct {
	Ib     uint
	Term   string
	Result TagSearchType
}

// TagSearchType is the top level of the JSON response
type TagSearchType struct {
	Body []Tags `json:"tagsearch"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *TagSearchModel) Get() (err error) {

	// Initialize response header
	response := TagSearchType{}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	tags := []Tags{}

	// Validate tag input
	if i.Term != "" {
		tag := validate.Validate{Input: i.Term, Max: config.Settings.Limits.TagMaxLength, Min: config.Settings.Limits.TagMinLength}
		if tag.MinLength() {
			return e.ErrInvalidParam
		} else if tag.MaxLength() {
			return e.ErrInvalidParam
		}
	}

	// split search term
	terms := strings.Split(strings.TrimSpace(i.Term), " ")

	var searchterm string

	// add plusses to the terms
	for i, term := range terms {
		// if not the first index then add a space before
		if i > 0 {
			searchterm += " "
		}
		// add a plus to the front of the term
		if len(term) > 0 && term != "" {
			searchterm += fmt.Sprintf("+%s", term)
		}
	}

	// add a wildcard to the end of the term
	wildterm := fmt.Sprintf("%s*", searchterm)

	rows, err := dbase.Query(`SELECT count,tag_id,tag_name,tagtype_id
	FROM (SELECT count(image_id) as count,ib_id,tags.tag_id,tag_name,tagtype_id,
	MATCH(tag_name) AGAINST (? IN BOOLEAN MODE) as relevance
	FROM tags
	LEFT JOIN tagmap on tags.tag_id = tagmap.tag_id
	WHERE ib_id = ? AND MATCH(tag_name) AGAINST (? IN BOOLEAN MODE)
	group by tag_id ORDER BY relevance DESC) as a`, searchterm, i.Ib, wildterm)
	if err != nil {
		return
	}

	for rows.Next() {
		// Initialize posts struct
		tag := Tags{}
		// Scan rows and place column into struct
		err := rows.Scan(&tag.Total, &tag.Id, &tag.Tag, &tag.Type)
		if err != nil {
			return err
		}

		// Append rows to info struct
		tags = append(tags, tag)
	}
	err = rows.Err()
	if err != nil {
		return
	}

	// Add pagedresponse to the response struct
	response.Body = tags

	// This is the data we will serialize
	i.Result = response

	return

}
<|endoftext|>


<commit_before>package models

import (
	"reflect"
	"testing"

	"github.com/alice02/go-todoapi/database"
)

func TestNewTaskModel(t *testing.T) {
	u := NewTaskModel(nil)
	expected := "*models.taskModel"
	actual := reflect.TypeOf(u).String()
	if actual != expected {
		t.Errorf("got %v want %v", actual, expected)
	}
}

func TestSaveAndFind(t *testing.T) {
	expected := []Task{
		{
			Description: "test1",
			Completed:   false,
		},
		{
			Description: "test2",
			Completed:   true,
		},
		{
			Description: "",
			Completed:   false,
		},
	}

	db, err := database.NewDB()
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Task{})
	u := NewTaskModel(db)

	for _, task := range expected {
		err = u.Save(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
	}
	actual, err := u.FindAll()

	if len(actual) != len(expected) {
		t.Errorf("got length %v want %v", len(actual), (expected))
	}
	for i := range actual {
		if actual[i].Description != expected[i].Description {
			t.Errorf("got %v want %v", actual[i].Description, expected[i].Description)
		}
		if actual[i].Completed != expected[i].Completed {
			t.Errorf("got %v want %v", actual[i].Completed, expected[i].Completed)
		}
	}

	db.DropTableIfExists(&Task{})
}

func TestUpdate(t *testing.T) {
	testData := []Task{
		{
			Description: "test1",
			Completed:   false,
		},
		{
			Description: "test2",
			Completed:   true,
		},
		{
			Description: "",
			Completed:   false,
		},
	}

	db, err := database.NewDB()
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Task{})
	u := NewTaskModel(db)

	for _, task := range testData {
		err = u.Save(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
		task.Description = "updated"
		err = u.Update(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
		if task.Description != "updated" {
			t.Errorf("got %v want %v", "updated", task.Description)
		}
	}
	db.DropTableIfExists(&Task{})
}
<commit_msg>Add test of validation<commit_after>package models

import (
	"reflect"
	"testing"

	"github.com/alice02/go-todoapi/database"
)

func TestNewTaskModel(t *testing.T) {
	u := NewTaskModel(nil)
	expected := "*models.taskModel"
	actual := reflect.TypeOf(u).String()
	if actual != expected {
		t.Errorf("got %v want %v", actual, expected)
	}
}

func TestValidate(t *testing.T) {
	task := Task{
		Description: "test",
		Completed:   false,
	}
	err := task.Validate()
	if err != nil {
		t.Errorf("got %v want nil", err)
	}
}

func TestValidateWithInvalidDescription(t *testing.T) {
	emptyDescription := Task{
		Description: "",
		Completed:   false,
	}
	actual := emptyDescription.Validate()
	if actual == nil {
		t.Errorf("got nil want validate error")
	}
	expected := "description: cannot be blank."
	if actual.Error() != expected {
		t.Errorf("got %v want %v", actual, expected)
	}

	overLengthDescription := Task{
		Description: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		Completed:   false,
	}
	actual = overLengthDescription.Validate()
	if actual == nil {
		t.Errorf("got nil want validate error")
	}
	expected = "description: the length must be between 1 and 140."
	if actual.Error() != expected {
		t.Errorf("got %v want %v", actual, expected)
	}

}

func TestSaveAndFind(t *testing.T) {
	expected := []Task{
		{
			Description: "test1",
			Completed:   false,
		},
		{
			Description: "test2",
			Completed:   true,
		},
		{
			Description: "",
			Completed:   false,
		},
	}

	db, err := database.NewDB()
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Task{})
	u := NewTaskModel(db)

	for _, task := range expected {
		err = u.Save(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
	}
	actual, err := u.FindAll()

	if len(actual) != len(expected) {
		t.Errorf("got length %v want %v", len(actual), (expected))
	}
	for i := range actual {
		if actual[i].Description != expected[i].Description {
			t.Errorf("got %v want %v", actual[i].Description, expected[i].Description)
		}
		if actual[i].Completed != expected[i].Completed {
			t.Errorf("got %v want %v", actual[i].Completed, expected[i].Completed)
		}
	}

	db.DropTableIfExists(&Task{})
}

func TestUpdate(t *testing.T) {
	testData := []Task{
		{
			Description: "test1",
			Completed:   false,
		},
		{
			Description: "test2",
			Completed:   true,
		},
		{
			Description: "",
			Completed:   false,
		},
	}

	db, err := database.NewDB()
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Task{})
	u := NewTaskModel(db)

	for _, task := range testData {
		err = u.Save(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
		task.Description = "updated"
		err = u.Update(&task)
		if err != nil {
			t.Errorf("database save failed")
		}
		if task.Description != "updated" {
			t.Errorf("got %v want %v", "updated", task.Description)
		}
	}
	db.DropTableIfExists(&Task{})
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Euan Kemp
// Copyright (c) 2017 Daniel Oaks
// released under the MIT license

package irc

import (
	"fmt"
	"testing"
)

func TestCasefoldChannel(t *testing.T) {
	type channelTest struct {
		channel string
		folded  string
		err     bool
	}
	testCases := []channelTest{
		{
			channel: "#foo",
			folded:  "#foo",
		},
		{
			channel: "#rfc1459[noncompliant]",
			folded:  "#rfc1459[noncompliant]",
		},
		{
			channel: "#{[]}",
			folded:  "#{[]}",
		},
		{
			channel: "#FOO",
			folded:  "#foo",
		},
		{
			channel: "#bang!",
			folded:  "#bang!",
		},
		{
			channel: "#",
			folded:  "#",
		},
		{
			channel: "#中文频道",
			folded:  "#中文频道",
		},
		{
			// Hebrew; it's up to the client to display this right-to-left, including the #
			channel: "#שלום",
			folded:  "#שלום",
		},
	}

	for _, errCase := range []string{
		"", "#*starpower", "# NASA", "#interro?", "OOF#", "foo",
		// bidi violation mixing latin and hebrew characters:
		"#shalomעליכם",
	} {
		testCases = append(testCases, channelTest{channel: errCase, err: true})
	}

	for i, tt := range testCases {
		t.Run(fmt.Sprintf("case %d: %s", i, tt.channel), func(t *testing.T) {
			res, err := CasefoldChannel(tt.channel)
			if tt.err && err == nil {
				t.Errorf("expected error when casefolding [%s], but did not receive one", tt.channel)
				return
			}
			if !tt.err && err != nil {
				t.Errorf("unexpected error while casefolding [%s]: %s", tt.channel, err.Error())
				return
			}
			if tt.folded != res {
				t.Errorf("expected [%v] to be [%v]", res, tt.folded)
			}
		})
	}
}

func TestCasefoldName(t *testing.T) {
	type nameTest struct {
		name   string
		folded string
		err    bool
	}
	testCases := []nameTest{
		{
			name:   "foo",
			folded: "foo",
		},
		{
			name:   "FOO",
			folded: "foo",
		},
	}

	for _, errCase := range []string{
		"", "#", "foo,bar", "star*man*junior", "lo7t?",
		"f.l", "excited!nick", "foo@bar", ":trail",
		"~o", "&o", "@o", "%h", "+v", "-m",
	} {
		testCases = append(testCases, nameTest{name: errCase, err: true})
	}

	for i, tt := range testCases {
		t.Run(fmt.Sprintf("case %d: %s", i, tt.name), func(t *testing.T) {
			res, err := CasefoldName(tt.name)
			if tt.err && err == nil {
				t.Errorf("expected error when casefolding [%s], but did not receive one", tt.name)
				return
			}
			if !tt.err && err != nil {
				t.Errorf("unexpected error while casefolding [%s]: %s", tt.name, err.Error())
				return
			}
			if tt.folded != res {
				t.Errorf("expected [%v] to be [%v]", res, tt.folded)
			}
		})
	}
}
<commit_msg>add more test cases<commit_after>// Copyright (c) 2017 Euan Kemp
// Copyright (c) 2017 Daniel Oaks
// released under the MIT license

package irc

import (
	"fmt"
	"testing"
)

func TestCasefoldChannel(t *testing.T) {
	type channelTest struct {
		channel string
		folded  string
		err     bool
	}
	testCases := []channelTest{
		{
			channel: "#foo",
			folded:  "#foo",
		},
		{
			channel: "#rfc1459[noncompliant]",
			folded:  "#rfc1459[noncompliant]",
		},
		{
			channel: "#{[]}",
			folded:  "#{[]}",
		},
		{
			channel: "#FOO",
			folded:  "#foo",
		},
		{
			channel: "#bang!",
			folded:  "#bang!",
		},
		{
			channel: "#",
			folded:  "#",
		},
		{
			channel: "##",
			folded:  "##",
		},
		{
			channel: "##Ubuntu",
			folded:  "##ubuntu",
		},
		{
			channel: "#中文频道",
			folded:  "#中文频道",
		},
		{
			// Hebrew; it's up to the client to display this right-to-left, including the #
			channel: "#שלום",
			folded:  "#שלום",
		},
	}

	for _, errCase := range []string{
		"", "#*starpower", "# NASA", "#interro?", "OOF#", "foo",
		// bidi violation mixing latin and hebrew characters:
		"#shalomעליכם",
	} {
		testCases = append(testCases, channelTest{channel: errCase, err: true})
	}

	for i, tt := range testCases {
		t.Run(fmt.Sprintf("case %d: %s", i, tt.channel), func(t *testing.T) {
			res, err := CasefoldChannel(tt.channel)
			if tt.err && err == nil {
				t.Errorf("expected error when casefolding [%s], but did not receive one", tt.channel)
				return
			}
			if !tt.err && err != nil {
				t.Errorf("unexpected error while casefolding [%s]: %s", tt.channel, err.Error())
				return
			}
			if tt.folded != res {
				t.Errorf("expected [%v] to be [%v]", res, tt.folded)
			}
		})
	}
}

func TestCasefoldName(t *testing.T) {
	type nameTest struct {
		name   string
		folded string
		err    bool
	}
	testCases := []nameTest{
		{
			name:   "foo",
			folded: "foo",
		},
		{
			name:   "FOO",
			folded: "foo",
		},
	}

	for _, errCase := range []string{
		"", "#", "foo,bar", "star*man*junior", "lo7t?",
		"f.l", "excited!nick", "foo@bar", ":trail",
		"~o", "&o", "@o", "%h", "+v", "-m",
	} {
		testCases = append(testCases, nameTest{name: errCase, err: true})
	}

	for i, tt := range testCases {
		t.Run(fmt.Sprintf("case %d: %s", i, tt.name), func(t *testing.T) {
			res, err := CasefoldName(tt.name)
			if tt.err && err == nil {
				t.Errorf("expected error when casefolding [%s], but did not receive one", tt.name)
				return
			}
			if !tt.err && err != nil {
				t.Errorf("unexpected error while casefolding [%s]: %s", tt.name, err.Error())
				return
			}
			if tt.folded != res {
				t.Errorf("expected [%v] to be [%v]", res, tt.folded)
			}
		})
	}
}
<|endoftext|>