<commit_before>package headerfs

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"sort"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcwallet/walletdb"
)

var (
	// indexBucket is the main top-level bucket for the header index.
	// Nothing is stored in this bucket other than the sub-buckets which
	// contains the indexes for the various header types.
	indexBucket = []byte("header-index")

	// bitcoinTip is the key which tracks the "tip" of the block header
	// chain. The value of this key will be the current block hash of the
	// best known chain that we're synced to.
	bitcoinTip = []byte("bitcoin")

	// regFilterTip is the key which tracks the "tip" of the regular
	// compact filter header chain. The value of this key will be the
	// current block hash of the best known chain that the headers for
	// regular filter are synced to.
	regFilterTip = []byte("regular")

	// extFilterTip is the key which tracks the "tip" of the extended
	// compact filter header chain. The value of this key will be the
	// current block hash of the best known chain that the headers for
	// extended filter are synced to.
	extFilterTip = []byte("ext")
)

var (
	// ErrHeightNotFound is returned when a specified height isn't found in
	// a target index.
	ErrHeightNotFound = fmt.Errorf("target height not found in index")

	// ErrHashNotFound is returned when a specified block hash isn't found
	// in a target index.
	ErrHashNotFound = fmt.Errorf("target hash not found in index")
)

// HeaderType is an enum-like type which defines the various header types that
// are stored within the index.
type HeaderType uint8

const (
	// Block is the header type that represents regular Bitcoin block
	// headers.
	Block HeaderType = iota

	// RegularFilter is a header type that represents the basic filter
	// header type for the filter header chain.
	RegularFilter
)

const (
	// BlockHeaderSize is the size in bytes of the Block header type.
	BlockHeaderSize = 80

	// RegularFilterHeaderSize is the size in bytes of the RegularFilter
	// header type.
	RegularFilterHeaderSize = 32
)

// headerIndex is an index stored within the database that allows for random
// access into the on-disk header file. This, in conjunction with a flat file
// of headers consists of header database. The keys have been specifically
// crafted in order to ensure maximum write performance during IBD, and also to
// provide the necessary indexing properties required.
type headerIndex struct {
	db walletdb.DB

	indexType HeaderType
}

// newHeaderIndex creates a new headerIndex given an already open database, and
// a particular header type.
func newHeaderIndex(db walletdb.DB, indexType HeaderType) (*headerIndex, error) {
	// As an initially step, we'll attempt to create all the buckets
	// necessary for functioning of the index. If these buckets has already
	// been created, then we can exit early.
	err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
		_, err := tx.CreateTopLevelBucket(indexBucket)
		return err

	})
	if err != nil && err != walletdb.ErrBucketExists {
		return nil, err
	}

	return &headerIndex{
		db:        db,
		indexType: indexType,
	}, nil
}

// headerEntry is an internal type that's used to quickly map a (height, hash)
// pair into the proper key that'll be stored within the database.
type headerEntry struct {
	hash   chainhash.Hash
	height uint32
}

// headerBatch is a batch of header entries to be written to disk.
//
// NOTE: The entries within a batch SHOULD be properly sorted by hash in
// order to ensure the batch is written in a sequential write.
type headerBatch []headerEntry

// Len returns the number of routes in the collection.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Len() int {
	return len(h)
}

// Less reports where the entry with index i should sort before the entry with
// index j. As we want to ensure the items are written in sequential order,
// items with the "first" hash.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Less(i, j int) bool {
	return bytes.Compare(h[i].hash[:], h[j].hash[:]) < 0
}

// Swap swaps the elements with indexes i and j.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
}

// addHeaders writes a batch of header entries in a single atomic batch
func (h *headerIndex) addHeaders(batch headerBatch) error {
	// If we're writing a 0-length batch, make no changes and return.
	if len(batch) == 0 {
		return nil
	}

	// In order to ensure optimal write performance, we'll ensure that the
	// items are sorted by their hash before insertion into the database.
	sort.Sort(batch)

	return walletdb.Update(h.db, func(tx walletdb.ReadWriteTx) error {
		rootBucket := tx.ReadWriteBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the key that tracks the tip of the chain
		// so we can update the index once all the header entries have
		// been updated.
		// TODO(roasbeef): only need block tip?
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown index type: %v", h.indexType)
		}

		var (
			chainTipHash   chainhash.Hash
			chainTipHeight uint32
		)

		for _, header := range batch {
			var heightBytes [4]byte
			binary.BigEndian.PutUint32(heightBytes[:], header.height)
			err := rootBucket.Put(header.hash[:], heightBytes[:])
			if err != nil {
				return err
			}

			// TODO(roasbeef): need to remedy if side-chain
			// tracking added
			if header.height >= chainTipHeight {
				chainTipHash = header.hash
				chainTipHeight = header.height
			}
		}

		return rootBucket.Put(tipKey, chainTipHash[:])
	})
}

// heightFromHash returns the height of the entry that matches the specified
// height. With this height, the caller is then able to seek to the appropriate
// spot in the flat files in order to extract the true header.
func (h *headerIndex) heightFromHash(hash *chainhash.Hash) (uint32, error) {
	var height uint32
	err := walletdb.View(h.db, func(tx walletdb.ReadTx) error {
		rootBucket := tx.ReadBucket(indexBucket)

		heightBytes := rootBucket.Get(hash[:])
		if heightBytes == nil {
			// If the hash wasn't found, then we don't know of this
			// hash within the index.
			return ErrHashNotFound
		}

		height = binary.BigEndian.Uint32(heightBytes)
		return nil
	})
	if err != nil {
		return 0, err
	}

	return height, nil
}

// chainTip returns the best hash and height that the index knows of.
func (h *headerIndex) chainTip() (*chainhash.Hash, uint32, error) {
	var (
		tipHeight uint32
		tipHash   *chainhash.Hash
	)

	err := walletdb.View(h.db, func(tx walletdb.ReadTx) error {
		rootBucket := tx.ReadBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the particular key that tracks the chain
		// tip.
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown chain tip index type: %v", h.indexType)
		}

		// Now that we have the particular tip key for this header
		// type, we'll fetch the hash for this tip, then using that
		// we'll fetch the height that corresponds to that hash.
		tipHashBytes := rootBucket.Get(tipKey)
		tipHeightBytes := rootBucket.Get(tipHashBytes)
		if len(tipHeightBytes) != 4 {
			return ErrHeightNotFound
		}

		// With the height fetched, we can now populate our return
		// parameters.
		h, err := chainhash.NewHash(tipHashBytes)
		if err != nil {
			return err
		}
		tipHash = h
		tipHeight = binary.BigEndian.Uint32(tipHeightBytes)

		return nil
	})
	if err != nil {
		return nil, 0, err
	}

	return tipHash, tipHeight, nil
}

// truncateIndex truncates the index for a particluar header type by a single
// header entry. The passed newTip pointer should point to the hash of the new
// chain tip. Optionally, if the entry is to be deleted as well, then the
// delete flag should be set to true.
func (h *headerIndex) truncateIndex(newTip *chainhash.Hash, delete bool) error {
	return walletdb.Update(h.db, func(tx walletdb.ReadWriteTx) error {
		rootBucket := tx.ReadWriteBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the key that tracks the tip of the chain
		// we need to update.
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown index type: %v", h.indexType)
		}

		// If the delete flag is set, then we'll also delete this entry
		// from the database as the primary index (block headers) is
		// being rolled back.
		if delete {
			prevTipHash := rootBucket.Get(tipKey)
			if err := rootBucket.Delete(prevTipHash); err != nil {
				return err
			}
		}

		// With the now stale entry deleted, we'll update the chain tip
		// to point to the new hash.
		return rootBucket.Put(tipKey, newTip[:])
	})
}
<commit_msg>headerfs: extract heightFromHashWithTx<commit_after>package headerfs

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"sort"

	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcwallet/walletdb"
)

var (
	// indexBucket is the main top-level bucket for the header index.
	// Nothing is stored in this bucket other than the sub-buckets which
	// contains the indexes for the various header types.
	indexBucket = []byte("header-index")

	// bitcoinTip is the key which tracks the "tip" of the block header
	// chain. The value of this key will be the current block hash of the
	// best known chain that we're synced to.
	bitcoinTip = []byte("bitcoin")

	// regFilterTip is the key which tracks the "tip" of the regular
	// compact filter header chain. The value of this key will be the
	// current block hash of the best known chain that the headers for
	// regular filter are synced to.
	regFilterTip = []byte("regular")

	// extFilterTip is the key which tracks the "tip" of the extended
	// compact filter header chain. The value of this key will be the
	// current block hash of the best known chain that the headers for
	// extended filter are synced to.
	extFilterTip = []byte("ext")
)

var (
	// ErrHeightNotFound is returned when a specified height isn't found in
	// a target index.
	ErrHeightNotFound = fmt.Errorf("target height not found in index")

	// ErrHashNotFound is returned when a specified block hash isn't found
	// in a target index.
	ErrHashNotFound = fmt.Errorf("target hash not found in index")
)

// HeaderType is an enum-like type which defines the various header types that
// are stored within the index.
type HeaderType uint8

const (
	// Block is the header type that represents regular Bitcoin block
	// headers.
	Block HeaderType = iota

	// RegularFilter is a header type that represents the basic filter
	// header type for the filter header chain.
	RegularFilter
)

const (
	// BlockHeaderSize is the size in bytes of the Block header type.
	BlockHeaderSize = 80

	// RegularFilterHeaderSize is the size in bytes of the RegularFilter
	// header type.
	RegularFilterHeaderSize = 32
)

// headerIndex is an index stored within the database that allows for random
// access into the on-disk header file. This, in conjunction with a flat file
// of headers consists of header database. The keys have been specifically
// crafted in order to ensure maximum write performance during IBD, and also to
// provide the necessary indexing properties required.
type headerIndex struct {
	db walletdb.DB

	indexType HeaderType
}

// newHeaderIndex creates a new headerIndex given an already open database, and
// a particular header type.
func newHeaderIndex(db walletdb.DB, indexType HeaderType) (*headerIndex, error) {
	// As an initially step, we'll attempt to create all the buckets
	// necessary for functioning of the index. If these buckets has already
	// been created, then we can exit early.
	err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
		_, err := tx.CreateTopLevelBucket(indexBucket)
		return err

	})
	if err != nil && err != walletdb.ErrBucketExists {
		return nil, err
	}

	return &headerIndex{
		db:        db,
		indexType: indexType,
	}, nil
}

// headerEntry is an internal type that's used to quickly map a (height, hash)
// pair into the proper key that'll be stored within the database.
type headerEntry struct {
	hash   chainhash.Hash
	height uint32
}

// headerBatch is a batch of header entries to be written to disk.
//
// NOTE: The entries within a batch SHOULD be properly sorted by hash in
// order to ensure the batch is written in a sequential write.
type headerBatch []headerEntry

// Len returns the number of routes in the collection.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Len() int {
	return len(h)
}

// Less reports where the entry with index i should sort before the entry with
// index j. As we want to ensure the items are written in sequential order,
// items with the "first" hash.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Less(i, j int) bool {
	return bytes.Compare(h[i].hash[:], h[j].hash[:]) < 0
}

// Swap swaps the elements with indexes i and j.
//
// NOTE: This is part of the sort.Interface implementation.
func (h headerBatch) Swap(i, j int) {
	h[i], h[j] = h[j], h[i]
}

// addHeaders writes a batch of header entries in a single atomic batch
func (h *headerIndex) addHeaders(batch headerBatch) error {
	// If we're writing a 0-length batch, make no changes and return.
	if len(batch) == 0 {
		return nil
	}

	// In order to ensure optimal write performance, we'll ensure that the
	// items are sorted by their hash before insertion into the database.
	sort.Sort(batch)

	return walletdb.Update(h.db, func(tx walletdb.ReadWriteTx) error {
		rootBucket := tx.ReadWriteBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the key that tracks the tip of the chain
		// so we can update the index once all the header entries have
		// been updated.
		// TODO(roasbeef): only need block tip?
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown index type: %v", h.indexType)
		}

		var (
			chainTipHash   chainhash.Hash
			chainTipHeight uint32
		)

		for _, header := range batch {
			var heightBytes [4]byte
			binary.BigEndian.PutUint32(heightBytes[:], header.height)
			err := rootBucket.Put(header.hash[:], heightBytes[:])
			if err != nil {
				return err
			}

			// TODO(roasbeef): need to remedy if side-chain
			// tracking added
			if header.height >= chainTipHeight {
				chainTipHash = header.hash
				chainTipHeight = header.height
			}
		}

		return rootBucket.Put(tipKey, chainTipHash[:])
	})
}

// heightFromHash returns the height of the entry that matches the specified
// height. With this height, the caller is then able to seek to the appropriate
// spot in the flat files in order to extract the true header.
func (h *headerIndex) heightFromHash(hash *chainhash.Hash) (uint32, error) {
	var height uint32
	err := walletdb.View(h.db, func(tx walletdb.ReadTx) error {
		var err error
		height, err = h.heightFromHashWithTx(tx, hash)
		return err
	})
	if err != nil {
		return 0, err
	}

	return height, nil
}

// heightFromHashWithTx returns the height of the entry that matches the
// specified hash by using the given DB transaction. With this height, the
// caller is then able to seek to the appropriate spot in the flat files in
// order to extract the true header.
func (h *headerIndex) heightFromHashWithTx(tx walletdb.ReadTx,
	hash *chainhash.Hash) (uint32, error) {

	rootBucket := tx.ReadBucket(indexBucket)

	heightBytes := rootBucket.Get(hash[:])
	if heightBytes == nil {
		// If the hash wasn't found, then we don't know of this hash
		// within the index.
		return 0, ErrHashNotFound
	}

	return binary.BigEndian.Uint32(heightBytes), nil
}

// chainTip returns the best hash and height that the index knows of.
func (h *headerIndex) chainTip() (*chainhash.Hash, uint32, error) {
	var (
		tipHeight uint32
		tipHash   *chainhash.Hash
	)

	err := walletdb.View(h.db, func(tx walletdb.ReadTx) error {
		rootBucket := tx.ReadBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the particular key that tracks the chain
		// tip.
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown chain tip index type: %v", h.indexType)
		}

		// Now that we have the particular tip key for this header
		// type, we'll fetch the hash for this tip, then using that
		// we'll fetch the height that corresponds to that hash.
		tipHashBytes := rootBucket.Get(tipKey)
		tipHeightBytes := rootBucket.Get(tipHashBytes)
		if len(tipHeightBytes) != 4 {
			return ErrHeightNotFound
		}

		// With the height fetched, we can now populate our return
		// parameters.
		h, err := chainhash.NewHash(tipHashBytes)
		if err != nil {
			return err
		}
		tipHash = h
		tipHeight = binary.BigEndian.Uint32(tipHeightBytes)

		return nil
	})
	if err != nil {
		return nil, 0, err
	}

	return tipHash, tipHeight, nil
}

// truncateIndex truncates the index for a particluar header type by a single
// header entry. The passed newTip pointer should point to the hash of the new
// chain tip. Optionally, if the entry is to be deleted as well, then the
// delete flag should be set to true.
func (h *headerIndex) truncateIndex(newTip *chainhash.Hash, delete bool) error {
	return walletdb.Update(h.db, func(tx walletdb.ReadWriteTx) error {
		rootBucket := tx.ReadWriteBucket(indexBucket)

		var tipKey []byte

		// Based on the specified index type of this instance of the
		// index, we'll grab the key that tracks the tip of the chain
		// we need to update.
		switch h.indexType {
		case Block:
			tipKey = bitcoinTip
		case RegularFilter:
			tipKey = regFilterTip
		default:
			return fmt.Errorf("unknown index type: %v", h.indexType)
		}

		// If the delete flag is set, then we'll also delete this entry
		// from the database as the primary index (block headers) is
		// being rolled back.
		if delete {
			prevTipHash := rootBucket.Get(tipKey)
			if err := rootBucket.Delete(prevTipHash); err != nil {
				return err
			}
		}

		// With the now stale entry deleted, we'll update the chain tip
		// to point to the new hash.
		return rootBucket.Put(tipKey, newTip[:])
	})
}
<|endoftext|>


<commit_before>package tools

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"

	yaml "gopkg.in/yaml.v2"

	"github.com/Originate/exosphere/src/types"
	"github.com/Originate/exosphere/src/util"
	dockerTypes "github.com/docker/docker/api/types"
	"github.com/moby/moby/client"
	"github.com/pkg/errors"
)

// CatFileInDockerImage reads the file fileName inside the given image
func CatFileInDockerImage(c *client.Client, imageName, fileName string) ([]byte, error) {
	if err := PullImage(c, imageName); err != nil {
		return []byte(""), err
	}
	command := fmt.Sprintf("cat %s", fileName)
	output, err := RunInDockerImage(imageName, command)
	return []byte(output), err
}

// GetDockerCompose reads docker-compose.yml at the given path and
// returns the dockerCompose object
func GetDockerCompose(dockerComposePath string) (result types.DockerCompose, err error) {
	yamlFile, err := ioutil.ReadFile(dockerComposePath)
	if err != nil {
		return result, err
	}
	err = yaml.Unmarshal(yamlFile, &result)
	if err != nil {
		return result, errors.Wrap(err, "Failed to unmarshal docker-compose.yml")
	}
	return result, nil
}

// GetExitCode returns the exit code for the given container
func GetExitCode(containerName string) (int, error) {
	c, err := client.NewEnvClient()
	if err != nil {
		return 1, err
	}
	containerJSON, err := c.ContainerInspect(context.Background(), containerName)
	if err != nil {
		return 1, err
	}
	if containerJSON.State.Status != "exited" {
		return 1, fmt.Errorf("%s has not exited", containerName)
	}
	return containerJSON.State.ExitCode, nil
}

// GetRenderedVolumes returns the rendered paths to the given volumes
func GetRenderedVolumes(volumes []string, appName string, role string, homeDir string) ([]string, error) {
	dataPath := path.Join(homeDir, ".exosphere", appName, role, "data")
	renderedVolumes := []string{}
	if err := os.MkdirAll(dataPath, 0777); err != nil { //nolint gas
		return renderedVolumes, errors.Wrap(err, "Failed to create the necessary directories for the volumes")
	}
	for _, volume := range volumes {
		renderedVolumes = append(renderedVolumes, strings.Replace(volume, "{{EXO_DATA_PATH}}", dataPath, -1))
	}
	return renderedVolumes, nil
}

// ListRunningContainers returns the names of running containers
// and an error (if any)
func ListRunningContainers(c *client.Client) ([]string, error) {
	containerNames := []string{}
	ctx := context.Background()
	containers, err := c.ContainerList(ctx, dockerTypes.ContainerListOptions{})
	if err != nil {
		return containerNames, err
	}
	for _, container := range containers {
		containerNames = append(containerNames, strings.Replace(container.Names[0], "/", "", -1))
	}
	return containerNames, nil
}

// ListImages returns the names of all images and an error (if any)
func ListImages(c *client.Client) ([]string, error) {
	imageNames := []string{}
	ctx := context.Background()
	imageSummaries, err := c.ImageList(ctx, dockerTypes.ImageListOptions{
		All: true,
	})
	if err != nil {
		return imageNames, err
	}
	for _, imageSummary := range imageSummaries {
		if len(imageSummary.RepoTags) > 0 {
			repoTag := imageSummary.RepoTags[0]
			imageNames = append(imageNames, strings.Split(repoTag, ":")[0])
		}
	}
	return imageNames, nil
}

// PullImage pulls the given image from DockerHub, returns an error if any
func PullImage(c *client.Client, image string) error {
	ctx := context.Background()
	stream, err := c.ImagePull(ctx, image, dockerTypes.ImagePullOptions{})
	if err != nil {
		return err
	}
	_, err = ioutil.ReadAll(stream)
	return err
}

// RunInDockerImage runs the given command in a new writeable container layer
// over the given image, removes the container when the command exits, and returns
// the output string and an error if any
func RunInDockerImage(imageName, command string) (string, error) {
	return util.Run("", fmt.Sprintf("docker run --rm %s %s", imageName, command))
}

// TagImage tags a docker image srcImage as targetImage
func TagImage(srcImage, targetImage string) error {
	dockerClient, err := client.NewEnvClient()
	if err != nil {
		return err
	}
	ctx := context.Background()
	return dockerClient.ImageTag(ctx, srcImage, targetImage)
}

// PushImage pushes image with imageName to the registry given an encoded auth object
func PushImage(c *client.Client, writer io.Writer, imageName, encodedAuth string) error {
	ctx := context.Background()
	stream, err := c.ImagePush(ctx, imageName, dockerTypes.ImagePushOptions{
		RegistryAuth: encodedAuth,
	})
	if err != nil {
		return err
	}
	scanner := bufio.NewScanner(stream)
	for scanner.Scan() {
		err = printPushProgress(writer, scanner.Text())
		if err != nil {
			return fmt.Errorf("Cannot push image '%s': %s", imageName, err)
		}
	}
	if err := scanner.Err(); err != nil {
		return errors.Wrap(err, "error reading ImagePush output")
	}
	return stream.Close()
}

func printPushProgress(writer io.Writer, output string) error {
	outputObject := struct {
		Status      string      `json:"status"`
		ID          string      `json:"id"`
		ErrorDetail interface{} `json:"errorDetail"`
		Error       string      `json:"error"`
	}{}
	err := json.Unmarshal([]byte(output), &outputObject)
	if err != nil {
		return err
	}
	if outputObject.Error != "" {
		return errors.New(outputObject.Error)
	}
	fmt.Fprintf(writer, "%s: %s\n", outputObject.Status, outputObject.ID)
	return nil
}
<commit_msg>exo deploy: print docker push command (#725)<commit_after>package tools

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	yaml "gopkg.in/yaml.v2"

	"github.com/Originate/exosphere/src/types"
	"github.com/Originate/exosphere/src/util"
	dockerTypes "github.com/docker/docker/api/types"
	"github.com/moby/moby/client"
	"github.com/pkg/errors"
)

// CatFileInDockerImage reads the file fileName inside the given image
func CatFileInDockerImage(c *client.Client, imageName, fileName string) ([]byte, error) {
	if err := PullImage(c, imageName); err != nil {
		return []byte(""), err
	}
	command := fmt.Sprintf("cat %s", fileName)
	output, err := RunInDockerImage(imageName, command)
	return []byte(output), err
}

// GetDockerCompose reads docker-compose.yml at the given path and
// returns the dockerCompose object
func GetDockerCompose(dockerComposePath string) (result types.DockerCompose, err error) {
	yamlFile, err := ioutil.ReadFile(dockerComposePath)
	if err != nil {
		return result, err
	}
	err = yaml.Unmarshal(yamlFile, &result)
	if err != nil {
		return result, errors.Wrap(err, "Failed to unmarshal docker-compose.yml")
	}
	return result, nil
}

// GetExitCode returns the exit code for the given container
func GetExitCode(containerName string) (int, error) {
	c, err := client.NewEnvClient()
	if err != nil {
		return 1, err
	}
	containerJSON, err := c.ContainerInspect(context.Background(), containerName)
	if err != nil {
		return 1, err
	}
	if containerJSON.State.Status != "exited" {
		return 1, fmt.Errorf("%s has not exited", containerName)
	}
	return containerJSON.State.ExitCode, nil
}

// GetRenderedVolumes returns the rendered paths to the given volumes
func GetRenderedVolumes(volumes []string, appName string, role string, homeDir string) ([]string, error) {
	dataPath := path.Join(homeDir, ".exosphere", appName, role, "data")
	renderedVolumes := []string{}
	if err := os.MkdirAll(dataPath, 0777); err != nil { //nolint gas
		return renderedVolumes, errors.Wrap(err, "Failed to create the necessary directories for the volumes")
	}
	for _, volume := range volumes {
		renderedVolumes = append(renderedVolumes, strings.Replace(volume, "{{EXO_DATA_PATH}}", dataPath, -1))
	}
	return renderedVolumes, nil
}

// ListRunningContainers returns the names of running containers
// and an error (if any)
func ListRunningContainers(c *client.Client) ([]string, error) {
	containerNames := []string{}
	ctx := context.Background()
	containers, err := c.ContainerList(ctx, dockerTypes.ContainerListOptions{})
	if err != nil {
		return containerNames, err
	}
	for _, container := range containers {
		containerNames = append(containerNames, strings.Replace(container.Names[0], "/", "", -1))
	}
	return containerNames, nil
}

// ListImages returns the names of all images and an error (if any)
func ListImages(c *client.Client) ([]string, error) {
	imageNames := []string{}
	ctx := context.Background()
	imageSummaries, err := c.ImageList(ctx, dockerTypes.ImageListOptions{
		All: true,
	})
	if err != nil {
		return imageNames, err
	}
	for _, imageSummary := range imageSummaries {
		if len(imageSummary.RepoTags) > 0 {
			repoTag := imageSummary.RepoTags[0]
			imageNames = append(imageNames, strings.Split(repoTag, ":")[0])
		}
	}
	return imageNames, nil
}

// PullImage pulls the given image from DockerHub, returns an error if any
func PullImage(c *client.Client, image string) error {
	ctx := context.Background()
	stream, err := c.ImagePull(ctx, image, dockerTypes.ImagePullOptions{})
	if err != nil {
		return err
	}
	_, err = ioutil.ReadAll(stream)
	return err
}

// RunInDockerImage runs the given command in a new writeable container layer
// over the given image, removes the container when the command exits, and returns
// the output string and an error if any
func RunInDockerImage(imageName, command string) (string, error) {
	return util.Run("", fmt.Sprintf("docker run --rm %s %s", imageName, command))
}

// TagImage tags a docker image srcImage as targetImage
func TagImage(srcImage, targetImage string) error {
	dockerClient, err := client.NewEnvClient()
	if err != nil {
		return err
	}
	ctx := context.Background()
	return dockerClient.ImageTag(ctx, srcImage, targetImage)
}

// PushImage pushes image with imageName to the registry given an encoded auth object
func PushImage(c *client.Client, writer io.Writer, imageName, encodedAuth string) error {
	util.PrintCommandHeader(writer, fmt.Sprintf("docker push %s", imageName))
	startTime := time.Now()
	ctx := context.Background()
	stream, err := c.ImagePush(ctx, imageName, dockerTypes.ImagePushOptions{
		RegistryAuth: encodedAuth,
	})
	if err != nil {
		return err
	}
	scanner := bufio.NewScanner(stream)
	for scanner.Scan() {
		err = printPushProgress(writer, scanner.Text())
		if err != nil {
			return fmt.Errorf("Cannot push image '%s': %s", imageName, err)
		}
	}
	if err := scanner.Err(); err != nil {
		return errors.Wrap(err, "error reading ImagePush output")
	}
	util.PrintCommandFooter(writer, time.Since(startTime))
	return stream.Close()
}

func printPushProgress(writer io.Writer, output string) error {
	outputObject := struct {
		Status      string      `json:"status"`
		ID          string      `json:"id"`
		ErrorDetail interface{} `json:"errorDetail"`
		Error       string      `json:"error"`
	}{}
	err := json.Unmarshal([]byte(output), &outputObject)
	if err != nil {
		return err
	}
	if outputObject.Error != "" {
		return errors.New(outputObject.Error)
	}
	fmt.Fprintf(writer, "%s: %s\n", outputObject.Status, outputObject.ID)
	return nil
}
<|endoftext|>


<commit_before>package lib

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"runtime"

	log "github.com/Sirupsen/logrus"
)

var (
	Err_Resource          = errors.New("invalid webfinger resource")
	Err_NotYetImplemented = errors.New("Not yet implemented")
	Err_Too_Many_Redirect = errors.New("Too many redirects")
	Err_HTTP_Redirect     = errors.New("Redirect to non-https server")
	Err_HTTP_Code         = errors.New("Received unexpected http code")
	Err_Subject_Missmatch = errors.New("Subject doesn't match resource")
)

// PassThru wraps an existing io.Reader.
//
// It simply forwards the Read() call, while displaying
// the results from individual calls to it.
type PassThru struct {
	io.Reader
	total    int64 // Total # of bytes transferred
	length   int64 // Expected length
	progress float64
}

func (d *Dkenv) DownloadDocker(version string) error {
	resp, err := d.getHttp(version)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	readerpt := &PassThru{Reader: resp.Body, length: resp.ContentLength}

	body, err := ioutil.ReadAll(readerpt)
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(d.DkenvDir+"/docker-"+version, body, 0777); err != nil {
		return fmt.Errorf("Error(s) writing docker binary: %v", err)
	}

	return nil
}

func (d *Dkenv) getHttp(version string) (*http.Response, error) {
	client := &http.Client{
		CheckRedirect: redirectPolicyFunc,
	}

	var system string

	switch {
	case runtime.GOOS == "windows":
		system = "Windows"
	case runtime.GOOS == "linux":
		system = "Linux"
	case runtime.GOOS == "darwin":
		system = "Darwin"
	default:
		return nil, fmt.Errorf("Unsupported system type - %v", runtime.GOOS)
	}

	resp, err := client.Get("https://get.docker.com/builds/" + system + "/x86_64/docker-" + version)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("No such docker version '%v'", version)
	}

	return resp, nil

}

func (pt *PassThru) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)

		if percentage-pt.progress > 2 {
			log.Debugf("Transferred %d percent", int(percentage))
			pt.progress = percentage
		}
	}

	return n, err
}

func redirectPolicyFunc(req *http.Request, via []*http.Request) error {
	if len(via) > 10 {
		return Err_Too_Many_Redirect
	}

	if req.URL.Scheme != "https" {
		return Err_HTTP_Redirect
	}

	return nil
}
<commit_msg>Change mode of binary to 0755<commit_after>package lib

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"runtime"

	log "github.com/Sirupsen/logrus"
)

var (
	Err_Resource          = errors.New("invalid webfinger resource")
	Err_NotYetImplemented = errors.New("Not yet implemented")
	Err_Too_Many_Redirect = errors.New("Too many redirects")
	Err_HTTP_Redirect     = errors.New("Redirect to non-https server")
	Err_HTTP_Code         = errors.New("Received unexpected http code")
	Err_Subject_Missmatch = errors.New("Subject doesn't match resource")
)

// PassThru wraps an existing io.Reader.
//
// It simply forwards the Read() call, while displaying
// the results from individual calls to it.
type PassThru struct {
	io.Reader
	total    int64 // Total # of bytes transferred
	length   int64 // Expected length
	progress float64
}

func (d *Dkenv) DownloadDocker(version string) error {
	resp, err := d.getHttp(version)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	readerpt := &PassThru{Reader: resp.Body, length: resp.ContentLength}

	body, err := ioutil.ReadAll(readerpt)
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(d.DkenvDir+"/docker-"+version, body, 0755); err != nil {
		return fmt.Errorf("Error(s) writing docker binary: %v", err)
	}

	return nil
}

func (d *Dkenv) getHttp(version string) (*http.Response, error) {
	client := &http.Client{
		CheckRedirect: redirectPolicyFunc,
	}

	var system string

	switch {
	case runtime.GOOS == "windows":
		system = "Windows"
	case runtime.GOOS == "linux":
		system = "Linux"
	case runtime.GOOS == "darwin":
		system = "Darwin"
	default:
		return nil, fmt.Errorf("Unsupported system type - %v", runtime.GOOS)
	}

	resp, err := client.Get("https://get.docker.com/builds/" + system + "/x86_64/docker-" + version)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("No such docker version '%v'", version)
	}

	return resp, nil

}

func (pt *PassThru) Read(p []byte) (int, error) {
	n, err := pt.Reader.Read(p)
	if n > 0 {
		pt.total += int64(n)
		percentage := float64(pt.total) / float64(pt.length) * float64(100)

		if percentage-pt.progress > 2 {
			log.Debugf("Transferred %d percent", int(percentage))
			pt.progress = percentage
		}
	}

	return n, err
}

func redirectPolicyFunc(req *http.Request, via []*http.Request) error {
	if len(via) > 10 {
		return Err_Too_Many_Redirect
	}

	if req.URL.Scheme != "https" {
		return Err_HTTP_Redirect
	}

	return nil
}
<|endoftext|>


<commit_before>package moxxiConf

import (
	"bufio"
	"fmt"
	"github.com/dchest/uniuri"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func inArr(a []string, t string) bool {
	for _, s := range a {
		if t == s {
			return true
		}
	}
	return false
}

func validHost(s string) string {
	s = strings.Trim(s, ".")
	parts := strings.Split(s, DomainSep)
	if len(parts) < 2 {
		return ""
	}
	for i := 0; i < len(parts)-1; {
		switch {
		case len(parts[i]) < 1:
			parts = append(parts[:i], parts[i+1:]...)
		case isNotAlphaNum.MatchString(parts[i]):
			return ""
		default:
			i++
		}
	}
	return strings.Join(parts, DomainSep)
}

func confCheck(host, ip string, destTLS bool, port int,
	blockedHeaders []string, ipList []*net.IPNet) (siteParams, Err) {
	var conf siteParams
	if conf.IntHost = validHost(host); conf.IntHost == "" {
		return siteParams{}, &NewErr{Code: ErrBadHost, value: host}
	}

	tempIP := net.ParseIP(ip)
	if tempIP == nil {
		return siteParams{}, &NewErr{Code: ErrBadIP, value: ip}
	}
	if len(ipList) > 0 && !ipListContains(tempIP, ipList) {
		return siteParams{}, &NewErr{Code: ErrBlockedIP, value: tempIP.String()}
	}

	conf.IntPort = 80
	if port > 0 && port < MaxAllowedPort {
		conf.IntPort = port
	}

	conf.IntIP = tempIP.String()
	conf.Encrypted = destTLS
	conf.StripHeaders = blockedHeaders

	return conf, nil
}

func confWrite(config HandlerConfig) func(siteParams) (siteParams, Err) {

	return func(siteConfig siteParams) (siteParams, Err) {

		err := os.ErrExist
		var randPart, fileName string
		var f *os.File

		for os.IsExist(err) {
			randPart = uniuri.NewLenChars(config.subdomainLen, SubdomainChars)
			// pick again if you got something reserved
			if inArr(config.exclude, randPart) {
				continue
			}
			if inArr(config.exclude, randPart+DomainSep+config.baseURL) {
				continue
			}
			fileName = strings.Join([]string{
				strings.TrimRight(config.confPath, PathSep),
				PathSep,
				randPart,
				DomainSep,
				config.baseURL,
				DomainSep,
				strings.TrimLeft(config.confExt, DomainSep)}, "")
			f, err = os.Create(fileName)
		}

		siteConfig.ExtHost = strings.Join([]string{
			randPart,
			DomainSep,
			config.baseURL}, "")

		if err == os.ErrPermission {
			return siteParams{ExtHost: randPart}, &NewErr{Code: ErrFilePerm, value: fileName, deepErr: err}
		} else if err != nil {
			return siteParams{ExtHost: randPart}, &NewErr{Code: ErrFileUnexpect, value: fileName, deepErr: err}
		}

		tErr := config.confTempl.Execute(f, siteConfig)

		if err = f.Close(); err != nil {
			return siteParams{}, &NewErr{Code: ErrCloseFile, value: fileName, deepErr: err}
		}

		if tErr != nil {
			if err = os.Remove(fileName); err != nil {
				return siteParams{}, &NewErr{Code: ErrRemoveFile, value: fileName, deepErr: err}
			}
		}

		return siteConfig, nil
	}
}

func parseCheckbox(in string) bool {
	checkedValues := []string{
		"true",
		"checked",
		"on",
		"yes",
		"y",
		"1",
	}

	for _, each := range checkedValues {
		if each == in {
			return true
		}
	}
	return false
}

func parseIPList(ipFile string) ([]*net.IPNet, Err) {
	file, err := os.Open(ipFile)
	if err != nil {
		return []*net.IPNet{}, NewErr{
			Code:    ErrConfigBadIPFile,
			value:   ipFile,
			deepErr: err,
		}
	}

	var out []*net.IPNet

	s := bufio.NewScanner(file)

	for s.Scan() {
		t := strings.TrimSpace(s.Text())
		switch {
		case strings.HasPrefix(t, "//"):
		case strings.HasPrefix(t, "#"):
		case strings.HasPrefix(t, ";"):
		default:
			_, ipNet, err := net.ParseCIDR(s.Text())
			if err == nil {
				out = append(out, ipNet)
			}
		}
	}
	return out, nil
}

func ipListContains(address net.IP, list []*net.IPNet) bool {
	for _, each := range list {
		if each.Contains(address) {
			return true
		}
	}
	return false
}

func redirectTrace(initURL string, initPort int) (string, int, Err) {
	resp, err := http.Head(fmt.Sprintf("http://%s:%d/", initURL, initPort))
	if err != nil {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: err,
		}
	}

	var respHost string
	var respPort int

	if resp.Request == nil {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: fmt.Errorf("did not get a request back from %s", initURL),
		}
	}

	var hostname string
	if resp.Request.Host != "" {
		hostname = resp.Request.Host
	} else if resp.Request.URL != nil {
		hostname = resp.Request.URL.Host
	} else {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: fmt.Errorf("cound not find the URL"),
		}
	}

	if strings.Contains(hostname, ":") {
		parts := strings.Split(hostname, ":")
		respPort, err = strconv.Atoi(parts[len(parts)-1])
		if err != nil {
			respHost = resp.Request.Host
		} else {
			respHost = strings.Join(parts[:len(parts)-1], ":")
		}
	} else {
		respHost = hostname
		if resp.TLS == nil {
			respPort = 80
		} else {
			respPort = 443
		}
	}

	return respHost, respPort, nil
}
<commit_msg>before I was not honoring the http/https when starting - fixed that<commit_after>package moxxiConf

import (
	"bufio"
	"fmt"
	"github.com/dchest/uniuri"
	"net"
	"net/http"
	"os"
	"strconv"
	"strings"
)

func inArr(a []string, t string) bool {
	for _, s := range a {
		if t == s {
			return true
		}
	}
	return false
}

func validHost(s string) string {
	s = strings.Trim(s, ".")
	parts := strings.Split(s, DomainSep)
	if len(parts) < 2 {
		return ""
	}
	for i := 0; i < len(parts)-1; {
		switch {
		case len(parts[i]) < 1:
			parts = append(parts[:i], parts[i+1:]...)
		case isNotAlphaNum.MatchString(parts[i]):
			return ""
		default:
			i++
		}
	}
	return strings.Join(parts, DomainSep)
}

func confCheck(host, ip string, destTLS bool, port int,
	blockedHeaders []string, ipList []*net.IPNet) (siteParams, Err) {
	var conf siteParams
	if conf.IntHost = validHost(host); conf.IntHost == "" {
		return siteParams{}, &NewErr{Code: ErrBadHost, value: host}
	}

	tempIP := net.ParseIP(ip)
	if tempIP == nil {
		return siteParams{}, &NewErr{Code: ErrBadIP, value: ip}
	}
	if len(ipList) > 0 && !ipListContains(tempIP, ipList) {
		return siteParams{}, &NewErr{Code: ErrBlockedIP, value: tempIP.String()}
	}

	conf.IntPort = 80
	if port > 0 && port < MaxAllowedPort {
		conf.IntPort = port
	}

	conf.IntIP = tempIP.String()
	conf.Encrypted = destTLS
	conf.StripHeaders = blockedHeaders

	return conf, nil
}

func confWrite(config HandlerConfig) func(siteParams) (siteParams, Err) {

	return func(siteConfig siteParams) (siteParams, Err) {

		err := os.ErrExist
		var randPart, fileName string
		var f *os.File

		for os.IsExist(err) {
			randPart = uniuri.NewLenChars(config.subdomainLen, SubdomainChars)
			// pick again if you got something reserved
			if inArr(config.exclude, randPart) {
				continue
			}
			if inArr(config.exclude, randPart+DomainSep+config.baseURL) {
				continue
			}
			fileName = strings.Join([]string{
				strings.TrimRight(config.confPath, PathSep),
				PathSep,
				randPart,
				DomainSep,
				config.baseURL,
				DomainSep,
				strings.TrimLeft(config.confExt, DomainSep)}, "")
			f, err = os.Create(fileName)
		}

		siteConfig.ExtHost = strings.Join([]string{
			randPart,
			DomainSep,
			config.baseURL}, "")

		if err == os.ErrPermission {
			return siteParams{ExtHost: randPart}, &NewErr{Code: ErrFilePerm, value: fileName, deepErr: err}
		} else if err != nil {
			return siteParams{ExtHost: randPart}, &NewErr{Code: ErrFileUnexpect, value: fileName, deepErr: err}
		}

		tErr := config.confTempl.Execute(f, siteConfig)

		if err = f.Close(); err != nil {
			return siteParams{}, &NewErr{Code: ErrCloseFile, value: fileName, deepErr: err}
		}

		if tErr != nil {
			if err = os.Remove(fileName); err != nil {
				return siteParams{}, &NewErr{Code: ErrRemoveFile, value: fileName, deepErr: err}
			}
		}

		return siteConfig, nil
	}
}

func parseCheckbox(in string) bool {
	checkedValues := []string{
		"true",
		"checked",
		"on",
		"yes",
		"y",
		"1",
	}

	for _, each := range checkedValues {
		if each == in {
			return true
		}
	}
	return false
}

func parseIPList(ipFile string) ([]*net.IPNet, Err) {
	file, err := os.Open(ipFile)
	if err != nil {
		return []*net.IPNet{}, NewErr{
			Code:    ErrConfigBadIPFile,
			value:   ipFile,
			deepErr: err,
		}
	}

	var out []*net.IPNet

	s := bufio.NewScanner(file)

	for s.Scan() {
		t := strings.TrimSpace(s.Text())
		switch {
		case strings.HasPrefix(t, "//"):
		case strings.HasPrefix(t, "#"):
		case strings.HasPrefix(t, ";"):
		default:
			_, ipNet, err := net.ParseCIDR(s.Text())
			if err == nil {
				out = append(out, ipNet)
			}
		}
	}
	return out, nil
}

func ipListContains(address net.IP, list []*net.IPNet) bool {
	for _, each := range list {
		if each.Contains(address) {
			return true
		}
	}
	return false
}

func redirectTrace(initHost string, initPort int) (string, int, Err) {

	var initURL string
	if initPort == 443 {
		initURL = (fmt.Sprintf("https://%s:%d/", initHost, initPort))
	} else {
		initURL = (fmt.Sprintf("http://%s:%d/", initHost, initPort))
	}

	resp, err := http.Head(initURL)
	if err != nil {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: err,
		}
	}

	var respHost string
	var respPort int

	if resp.Request == nil {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: fmt.Errorf("did not get a request back from %s", initURL),
		}
	}

	var hostname string
	if resp.Request.Host != "" {
		hostname = resp.Request.Host
	} else if resp.Request.URL != nil {
		hostname = resp.Request.URL.Host
	} else {
		return "", 0, NewErr{
			Code:    ErrBadHostnameTrace,
			value:   initURL,
			deepErr: fmt.Errorf("cound not find the URL"),
		}
	}

	if strings.Contains(hostname, ":") {
		parts := strings.Split(hostname, ":")
		respPort, err = strconv.Atoi(parts[len(parts)-1])
		if err != nil {
			respHost = resp.Request.Host
		} else {
			respHost = strings.Join(parts[:len(parts)-1], ":")
		}
	} else {
		respHost = hostname
		if resp.TLS == nil {
			respPort = 80
		} else {
			respPort = 443
		}
	}

	return respHost, respPort, nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/jessevdk/go-flags"
	"os"
)

var parser = flags.NewNamedParser("docket", flags.Default | flags.HelpFlag)

var EXIT_BADARGS = 1
var EXIT_PANIC = 2

func main() {
	_, err := parser.Parse()
	if err != nil {
		os.Exit(EXIT_BADARGS)
	}
	os.Exit(0)
}

func init() {
	// parser.AddCommand(
	// 	"command",
	// 	"description",
	// 	"long description",
	// 	&whateverCmd{}
	// )
	parser.AddCommand(
		"run",
		"Run a container",
		"Run a container based on configuration in the current directory.",
		&runCmdOpts{},
	)
	parser.AddCommand(
		"build",
		"Transform a container",
		"Transform a container based on configuration in the current directory.",
		&buildCmdOpts{},
	)
}
<commit_msg>Added help command & default help action.<commit_after>package main

import (
	"github.com/jessevdk/go-flags"
	"os"
)

var parser = flags.NewNamedParser("docket", flags.Default | flags.HelpFlag)

var EXIT_BADARGS = 1
var EXIT_PANIC = 2

func main() {
	//Go-flags is a little too clever with sub-commands.
	//To keep the help-command parity with git & docker / etc, check for 'help' manually before args parse
	if len(os.Args) < 2 || os.Args[1] == "help" {
		parser.WriteHelp(os.Stdout)
		os.Exit(0)
	}

	//Parse for command & flags, and exit with a relevant return code.
	_, err := parser.Parse()
	if err != nil {
		os.Exit(EXIT_BADARGS)
	} else {
		os.Exit(0)
	}
}

func init() {
	// parser.AddCommand(
	// 	"command",
	// 	"description",
	// 	"long description",
	// 	&whateverCmd{}
	// )
	parser.AddCommand(
		"run",
		"Run a container",
		"Run a container based on configuration in the current directory.",
		&runCmdOpts{},
	)
	parser.AddCommand(
		"build",
		"Transform a container",
		"Transform a container based on configuration in the current directory.",
		&buildCmdOpts{},
	)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"../interpreter"
	"../lua"
)

func setLuaArg(L lua.Lua, arg0 string) {
	L.NewTable()
	L.PushString(arg0)
	L.RawSetI(-2, 0)
	for i, arg1 := range flag.Args() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i+1))
	}
	L.SetGlobal("arg")
}

func optionParse(it *interpreter.Interpreter, L lua.Lua) bool {
	result := true

	if *optionK != "" {
		it.Interpret(*optionK)
	}
	if *optionC != "" {
		it.Interpret(*optionC)
		result = false
	}
	if *optionF != "" {
		setLuaArg(L, *optionF)
		err := L.Source(*optionF)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		}
		result = false
	}
	if *optionE != "" {
		err := L.LoadString(*optionE)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		} else {
			setLuaArg(L, *optionE)
			L.Call(0, 0)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		}
		result = false
	}
	return result
}
<commit_msg>Support nyagos -f COMMANDTEXT whose suffix is not .lua (close #131)<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"

	"../interpreter"
	"../lua"
)

func setLuaArg(L lua.Lua, arg0 string) {
	L.NewTable()
	L.PushString(arg0)
	L.RawSetI(-2, 0)
	for i, arg1 := range flag.Args() {
		L.PushString(arg1)
		L.RawSetI(-2, lua.Integer(i+1))
	}
	L.SetGlobal("arg")
}

func optionParse(it *interpreter.Interpreter, L lua.Lua) bool {
	result := true

	if *optionK != "" {
		it.Interpret(*optionK)
	}
	if *optionC != "" {
		it.Interpret(*optionC)
		result = false
	}
	if *optionF != "" {
		if strings.HasSuffix(strings.ToLower(*optionF), ".lua") {
			// lua script
			setLuaArg(L, *optionF)
			err := L.Source(*optionF)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		} else {
			// command script
			fd, fd_err := os.Open(*optionF)
			if fd_err != nil {
				fmt.Fprintf(os.Stderr, "%s: %s\n", *optionF, fd_err.Error())
			} else {
				scanner := bufio.NewScanner(fd)
				for scanner.Scan() {
					it.Interpret(scanner.Text())
				}
				fd.Close()
			}
		}
		result = false
	}
	if *optionE != "" {
		err := L.LoadString(*optionE)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
		} else {
			setLuaArg(L, *optionE)
			L.Call(0, 0)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		}
		result = false
	}
	return result
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strings"

	"github.com/ava-labs/go-ethereum/p2p/nat"

	"github.com/ava-labs/gecko/database/leveldb"
	"github.com/ava-labs/gecko/database/memdb"
	"github.com/ava-labs/gecko/genesis"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/node"
	"github.com/ava-labs/gecko/snow/networking/router"
	"github.com/ava-labs/gecko/utils"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/hashing"
	"github.com/ava-labs/gecko/utils/logging"
	"github.com/ava-labs/gecko/utils/wrappers"
)

// Results of parsing the CLI
var (
	Config = node.Config{}
	Err    error
)

// GetIPs returns the default IPs for each network
func GetIPs(networkID uint32) []string {
	switch networkID {
	case genesis.CascadeID:
		return []string{
			"3.227.207.132:21001",
			"34.207.133.167:21001",
			"107.23.241.199:21001",
			"54.197.215.186:21001",
			"18.234.153.22:21001",
		}
	default:
		return nil
	}
}

var (
	errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs")
)

// Parse the CLI arguments
func init() {
	errs := &wrappers.Errs{}
	defer func() { Err = errs.Err }()

	loggingConfig, err := logging.DefaultConfig()
	errs.Add(err)

	fs := flag.NewFlagSet("gecko", flag.ContinueOnError)

	// NetworkID:
	networkName := fs.String("network-id", genesis.CascadeName, "Network ID this node will connect to")

	// Ava fees:
	fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva")

	// Assertions:
	fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution")

	// Crypto:
	fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification")

	// Database:
	db := fs.Bool("db-enabled", true, "Turn on persistent storage")
	dbDir := fs.String("db-dir", "db", "Database directory for Ava state")

	// IP:
	consensusIP := fs.String("public-ip", "", "Public IP of this node")

	// HTTP Server:
	httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server")
	fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs")
	fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server")
	fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server")

	// Bootstrapping:
	bootstrapIPs := fs.String("bootstrap-ips", "default", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631")
	bootstrapIDs := fs.String("bootstrap-ids", "default", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")

	// Staking:
	consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server")
	fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections")
	fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "keys/staker.key", "TLS private key file for staking connections")
	fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "keys/staker.crt", "TLS certificate file for staking connections")

	// Logging:
	logsDir := fs.String("log-dir", "", "Logging directory for Ava")
	logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}")
	logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}")

	fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 5, "Number of nodes to query for each network poll")
	fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 4, "Alpha value to use for required number positive results")
	fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions")
	fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions")
	fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex")
	fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex")
	fs.IntVar(&Config.ConsensusParams.ConcurrentRepolls, "snow-concurrent-repolls", 1, "Minimum number of concurrent polls for finalizing consensus")

	// Enable/Disable APIs:
	fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
	fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
	fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
	fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened")

	// Throughput Server
	throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server")
	fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created")

	ferr := fs.Parse(os.Args[1:])

	if ferr == flag.ErrHelp {
		// display usage/help text and exit successfully
		os.Exit(0)
	}

	if ferr != nil {
		// other type of error occurred when parsing args
		os.Exit(2)
	}

	networkID, err := genesis.NetworkID(*networkName)
	errs.Add(err)

	Config.NetworkID = networkID

	// DB:
	if *db && err == nil {
		// TODO: Add better params here
		dbPath := path.Join(*dbDir, genesis.NetworkName(Config.NetworkID))
		db, err := leveldb.New(dbPath, 0, 0, 0)
		Config.DB = db
		errs.Add(err)
	} else {
		Config.DB = memdb.New()
	}

	Config.Nat = nat.Any()

	var ip net.IP
	// If public IP is not specified, get it using shell command dig
	if *consensusIP == "" {
		ip, err = Config.Nat.ExternalIP()
		errs.Add(fmt.Errorf("%s\nIf you are trying to create a local network, try adding --public-ip=127.0.0.1", err))
	} else {
		ip = net.ParseIP(*consensusIP)
	}

	if ip == nil {
		errs.Add(fmt.Errorf("Invalid IP Address %s", *consensusIP))
	}
	Config.StakingIP = utils.IPDesc{
		IP:   ip,
		Port: uint16(*consensusPort),
	}

	// Bootstrapping:
	if *bootstrapIPs == "default" {
		*bootstrapIPs = strings.Join(GetIPs(networkID), ",")
	}
	for _, ip := range strings.Split(*bootstrapIPs, ",") {
		if ip != "" {
			addr, err := utils.ToIPDesc(ip)
			errs.Add(err)
			Config.BootstrapPeers = append(Config.BootstrapPeers, &node.Peer{
				IP: addr,
			})
		}
	}

	if *bootstrapIDs == "default" {
		if *bootstrapIPs == "" {
			*bootstrapIDs = ""
		} else {
			*bootstrapIDs = strings.Join(genesis.GetConfig(networkID).StakerIDs, ",")
		}
	}
	if Config.EnableStaking {
		i := 0
		cb58 := formatting.CB58{}
		for _, id := range strings.Split(*bootstrapIDs, ",") {
			if id != "" {
				errs.Add(cb58.FromString(id))
				cert, err := ids.ToShortID(cb58.Bytes)
				errs.Add(err)

				if len(Config.BootstrapPeers) <= i {
					errs.Add(errBootstrapMismatch)
					continue
				}
				Config.BootstrapPeers[i].ID = cert
				i++
			}
		}
		if len(Config.BootstrapPeers) != i {
			errs.Add(fmt.Errorf("More bootstrap IPs, %d, provided than bootstrap IDs, %d", len(Config.BootstrapPeers), i))
		}
	} else {
		for _, peer := range Config.BootstrapPeers {
			peer.ID = ids.NewShortID(hashing.ComputeHash160Array([]byte(peer.IP.String())))
		}
	}

	// HTTP:
	Config.HTTPPort = uint16(*httpPort)

	// Logging:
	if *logsDir != "" {
		loggingConfig.Directory = *logsDir
	}
	logFileLevel, err := logging.ToLevel(*logLevel)
	errs.Add(err)
	loggingConfig.LogLevel = logFileLevel

	if *logDisplayLevel == "" {
		*logDisplayLevel = *logLevel
	}
	displayLevel, err := logging.ToLevel(*logDisplayLevel)
	errs.Add(err)
	loggingConfig.DisplayLevel = displayLevel

	Config.LoggingConfig = loggingConfig

	// Throughput:
	Config.ThroughputPort = uint16(*throughputPort)

	// Router used for consensus
	Config.ConsensusRouter = &router.ChainRouter{}
}
<commit_msg>Changed defaults for pre-release<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"os"
	"path"
	"strings"

	"github.com/ava-labs/go-ethereum/p2p/nat"

	"github.com/ava-labs/gecko/database/leveldb"
	"github.com/ava-labs/gecko/database/memdb"
	"github.com/ava-labs/gecko/genesis"
	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/node"
	"github.com/ava-labs/gecko/snow/networking/router"
	"github.com/ava-labs/gecko/utils"
	"github.com/ava-labs/gecko/utils/formatting"
	"github.com/ava-labs/gecko/utils/hashing"
	"github.com/ava-labs/gecko/utils/logging"
	"github.com/ava-labs/gecko/utils/wrappers"
)

// Results of parsing the CLI
var (
	Config = node.Config{}
	Err    error
)

// GetIPs returns the default IPs for each network
func GetIPs(networkID uint32) []string {
	switch networkID {
	default:
		return nil
	}
}

var (
	errBootstrapMismatch = errors.New("more bootstrap IDs provided than bootstrap IPs")
)

// Parse the CLI arguments
func init() {
	errs := &wrappers.Errs{}
	defer func() { Err = errs.Err }()

	loggingConfig, err := logging.DefaultConfig()
	errs.Add(err)

	fs := flag.NewFlagSet("gecko", flag.ContinueOnError)

	// NetworkID:
	networkName := fs.String("network-id", genesis.LocalName, "Network ID this node will connect to")

	// Ava fees:
	fs.Uint64Var(&Config.AvaTxFee, "ava-tx-fee", 0, "Ava transaction fee, in $nAva")

	// Assertions:
	fs.BoolVar(&loggingConfig.Assertions, "assertions-enabled", true, "Turn on assertion execution")

	// Crypto:
	fs.BoolVar(&Config.EnableCrypto, "signature-verification-enabled", true, "Turn on signature verification")

	// Database:
	db := fs.Bool("db-enabled", true, "Turn on persistent storage")
	dbDir := fs.String("db-dir", "db", "Database directory for Ava state")

	// IP:
	consensusIP := fs.String("public-ip", "", "Public IP of this node")

	// HTTP Server:
	httpPort := fs.Uint("http-port", 9650, "Port of the HTTP server")
	fs.BoolVar(&Config.EnableHTTPS, "http-tls-enabled", false, "Upgrade the HTTP server to HTTPs")
	fs.StringVar(&Config.HTTPSKeyFile, "http-tls-key-file", "", "TLS private key file for the HTTPs server")
	fs.StringVar(&Config.HTTPSCertFile, "http-tls-cert-file", "", "TLS certificate file for the HTTPs server")

	// Bootstrapping:
	bootstrapIPs := fs.String("bootstrap-ips", "default", "Comma separated list of bootstrap peer ips to connect to. Example: 127.0.0.1:9630,127.0.0.1:9631")
	bootstrapIDs := fs.String("bootstrap-ids", "default", "Comma separated list of bootstrap peer ids to connect to. Example: JR4dVmy6ffUGAKCBDkyCbeZbyHQBeDsET,8CrVPQZ4VSqgL8zTdvL14G8HqAfrBr4z")

	// Staking:
	consensusPort := fs.Uint("staking-port", 9651, "Port of the consensus server")
	fs.BoolVar(&Config.EnableStaking, "staking-tls-enabled", true, "Require TLS to authenticate staking connections")
	fs.StringVar(&Config.StakingKeyFile, "staking-tls-key-file", "keys/staker.key", "TLS private key file for staking connections")
	fs.StringVar(&Config.StakingCertFile, "staking-tls-cert-file", "keys/staker.crt", "TLS certificate file for staking connections")

	// Logging:
	logsDir := fs.String("log-dir", "", "Logging directory for Ava")
	logLevel := fs.String("log-level", "info", "The log level. Should be one of {verbo, debug, info, warn, error, fatal, off}")
	logDisplayLevel := fs.String("log-display-level", "", "The log display level. If left blank, will inherit the value of log-level. Otherwise, should be one of {verbo, debug, info, warn, error, fatal, off}")

	fs.IntVar(&Config.ConsensusParams.K, "snow-sample-size", 5, "Number of nodes to query for each network poll")
	fs.IntVar(&Config.ConsensusParams.Alpha, "snow-quorum-size", 4, "Alpha value to use for required number positive results")
	fs.IntVar(&Config.ConsensusParams.BetaVirtuous, "snow-virtuous-commit-threshold", 20, "Beta value to use for virtuous transactions")
	fs.IntVar(&Config.ConsensusParams.BetaRogue, "snow-rogue-commit-threshold", 30, "Beta value to use for rogue transactions")
	fs.IntVar(&Config.ConsensusParams.Parents, "snow-avalanche-num-parents", 5, "Number of vertexes for reference from each new vertex")
	fs.IntVar(&Config.ConsensusParams.BatchSize, "snow-avalanche-batch-size", 30, "Number of operations to batch in each new vertex")
	fs.IntVar(&Config.ConsensusParams.ConcurrentRepolls, "snow-concurrent-repolls", 1, "Minimum number of concurrent polls for finalizing consensus")

	// Enable/Disable APIs:
	fs.BoolVar(&Config.AdminAPIEnabled, "api-admin-enabled", true, "If true, this node exposes the Admin API")
	fs.BoolVar(&Config.KeystoreAPIEnabled, "api-keystore-enabled", true, "If true, this node exposes the Keystore API")
	fs.BoolVar(&Config.MetricsAPIEnabled, "api-metrics-enabled", true, "If true, this node exposes the Metrics API")
	fs.BoolVar(&Config.IPCEnabled, "api-ipcs-enabled", false, "If true, IPCs can be opened")

	// Throughput Server
	throughputPort := fs.Uint("xput-server-port", 9652, "Port of the deprecated throughput test server")
	fs.BoolVar(&Config.ThroughputServerEnabled, "xput-server-enabled", false, "If true, throughput test server is created")

	ferr := fs.Parse(os.Args[1:])

	if ferr == flag.ErrHelp {
		// display usage/help text and exit successfully
		os.Exit(0)
	}

	if ferr != nil {
		// other type of error occurred when parsing args
		os.Exit(2)
	}

	networkID, err := genesis.NetworkID(*networkName)
	errs.Add(err)

	Config.NetworkID = networkID

	// DB:
	if *db && err == nil {
		// TODO: Add better params here
		dbPath := path.Join(*dbDir, genesis.NetworkName(Config.NetworkID))
		db, err := leveldb.New(dbPath, 0, 0, 0)
		Config.DB = db
		errs.Add(err)
	} else {
		Config.DB = memdb.New()
	}

	Config.Nat = nat.Any()

	var ip net.IP
	// If public IP is not specified, get it using shell command dig
	if *consensusIP == "" {
		ip, err = Config.Nat.ExternalIP()
		errs.Add(fmt.Errorf("%s\nIf you are trying to create a local network, try adding --public-ip=127.0.0.1", err))
	} else {
		ip = net.ParseIP(*consensusIP)
	}

	if ip == nil {
		errs.Add(fmt.Errorf("Invalid IP Address %s", *consensusIP))
	}
	Config.StakingIP = utils.IPDesc{
		IP:   ip,
		Port: uint16(*consensusPort),
	}

	// Bootstrapping:
	if *bootstrapIPs == "default" {
		*bootstrapIPs = strings.Join(GetIPs(networkID), ",")
	}
	for _, ip := range strings.Split(*bootstrapIPs, ",") {
		if ip != "" {
			addr, err := utils.ToIPDesc(ip)
			errs.Add(err)
			Config.BootstrapPeers = append(Config.BootstrapPeers, &node.Peer{
				IP: addr,
			})
		}
	}

	if *bootstrapIDs == "default" {
		if *bootstrapIPs == "" {
			*bootstrapIDs = ""
		} else {
			*bootstrapIDs = strings.Join(genesis.GetConfig(networkID).StakerIDs, ",")
		}
	}
	if Config.EnableStaking {
		i := 0
		cb58 := formatting.CB58{}
		for _, id := range strings.Split(*bootstrapIDs, ",") {
			if id != "" {
				errs.Add(cb58.FromString(id))
				cert, err := ids.ToShortID(cb58.Bytes)
				errs.Add(err)

				if len(Config.BootstrapPeers) <= i {
					errs.Add(errBootstrapMismatch)
					continue
				}
				Config.BootstrapPeers[i].ID = cert
				i++
			}
		}
		if len(Config.BootstrapPeers) != i {
			errs.Add(fmt.Errorf("More bootstrap IPs, %d, provided than bootstrap IDs, %d", len(Config.BootstrapPeers), i))
		}
	} else {
		for _, peer := range Config.BootstrapPeers {
			peer.ID = ids.NewShortID(hashing.ComputeHash160Array([]byte(peer.IP.String())))
		}
	}

	// HTTP:
	Config.HTTPPort = uint16(*httpPort)

	// Logging:
	if *logsDir != "" {
		loggingConfig.Directory = *logsDir
	}
	logFileLevel, err := logging.ToLevel(*logLevel)
	errs.Add(err)
	loggingConfig.LogLevel = logFileLevel

	if *logDisplayLevel == "" {
		*logDisplayLevel = *logLevel
	}
	displayLevel, err := logging.ToLevel(*logDisplayLevel)
	errs.Add(err)
	loggingConfig.DisplayLevel = displayLevel

	Config.LoggingConfig = loggingConfig

	// Throughput:
	Config.ThroughputPort = uint16(*throughputPort)

	// Router used for consensus
	Config.ConsensusRouter = &router.ChainRouter{}
}
<|endoftext|>


<commit_before>package helpers

import (
	"encoding/json"
	"os"
	"path/filepath"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
)

type Config struct {
	ApiEndpoint  string `json:"api"`
	SystemDomain string `json:"system_domain"`
	ClientSecret string `json:"client_secret"`
	AppsDomain   string `json:"apps_domain"`
	UseHttp      bool   `json:"use_http"`

	AdminUser     string `json:"admin_user"`
	AdminPassword string `json:"admin_password"`

	UseExistingUser      bool   `json:"use_existing_user"`
	ShouldKeepUser       bool   `json:"keep_user_at_suite_end"`
	ExistingUser         string `json:"existing_user"`
	ExistingUserPassword string `json:"existing_user_password"`

	ConfigurableTestPassword string `json:"test_password"`

	PersistentAppHost      string `json:"persistent_app_host"`
	PersistentAppSpace     string `json:"persistent_app_space"`
	PersistentAppOrg       string `json:"persistent_app_org"`
	PersistentAppQuotaName string `json:"persistent_app_quota_name"`

	SkipSSLValidation bool `json:"skip_ssl_validation"`
	UseDiego          bool `json:"use_diego"`

	ArtifactsDirectory string `json:"artifacts_directory"`

	DefaultTimeout     time.Duration `json:"default_timeout"`
	DetectTimeout      time.Duration `json:"detect_timeout"`
	CfPushTimeout      time.Duration `json:"cf_push_timeout"`
	LongCurlTimeout    time.Duration `json:"long_curl_timeout"`
	BrokerStartTimeout time.Duration `json:"broker_start_timeout"`

	TimeoutScale float64 `json:"timeout_scale"`

	SyslogDrainPort int    `json:"syslog_drain_port"`
	SyslogIpAddress string `json:"syslog_ip_address"`

	SecureAddress string `json:"secure_address"`

	DockerExecutable      string   `json:"docker_executable"`
	DockerParameters      []string `json:"docker_parameters"`
	DockerRegistryAddress string   `json:"docker_registry_address"`
	DockerPrivateImage    string   `json:"docker_private_image"`
	DockerUser            string   `json:"docker_user"`
	DockerPassword        string   `json:"docker_password"`
	DockerEmail           string   `json:"docker_email"`

	StaticFileBuildpackName string `json:"staticfile_buildpack_name"`
	JavaBuildpackName       string `json:"java_buildpack_name"`
	RubyBuildpackName       string `json:"ruby_buildpack_name"`
	NodejsBuildpackName     string `json:"nodejs_buildpack_name"`
	GoBuildpackName         string `json:"go_buildpack_name"`
	PythonBuildpackName     string `json:"python_buildpack_name"`
	PhpBuildpackName        string `json:"php_buildpack_name"`
	BinaryBuildpackName     string `json:"binary_buildpack_name"`
}

func (c Config) ScaledTimeout(timeout time.Duration) time.Duration {
	return time.Duration(float64(timeout) * c.TimeoutScale)
}

var loadedConfig *Config

func LoadConfig() Config {
	if loadedConfig == nil {
		loadedConfig = loadConfigJsonFromPath()
	}

	if loadedConfig.ApiEndpoint == "" {
		panic("missing configuration 'api'")
	}

	if loadedConfig.AdminUser == "" {
		panic("missing configuration 'admin_user'")
	}

	if loadedConfig.ApiEndpoint == "" {
		panic("missing configuration 'admin_password'")
	}

	if loadedConfig.TimeoutScale <= 0 {
		loadedConfig.TimeoutScale = 1.0
	}

	runner.SkipSSLValidation = loadedConfig.SkipSSLValidation

	return *loadedConfig
}

func (c Config) Protocol() string {
	if c.UseHttp {
		return "http://"
	} else {
		return "https://"
	}
}

func loadConfigJsonFromPath() *Config {
	var config *Config = &Config{
		PersistentAppHost:      "CATS-persistent-app",
		PersistentAppSpace:     "CATS-persistent-space",
		PersistentAppOrg:       "CATS-persistent-org",
		PersistentAppQuotaName: "CATS-persistent-quota",

		StaticFileBuildpackName: "staticfile_buildpack",
		JavaBuildpackName:       "java_buildpack",
		RubyBuildpackName:       "ruby_buildpack",
		NodejsBuildpackName:     "nodejs_buildpack",
		GoBuildpackName:         "go_buildpack",
		PythonBuildpackName:     "python_buildpack",
		PhpBuildpackName:        "php_buildpack",
		BinaryBuildpackName:     "binary_buildpack",

		ArtifactsDirectory: filepath.Join("..", "results"),
	}

	path := configPath()

	configFile, err := os.Open(path)
	if err != nil {
		panic(err)
	}

	decoder := json.NewDecoder(configFile)
	err = decoder.Decode(config)
	if err != nil {
		panic(err)
	}

	return config
}

func configPath() string {
	path := os.Getenv("CONFIG")
	if path == "" {
		panic("Must set $CONFIG to point to an integration config .json file.")
	}

	return path
}
<commit_msg>Add include_route_services flag<commit_after>package helpers

import (
	"encoding/json"
	"os"
	"path/filepath"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/runner"
)

type Config struct {
	ApiEndpoint  string `json:"api"`
	SystemDomain string `json:"system_domain"`
	ClientSecret string `json:"client_secret"`
	AppsDomain   string `json:"apps_domain"`
	UseHttp      bool   `json:"use_http"`

	AdminUser     string `json:"admin_user"`
	AdminPassword string `json:"admin_password"`

	UseExistingUser      bool   `json:"use_existing_user"`
	ShouldKeepUser       bool   `json:"keep_user_at_suite_end"`
	ExistingUser         string `json:"existing_user"`
	ExistingUserPassword string `json:"existing_user_password"`

	ConfigurableTestPassword string `json:"test_password"`

	PersistentAppHost      string `json:"persistent_app_host"`
	PersistentAppSpace     string `json:"persistent_app_space"`
	PersistentAppOrg       string `json:"persistent_app_org"`
	PersistentAppQuotaName string `json:"persistent_app_quota_name"`

	SkipSSLValidation    bool `json:"skip_ssl_validation"`
	UseDiego             bool `json:"use_diego"`
	IncludeRouteServices bool `json:"include_route_services"`

	ArtifactsDirectory string `json:"artifacts_directory"`

	DefaultTimeout     time.Duration `json:"default_timeout"`
	DetectTimeout      time.Duration `json:"detect_timeout"`
	CfPushTimeout      time.Duration `json:"cf_push_timeout"`
	LongCurlTimeout    time.Duration `json:"long_curl_timeout"`
	BrokerStartTimeout time.Duration `json:"broker_start_timeout"`

	TimeoutScale float64 `json:"timeout_scale"`

	SyslogDrainPort int    `json:"syslog_drain_port"`
	SyslogIpAddress string `json:"syslog_ip_address"`

	SecureAddress string `json:"secure_address"`

	DockerExecutable      string   `json:"docker_executable"`
	DockerParameters      []string `json:"docker_parameters"`
	DockerRegistryAddress string   `json:"docker_registry_address"`
	DockerPrivateImage    string   `json:"docker_private_image"`
	DockerUser            string   `json:"docker_user"`
	DockerPassword        string   `json:"docker_password"`
	DockerEmail           string   `json:"docker_email"`

	StaticFileBuildpackName string `json:"staticfile_buildpack_name"`
	JavaBuildpackName       string `json:"java_buildpack_name"`
	RubyBuildpackName       string `json:"ruby_buildpack_name"`
	NodejsBuildpackName     string `json:"nodejs_buildpack_name"`
	GoBuildpackName         string `json:"go_buildpack_name"`
	PythonBuildpackName     string `json:"python_buildpack_name"`
	PhpBuildpackName        string `json:"php_buildpack_name"`
	BinaryBuildpackName     string `json:"binary_buildpack_name"`
}

func (c Config) ScaledTimeout(timeout time.Duration) time.Duration {
	return time.Duration(float64(timeout) * c.TimeoutScale)
}

var loadedConfig *Config

func LoadConfig() Config {
	if loadedConfig == nil {
		loadedConfig = loadConfigJsonFromPath()
	}

	if loadedConfig.ApiEndpoint == "" {
		panic("missing configuration 'api'")
	}

	if loadedConfig.AdminUser == "" {
		panic("missing configuration 'admin_user'")
	}

	if loadedConfig.ApiEndpoint == "" {
		panic("missing configuration 'admin_password'")
	}

	if loadedConfig.TimeoutScale <= 0 {
		loadedConfig.TimeoutScale = 1.0
	}

	runner.SkipSSLValidation = loadedConfig.SkipSSLValidation

	return *loadedConfig
}

func (c Config) Protocol() string {
	if c.UseHttp {
		return "http://"
	} else {
		return "https://"
	}
}

func loadConfigJsonFromPath() *Config {
	var config *Config = &Config{
		PersistentAppHost:      "CATS-persistent-app",
		PersistentAppSpace:     "CATS-persistent-space",
		PersistentAppOrg:       "CATS-persistent-org",
		PersistentAppQuotaName: "CATS-persistent-quota",

		StaticFileBuildpackName: "staticfile_buildpack",
		JavaBuildpackName:       "java_buildpack",
		RubyBuildpackName:       "ruby_buildpack",
		NodejsBuildpackName:     "nodejs_buildpack",
		GoBuildpackName:         "go_buildpack",
		PythonBuildpackName:     "python_buildpack",
		PhpBuildpackName:        "php_buildpack",
		BinaryBuildpackName:     "binary_buildpack",

		ArtifactsDirectory: filepath.Join("..", "results"),
	}

	path := configPath()

	configFile, err := os.Open(path)
	if err != nil {
		panic(err)
	}

	decoder := json.NewDecoder(configFile)
	err = decoder.Decode(config)
	if err != nil {
		panic(err)
	}

	return config
}

func configPath() string {
	path := os.Getenv("CONFIG")
	if path == "" {
		panic("Must set $CONFIG to point to an integration config .json file.")
	}

	return path
}
<|endoftext|>


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

package expvar

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net"
	"net/http/httptest"
	"reflect"
	"runtime"
	"strconv"
	"sync"
	"sync/atomic"
	"testing"
)

// RemoveAll removes all exported variables.
// This is for tests only.
func RemoveAll() {
	mutex.Lock()
	defer mutex.Unlock()
	vars = make(map[string]Var)
	varKeys = nil
}

func TestNil(t *testing.T) {
	RemoveAll()
	val := Get("missing")
	if val != nil {
		t.Errorf("got %v, want nil", val)
	}
}

func TestInt(t *testing.T) {
	RemoveAll()
	reqs := NewInt("requests")
	if reqs.i != 0 {
		t.Errorf("reqs.i = %v, want 0", reqs.i)
	}
	if reqs != Get("requests").(*Int) {
		t.Errorf("Get() failed.")
	}

	reqs.Add(1)
	reqs.Add(3)
	if reqs.i != 4 {
		t.Errorf("reqs.i = %v, want 4", reqs.i)
	}

	if s := reqs.String(); s != "4" {
		t.Errorf("reqs.String() = %q, want \"4\"", s)
	}

	reqs.Set(-2)
	if reqs.i != -2 {
		t.Errorf("reqs.i = %v, want -2", reqs.i)
	}

	if v, want := reqs.Value(), int64(-2); v != want {
		t.Errorf("reqs.Value() = %q, want %q", v, want)
	}
}

func BenchmarkIntAdd(b *testing.B) {
	var v Int

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			v.Add(1)
		}
	})
}

func BenchmarkIntSet(b *testing.B) {
	var v Int

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			v.Set(1)
		}
	})
}

func TestFloat(t *testing.T) {
	RemoveAll()
	reqs := NewFloat("requests-float")
	if reqs.f != 0.0 {
		t.Errorf("reqs.f = %v, want 0", reqs.f)
	}
	if reqs != Get("requests-float").(*Float) {
		t.Errorf("Get() failed.")
	}

	reqs.Add(1.5)
	reqs.Add(1.25)
	if v := reqs.Value(); v != 2.75 {
		t.Errorf("reqs.Value() = %v, want 2.75", v)
	}

	if s := reqs.String(); s != "2.75" {
		t.Errorf("reqs.String() = %q, want \"4.64\"", s)
	}

	reqs.Add(-2)
	if v := reqs.Value(); v != 0.75 {
		t.Errorf("reqs.Value() = %v, want 0.75", v)
	}
}

func BenchmarkFloatAdd(b *testing.B) {
	var f Float

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			f.Add(1.0)
		}
	})
}

func BenchmarkFloatSet(b *testing.B) {
	var f Float

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			f.Set(1.0)
		}
	})
}

func TestString(t *testing.T) {
	RemoveAll()
	name := NewString("my-name")
	if name.s != "" {
		t.Errorf("name.s = %q, want \"\"", name.s)
	}

	name.Set("Mike")
	if name.s != "Mike" {
		t.Errorf("name.s = %q, want \"Mike\"", name.s)
	}

	if s, want := name.String(), `"Mike"`; s != want {
		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
	}

	if s, want := name.Value(), "Mike"; s != want {
		t.Errorf("from %q, name.Value() = %q, want %q", name.s, s, want)
	}

	// Make sure we produce safe JSON output.
	name.Set(`<`)
	if s, want := name.String(), "\"\\u003c\""; s != want {
		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
	}
}

func BenchmarkStringSet(b *testing.B) {
	var s String

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			s.Set("red")
		}
	})
}

func TestMapCounter(t *testing.T) {
	RemoveAll()
	colors := NewMap("bike-shed-colors")

	colors.Add("red", 1)
	colors.Add("red", 2)
	colors.Add("blue", 4)
	colors.AddFloat(`green "midori"`, 4.125)
	if x := colors.m["red"].(*Int).i; x != 3 {
		t.Errorf("colors.m[\"red\"] = %v, want 3", x)
	}
	if x := colors.m["blue"].(*Int).i; x != 4 {
		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
	}
	if x := colors.m[`green "midori"`].(*Float).Value(); x != 4.125 {
		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
	}

	// colors.String() should be '{"red":3, "blue":4}',
	// though the order of red and blue could vary.
	s := colors.String()
	var j interface{}
	err := json.Unmarshal([]byte(s), &j)
	if err != nil {
		t.Errorf("colors.String() isn't valid JSON: %v", err)
	}
	m, ok := j.(map[string]interface{})
	if !ok {
		t.Error("colors.String() didn't produce a map.")
	}
	red := m["red"]
	x, ok := red.(float64)
	if !ok {
		t.Error("red.Kind() is not a number.")
	}
	if x != 3 {
		t.Errorf("red = %v, want 3", x)
	}
}

func BenchmarkMapSet(b *testing.B) {
	m := new(Map).Init()

	v := new(Int)

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			m.Set("red", v)
		}
	})
}

func BenchmarkMapAddSame(b *testing.B) {
	m := new(Map).Init()
	b.ResetTimer()

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			m.Add("red", 1)
		}
	})
}

func BenchmarkMapAddDifferent(b *testing.B) {
	procKeys := make([][]string, runtime.GOMAXPROCS(0))
	for i := range procKeys {
		keys := make([]string, 4)
		for j := range keys {
			keys[j] = fmt.Sprint(i, j)
		}
		procKeys[i] = keys
	}

	m := new(Map).Init()
	b.ResetTimer()

	var n int32
	b.RunParallel(func(pb *testing.PB) {
		i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
		keys := procKeys[i]
		j := 0

		for pb.Next() {
			m.Add(keys[j], 1)
			if j++; j == len(keys) {
				j = 0
			}
		}
	})
}

func TestFunc(t *testing.T) {
	RemoveAll()
	var x interface{} = []string{"a", "b"}
	f := Func(func() interface{} { return x })
	if s, exp := f.String(), `["a","b"]`; s != exp {
		t.Errorf(`f.String() = %q, want %q`, s, exp)
	}
	if v := f.Value(); !reflect.DeepEqual(v, x) {
		t.Errorf(`f.Value() = %q, want %q`, v, x)
	}

	x = 17
	if s, exp := f.String(), `17`; s != exp {
		t.Errorf(`f.String() = %q, want %q`, s, exp)
	}
}

func TestHandler(t *testing.T) {
	RemoveAll()
	m := NewMap("map1")
	m.Add("a", 1)
	m.Add("z", 2)
	m2 := NewMap("map2")
	for i := 0; i < 9; i++ {
		m2.Add(strconv.Itoa(i), int64(i))
	}
	rr := httptest.NewRecorder()
	rr.Body = new(bytes.Buffer)
	expvarHandler(rr, nil)
	want := `{
"map1": {"a": 1, "z": 2},
"map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
}
`
	if got := rr.Body.String(); got != want {
		t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
	}
}

func BenchmarkRealworldExpvarUsage(b *testing.B) {
	var (
		bytesSent Int
		bytesRead Int
	)

	// The benchmark creates GOMAXPROCS client/server pairs.
	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
	// The benchmark stresses concurrent reading and writing to the same connection.
	// Such pattern is used in net/http and net/rpc.

	b.StopTimer()

	P := runtime.GOMAXPROCS(0)
	N := b.N / P
	W := 1000

	// Setup P client/server connections.
	clients := make([]net.Conn, P)
	servers := make([]net.Conn, P)
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		b.Fatalf("Listen failed: %v", err)
	}
	defer ln.Close()
	done := make(chan bool)
	go func() {
		for p := 0; p < P; p++ {
			s, err := ln.Accept()
			if err != nil {
				b.Errorf("Accept failed: %v", err)
				return
			}
			servers[p] = s
		}
		done <- true
	}()
	for p := 0; p < P; p++ {
		c, err := net.Dial("tcp", ln.Addr().String())
		if err != nil {
			b.Fatalf("Dial failed: %v", err)
		}
		clients[p] = c
	}
	<-done

	b.StartTimer()

	var wg sync.WaitGroup
	wg.Add(4 * P)
	for p := 0; p < P; p++ {
		// Client writer.
		go func(c net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				v := byte(i)
				for w := 0; w < W; w++ {
					v *= v
				}
				buf[0] = v
				n, err := c.Write(buf[:])
				if err != nil {
					b.Errorf("Write failed: %v", err)
					return
				}

				bytesSent.Add(int64(n))
			}
		}(clients[p])

		// Pipe between server reader and server writer.
		pipe := make(chan byte, 128)

		// Server reader.
		go func(s net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				n, err := s.Read(buf[:])

				if err != nil {
					b.Errorf("Read failed: %v", err)
					return
				}

				bytesRead.Add(int64(n))
				pipe <- buf[0]
			}
		}(servers[p])

		// Server writer.
		go func(s net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				v := <-pipe
				for w := 0; w < W; w++ {
					v *= v
				}
				buf[0] = v
				n, err := s.Write(buf[:])
				if err != nil {
					b.Errorf("Write failed: %v", err)
					return
				}

				bytesSent.Add(int64(n))
			}
			s.Close()
		}(servers[p])

		// Client reader.
		go func(c net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				n, err := c.Read(buf[:])

				if err != nil {
					b.Errorf("Read failed: %v", err)
					return
				}

				bytesRead.Add(int64(n))
			}
			c.Close()
		}(clients[p])
	}
	wg.Wait()
}
<commit_msg>expvar: make BenchmarkAdd{Same,Different} comparable to 1.8<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package expvar

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net"
	"net/http/httptest"
	"reflect"
	"runtime"
	"strconv"
	"sync"
	"sync/atomic"
	"testing"
)

// RemoveAll removes all exported variables.
// This is for tests only.
func RemoveAll() {
	mutex.Lock()
	defer mutex.Unlock()
	vars = make(map[string]Var)
	varKeys = nil
}

func TestNil(t *testing.T) {
	RemoveAll()
	val := Get("missing")
	if val != nil {
		t.Errorf("got %v, want nil", val)
	}
}

func TestInt(t *testing.T) {
	RemoveAll()
	reqs := NewInt("requests")
	if reqs.i != 0 {
		t.Errorf("reqs.i = %v, want 0", reqs.i)
	}
	if reqs != Get("requests").(*Int) {
		t.Errorf("Get() failed.")
	}

	reqs.Add(1)
	reqs.Add(3)
	if reqs.i != 4 {
		t.Errorf("reqs.i = %v, want 4", reqs.i)
	}

	if s := reqs.String(); s != "4" {
		t.Errorf("reqs.String() = %q, want \"4\"", s)
	}

	reqs.Set(-2)
	if reqs.i != -2 {
		t.Errorf("reqs.i = %v, want -2", reqs.i)
	}

	if v, want := reqs.Value(), int64(-2); v != want {
		t.Errorf("reqs.Value() = %q, want %q", v, want)
	}
}

func BenchmarkIntAdd(b *testing.B) {
	var v Int

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			v.Add(1)
		}
	})
}

func BenchmarkIntSet(b *testing.B) {
	var v Int

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			v.Set(1)
		}
	})
}

func TestFloat(t *testing.T) {
	RemoveAll()
	reqs := NewFloat("requests-float")
	if reqs.f != 0.0 {
		t.Errorf("reqs.f = %v, want 0", reqs.f)
	}
	if reqs != Get("requests-float").(*Float) {
		t.Errorf("Get() failed.")
	}

	reqs.Add(1.5)
	reqs.Add(1.25)
	if v := reqs.Value(); v != 2.75 {
		t.Errorf("reqs.Value() = %v, want 2.75", v)
	}

	if s := reqs.String(); s != "2.75" {
		t.Errorf("reqs.String() = %q, want \"4.64\"", s)
	}

	reqs.Add(-2)
	if v := reqs.Value(); v != 0.75 {
		t.Errorf("reqs.Value() = %v, want 0.75", v)
	}
}

func BenchmarkFloatAdd(b *testing.B) {
	var f Float

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			f.Add(1.0)
		}
	})
}

func BenchmarkFloatSet(b *testing.B) {
	var f Float

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			f.Set(1.0)
		}
	})
}

func TestString(t *testing.T) {
	RemoveAll()
	name := NewString("my-name")
	if name.s != "" {
		t.Errorf("name.s = %q, want \"\"", name.s)
	}

	name.Set("Mike")
	if name.s != "Mike" {
		t.Errorf("name.s = %q, want \"Mike\"", name.s)
	}

	if s, want := name.String(), `"Mike"`; s != want {
		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
	}

	if s, want := name.Value(), "Mike"; s != want {
		t.Errorf("from %q, name.Value() = %q, want %q", name.s, s, want)
	}

	// Make sure we produce safe JSON output.
	name.Set(`<`)
	if s, want := name.String(), "\"\\u003c\""; s != want {
		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
	}
}

func BenchmarkStringSet(b *testing.B) {
	var s String

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			s.Set("red")
		}
	})
}

func TestMapCounter(t *testing.T) {
	RemoveAll()
	colors := NewMap("bike-shed-colors")

	colors.Add("red", 1)
	colors.Add("red", 2)
	colors.Add("blue", 4)
	colors.AddFloat(`green "midori"`, 4.125)
	if x := colors.m["red"].(*Int).i; x != 3 {
		t.Errorf("colors.m[\"red\"] = %v, want 3", x)
	}
	if x := colors.m["blue"].(*Int).i; x != 4 {
		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
	}
	if x := colors.m[`green "midori"`].(*Float).Value(); x != 4.125 {
		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
	}

	// colors.String() should be '{"red":3, "blue":4}',
	// though the order of red and blue could vary.
	s := colors.String()
	var j interface{}
	err := json.Unmarshal([]byte(s), &j)
	if err != nil {
		t.Errorf("colors.String() isn't valid JSON: %v", err)
	}
	m, ok := j.(map[string]interface{})
	if !ok {
		t.Error("colors.String() didn't produce a map.")
	}
	red := m["red"]
	x, ok := red.(float64)
	if !ok {
		t.Error("red.Kind() is not a number.")
	}
	if x != 3 {
		t.Errorf("red = %v, want 3", x)
	}
}

func BenchmarkMapSet(b *testing.B) {
	m := new(Map).Init()

	v := new(Int)

	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			m.Set("red", v)
		}
	})
}

func BenchmarkMapAddSame(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			m := new(Map).Init()
			m.Add("red", 1)
			m.Add("red", 1)
			m.Add("red", 1)
			m.Add("red", 1)
		}
	})
}

func BenchmarkMapAddDifferent(b *testing.B) {
	procKeys := make([][]string, runtime.GOMAXPROCS(0))
	for i := range procKeys {
		keys := make([]string, 4)
		for j := range keys {
			keys[j] = fmt.Sprint(i, j)
		}
		procKeys[i] = keys
	}

	b.ResetTimer()

	var n int32
	b.RunParallel(func(pb *testing.PB) {
		i := int(atomic.AddInt32(&n, 1)-1) % len(procKeys)
		keys := procKeys[i]

		for pb.Next() {
			m := new(Map).Init()
			for _, k := range keys {
				m.Add(k, 1)
			}
		}
	})
}

func TestFunc(t *testing.T) {
	RemoveAll()
	var x interface{} = []string{"a", "b"}
	f := Func(func() interface{} { return x })
	if s, exp := f.String(), `["a","b"]`; s != exp {
		t.Errorf(`f.String() = %q, want %q`, s, exp)
	}
	if v := f.Value(); !reflect.DeepEqual(v, x) {
		t.Errorf(`f.Value() = %q, want %q`, v, x)
	}

	x = 17
	if s, exp := f.String(), `17`; s != exp {
		t.Errorf(`f.String() = %q, want %q`, s, exp)
	}
}

func TestHandler(t *testing.T) {
	RemoveAll()
	m := NewMap("map1")
	m.Add("a", 1)
	m.Add("z", 2)
	m2 := NewMap("map2")
	for i := 0; i < 9; i++ {
		m2.Add(strconv.Itoa(i), int64(i))
	}
	rr := httptest.NewRecorder()
	rr.Body = new(bytes.Buffer)
	expvarHandler(rr, nil)
	want := `{
"map1": {"a": 1, "z": 2},
"map2": {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8}
}
`
	if got := rr.Body.String(); got != want {
		t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
	}
}

func BenchmarkRealworldExpvarUsage(b *testing.B) {
	var (
		bytesSent Int
		bytesRead Int
	)

	// The benchmark creates GOMAXPROCS client/server pairs.
	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
	// The benchmark stresses concurrent reading and writing to the same connection.
	// Such pattern is used in net/http and net/rpc.

	b.StopTimer()

	P := runtime.GOMAXPROCS(0)
	N := b.N / P
	W := 1000

	// Setup P client/server connections.
	clients := make([]net.Conn, P)
	servers := make([]net.Conn, P)
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		b.Fatalf("Listen failed: %v", err)
	}
	defer ln.Close()
	done := make(chan bool)
	go func() {
		for p := 0; p < P; p++ {
			s, err := ln.Accept()
			if err != nil {
				b.Errorf("Accept failed: %v", err)
				return
			}
			servers[p] = s
		}
		done <- true
	}()
	for p := 0; p < P; p++ {
		c, err := net.Dial("tcp", ln.Addr().String())
		if err != nil {
			b.Fatalf("Dial failed: %v", err)
		}
		clients[p] = c
	}
	<-done

	b.StartTimer()

	var wg sync.WaitGroup
	wg.Add(4 * P)
	for p := 0; p < P; p++ {
		// Client writer.
		go func(c net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				v := byte(i)
				for w := 0; w < W; w++ {
					v *= v
				}
				buf[0] = v
				n, err := c.Write(buf[:])
				if err != nil {
					b.Errorf("Write failed: %v", err)
					return
				}

				bytesSent.Add(int64(n))
			}
		}(clients[p])

		// Pipe between server reader and server writer.
		pipe := make(chan byte, 128)

		// Server reader.
		go func(s net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				n, err := s.Read(buf[:])

				if err != nil {
					b.Errorf("Read failed: %v", err)
					return
				}

				bytesRead.Add(int64(n))
				pipe <- buf[0]
			}
		}(servers[p])

		// Server writer.
		go func(s net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				v := <-pipe
				for w := 0; w < W; w++ {
					v *= v
				}
				buf[0] = v
				n, err := s.Write(buf[:])
				if err != nil {
					b.Errorf("Write failed: %v", err)
					return
				}

				bytesSent.Add(int64(n))
			}
			s.Close()
		}(servers[p])

		// Client reader.
		go func(c net.Conn) {
			defer wg.Done()
			var buf [1]byte
			for i := 0; i < N; i++ {
				n, err := c.Read(buf[:])

				if err != nil {
					b.Errorf("Read failed: %v", err)
					return
				}

				bytesRead.Add(int64(n))
			}
			c.Close()
		}(clients[p])
	}
	wg.Wait()
}
<|endoftext|>