<commit_before>// This package implements a provisioner for Packer that executes
// Puppet on the remote machine, configured to apply a local manifest
// versus connecting to a Puppet master.
package puppetmasterless

import (
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"os"
	"path/filepath"
	"strings"
)

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	tpl                 *packer.ConfigTemplate

	// The command used to execute Puppet.
	ExecuteCommand string `mapstructure:"execute_command"`

	// Additional facts to set when executing Puppet
	Facter map[string]string

	// Path to a hiera configuration file to upload and use.
	HieraConfigPath string `mapstructure:"hiera_config_path"`

	// An array of local paths of modules to upload.
	ModulePaths []string `mapstructure:"module_paths"`

	// The main manifest file to apply to kick off the entire thing.
	ManifestFile string `mapstructure:"manifest_file"`

	// A directory of manifest files that will be uploaded to the remote
	// machine.
	ManifestDir string `mapstructure:"manifest_dir"`

	// If true, `sudo` will NOT be used to execute Puppet.
	PreventSudo bool `mapstructure:"prevent_sudo"`

	// The directory where files will be uploaded. Packer requires write
	// permissions in this directory.
	StagingDir string `mapstructure:"staging_directory"`
}

type Provisioner struct {
	config Config
}

type ExecuteTemplate struct {
	FacterVars      string
	HieraConfigPath string
	ModulePath      string
	ManifestFile    string
	ManifestDir     string
	Sudo            bool
}

func (p *Provisioner) Prepare(raws ...interface{}) error {
	md, err := common.DecodeConfig(&p.config, raws...)
	if err != nil {
		return err
	}

	p.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	p.config.tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)

	// Set some defaults
	if p.config.ExecuteCommand == "" {
		p.config.ExecuteCommand = "{{.FacterVars}} {{if .Sudo}} sudo -E {{end}}" +
			"puppet apply --verbose --modulepath='{{.ModulePath}}' " +
			"{{if ne .HieraConfigPath \"\"}}--hiera_config='{{.HieraConfigPath}}' {{end}}" +
			"{{if ne .ManifestDir \"\"}}--manifestdir='{{.ManifestDir}}' {{end}}" +
			"--detailed-exitcodes " +
			"{{.ManifestFile}}"
	}

	if p.config.StagingDir == "" {
		p.config.StagingDir = "/tmp/packer-puppet-masterless"
	}

	// Templates
	templates := map[string]*string{
		"hiera_config_path": &p.config.HieraConfigPath,
		"manifest_file":     &p.config.ManifestFile,
		"manifest_dir":      &p.config.ManifestDir,
		"staging_dir":       &p.config.StagingDir,
	}

	for n, ptr := range templates {
		var err error
		*ptr, err = p.config.tpl.Process(*ptr, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}

	sliceTemplates := map[string][]string{
		"module_paths": p.config.ModulePaths,
	}

	for n, slice := range sliceTemplates {
		for i, elem := range slice {
			var err error
			slice[i], err = p.config.tpl.Process(elem, nil)
			if err != nil {
				errs = packer.MultiErrorAppend(
					errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err))
			}
		}
	}

	validates := map[string]*string{
		"execute_command": &p.config.ExecuteCommand,
	}

	for n, ptr := range validates {
		if err := p.config.tpl.Validate(*ptr); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error parsing %s: %s", n, err))
		}
	}

	newFacts := make(map[string]string)
	for k, v := range p.config.Facter {
		k, err := p.config.tpl.Process(k, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("Error processing facter key %s: %s", k, err))
			continue
		}

		v, err := p.config.tpl.Process(v, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("Error processing facter value '%s': %s", v, err))
			continue
		}

		newFacts[k] = v
	}

	p.config.Facter = newFacts

	// Validation
	if p.config.HieraConfigPath != "" {
		info, err := os.Stat(p.config.HieraConfigPath)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("hiera_config_path is invalid: %s", err))
		} else if info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("hiera_config_path must point to a file"))
		}
	}

	if p.config.ManifestDir != "" {
		info, err := os.Stat(p.config.ManifestDir)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_dir is invalid: %s", err))
		} else if !info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_dir must point to a directory"))
		}
	}

	if p.config.ManifestFile == "" {
		errs = packer.MultiErrorAppend(errs,
			fmt.Errorf("A manifest_file must be specified."))
	} else {
		info, err := os.Stat(p.config.ManifestFile)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_file is invalid: %s", err))
		} else if info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_file must point to a file"))
		}
	}

	for i, path := range p.config.ModulePaths {
		info, err := os.Stat(path)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("module_path[%d] is invalid: %s", i, err))
		} else if !info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("module_path[%d] must point to a directory"))
		}
	}

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
	ui.Say("Provisioning with Puppet...")
	ui.Message("Creating Puppet staging directory...")
	if err := p.createDir(ui, comm, p.config.StagingDir); err != nil {
		return fmt.Errorf("Error creating staging directory: %s", err)
	}

	// Upload hiera config if set
	remoteHieraConfigPath := ""
	if p.config.HieraConfigPath != "" {
		var err error
		remoteHieraConfigPath, err = p.uploadHieraConfig(ui, comm)
		if err != nil {
			return fmt.Errorf("Error uploading hiera config: %s", err)
		}
	}

	// Upload manifest dir if set
	remoteManifestDir := ""
	if p.config.ManifestDir != "" {
		ui.Message(fmt.Sprintf(
			"Uploading manifest directory from: %s", p.config.ManifestDir))
		remoteManifestDir = fmt.Sprintf("%s/manifests", p.config.StagingDir)
		err := p.uploadDirectory(ui, comm, remoteManifestDir, p.config.ManifestDir)
		if err != nil {
			return fmt.Errorf("Error uploading manifest dir: %s", err)
		}
	}

	// Upload all modules
	modulePaths := make([]string, 0, len(p.config.ModulePaths))
	for i, path := range p.config.ModulePaths {
		ui.Message(fmt.Sprintf("Uploading local modules from: %s", path))
		targetPath := fmt.Sprintf("%s/module-%d", p.config.StagingDir, i)
		if err := p.uploadDirectory(ui, comm, targetPath, path); err != nil {
			return fmt.Errorf("Error uploading modules: %s", err)
		}

		modulePaths = append(modulePaths, targetPath)
	}

	// Upload manifests
	remoteManifestFile, err := p.uploadManifests(ui, comm)
	if err != nil {
		return fmt.Errorf("Error uploading manifests: %s", err)
	}

	// Compile the facter variables
	facterVars := make([]string, 0, len(p.config.Facter))
	for k, v := range p.config.Facter {
		facterVars = append(facterVars, fmt.Sprintf("FACTER_%s='%s'", k, v))
	}

	// Execute Puppet
	command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteTemplate{
		FacterVars:      strings.Join(facterVars, " "),
		HieraConfigPath: remoteHieraConfigPath,
		ManifestDir:     remoteManifestDir,
		ManifestFile:    remoteManifestFile,
		ModulePath:      strings.Join(modulePaths, ":"),
		Sudo:            !p.config.PreventSudo,
	})
	if err != nil {
		return err
	}

	cmd := &packer.RemoteCmd{
		Command: command,
	}

	ui.Message(fmt.Sprintf("Running Puppet: %s", command))
	if err := cmd.StartWithUi(comm, ui); err != nil {
		return err
	}

	if cmd.ExitStatus != 0 && cmd.ExitStatus != 2 {
		return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus)
	}

	return nil
}

func (p *Provisioner) Cancel() {
	// Just hard quit. It isn't a big deal if what we're doing keeps
	// running on the other side.
	os.Exit(0)
}

func (p *Provisioner) uploadHieraConfig(ui packer.Ui, comm packer.Communicator) (string, error) {
	ui.Message("Uploading hiera configuration...")
	f, err := os.Open(p.config.HieraConfigPath)
	if err != nil {
		return "", err
	}
	defer f.Close()

	path := fmt.Sprintf("%s/hiera.yaml", p.config.StagingDir)
	if err := comm.Upload(path, f, nil); err != nil {
		return "", err
	}

	return path, nil
}

func (p *Provisioner) uploadManifests(ui packer.Ui, comm packer.Communicator) (string, error) {
	// Create the remote manifests directory...
	ui.Message("Uploading manifests...")
	remoteManifestsPath := fmt.Sprintf("%s/manifests", p.config.StagingDir)
	if err := p.createDir(ui, comm, remoteManifestsPath); err != nil {
		return "", fmt.Errorf("Error creating manifests directory: %s", err)
	}

	// Upload the main manifest
	f, err := os.Open(p.config.ManifestFile)
	if err != nil {
		return "", err
	}
	defer f.Close()

	manifestFilename := filepath.Base(p.config.ManifestFile)
	remoteManifestFile := fmt.Sprintf("%s/%s", remoteManifestsPath, manifestFilename)
	if err := comm.Upload(remoteManifestFile, f, nil); err != nil {
		return "", err
	}

	return remoteManifestFile, nil
}

func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
	cmd := &packer.RemoteCmd{
		Command: fmt.Sprintf("mkdir -p '%s'", dir),
	}

	if err := cmd.StartWithUi(comm, ui); err != nil {
		return err
	}

	if cmd.ExitStatus != 0 {
		return fmt.Errorf("Non-zero exit status.")
	}

	return nil
}

func (p *Provisioner) uploadDirectory(ui packer.Ui, comm packer.Communicator, dst string, src string) error {
	if err := p.createDir(ui, comm, dst); err != nil {
		return err
	}

	// Make sure there is a trailing "/" so that the directory isn't
	// created on the other side.
	if src[len(src)-1] != '/' {
		src = src + "/"
	}

	return comm.UploadDir(dst, src, nil)
}
<commit_msg>Allow manifest_file to be a directory<commit_after>// This package implements a provisioner for Packer that executes
// Puppet on the remote machine, configured to apply a local manifest
// versus connecting to a Puppet master.
package puppetmasterless

import (
	"fmt"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"os"
	"path/filepath"
	"strings"
)

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	tpl                 *packer.ConfigTemplate

	// The command used to execute Puppet.
	ExecuteCommand string `mapstructure:"execute_command"`

	// Additional facts to set when executing Puppet
	Facter map[string]string

	// Path to a hiera configuration file to upload and use.
	HieraConfigPath string `mapstructure:"hiera_config_path"`

	// An array of local paths of modules to upload.
	ModulePaths []string `mapstructure:"module_paths"`

	// The main manifest file to apply to kick off the entire thing.
	ManifestFile string `mapstructure:"manifest_file"`

	// A directory of manifest files that will be uploaded to the remote
	// machine.
	ManifestDir string `mapstructure:"manifest_dir"`

	// If true, `sudo` will NOT be used to execute Puppet.
	PreventSudo bool `mapstructure:"prevent_sudo"`

	// The directory where files will be uploaded. Packer requires write
	// permissions in this directory.
	StagingDir string `mapstructure:"staging_directory"`
}

type Provisioner struct {
	config Config
}

type ExecuteTemplate struct {
	FacterVars      string
	HieraConfigPath string
	ModulePath      string
	ManifestFile    string
	ManifestDir     string
	Sudo            bool
}

func (p *Provisioner) Prepare(raws ...interface{}) error {
	md, err := common.DecodeConfig(&p.config, raws...)
	if err != nil {
		return err
	}

	p.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
		return err
	}
	p.config.tpl.UserVars = p.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)

	// Set some defaults
	if p.config.ExecuteCommand == "" {
		p.config.ExecuteCommand = "{{.FacterVars}} {{if .Sudo}} sudo -E {{end}}" +
			"puppet apply --verbose --modulepath='{{.ModulePath}}' " +
			"{{if ne .HieraConfigPath \"\"}}--hiera_config='{{.HieraConfigPath}}' {{end}}" +
			"{{if ne .ManifestDir \"\"}}--manifestdir='{{.ManifestDir}}' {{end}}" +
			"--detailed-exitcodes " +
			"{{.ManifestFile}}"
	}

	if p.config.StagingDir == "" {
		p.config.StagingDir = "/tmp/packer-puppet-masterless"
	}

	// Templates
	templates := map[string]*string{
		"hiera_config_path": &p.config.HieraConfigPath,
		"manifest_file":     &p.config.ManifestFile,
		"manifest_dir":      &p.config.ManifestDir,
		"staging_dir":       &p.config.StagingDir,
	}

	for n, ptr := range templates {
		var err error
		*ptr, err = p.config.tpl.Process(*ptr, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error processing %s: %s", n, err))
		}
	}

	sliceTemplates := map[string][]string{
		"module_paths": p.config.ModulePaths,
	}

	for n, slice := range sliceTemplates {
		for i, elem := range slice {
			var err error
			slice[i], err = p.config.tpl.Process(elem, nil)
			if err != nil {
				errs = packer.MultiErrorAppend(
					errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err))
			}
		}
	}

	validates := map[string]*string{
		"execute_command": &p.config.ExecuteCommand,
	}

	for n, ptr := range validates {
		if err := p.config.tpl.Validate(*ptr); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("Error parsing %s: %s", n, err))
		}
	}

	newFacts := make(map[string]string)
	for k, v := range p.config.Facter {
		k, err := p.config.tpl.Process(k, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("Error processing facter key %s: %s", k, err))
			continue
		}

		v, err := p.config.tpl.Process(v, nil)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("Error processing facter value '%s': %s", v, err))
			continue
		}

		newFacts[k] = v
	}

	p.config.Facter = newFacts

	// Validation
	if p.config.HieraConfigPath != "" {
		info, err := os.Stat(p.config.HieraConfigPath)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("hiera_config_path is invalid: %s", err))
		} else if info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("hiera_config_path must point to a file"))
		}
	}

	if p.config.ManifestDir != "" {
		info, err := os.Stat(p.config.ManifestDir)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_dir is invalid: %s", err))
		} else if !info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_dir must point to a directory"))
		}
	}

	if p.config.ManifestFile == "" {
		errs = packer.MultiErrorAppend(errs,
			fmt.Errorf("A manifest_file must be specified."))
	} else {
		info, err := os.Stat(p.config.ManifestFile)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("manifest_file is invalid: %s", err))
		}
	}

	for i, path := range p.config.ModulePaths {
		info, err := os.Stat(path)
		if err != nil {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("module_path[%d] is invalid: %s", i, err))
		} else if !info.IsDir() {
			errs = packer.MultiErrorAppend(errs,
				fmt.Errorf("module_path[%d] must point to a directory"))
		}
	}

	if errs != nil && len(errs.Errors) > 0 {
		return errs
	}

	return nil
}

func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error {
	ui.Say("Provisioning with Puppet...")
	ui.Message("Creating Puppet staging directory...")
	if err := p.createDir(ui, comm, p.config.StagingDir); err != nil {
		return fmt.Errorf("Error creating staging directory: %s", err)
	}

	// Upload hiera config if set
	remoteHieraConfigPath := ""
	if p.config.HieraConfigPath != "" {
		var err error
		remoteHieraConfigPath, err = p.uploadHieraConfig(ui, comm)
		if err != nil {
			return fmt.Errorf("Error uploading hiera config: %s", err)
		}
	}

	// Upload manifest dir if set
	remoteManifestDir := ""
	if p.config.ManifestDir != "" {
		ui.Message(fmt.Sprintf(
			"Uploading manifest directory from: %s", p.config.ManifestDir))
		remoteManifestDir = fmt.Sprintf("%s/manifests", p.config.StagingDir)
		err := p.uploadDirectory(ui, comm, remoteManifestDir, p.config.ManifestDir)
		if err != nil {
			return fmt.Errorf("Error uploading manifest dir: %s", err)
		}
	}

	// Upload all modules
	modulePaths := make([]string, 0, len(p.config.ModulePaths))
	for i, path := range p.config.ModulePaths {
		ui.Message(fmt.Sprintf("Uploading local modules from: %s", path))
		targetPath := fmt.Sprintf("%s/module-%d", p.config.StagingDir, i)
		if err := p.uploadDirectory(ui, comm, targetPath, path); err != nil {
			return fmt.Errorf("Error uploading modules: %s", err)
		}

		modulePaths = append(modulePaths, targetPath)
	}

	// Upload manifests
	remoteManifestFile, err := p.uploadManifests(ui, comm)
	if err != nil {
		return fmt.Errorf("Error uploading manifests: %s", err)
	}

	// Compile the facter variables
	facterVars := make([]string, 0, len(p.config.Facter))
	for k, v := range p.config.Facter {
		facterVars = append(facterVars, fmt.Sprintf("FACTER_%s='%s'", k, v))
	}

	// Execute Puppet
	command, err := p.config.tpl.Process(p.config.ExecuteCommand, &ExecuteTemplate{
		FacterVars:      strings.Join(facterVars, " "),
		HieraConfigPath: remoteHieraConfigPath,
		ManifestDir:     remoteManifestDir,
		ManifestFile:    remoteManifestFile,
		ModulePath:      strings.Join(modulePaths, ":"),
		Sudo:            !p.config.PreventSudo,
	})
	if err != nil {
		return err
	}

	cmd := &packer.RemoteCmd{
		Command: command,
	}

	ui.Message(fmt.Sprintf("Running Puppet: %s", command))
	if err := cmd.StartWithUi(comm, ui); err != nil {
		return err
	}

	if cmd.ExitStatus != 0 && cmd.ExitStatus != 2 {
		return fmt.Errorf("Puppet exited with a non-zero exit status: %d", cmd.ExitStatus)
	}

	return nil
}

func (p *Provisioner) Cancel() {
	// Just hard quit. It isn't a big deal if what we're doing keeps
	// running on the other side.
	os.Exit(0)
}

func (p *Provisioner) uploadHieraConfig(ui packer.Ui, comm packer.Communicator) (string, error) {
	ui.Message("Uploading hiera configuration...")
	f, err := os.Open(p.config.HieraConfigPath)
	if err != nil {
		return "", err
	}
	defer f.Close()

	path := fmt.Sprintf("%s/hiera.yaml", p.config.StagingDir)
	if err := comm.Upload(path, f, nil); err != nil {
		return "", err
	}

	return path, nil
}

func (p *Provisioner) uploadManifests(ui packer.Ui, comm packer.Communicator) (string, error) {
	// Create the remote manifests directory...
	ui.Message("Uploading manifests...")
	remoteManifestsPath := fmt.Sprintf("%s/manifests", p.config.StagingDir)
	if err := p.createDir(ui, comm, remoteManifestsPath); err != nil {
		return "", fmt.Errorf("Error creating manifests directory: %s", err)
	}

	// Upload the main manifest
	f, err := os.Open(p.config.ManifestFile)
	if err != nil {
		return "", err
	}
	defer f.Close()

	manifestFilename := filepath.Base(p.config.ManifestFile)
	remoteManifestFile := fmt.Sprintf("%s/%s", remoteManifestsPath, manifestFilename)
	if err := comm.Upload(remoteManifestFile, f, nil); err != nil {
		return "", err
	}

	return remoteManifestFile, nil
}

func (p *Provisioner) createDir(ui packer.Ui, comm packer.Communicator, dir string) error {
	cmd := &packer.RemoteCmd{
		Command: fmt.Sprintf("mkdir -p '%s'", dir),
	}

	if err := cmd.StartWithUi(comm, ui); err != nil {
		return err
	}

	if cmd.ExitStatus != 0 {
		return fmt.Errorf("Non-zero exit status.")
	}

	return nil
}

func (p *Provisioner) uploadDirectory(ui packer.Ui, comm packer.Communicator, dst string, src string) error {
	if err := p.createDir(ui, comm, dst); err != nil {
		return err
	}

	// Make sure there is a trailing "/" so that the directory isn't
	// created on the other side.
	if src[len(src)-1] != '/' {
		src = src + "/"
	}

	return comm.UploadDir(dst, src, nil)
}
<|endoftext|>


<commit_before><commit_msg>Indicate port in startup log message<commit_after><|endoftext|>


<commit_before>// 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 converter

import (
	"reflect"
	"testing"
)

func TestConvertLocal(t *testing.T) {
	provider := new(LocalProvider)
	cases := []struct {
		rates    Rates
		amount   float64
		expected ConvertedRates
	}{
		{
			Rates{
				"USD": 1,
				"PLN": 1.5,
				"EUR": 0.5,
			},
			10,
			ConvertedRates{
				"USD": 10,
				"PLN": 15,
				"EUR": 5,
			},
		},
	}

	for _, c := range cases {
		actual := provider.convert(c.rates, c.amount)

		if !reflect.DeepEqual(actual, c.expected) {
			t.Errorf("LocalProvider.convert(%v, %v) == \ngot: %v, \nexpected %v",
				c.rates, c.amount, actual, c.expected)
		}
	}
}
<commit_msg>More tests<commit_after>// 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 converter

import (
	"errors"
	"reflect"
	"testing"
)

func TestConvertLocal(t *testing.T) {
	provider := new(LocalProvider)
	cases := []struct {
		rates    Rates
		amount   float64
		expected ConvertedRates
	}{
		{
			Rates{
				"USD": 1,
				"PLN": 1.5,
				"EUR": 0.5,
			},
			10,
			ConvertedRates{
				"USD": 10,
				"PLN": 15,
				"EUR": 5,
			},
		},
	}

	for _, c := range cases {
		actual := provider.convert(c.rates, c.amount)

		if !reflect.DeepEqual(actual, c.expected) {
			t.Errorf("LocalProvider.convert(%v, %v) == \ngot: %v, \nexpected %v",
				c.rates, c.amount, actual, c.expected)
		}
	}
}

func TestConvert(t *testing.T) {
	provider := new(LocalProvider)
	cases := []struct {
		currency      string
		amount        float64
		expected      *ConverterResponse
		expectedError error
	}{
		{
			CURRENCY_PLN, 10,
			&ConverterResponse{
				Amount:   10,
				Currency: CURRENCY_PLN,
				Converted: ConvertedRates{
					"IDR": 32982, "JPY": 265.65, "ZAR": 34.31, "BRL": 8.05, "HRK": 17.35,
					"MXN": 47.87, "MYR": 10.62, "NOK": 20.88, "USD": 2.53, "CNY": 17.14,
					"HKD": 19.61, "PHP": 122.61, "RUB": 160.01, "CHF": 2.5, "NZD": 3.54,
					"SEK": 22.79, "EUR": 2.31, "ILS": 9.74, "GBP": 2.08, "KRW": 2899.6,
					"BGN": 4.52, "CAD": 3.39, "CZK": 62.44, "DKK": 17.19, "HUF": 712.69,
					"INR": 168.89, "AUD": 3.33, "TRY": 7.85, "SGD": 3.52, "THB": 88.56,
					"RON": 10.41,
				}}, nil,
		},
		{
			"ERR_CURRENCY", 10,
			nil,
			errors.New("Currency ERR_CURRENCY not supported by local provider."),
		},
	}

	for _, c := range cases {
		actual, err := provider.Convert(c.amount, c.currency)

		if !reflect.DeepEqual(err, c.expectedError) {
			t.Errorf("LocalProvider.Convert(%f, %s) == \ngot: %s, \nexpected: %s",
				c.amount, c.currency, err, c.expectedError)
		}

		if !reflect.DeepEqual(actual, c.expected) {
			t.Errorf("LocalProvider.convert(%f, %s) == \ngot: %v, \nexpected: %v",
				c.amount, c.currency, actual, c.expected)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
)

// DBlock is a Factom Network Directory Block containing the Merkel root of all
// of the Entries and blocks from a 10 minute period in the Factom Network. The
// Directory Block Key Merkel Root is anchored into the Bitcoin and other
// blockchains for added security and immutability.
type DBlock struct {
	DBHash         string `json:"dbhash"`
	KeyMR          string `json:"keymr"`
	HeaderHash     string `json:"headerhash"`
	SequenceNumber int64  `json:"sequencenynumber"`
	Header         struct {
		Version      int    `json:"version"`
		NetworkID    int    `json:"networkid"`
		BodyMR       string `json:"bodymr"`
		PrevKeyMR    string `json:"prevkeymr"`
		PrevFullHash string `json:"prevfullhash"`
		Timestamp    int    `json:"timestamp"` //in minutes
		DBHeight     int    `json:"dbheight"`
		BlockCount   int    `json:"blockcount"`
	} `json:"header"`
	DBEntries []struct {
		ChainID string `json:"chainid"`
		KeyMR   string `json:"keymr"`
	} `json:"dbentries"`
}

func (db *DBlock) String() string {
	var s string

	s += fmt.Sprintln("DBHash:", db.DBHash)
	s += fmt.Sprintln("KeyMR:", db.KeyMR)
	s += fmt.Sprintln("HeaderHash:", db.HeaderHash)
	s += fmt.Sprintln("SequenceNumber:", db.SequenceNumber)
	s += fmt.Sprintln("Version:", db.Header.Version)
	s += fmt.Sprintln("NetworkID:", db.Header.NetworkID)
	s += fmt.Sprintln("BodyMR:", db.Header.BodyMR)
	s += fmt.Sprintln("PrevKeyMR:", db.Header.PrevKeyMR)
	s += fmt.Sprintln("PrevFullHash:", db.Header.PrevFullHash)
	s += fmt.Sprintln("Timestamp:", db.Header.Timestamp)
	s += fmt.Sprintln("DBHeight:", db.Header.DBHeight)
	s += fmt.Sprintln("BlockCount:", db.Header.BlockCount)

	s += fmt.Sprintln("DBEntries {")
	for _, v := range db.DBEntries {
		s += fmt.Sprintln("	ChainID:", v.ChainID)
		s += fmt.Sprintln("	KeyMR:", v.KeyMR)
	}
	s += fmt.Sprintln("}")

	return s
}

// TODO: GetDBlock should use the dblock api call directy instead of
// re-directing to dblock-by-height.
// we either need to change the "directoy-block" API call or add a new call to
// return the propper information (it should match the dblock-by-height call)

// GetDBlock requests a Directory Block by its Key Merkle Root from the factomd
// API.
func GetDBlock(keymr string) (dblock *DBlock, raw []byte, err error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("directory-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return
	}
	if resp.Error != nil {
		return nil, nil, resp.Error
	}

	db := new(struct {
		DBHash string `json:"dbhash"`
		Header struct {
			PrevBlockKeyMR string `json:"prevblockkeymr"`
			SequenceNumber int64  `json:"sequencenumber"`
			Timestamp      int64  `json:"timestamp"`
		} `json:"header"`
		EntryBlockList []struct {
			ChainID string `json:"chainid"`
			KeyMR   string `json:"keymr"`
		} `json:"entryblocklist"`
	})

	err = json.Unmarshal(resp.JSONResult(), db)
	if err != nil {
		return
	}

	// TODO: we need a better api call for dblock by keymr so that API will
	// retrun the same as dblock-byheight
	dblockHold, rawHold, errHold := GetDBlockByHeight(db.Header.SequenceNumber)
	dblockHold.SequenceNumber = db.Header.SequenceNumber
	return dblockHold, rawHold, errHold
}

// GetDBlockByHeight requests a Directory Block by its block height from the factomd
// API.
func GetDBlockByHeight(height int64) (dblock *DBlock, raw []byte, err error) {
	params := heightRequest{Height: height}
	req := NewJSON2Request("dblock-by-height", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return
	}
	if resp.Error != nil {
		return nil, nil, resp.Error
	}

	wrap := new(struct {
		DBlock  *DBlock `json:"dblock"`
		RawData string  `json:"rawdata"`
	})

	err = json.Unmarshal(resp.JSONResult(), wrap)
	if err != nil {
		return
	}

	raw, err = hex.DecodeString(wrap.RawData)
	if err != nil {
		return
	}

	return wrap.DBlock, raw, nil
}

// GetDBlockHead requests the most recent Directory Block Key Merkel Root
// created by the Factom Network.
func GetDBlockHead() (string, error) {
	req := NewJSON2Request("directory-block-head", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(struct {
		KeyMR string `json:"keymr"`
	})
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.KeyMR, nil
}
<commit_msg>moved where sequence number is added<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
)

// DBlock is a Factom Network Directory Block containing the Merkel root of all
// of the Entries and blocks from a 10 minute period in the Factom Network. The
// Directory Block Key Merkel Root is anchored into the Bitcoin and other
// blockchains for added security and immutability.
type DBlock struct {
	DBHash         string `json:"dbhash"`
	KeyMR          string `json:"keymr"`
	HeaderHash     string `json:"headerhash"`
	SequenceNumber int64  `json:"sequencenynumber"`
	Header         struct {
		Version      int    `json:"version"`
		NetworkID    int    `json:"networkid"`
		BodyMR       string `json:"bodymr"`
		PrevKeyMR    string `json:"prevkeymr"`
		PrevFullHash string `json:"prevfullhash"`
		Timestamp    int    `json:"timestamp"` //in minutes
		DBHeight     int    `json:"dbheight"`
		BlockCount   int    `json:"blockcount"`
	} `json:"header"`
	DBEntries []struct {
		ChainID string `json:"chainid"`
		KeyMR   string `json:"keymr"`
	} `json:"dbentries"`
}

func (db *DBlock) String() string {
	var s string

	s += fmt.Sprintln("DBHash:", db.DBHash)
	s += fmt.Sprintln("KeyMR:", db.KeyMR)
	s += fmt.Sprintln("HeaderHash:", db.HeaderHash)
	s += fmt.Sprintln("SequenceNumber:", db.SequenceNumber)
	s += fmt.Sprintln("Version:", db.Header.Version)
	s += fmt.Sprintln("NetworkID:", db.Header.NetworkID)
	s += fmt.Sprintln("BodyMR:", db.Header.BodyMR)
	s += fmt.Sprintln("PrevKeyMR:", db.Header.PrevKeyMR)
	s += fmt.Sprintln("PrevFullHash:", db.Header.PrevFullHash)
	s += fmt.Sprintln("Timestamp:", db.Header.Timestamp)
	s += fmt.Sprintln("DBHeight:", db.Header.DBHeight)
	s += fmt.Sprintln("BlockCount:", db.Header.BlockCount)

	s += fmt.Sprintln("DBEntries {")
	for _, v := range db.DBEntries {
		s += fmt.Sprintln("	ChainID:", v.ChainID)
		s += fmt.Sprintln("	KeyMR:", v.KeyMR)
	}
	s += fmt.Sprintln("}")

	return s
}

// TODO: GetDBlock should use the dblock api call directy instead of
// re-directing to dblock-by-height.
// we either need to change the "directoy-block" API call or add a new call to
// return the propper information (it should match the dblock-by-height call)

// GetDBlock requests a Directory Block by its Key Merkle Root from the factomd
// API.
func GetDBlock(keymr string) (dblock *DBlock, raw []byte, err error) {
	params := keyMRRequest{KeyMR: keymr}
	req := NewJSON2Request("directory-block", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return
	}
	if resp.Error != nil {
		return nil, nil, resp.Error
	}

	db := new(struct {
		DBHash string `json:"dbhash"`
		Header struct {
			PrevBlockKeyMR string `json:"prevblockkeymr"`
			SequenceNumber int64  `json:"sequencenumber"`
			Timestamp      int64  `json:"timestamp"`
		} `json:"header"`
		EntryBlockList []struct {
			ChainID string `json:"chainid"`
			KeyMR   string `json:"keymr"`
		} `json:"entryblocklist"`
	})

	err = json.Unmarshal(resp.JSONResult(), db)
	if err != nil {
		return
	}

	// TODO: we need a better api call for dblock by keymr so that API will
	// retrun the same as dblock-byheight
	//dblockHold, rawHold, errHold := GetDBlockByHeight(db.Header.SequenceNumber)
	//dblockHold.SequenceNumber = db.Header.SequenceNumber
	//return dblockHold, rawHold, errHold
	return GetDBlockByHeight(db.Header.SequenceNumber)
}

// GetDBlockByHeight requests a Directory Block by its block height from the factomd
// API.
func GetDBlockByHeight(height int64) (dblock *DBlock, raw []byte, err error) {
	params := heightRequest{Height: height}
	req := NewJSON2Request("dblock-by-height", APICounter(), params)
	resp, err := factomdRequest(req)
	if err != nil {
		return
	}
	if resp.Error != nil {
		return nil, nil, resp.Error
	}

	wrap := new(struct {
		DBlock  *DBlock `json:"dblock"`
		RawData string  `json:"rawdata"`
	})

	err = json.Unmarshal(resp.JSONResult(), wrap)
	if err != nil {
		return
	}

	raw, err = hex.DecodeString(wrap.RawData)
	if err != nil {
		return
	}

	wrap.DBlock.SequenceNumber = height
	return wrap.DBlock, raw, nil
}

// GetDBlockHead requests the most recent Directory Block Key Merkel Root
// created by the Factom Network.
func GetDBlockHead() (string, error) {
	req := NewJSON2Request("directory-block-head", APICounter(), nil)
	resp, err := factomdRequest(req)
	if err != nil {
		return "", err
	}
	if resp.Error != nil {
		return "", resp.Error
	}

	head := new(struct {
		KeyMR string `json:"keymr"`
	})
	if err := json.Unmarshal(resp.JSONResult(), head); err != nil {
		return "", err
	}

	return head.KeyMR, nil
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/jinzhu/gorm"
)

var (
	schemaModels = []interface{}{
		&Match{},
		&Alias{},
		&Player{},
		&WeaponStat{},
		&PlayerMatchStat{},
		&ItemStat{},
	}
)

func CreateSchema(db *gorm.DB) error {
	db.AutoMigrate(schemaModels...)
	return nil
}
<commit_msg>models/schema: use store.DB interface<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/bboozzoo/q3stats/store"
)

var (
	schemaModels = []interface{}{
		&Match{},
		&Alias{},
		&Player{},
		&WeaponStat{},
		&PlayerMatchStat{},
		&ItemStat{},
	}
)

func CreateSchema(store store.DB) error {
	store.Conn().AutoMigrate(schemaModels...)
	return nil
}
<|endoftext|>


<commit_before><commit_msg>Ensure container proc output goes to GinkgoWriter<commit_after><|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.

// Represents bencode data structure using native Go types: booleans, floats,
// strings, arrays, and maps.

package bencode

import (
	"container/vector"
	"io"
	"os"
)

// Decode a bencode stream

// Decode parses the stream r and returns the
// generic bencode object representation.  The object representation is a tree
// of Go data types.  The data return value may be one of string,
// int64, uint64, []interface{} or map[string]interface{}.  The array and map
// elements may in turn contain any of the types listed above and so on.
//
// If Decode encounters a syntax error, it returns with err set to an
// instance of ParseError.  See ParseError documentation for details.
func Decode(r io.Reader) (data interface{}, err os.Error) {
	jb := newDecoder(nil, nil)
	err = Parse(r, jb)
	if err == nil {
		data = jb.Data()
	}
	return
}

type decoder struct {
	// A value being constructed.
	value interface{}
	// Container entity to flush into.  Can be either vector.Vector or
	// map[string]interface{}.
	container interface{}
	// The index into the container interface.  Either int or string.
	index interface{}
}

func newDecoder(container interface{}, key interface{}) *decoder {
	return &decoder{container: container, index: key}
}

func (j *decoder) Int64(i int64) { j.value = int64(i) }

func (j *decoder) Uint64(i uint64) { j.value = uint64(i) }

func (j *decoder) Float64(f float64) { j.value = float64(f) }

func (j *decoder) String(s string) { j.value = s }

func (j *decoder) Bool(b bool) { j.value = b }

func (j *decoder) Null() { j.value = nil }

func (j *decoder) Array() { j.value = new(vector.Vector) }

func (j *decoder) Map() { j.value = make(map[string]interface{}) }

func (j *decoder) Elem(i int) Builder {
	v, ok := j.value.(*vector.Vector)
	if !ok {
		v = new(vector.Vector)
		j.value = v
	}
	if v.Len() <= i {
		v.Resize(i+1, (i+1)*2)
	}
	return newDecoder(v, i)
}

func (j *decoder) Key(s string) Builder {
	m, ok := j.value.(map[string]interface{})
	if !ok {
		m = make(map[string]interface{})
		j.value = m
	}
	return newDecoder(m, s)
}

func (j *decoder) Flush() {
	switch c := j.container.(type) {
	case *vector.Vector:
		index := j.index.(int)
		c.Set(index, j.Data())
	case map[string]interface{}:
		index := j.index.(string)
		c[index] = j.Data()
	}
}

// Get the value built by this builder.
func (j *decoder) Data() interface{} {
	switch v := j.value.(type) {
	case *vector.Vector:
		return v.Data()
	}
	return j.value
}
<commit_msg>Fix build problem with recent go release: vector Data() was renamed to Copy(). Also changed our own decoder method to reflect this.<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.

// Represents bencode data structure using native Go types: booleans, floats,
// strings, arrays, and maps.

package bencode

import (
	"container/vector"
	"io"
	"os"
)

// Decode a bencode stream

// Decode parses the stream r and returns the
// generic bencode object representation.  The object representation is a tree
// of Go data types.  The data return value may be one of string,
// int64, uint64, []interface{} or map[string]interface{}.  The array and map
// elements may in turn contain any of the types listed above and so on.
//
// If Decode encounters a syntax error, it returns with err set to an
// instance of ParseError.  See ParseError documentation for details.
func Decode(r io.Reader) (data interface{}, err os.Error) {
	jb := newDecoder(nil, nil)
	err = Parse(r, jb)
	if err == nil {
		data = jb.Copy()
	}
	return
}

type decoder struct {
	// A value being constructed.
	value interface{}
	// Container entity to flush into.  Can be either vector.Vector or
	// map[string]interface{}.
	container interface{}
	// The index into the container interface.  Either int or string.
	index interface{}
}

func newDecoder(container interface{}, key interface{}) *decoder {
	return &decoder{container: container, index: key}
}

func (j *decoder) Int64(i int64) { j.value = int64(i) }

func (j *decoder) Uint64(i uint64) { j.value = uint64(i) }

func (j *decoder) Float64(f float64) { j.value = float64(f) }

func (j *decoder) String(s string) { j.value = s }

func (j *decoder) Bool(b bool) { j.value = b }

func (j *decoder) Null() { j.value = nil }

func (j *decoder) Array() { j.value = new(vector.Vector) }

func (j *decoder) Map() { j.value = make(map[string]interface{}) }

func (j *decoder) Elem(i int) Builder {
	v, ok := j.value.(*vector.Vector)
	if !ok {
		v = new(vector.Vector)
		j.value = v
	}
	if v.Len() <= i {
		v.Resize(i+1, (i+1)*2)
	}
	return newDecoder(v, i)
}

func (j *decoder) Key(s string) Builder {
	m, ok := j.value.(map[string]interface{})
	if !ok {
		m = make(map[string]interface{})
		j.value = m
	}
	return newDecoder(m, s)
}

func (j *decoder) Flush() {
	switch c := j.container.(type) {
	case *vector.Vector:
		index := j.index.(int)
		c.Set(index, j.Copy())
	case map[string]interface{}:
		index := j.index.(string)
		c[index] = j.Copy()
	}
}

// Get the value built by this builder.
func (j *decoder) Copy() interface{} {
	switch v := j.value.(type) {
	case *vector.Vector:
		return v.Copy()
	}
	return j.value
}
<|endoftext|>


<commit_before>package fitsio

import (
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
)

type Decoder interface {
	DecodeHDU() (HDU, error)
}

// NewDecoder creates a new Decoder according to the capabilities of the underlying io.Reader
func NewDecoder(r io.Reader) Decoder {
	// FIXME(sbinet)
	// if rr, ok := r.(io.ReadSeeker); ok {
	// 	return &seekDecoder{r: rr}
	// }
	return &streamDecoder{r: r}
}

// streamDecoder is a decoder which can not perform random access
// into the underlying Reader
type streamDecoder struct {
	r io.Reader
}

func (dec *streamDecoder) DecodeHDU() (HDU, error) {
	var err error
	var hdu HDU

	cards := make(map[string]int, 30)
	slice := make([]Card, 0, 1)

	get_card := func(k string) (Card, bool) {
		i, dup := cards[k]
		if dup {
			return slice[i], dup
		}
		return Card{}, dup
	}

	add_card := func(c *Card) {
		n := c.Name
		if n == "COMMENT" || n == "HISTORY" || n == "" {
			slice = append(slice, *c)
			return
		}
		_, dup := cards[n]
		if dup {
			panic(fmt.Errorf("fitsio: duplicate keyword [%s]", n))
		}
		cards[n] = len(slice)
		slice = append(slice, *c)
	}

	axes := []int{}

	iblock := -1
blocks_loop:
	for {
		iblock += 1
		buf, err := readBlock(dec.r)
		if err != nil {
			return nil, err
		}

		// each FITS header block is comprised of up to 36 80-byte lines
		const maxlines = 36
		for i := 0; i < maxlines; i++ {
			card, err := parseHeaderLine(buf[i*80 : (i+1)*80])
			if err != nil {
				return nil, err
			}
			if card.Name == "CONTINUE" {
				idx := len(slice) - 1
				last := slice[idx]
				str := last.Value.(string)
				if len(str) > 0 {
					last.Value = str[:len(str)-1] + card.Comment
				}
				slice[idx] = last
				continue
			}
			add_card(card)
			if card.Name == "END" {
				break
			}
		}

		_, ends := get_card("END")
		if ends {
			card, ok := get_card("NAXIS")
			if ok {
				n := card.Value.(int)
				axes = make([]int, n)
				for i := 0; i < n; i++ {
					k := fmt.Sprintf("NAXIS%d", i+1)
					c, ok := get_card(k)
					if !ok {
						return nil, fmt.Errorf("fitsio: missing '%s' key", k)
					}
					axes[i] = c.Value.(int)
				}
			}
			break blocks_loop
		}
	}

	htype, primary, err := hduTypeFrom(slice)
	if err != nil {
		return nil, err
	}

	bitpix := 0
	if card, ok := get_card("BITPIX"); ok {
		bitpix = int(reflect.ValueOf(card.Value).Int())
	} else {
		return nil, fmt.Errorf("fitsio: missing 'BITPIX' card")
	}

	hdr := NewHeader(slice, htype, bitpix, axes)
	switch htype {
	case IMAGE_HDU:
		var data []byte
		data, err = dec.loadImage(hdr)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading image: %v", err)
		}

		switch primary {
		case true:
			hdu = &primaryHDU{
				imageHDU: imageHDU{
					hdr: *hdr,
					raw: data,
				},
			}
		case false:
			hdu = &imageHDU{
				hdr: *hdr,
				raw: data,
			}
		}

	case BINARY_TBL:
		hdu, err = dec.loadTable(hdr, htype)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading binary table: %v", err)
		}

	case ASCII_TBL:
		hdu, err = dec.loadTable(hdr, htype)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading ascii table: %v", err)
		}

	case ANY_HDU:
		fallthrough
	default:
		return nil, fmt.Errorf("fitsio: invalid HDU Type (%v)", htype)
	}

	return hdu, err
}

func (dec *streamDecoder) loadImage(hdr *Header) ([]byte, error) {
	var err error
	var buf []byte

	nelmts := 1
	for _, dim := range hdr.Axes() {
		nelmts *= dim
	}

	if len(hdr.Axes()) <= 0 {
		nelmts = 0
	}

	pixsz := hdr.Bitpix() / 8
	if pixsz < 0 {
		pixsz = -pixsz
	}

	buf = make([]byte, nelmts*pixsz)
	if nelmts == 0 {
		return buf, nil
	}

	n, err := dec.r.Read(buf)
	if err != nil {
		return nil, fmt.Errorf("fitsio: error reading buffer: %v", err)
	}
	if n != len(buf) {
		return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(buf))
	}

	// data array is also aligned at 2880-bytes blocks
	pad := padBlock(n)
	if pad > 0 {
		n, err = dec.r.Read(make([]byte, pad))
		if err != nil {
			return nil, fmt.Errorf("fitsio: error reading buffer: %v", err)
		}
		if n != pad {
			return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(buf))
		}
	}

	return buf, err
}

func (dec *streamDecoder) loadTable(hdr *Header, htype HDUType) (*Table, error) {
	var err error
	var table *Table

	isbinary := true
	switch htype {
	case ASCII_TBL:
		isbinary = false
	case BINARY_TBL:
		isbinary = true
	default:
		return nil, fmt.Errorf("fitsio: invalid HDU type (%v)", htype)
	}

	rowsz := hdr.Axes()[0]
	nrows := int64(hdr.Axes()[1])
	ncols := 0
	if card := hdr.Get("TFIELDS"); card != nil {
		ncols = card.Value.(int)
	}

	datasz := int(nrows) * rowsz
	heapsz := 0
	if card := hdr.Get("PCOUNT"); card != nil {
		heapsz = card.Value.(int)
	}

	blocksz := alignBlock(datasz + heapsz)

	block := make([]byte, blocksz)
	n, err := dec.r.Read(block)
	if err != nil {
		return nil, err
	}
	if n != len(block) {
		return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(block))
	}

	gapsz := 0
	if card := hdr.Get("THEAP"); card != nil {
		gapsz = card.Value.(int)
	}

	data := block[:datasz]
	heap := block[datasz+gapsz:]

	cols := make([]Column, ncols)
	colidx := make(map[string]int, ncols)

	get := func(str string, ii int) *Card {
		return hdr.Get(fmt.Sprintf(str+"%d", ii+1))
	}

	offset := 0
	for i := 0; i < ncols; i++ {
		col := &cols[i]

		switch htype {
		case BINARY_TBL:
			col.write = col.writeBin
			col.read = col.readBin
		case ASCII_TBL:
			col.write = col.writeTxt
			col.read = col.readTxt
		default:
			return nil, fmt.Errorf("fitsio: invalid HDUType (%v)", htype)
		}

		col.offset = offset

		card := get("TTYPE", i)
		col.Name = card.Value.(string)

		card = get("TFORM", i)
		if card == nil {
			return nil, fmt.Errorf("fitsio: missing 'TFORM%d' for column '%s'", i+1, col.Name)
		} else {
			col.Format = card.Value.(string)
		}

		card = get("TUNIT", i)
		if card != nil {
			col.Unit = card.Value.(string)
		}

		card = get("TNULL", i)
		if card != nil {
			col.Null = fmt.Sprintf("%v", card.Value)
		}

		card = get("TSCAL", i)
		if card != nil {
			switch vv := card.Value.(type) {
			case float64:
				col.Bscale = vv
			case int64:
				col.Bscale = float64(vv)
			case int:
				col.Bscale = float64(vv)
			default:
				return nil, fmt.Errorf("fitsio: unhandled type [%T]", vv)
			}
		} else {
			col.Bscale = 1.0
		}

		card = get("TZERO", i)
		if card != nil {
			switch vv := card.Value.(type) {
			case float64:
				col.Bzero = vv
			case int64:
				col.Bzero = float64(vv)
			case int:
				col.Bzero = float64(vv)
			default:
				return nil, fmt.Errorf("fitsio: unhandled type [%T]", vv)
			}
		} else {
			col.Bzero = 0.0
		}

		card = get("TDISP", i)
		if card != nil {
			col.Display = card.Value.(string)
		}

		card = get("TDIM", i)
		if card != nil {
			dims := card.Value.(string)
			dims = strings.Replace(dims, "(", "", -1)
			dims = strings.Replace(dims, ")", "", -1)
			toks := make([]string, 0)
			for _, tok := range strings.Split(dims, ",") {
				tok = strings.Trim(tok, " \t\n")
				if tok == "" {
					continue
				}
				toks = append(toks, tok)
			}
			col.Dim = make([]int64, 0, len(toks))
			for _, tok := range toks {
				dim, err := strconv.ParseInt(tok, 10, 64)
				if err != nil {
					return nil, err
				}
				col.Dim = append(col.Dim, dim)
			}
		}

		card = get("TBCOL", i)
		if card != nil {
			col.Start = int64(card.Value.(int))
		}

		col.dtype, err = typeFromForm(col.Format, htype)
		if err != nil {
			return nil, err
		}
		offset += col.dtype.dsize * col.dtype.len
		if htype == ASCII_TBL {
			col.txtfmt = txtfmtFromForm(col.Format)
		}
		colidx[col.Name] = i
	}

	table = &Table{
		hdr:    *hdr,
		binary: isbinary,
		data:   data,
		heap:   heap,
		rowsz:  rowsz,
		nrows:  nrows,
		cols:   cols,
		colidx: colidx,
	}

	return table, err
}

// seekDecoder is a decoder which can perform random access into
// the underlying Reader
type seekDecoder struct {
	r io.ReadSeeker
}

func (dec *seekDecoder) DecodeHDU() (HDU, error) {
	var err error
	panic("not implemented")
	return nil, err
}

func hduTypeFrom(cards []Card) (HDUType, bool, error) {
	var err error
	var htype HDUType = -1
	var primary bool

	keys := make([]string, 0, len(cards))
	for _, card := range cards {
		keys = append(keys, card.Name)
		switch card.Name {
		case "SIMPLE":
			primary = true
			return IMAGE_HDU, primary, nil
		case "XTENSION":
			str := card.Value.(string)
			switch str {
			case "IMAGE":
				htype = IMAGE_HDU
			case "TABLE":
				htype = ASCII_TBL
			case "BINTABLE":
				htype = BINARY_TBL
			case "ANY", "ANY_HDU":
				htype = ANY_HDU
			default:
				return htype, primary, fmt.Errorf("fitsio: invalid 'XTENSION' value: %q", str)
			}

			return htype, primary, err
		}
	}

	return htype, primary, fmt.Errorf("fitsio: invalid header (missing 'SIMPLE' or 'XTENSION' card): keys=%v", keys)
}
<commit_msg>decode: more resilient against interesting tables' values<commit_after>package fitsio

import (
	"fmt"
	"io"
	"reflect"
	"strconv"
	"strings"
)

type Decoder interface {
	DecodeHDU() (HDU, error)
}

// NewDecoder creates a new Decoder according to the capabilities of the underlying io.Reader
func NewDecoder(r io.Reader) Decoder {
	// FIXME(sbinet)
	// if rr, ok := r.(io.ReadSeeker); ok {
	// 	return &seekDecoder{r: rr}
	// }
	return &streamDecoder{r: r}
}

// streamDecoder is a decoder which can not perform random access
// into the underlying Reader
type streamDecoder struct {
	r io.Reader
}

func (dec *streamDecoder) DecodeHDU() (HDU, error) {
	var err error
	var hdu HDU

	cards := make(map[string]int, 30)
	slice := make([]Card, 0, 1)

	get_card := func(k string) (Card, bool) {
		i, dup := cards[k]
		if dup {
			return slice[i], dup
		}
		return Card{}, dup
	}

	add_card := func(c *Card) {
		n := c.Name
		if n == "COMMENT" || n == "HISTORY" || n == "" {
			slice = append(slice, *c)
			return
		}
		_, dup := cards[n]
		if dup {
			panic(fmt.Errorf("fitsio: duplicate keyword [%s]", n))
		}
		cards[n] = len(slice)
		slice = append(slice, *c)
	}

	axes := []int{}

	iblock := -1
blocks_loop:
	for {
		iblock += 1
		buf, err := readBlock(dec.r)
		if err != nil {
			return nil, err
		}

		// each FITS header block is comprised of up to 36 80-byte lines
		const maxlines = 36
		for i := 0; i < maxlines; i++ {
			card, err := parseHeaderLine(buf[i*80 : (i+1)*80])
			if err != nil {
				return nil, err
			}
			if card.Name == "CONTINUE" {
				idx := len(slice) - 1
				last := slice[idx]
				str := last.Value.(string)
				if len(str) > 0 {
					last.Value = str[:len(str)-1] + card.Comment
				}
				slice[idx] = last
				continue
			}
			add_card(card)
			if card.Name == "END" {
				break
			}
		}

		_, ends := get_card("END")
		if ends {
			card, ok := get_card("NAXIS")
			if ok {
				n := card.Value.(int)
				axes = make([]int, n)
				for i := 0; i < n; i++ {
					k := fmt.Sprintf("NAXIS%d", i+1)
					c, ok := get_card(k)
					if !ok {
						return nil, fmt.Errorf("fitsio: missing '%s' key", k)
					}
					axes[i] = c.Value.(int)
				}
			}
			break blocks_loop
		}
	}

	htype, primary, err := hduTypeFrom(slice)
	if err != nil {
		return nil, err
	}

	bitpix := 0
	if card, ok := get_card("BITPIX"); ok {
		bitpix = int(reflect.ValueOf(card.Value).Int())
	} else {
		return nil, fmt.Errorf("fitsio: missing 'BITPIX' card")
	}

	hdr := NewHeader(slice, htype, bitpix, axes)
	switch htype {
	case IMAGE_HDU:
		var data []byte
		data, err = dec.loadImage(hdr)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading image: %v", err)
		}

		switch primary {
		case true:
			hdu = &primaryHDU{
				imageHDU: imageHDU{
					hdr: *hdr,
					raw: data,
				},
			}
		case false:
			hdu = &imageHDU{
				hdr: *hdr,
				raw: data,
			}
		}

	case BINARY_TBL:
		hdu, err = dec.loadTable(hdr, htype)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading binary table: %v", err)
		}

	case ASCII_TBL:
		hdu, err = dec.loadTable(hdr, htype)
		if err != nil {
			return nil, fmt.Errorf("fitsio: error loading ascii table: %v", err)
		}

	case ANY_HDU:
		fallthrough
	default:
		return nil, fmt.Errorf("fitsio: invalid HDU Type (%v)", htype)
	}

	return hdu, err
}

func (dec *streamDecoder) loadImage(hdr *Header) ([]byte, error) {
	var err error
	var buf []byte

	nelmts := 1
	for _, dim := range hdr.Axes() {
		nelmts *= dim
	}

	if len(hdr.Axes()) <= 0 {
		nelmts = 0
	}

	pixsz := hdr.Bitpix() / 8
	if pixsz < 0 {
		pixsz = -pixsz
	}

	buf = make([]byte, nelmts*pixsz)
	if nelmts == 0 {
		return buf, nil
	}

	n, err := dec.r.Read(buf)
	if err != nil {
		return nil, fmt.Errorf("fitsio: error reading buffer: %v", err)
	}
	if n != len(buf) {
		return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(buf))
	}

	// data array is also aligned at 2880-bytes blocks
	pad := padBlock(n)
	if pad > 0 {
		n, err = dec.r.Read(make([]byte, pad))
		if err != nil {
			return nil, fmt.Errorf("fitsio: error reading buffer: %v", err)
		}
		if n != pad {
			return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(buf))
		}
	}

	return buf, err
}

func (dec *streamDecoder) loadTable(hdr *Header, htype HDUType) (*Table, error) {
	var err error
	var table *Table

	isbinary := true
	switch htype {
	case ASCII_TBL:
		isbinary = false
	case BINARY_TBL:
		isbinary = true
	default:
		return nil, fmt.Errorf("fitsio: invalid HDU type (%v)", htype)
	}

	rowsz := hdr.Axes()[0]
	nrows := int64(hdr.Axes()[1])
	ncols := 0
	if card := hdr.Get("TFIELDS"); card != nil && card.Value != nil {
		ncols = card.Value.(int)
	}

	datasz := int(nrows) * rowsz
	heapsz := 0
	if card := hdr.Get("PCOUNT"); card != nil && card.Value != nil {
		heapsz = card.Value.(int)
	}

	blocksz := alignBlock(datasz + heapsz)

	block := make([]byte, blocksz)
	n, err := dec.r.Read(block)
	if err != nil {
		return nil, err
	}
	if n != len(block) {
		return nil, fmt.Errorf("fitsio: read too few bytes (%d). expected %d", n, len(block))
	}

	gapsz := 0
	if card := hdr.Get("THEAP"); card != nil && card.Value != nil {
		gapsz = card.Value.(int)
	}

	data := block[:datasz]
	heap := block[datasz+gapsz:]

	cols := make([]Column, ncols)
	colidx := make(map[string]int, ncols)

	get := func(str string, ii int) *Card {
		return hdr.Get(fmt.Sprintf(str+"%d", ii+1))
	}

	offset := 0
	for i := 0; i < ncols; i++ {
		col := &cols[i]

		switch htype {
		case BINARY_TBL:
			col.write = col.writeBin
			col.read = col.readBin
		case ASCII_TBL:
			col.write = col.writeTxt
			col.read = col.readTxt
		default:
			return nil, fmt.Errorf("fitsio: invalid HDUType (%v)", htype)
		}

		col.offset = offset

		card := get("TTYPE", i)
		col.Name = card.Value.(string)

		card = get("TFORM", i)
		if card == nil {
			return nil, fmt.Errorf("fitsio: missing 'TFORM%d' for column '%s'", i+1, col.Name)
		} else {
			col.Format = card.Value.(string)
		}

		card = get("TUNIT", i)
		if card != nil && card.Value != nil {
			col.Unit = card.Value.(string)
		}

		card = get("TNULL", i)
		if card != nil && card.Value != nil {
			col.Null = fmt.Sprintf("%v", card.Value)
		}

		card = get("TSCAL", i)
		if card != nil && card.Value != nil {
			switch vv := card.Value.(type) {
			case float64:
				col.Bscale = vv
			case int64:
				col.Bscale = float64(vv)
			case int:
				col.Bscale = float64(vv)
			default:
				return nil, fmt.Errorf("fitsio: unhandled type [%T]", vv)
			}
		} else {
			col.Bscale = 1.0
		}

		card = get("TZERO", i)
		if card != nil && card.Value != nil {
			switch vv := card.Value.(type) {
			case float64:
				col.Bzero = vv
			case int64:
				col.Bzero = float64(vv)
			case int:
				col.Bzero = float64(vv)
			default:
				return nil, fmt.Errorf("fitsio: unhandled type [%T]", vv)
			}
		} else {
			col.Bzero = 0.0
		}

		card = get("TDISP", i)
		if card != nil && card.Value != nil {
			col.Display = card.Value.(string)
		}

		card = get("TDIM", i)
		if card != nil && card.Value != nil {
			dims := card.Value.(string)
			dims = strings.Replace(dims, "(", "", -1)
			dims = strings.Replace(dims, ")", "", -1)
			toks := make([]string, 0)
			for _, tok := range strings.Split(dims, ",") {
				tok = strings.Trim(tok, " \t\n")
				if tok == "" {
					continue
				}
				toks = append(toks, tok)
			}
			col.Dim = make([]int64, 0, len(toks))
			for _, tok := range toks {
				dim, err := strconv.ParseInt(tok, 10, 64)
				if err != nil {
					return nil, err
				}
				col.Dim = append(col.Dim, dim)
			}
		}

		card = get("TBCOL", i)
		if card != nil && card.Value != nil {
			col.Start = int64(card.Value.(int))
		}

		col.dtype, err = typeFromForm(col.Format, htype)
		if err != nil {
			return nil, err
		}
		offset += col.dtype.dsize * col.dtype.len
		if htype == ASCII_TBL {
			col.txtfmt = txtfmtFromForm(col.Format)
		}
		colidx[col.Name] = i
	}

	table = &Table{
		hdr:    *hdr,
		binary: isbinary,
		data:   data,
		heap:   heap,
		rowsz:  rowsz,
		nrows:  nrows,
		cols:   cols,
		colidx: colidx,
	}

	return table, err
}

// seekDecoder is a decoder which can perform random access into
// the underlying Reader
type seekDecoder struct {
	r io.ReadSeeker
}

func (dec *seekDecoder) DecodeHDU() (HDU, error) {
	var err error
	panic("not implemented")
	return nil, err
}

func hduTypeFrom(cards []Card) (HDUType, bool, error) {
	var err error
	var htype HDUType = -1
	var primary bool

	keys := make([]string, 0, len(cards))
	for _, card := range cards {
		keys = append(keys, card.Name)
		switch card.Name {
		case "SIMPLE":
			primary = true
			return IMAGE_HDU, primary, nil
		case "XTENSION":
			str := card.Value.(string)
			switch str {
			case "IMAGE":
				htype = IMAGE_HDU
			case "TABLE":
				htype = ASCII_TBL
			case "BINTABLE":
				htype = BINARY_TBL
			case "ANY", "ANY_HDU":
				htype = ANY_HDU
			default:
				return htype, primary, fmt.Errorf("fitsio: invalid 'XTENSION' value: %q", str)
			}

			return htype, primary, err
		}
	}

	return htype, primary, fmt.Errorf("fitsio: invalid header (missing 'SIMPLE' or 'XTENSION' card): keys=%v", keys)
}
<|endoftext|>


<commit_before>package logfmt

import (
	"errors"
	"fmt"
	"io"
)

type Decoder struct {
	r     io.ByteScanner
	state stateFn
	err   error
}

func NewDecoder(r io.ByteScanner) *Decoder {
	dec := &Decoder{
		r:     r,
		state: garbage,
	}
	return dec
}

func (dec *Decoder) DecodeKeyval() (key, value []byte, err error) {
	k, err := dec.Token()
	if err != nil {
		return nil, nil, err
	}
	if _, ok := k.(EndOfRecord); ok {
		return nil, nil, nil
	}
	kk, ok := k.(Key)
	if !ok {
		return nil, nil, fmt.Errorf("unexpected token, wanted %T, got %T", kk, k)
	}
	v, err := dec.Token()
	if err != nil {
		return nil, nil, err
	}
	vv, ok := v.(Value)
	if !ok {
		return nil, nil, fmt.Errorf("unexpected token, wanted %T, got %T", vv, v)
	}
	return kk, vv, nil
}

// func (dec *Decoder) NextRecord() error {
// }

func (dec *Decoder) Token() (Token, error) {
	var t Token
	for dec.err == nil && dec.state != nil && t == nil {
		dec.state, t, dec.err = dec.state(dec.r)
	}
	return t, dec.err
}

type stateFn func(io.ByteScanner) (stateFn, Token, error)

func garbage(r io.ByteScanner) (stateFn, Token, error) {
	for {
		c, err := r.ReadByte()
		if err != nil {
			return nil, nil, err
		}
		switch {
		case c == '\n':
			return garbage, EndOfRecord{}, nil
		case c > ' ' && c != '"' && c != '=':
			return key, nil, r.UnreadByte()
		}
	}
}

func key(r io.ByteScanner) (stateFn, Token, error) {
	var k []byte
	for {
		c, err := r.ReadByte()
		if err == io.EOF {
			return nvalue, Key(k), nil
		}
		if err != nil {
			return nil, Key(k), err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			k = append(k, c)
		case c == '=':
			return equal, Key(k), nil
		default:
			return nvalue, Key(k), r.UnreadByte()
		}
	}
}

func equal(r io.ByteScanner) (stateFn, Token, error) {
	for {
		c, err := r.ReadByte()
		if err == io.EOF {
			return nvalue, nil, nil
		}
		if err != nil {
			return nil, nil, err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			return ivalue, nil, r.UnreadByte()
		case c == '"':
			return qvalue, nil, r.UnreadByte()
		default:
			return nvalue, nil, r.UnreadByte()
		}
	}
}

func nvalue(r io.ByteScanner) (stateFn, Token, error) {
	return garbage, Value(nil), nil
}

func ivalue(r io.ByteScanner) (stateFn, Token, error) {
	var v []byte
	for {
		c, err := r.ReadByte()
		if err != nil {
			return nil, Value(v), err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			v = append(v, c)
		default:
			return garbage, Value(v), r.UnreadByte()
		}
	}
}

var (
	ErrUnterminatedValue  = errors.New("unterminated quoted value")
	ErrInvalidQuotedValue = errors.New("invalid quoted value")
)

func qvalue(r io.ByteScanner) (stateFn, Token, error) {
	var v []byte
	hasEsc, esc := false, false
	for {
		c, err := r.ReadByte()
		if err != nil {
			return nil, nil, ErrUnterminatedValue
		}
		switch {
		case esc:
			v = append(v, c)
			esc = false
		case c == '\\':
			v = append(v, c)
			hasEsc, esc = true, true
		case c == '"':
			v = append(v, c)
			if len(v) == 1 {
				break
			}
			if !hasEsc {
				return garbage, Value(v[1 : len(v)-1]), nil
			}
			uq, ok := unquoteBytes(v)
			if !ok {
				return nil, nil, ErrInvalidQuotedValue
			}
			return garbage, Value(uq), nil
		default:
			v = append(v, c)
		}
	}
}

// Token holds a value of one of these types:
//
//    Key
//    Value
//    EndOfRecord
type Token interface{}

type Key []byte

type Value []byte

type EndOfRecord struct{}
<commit_msg>Use internal bufio.Reader.<commit_after>package logfmt

import (
	"bufio"
	"errors"
	"fmt"
	"io"
)

type Decoder struct {
	r     *bufio.Reader
	state stateFn
	err   error
}

func NewDecoder(r io.Reader) *Decoder {
	dec := &Decoder{
		r: bufio.NewReader(r),
	}
	dec.state = garbage
	return dec
}

func (dec *Decoder) DecodeKeyval() (key, value []byte, err error) {
	k, err := dec.Token()
	if err != nil {
		return nil, nil, err
	}
	if _, ok := k.(EndOfRecord); ok {
		return nil, nil, nil
	}
	kk, ok := k.(Key)
	if !ok {
		return nil, nil, fmt.Errorf("unexpected token, wanted %T, got %T", kk, k)
	}
	v, err := dec.Token()
	if err != nil {
		return nil, nil, err
	}
	vv, ok := v.(Value)
	if !ok {
		return nil, nil, fmt.Errorf("unexpected token, wanted %T, got %T", vv, v)
	}
	return kk, vv, nil
}

// func (dec *Decoder) NextRecord() error {
// }

func (dec *Decoder) Token() (Token, error) {
	var t Token
	for dec.err == nil && dec.state != nil && t == nil {
		dec.state, t, dec.err = dec.state(dec)
	}
	return t, dec.err
}

type stateFn func(*Decoder) (stateFn, Token, error)

func garbage(dec *Decoder) (stateFn, Token, error) {
	for {
		c, err := dec.r.ReadByte()
		if err != nil {
			return nil, nil, err
		}
		switch {
		case c == '\n':
			return garbage, EndOfRecord{}, nil
		case c > ' ' && c != '"' && c != '=':
			return key, nil, dec.r.UnreadByte()
		}
	}
}

func key(dec *Decoder) (stateFn, Token, error) {
	var k []byte
	for {
		c, err := dec.r.ReadByte()
		if err == io.EOF {
			return nvalue, Key(k), nil
		}
		if err != nil {
			return nil, Key(k), err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			k = append(k, c)
		case c == '=':
			return equal, Key(k), nil
		default:
			return nvalue, Key(k), dec.r.UnreadByte()
		}
	}
}

func equal(dec *Decoder) (stateFn, Token, error) {
	for {
		c, err := dec.r.ReadByte()
		if err == io.EOF {
			return nvalue, nil, nil
		}
		if err != nil {
			return nil, nil, err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			return ivalue, nil, dec.r.UnreadByte()
		case c == '"':
			return qvalue, nil, dec.r.UnreadByte()
		default:
			return nvalue, nil, dec.r.UnreadByte()
		}
	}
}

func nvalue(dec *Decoder) (stateFn, Token, error) {
	return garbage, Value(nil), nil
}

func ivalue(dec *Decoder) (stateFn, Token, error) {
	var v []byte
	for {
		c, err := dec.r.ReadByte()
		if err != nil {
			return nil, Value(v), err
		}
		switch {
		case c > ' ' && c != '"' && c != '=':
			v = append(v, c)
		default:
			return garbage, Value(v), dec.r.UnreadByte()
		}
	}
}

var (
	ErrUnterminatedValue  = errors.New("unterminated quoted value")
	ErrInvalidQuotedValue = errors.New("invalid quoted value")
)

func qvalue(dec *Decoder) (stateFn, Token, error) {
	var v []byte
	hasEsc, esc := false, false
	for {
		c, err := dec.r.ReadByte()
		if err != nil {
			return nil, nil, ErrUnterminatedValue
		}
		switch {
		case esc:
			v = append(v, c)
			esc = false
		case c == '\\':
			v = append(v, c)
			hasEsc, esc = true, true
		case c == '"':
			v = append(v, c)
			if len(v) == 1 {
				break
			}
			if !hasEsc {
				return garbage, Value(v[1 : len(v)-1]), nil
			}
			uq, ok := unquoteBytes(v)
			if !ok {
				return nil, nil, ErrInvalidQuotedValue
			}
			return garbage, Value(uq), nil
		default:
			v = append(v, c)
		}
	}
}

// Token holds a value of one of these types:
//
//    Key
//    Value
//    EndOfRecord
type Token interface{}

type Key []byte

type Value []byte

type EndOfRecord struct{}
<|endoftext|>


<commit_before>package autonat

import (
	"context"
	"fmt"

	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"

	pb "github.com/libp2p/go-libp2p-autonat/pb"

	protoio "github.com/libp2p/go-msgio/protoio"
	ma "github.com/multiformats/go-multiaddr"
)

// Error wraps errors signalled by AutoNAT services
type Error struct {
	Status pb.Message_ResponseStatus
	Text   string
}

// NewAutoNATClient creates a fresh instance of an AutoNATClient
// If addrFunc is nil, h.Addrs will be used
func NewAutoNATClient(h host.Host, addrFunc AddrFunc) Client {
	if addrFunc == nil {
		addrFunc = h.Addrs
	}
	return &client{h: h, addrFunc: addrFunc}
}

type client struct {
	h        host.Host
	addrFunc AddrFunc
}

func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error) {
	s, err := c.h.NewStream(ctx, p, AutoNATProto)
	if err != nil {
		return nil, err
	}
	// Might as well just reset the stream. Once we get to this point, we
	// don't care about being nice.
	defer s.Close()

	r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
	w := protoio.NewDelimitedWriter(s)

	req := newDialMessage(peer.AddrInfo{ID: c.h.ID(), Addrs: c.addrFunc()})
	err = w.WriteMsg(req)
	if err != nil {
		s.Reset()
		return nil, err
	}

	var res pb.Message
	err = r.ReadMsg(&res)
	if err != nil {
		s.Reset()
		return nil, err
	}

	if res.GetType() != pb.Message_DIAL_RESPONSE {
		return nil, fmt.Errorf("unexpected response: %s", res.GetType().String())
	}

	status := res.GetDialResponse().GetStatus()
	switch status {
	case pb.Message_OK:
		addr := res.GetDialResponse().GetAddr()
		return ma.NewMultiaddrBytes(addr)

	default:
		return nil, Error{Status: status, Text: res.GetDialResponse().GetStatusText()}
	}
}

func (e Error) Error() string {
	return fmt.Sprintf("AutoNAT error: %s (%s)", e.Text, e.Status.String())
}

// IsDialError returns true if the error was due to a dial back failure
func (e Error) IsDialError() bool {
	return e.Status == pb.Message_E_DIAL_ERROR
}

// IsDialRefused returns true if the error was due to a refusal to dial back
func (e Error) IsDialRefused() bool {
	return e.Status == pb.Message_E_DIAL_REFUSED
}

// IsDialError returns true if the AutoNAT peer signalled an error dialing back
func IsDialError(e error) bool {
	ae, ok := e.(Error)
	return ok && ae.IsDialError()
}

// IsDialRefused returns true if the AutoNAT peer signalled refusal to dial back
func IsDialRefused(e error) bool {
	ae, ok := e.(Error)
	return ok && ae.IsDialRefused()
}
<commit_msg>also set a deadline on the stream opened by the client<commit_after>package autonat

import (
	"context"
	"fmt"
	"time"

	pb "github.com/libp2p/go-libp2p-autonat/pb"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-msgio/protoio"

	ma "github.com/multiformats/go-multiaddr"
)

// NewAutoNATClient creates a fresh instance of an AutoNATClient
// If addrFunc is nil, h.Addrs will be used
func NewAutoNATClient(h host.Host, addrFunc AddrFunc) Client {
	if addrFunc == nil {
		addrFunc = h.Addrs
	}
	return &client{h: h, addrFunc: addrFunc}
}

type client struct {
	h        host.Host
	addrFunc AddrFunc
}

// DialBack asks peer p to dial us back on all addresses returned by the addrFunc.
// It blocks until we've received a response from the peer.
func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error) {
	s, err := c.h.NewStream(ctx, p, AutoNATProto)
	if err != nil {
		return nil, err
	}
	s.SetDeadline(time.Now().Add(streamTimeout))
	// Might as well just reset the stream. Once we get to this point, we
	// don't care about being nice.
	defer s.Close()

	r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
	w := protoio.NewDelimitedWriter(s)

	req := newDialMessage(peer.AddrInfo{ID: c.h.ID(), Addrs: c.addrFunc()})
	if err := w.WriteMsg(req); err != nil {
		s.Reset()
		return nil, err
	}

	var res pb.Message
	if err := r.ReadMsg(&res); err != nil {
		s.Reset()
		return nil, err
	}

	if res.GetType() != pb.Message_DIAL_RESPONSE {
		return nil, fmt.Errorf("unexpected response: %s", res.GetType().String())
	}

	status := res.GetDialResponse().GetStatus()
	switch status {
	case pb.Message_OK:
		addr := res.GetDialResponse().GetAddr()
		return ma.NewMultiaddrBytes(addr)
	default:
		return nil, Error{Status: status, Text: res.GetDialResponse().GetStatusText()}
	}
}

// Error wraps errors signalled by AutoNAT services
type Error struct {
	Status pb.Message_ResponseStatus
	Text   string
}

func (e Error) Error() string {
	return fmt.Sprintf("AutoNAT error: %s (%s)", e.Text, e.Status.String())
}

// IsDialError returns true if the error was due to a dial back failure
func (e Error) IsDialError() bool {
	return e.Status == pb.Message_E_DIAL_ERROR
}

// IsDialRefused returns true if the error was due to a refusal to dial back
func (e Error) IsDialRefused() bool {
	return e.Status == pb.Message_E_DIAL_REFUSED
}

// IsDialError returns true if the AutoNAT peer signalled an error dialing back
func IsDialError(e error) bool {
	ae, ok := e.(Error)
	return ok && ae.IsDialError()
}

// IsDialRefused returns true if the AutoNAT peer signalled refusal to dial back
func IsDialRefused(e error) bool {
	ae, ok := e.(Error)
	return ok && ae.IsDialRefused()
}
<|endoftext|>


<commit_before>package libp2pquic

import (
	"context"

	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/mux"
	"github.com/libp2p/go-libp2p-core/peer"
	tpt "github.com/libp2p/go-libp2p-core/transport"

	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
)

type conn struct {
	sess      quic.Session
	transport tpt.Transport

	localPeer      peer.ID
	privKey        ic.PrivKey
	localMultiaddr ma.Multiaddr

	remotePeerID    peer.ID
	remotePubKey    ic.PubKey
	remoteMultiaddr ma.Multiaddr
}

var _ tpt.CapableConn = &conn{}

func (c *conn) Close() error {
	return c.sess.Close()
}

// IsClosed returns whether a connection is fully closed.
func (c *conn) IsClosed() bool {
	return c.sess.Context().Err() != nil
}

// OpenStream creates a new stream.
func (c *conn) OpenStream() (mux.MuxedStream, error) {
	qstr, err := c.sess.OpenStreamSync(context.Background())
	return &stream{Stream: qstr}, err
}

// AcceptStream accepts a stream opened by the other side.
func (c *conn) AcceptStream() (mux.MuxedStream, error) {
	qstr, err := c.sess.AcceptStream(context.Background())
	return &stream{Stream: qstr}, err
}

// LocalPeer returns our peer ID
func (c *conn) LocalPeer() peer.ID {
	return c.localPeer
}

// LocalPrivateKey returns our private key
func (c *conn) LocalPrivateKey() ic.PrivKey {
	return c.privKey
}

// RemotePeer returns the peer ID of the remote peer.
func (c *conn) RemotePeer() peer.ID {
	return c.remotePeerID
}

// RemotePublicKey returns the public key of the remote peer.
func (c *conn) RemotePublicKey() ic.PubKey {
	return c.remotePubKey
}

// LocalMultiaddr returns the local Multiaddr associated
func (c *conn) LocalMultiaddr() ma.Multiaddr {
	return c.localMultiaddr
}

// RemoteMultiaddr returns the remote Multiaddr associated
func (c *conn) RemoteMultiaddr() ma.Multiaddr {
	return c.remoteMultiaddr
}

func (c *conn) Transport() tpt.Transport {
	return c.transport
}
<commit_msg>update quic-go to v0.15.0<commit_after>package libp2pquic

import (
	"context"

	ic "github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/mux"
	"github.com/libp2p/go-libp2p-core/peer"
	tpt "github.com/libp2p/go-libp2p-core/transport"

	quic "github.com/lucas-clemente/quic-go"
	ma "github.com/multiformats/go-multiaddr"
)

type conn struct {
	sess      quic.Session
	transport tpt.Transport

	localPeer      peer.ID
	privKey        ic.PrivKey
	localMultiaddr ma.Multiaddr

	remotePeerID    peer.ID
	remotePubKey    ic.PubKey
	remoteMultiaddr ma.Multiaddr
}

var _ tpt.CapableConn = &conn{}

func (c *conn) Close() error {
	return c.sess.CloseWithError(0, "")
}

// IsClosed returns whether a connection is fully closed.
func (c *conn) IsClosed() bool {
	return c.sess.Context().Err() != nil
}

// OpenStream creates a new stream.
func (c *conn) OpenStream() (mux.MuxedStream, error) {
	qstr, err := c.sess.OpenStreamSync(context.Background())
	return &stream{Stream: qstr}, err
}

// AcceptStream accepts a stream opened by the other side.
func (c *conn) AcceptStream() (mux.MuxedStream, error) {
	qstr, err := c.sess.AcceptStream(context.Background())
	return &stream{Stream: qstr}, err
}

// LocalPeer returns our peer ID
func (c *conn) LocalPeer() peer.ID {
	return c.localPeer
}

// LocalPrivateKey returns our private key
func (c *conn) LocalPrivateKey() ic.PrivKey {
	return c.privKey
}

// RemotePeer returns the peer ID of the remote peer.
func (c *conn) RemotePeer() peer.ID {
	return c.remotePeerID
}

// RemotePublicKey returns the public key of the remote peer.
func (c *conn) RemotePublicKey() ic.PubKey {
	return c.remotePubKey
}

// LocalMultiaddr returns the local Multiaddr associated
func (c *conn) LocalMultiaddr() ma.Multiaddr {
	return c.localMultiaddr
}

// RemoteMultiaddr returns the remote Multiaddr associated
func (c *conn) RemoteMultiaddr() ma.Multiaddr {
	return c.remoteMultiaddr
}

func (c *conn) Transport() tpt.Transport {
	return c.transport
}
<|endoftext|>


<commit_before>package posix

import (
	"github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
)

type PosixKernel struct {
	common.KernelBase
	Unpack func(common.Buf, interface{})
}

func packAddrs(u models.Usercorn, addrs []uint64) ([]byte, error) {
	buf := make([]byte, int(u.Bits())/8*(len(addrs)+1))
	pos := buf
	rev := append([]uint64{0}, addrs...)
	for i := len(rev) - 1; i >= 0; i-- {
		x, err := u.PackAddr(pos, rev[i])
		if err != nil {
			return nil, err
		}
		pos = pos[len(x):]
	}
	return buf, nil
}

func pushStrings(u models.Usercorn, args ...string) ([]uint64, error) {
	addrs := make([]uint64, 0, len(args)+1)
	for _, arg := range args {
		if addr, err := u.PushBytes([]byte(arg + "\x00")); err != nil {
			return nil, err
		} else {
			addrs = append(addrs, addr)
		}
	}
	return addrs, nil
}

func StackInit(u models.Usercorn, args, env []string, auxv []byte) error {
	// push argv and envp strings
	envp, err := pushStrings(u, env...)
	if err != nil {
		return err
	}
	argv, err := pushStrings(u, args...)
	if err != nil {
		return err
	}
	// precalc envp -> argc for stack alignment
	envpb, err := packAddrs(u, envp)
	if err != nil {
		return err
	}
	argvb, err := packAddrs(u, argv)
	if err != nil {
		return err
	}
	var tmp [8]byte
	argcb, err := u.PackAddr(tmp[:], uint64(len(argv)))
	init := append(argcb, argvb...)
	init = append(init, envpb...)
	// align stack pointer
	sp, _ := u.RegRead(u.Arch().SP)
	sp &= ^uint64(15)
	off := len(init) & 15
	if off > 0 {
		sp -= uint64(16 - off)
	}
	u.RegWrite(u.Arch().SP, sp)
	// auxv
	if len(auxv) > 0 {
		if _, err := u.PushBytes(auxv); err != nil {
			return err
		}
	}
	// write envp -> argc
	u.PushBytes(init)
	return err
}
<commit_msg>fix reversed argv<commit_after>package posix

import (
	"github.com/lunixbochs/usercorn/go/kernel/common"
	"github.com/lunixbochs/usercorn/go/models"
)

type PosixKernel struct {
	common.KernelBase
	Unpack func(common.Buf, interface{})
}

func packAddrs(u models.Usercorn, addrs []uint64) ([]byte, error) {
	buf := make([]byte, int(u.Bits())/8*(len(addrs)+1))
	pos := buf
	for _, v := range addrs {
		x, err := u.PackAddr(pos, v)
		if err != nil {
			return nil, err
		}
		pos = pos[len(x):]
	}
	return buf, nil
}

func pushStrings(u models.Usercorn, args ...string) ([]uint64, error) {
	addrs := make([]uint64, 0, len(args)+1)
	for _, arg := range args {
		if addr, err := u.PushBytes([]byte(arg + "\x00")); err != nil {
			return nil, err
		} else {
			addrs = append(addrs, addr)
		}
	}
	return addrs, nil
}

func StackInit(u models.Usercorn, args, env []string, auxv []byte) error {
	// push argv and envp strings
	envp, err := pushStrings(u, env...)
	if err != nil {
		return err
	}
	argv, err := pushStrings(u, args...)
	if err != nil {
		return err
	}
	// precalc envp -> argc for stack alignment
	envpb, err := packAddrs(u, envp)
	if err != nil {
		return err
	}
	argvb, err := packAddrs(u, argv)
	if err != nil {
		return err
	}
	var tmp [8]byte
	argcb, err := u.PackAddr(tmp[:], uint64(len(argv)))
	init := append(argcb, argvb...)
	init = append(init, envpb...)
	// align stack pointer
	sp, _ := u.RegRead(u.Arch().SP)
	sp &= ^uint64(15)
	off := len(init) & 15
	if off > 0 {
		sp -= uint64(16 - off)
	}
	u.RegWrite(u.Arch().SP, sp)
	// auxv
	if len(auxv) > 0 {
		if _, err := u.PushBytes(auxv); err != nil {
			return err
		}
	}
	// write envp -> argc
	u.PushBytes(init)
	return err
}
<|endoftext|>


<commit_before>// 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 signature provides implementations of the Signer and Verifier
// primitives.
//
// To sign data using Tink you can use ECDSA or ED25519 key templates.
//
// Example:
//
//   package main
//
//   import (
//       "fmt"
//
//       "github.com/google/tink/go/signature"
//       "github.com/google/tink/go/keyset"
//   )
//
//   func main() {
//
//       kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) // other key templates can also be used
//       if err != nil {
//           // handle the error
//       }
//
//       s := signature.NewSigner(kh)
//
//       a , err := s.Sign([]byte("this data needs to be signed"))
//       if err != nil {
//           // handle error
//       }
//
//       v := signature.NewVerifier(kh)
//
//       if err := v.Verify(a, []byte("this data needs to be signed")); err != nil {
//           // handle error
//       }
//   }
package signature

import (
	"fmt"

	"github.com/google/tink/go/core/registry"
)

func init() {
	// ECDSA
	if err := registry.RegisterKeyManager(newECDSASignerKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
	if err := registry.RegisterKeyManager(newECDSAVerifierKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}

	// ED25519
	if err := registry.RegisterKeyManager(newED25519SignerKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
	if err := registry.RegisterKeyManager(newED25519VerifierKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
}
<commit_msg>updated golang signature example in doc comment<commit_after>// 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 signature provides implementations of the Signer and Verifier
// primitives.
//
// To sign data using Tink you can use ECDSA or ED25519 key templates.
//
// Example:
//
//   package main
//
//   import (
//       "fmt"
//
//       "github.com/google/tink/go/signature"
//       "github.com/google/tink/go/keyset"
//   )
//
//   func main() {
//
//       kh, err := keyset.NewHandle(signature.ECDSAP256KeyTemplate()) // other key templates can also be used
//       if err != nil {
//           // handle the error
//       }
//
//       s, err := signature.NewSigner(kh)
//	     if err != nil {
//		     // handle error
//       }
//
//       a , err := s.Sign([]byte("this data needs to be signed"))
//       if err != nil {
//           // handle the error
//       }
//
//       pubkh, err := kh.Public()
//	     if err != nil {
//           // handle the error
//       }
//
//       v, err := signature.NewVerifier(pubkh)
//	     if err != nil {
//           // handle the error
//       }
//
//       if err := v.Verify(a, []byte("this data needs to be signed")); err != nil {
//           // handle the error
//       }
//   }
package signature

import (
	"fmt"

	"github.com/google/tink/go/core/registry"
)

func init() {
	// ECDSA
	if err := registry.RegisterKeyManager(newECDSASignerKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
	if err := registry.RegisterKeyManager(newECDSAVerifierKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}

	// ED25519
	if err := registry.RegisterKeyManager(newED25519SignerKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
	if err := registry.RegisterKeyManager(newED25519VerifierKeyManager()); err != nil {
		panic(fmt.Sprintf("signature.init() failed: %v", err))
	}
}
<|endoftext|>


<commit_before>// Copyright 2013, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package topo

import (
//	"errors"
//	"flag"
//	"fmt"
//	"time"

//	log "github.com/golang/glog"
)

// ReplicationLink describes a MySQL replication relationship
type ReplicationLink struct {
	TabletAlias TabletAlias
	Parent      TabletAlias
}

// The ShardReplication object describes the MySQL replication relationships
// whithin a cell.
type ShardReplication struct {
	// Note there can be only one ReplicationLink in this array
	// for a given Slave (each Slave can only have one parent)
	ReplicationLinks []ReplicationLink
}

// The ShardReplicationInfo is the companion structure for ShardReplication
type ShardReplicationInfo struct {
	*ShardReplication
	cell     string
	keyspace string
	shard    string
}

func NewShardReplicationInfo(sr *ShardReplication, cell, keyspace, shard string) *ShardReplicationInfo {
	return &ShardReplicationInfo{
		ShardReplication: sr,
		cell:             cell,
		keyspace:         keyspace,
		shard:            shard,
	}
}

func (sri *ShardReplicationInfo) Cell() string {
	return sri.cell
}

func (sri *ShardReplicationInfo) Keyspace() string {
	return sri.keyspace
}

func (sri *ShardReplicationInfo) Shard() string {
	return sri.shard
}
<commit_msg>Cosmetic changes.<commit_after>// Copyright 2013, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package topo

// ReplicationLink describes a MySQL replication relationship
type ReplicationLink struct {
	TabletAlias TabletAlias
	Parent      TabletAlias
}

// ShardReplication describes the MySQL replication relationships
// whithin a cell.
type ShardReplication struct {
	// Note there can be only one ReplicationLink in this array
	// for a given Slave (each Slave can only have one parent)
	ReplicationLinks []ReplicationLink
}

// ShardReplicationInfo is the companion structure for ShardReplication.
type ShardReplicationInfo struct {
	*ShardReplication
	cell     string
	keyspace string
	shard    string
}

// For topo.Server implementations to create the structure
func NewShardReplicationInfo(sr *ShardReplication, cell, keyspace, shard string) *ShardReplicationInfo {
	return &ShardReplicationInfo{
		ShardReplication: sr,
		cell:             cell,
		keyspace:         keyspace,
		shard:            shard,
	}
}

// Accessor methods

func (sri *ShardReplicationInfo) Cell() string {
	return sri.cell
}

func (sri *ShardReplicationInfo) Keyspace() string {
	return sri.keyspace
}

func (sri *ShardReplicationInfo) Shard() string {
	return sri.shard
}
<|endoftext|>


<commit_before><commit_msg>Show hex exit code for windows prereqs<commit_after><|endoftext|>


<commit_before>package dstest

import (
	"bytes"
	"fmt"
	"math/rand"
	"reflect"
	"strings"
	"testing"

	dstore "github.com/ipfs/go-datastore"
	dsq "github.com/ipfs/go-datastore/query"
)

func SubtestBasicPutGet(t *testing.T, ds dstore.Datastore) {
	k := dstore.NewKey("foo")
	val := []byte("Hello Datastore!")

	err := ds.Put(k, val)
	if err != nil {
		t.Fatal("error putting to datastore: ", err)
	}

	have, err := ds.Has(k)
	if err != nil {
		t.Fatal("error calling has on key we just put: ", err)
	}

	if !have {
		t.Fatal("should have key foo, has returned false")
	}

	size, err := ds.GetSize(k)
	if err != nil {
		t.Fatal("error getting size after put: ", err)
	}
	if size != len(val) {
		t.Fatalf("incorrect size: expected %d, got %d", len(val), size)
	}

	out, err := ds.Get(k)
	if err != nil {
		t.Fatal("error getting value after put: ", err)
	}

	if !bytes.Equal(out, val) {
		t.Fatal("value received on get wasnt what we expected:", out)
	}

	have, err = ds.Has(k)
	if err != nil {
		t.Fatal("error calling has after get: ", err)
	}

	if !have {
		t.Fatal("should have key foo, has returned false")
	}

	size, err = ds.GetSize(k)
	if err != nil {
		t.Fatal("error getting size after get: ", err)
	}
	if size != len(val) {
		t.Fatalf("incorrect size: expected %d, got %d", len(val), size)
	}

	err = ds.Delete(k)
	if err != nil {
		t.Fatal("error calling delete: ", err)
	}

	have, err = ds.Has(k)
	if err != nil {
		t.Fatal("error calling has after delete: ", err)
	}

	if have {
		t.Fatal("should not have key foo, has returned true")
	}

	size, err = ds.GetSize(k)
	switch err {
	case dstore.ErrNotFound:
	case nil:
		t.Fatal("expected error getting size after delete")
	default:
		t.Fatal("wrong error getting size after delete: ", err)
	}
	if size != -1 {
		t.Fatal("expected missing size to be -1")
	}
}

func SubtestNotFounds(t *testing.T, ds dstore.Datastore) {
	badk := dstore.NewKey("notreal")

	val, err := ds.Get(badk)
	if err != dstore.ErrNotFound {
		t.Fatal("expected ErrNotFound for key that doesnt exist, got: ", err)
	}

	if val != nil {
		t.Fatal("get should always return nil for not found values")
	}

	have, err := ds.Has(badk)
	if err != nil {
		t.Fatal("error calling has on not found key: ", err)
	}
	if have {
		t.Fatal("has returned true for key we don't have")
	}

	size, err := ds.GetSize(badk)
	switch err {
	case dstore.ErrNotFound:
	case nil:
		t.Fatal("expected error getting size after delete")
	default:
		t.Fatal("wrong error getting size after delete: ", err)
	}
	if size != -1 {
		t.Fatal("expected missing size to be -1")
	}
}

func SubtestOrder(t *testing.T, ds dstore.Datastore) {
	test := func(orders ...dsq.Order) {
		var types []string
		for _, o := range orders {
			types = append(types, fmt.Sprintf("%T", o))
		}
		name := strings.Join(types, ">")
		t.Run(name, func(t *testing.T) {
			subtestQuery(t, ds, dsq.Query{
				Orders: orders,
			})
		})
	}
	test(dsq.OrderByKey{})
	test(new(dsq.OrderByKey))
	test(dsq.OrderByKeyDescending{})
	test(new(dsq.OrderByKeyDescending))
	test(dsq.OrderByValue{})
	test(dsq.OrderByValue{}, dsq.OrderByKey{})
	test(dsq.OrderByFunction(func(a, b dsq.Entry) int {
		return bytes.Compare(a.Value, b.Value)
	}))
}

func SubtestManyKeysAndQuery(t *testing.T, ds dstore.Datastore) {
	subtestQuery(t, ds, dsq.Query{KeysOnly: true})
}

// need a custom test filter to test the "fallback" filter case for unknown
// filters.
type testFilter struct{}

func (testFilter) Filter(e dsq.Entry) bool {
	return len(e.Key)%2 == 0
}

func SubtestFilter(t *testing.T, ds dstore.Datastore) {
	test := func(filters ...dsq.Filter) {
		var types []string
		for _, o := range filters {
			types = append(types, fmt.Sprintf("%T", o))
		}
		name := strings.Join(types, ">")
		t.Run(name, func(t *testing.T) {
			subtestQuery(t, ds, dsq.Query{
				Filters: filters,
			})
		})
	}
	test(dsq.FilterKeyCompare{
		Op:  dsq.Equal,
		Key: "/0key0",
	})

	test(dsq.FilterKeyCompare{
		Op:  dsq.LessThan,
		Key: "/2",
	})

	test(&dsq.FilterKeyCompare{
		Op:  dsq.Equal,
		Key: "/0key0",
	})

	test(dsq.FilterKeyPrefix{
		Prefix: "/0key0",
	})

	test(&dsq.FilterKeyPrefix{
		Prefix: "/0key0",
	})

	test(dsq.FilterValueCompare{
		Op:    dsq.LessThan,
		Value: randValue(),
	})

	test(new(testFilter))
}

func randValue() []byte {
	value := make([]byte, 64)
	rand.Read(value)
	return value
}

func subtestQuery(t *testing.T, ds dstore.Datastore, q dsq.Query) {
	var input []dsq.Entry
	count := 100
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("%dkey%d", i, i)
		key := dstore.NewKey(s).String()
		value := randValue()
		input = append(input, dsq.Entry{
			Key:   key,
			Value: value,
		})
	}

	t.Logf("putting %d values", count)
	for i, e := range input {
		err := ds.Put(dstore.RawKey(e.Key), e.Value)
		if err != nil {
			t.Fatalf("error on put[%d]: %s", i, err)
		}
	}

	t.Log("getting values back")
	for i, e := range input {
		val, err := ds.Get(dstore.RawKey(e.Key))
		if err != nil {
			t.Fatalf("error on get[%d]: %s", i, err)
		}

		if !bytes.Equal(val, e.Value) {
			t.Fatal("input value didnt match the one returned from Get")
		}
	}

	t.Log("querying values")
	resp, err := ds.Query(q)
	if err != nil {
		t.Fatal("calling query: ", err)
	}

	if rq := resp.Query(); !reflect.DeepEqual(rq, q) {
		t.Errorf("returned query\n  %s\nexpected query\n  %s", &rq, q)
	}

	t.Log("aggregating query results")
	actual, err := resp.Rest()
	if err != nil {
		t.Fatal("query result error: ", err)
	}

	t.Log("verifying query output")
	expected, err := dsq.NaiveQueryApply(q, dsq.ResultsWithEntries(q, input)).Rest()
	if err != nil {
		t.Fatal("naive query error: ", err)
	}
	if len(actual) != len(expected) {
		t.Fatalf("expected %d results, got %d", len(expected), len(actual))
	}
	if len(q.Orders) == 0 {
		dsq.Sort([]dsq.Order{dsq.OrderByKey{}}, actual)
		dsq.Sort([]dsq.Order{dsq.OrderByKey{}}, expected)
	}
	for i := range actual {
		if actual[i].Key != expected[i].Key {
			t.Errorf("for result %d, expected key %q, got %q", i, expected[i].Key, actual[i].Key)
			continue
		}
		if !q.KeysOnly && !bytes.Equal(actual[i].Value, expected[i].Value) {
			t.Errorf("value mismatch for result %d (key=%q)", i, expected[i].Key)
		}

	}

	t.Log("deleting all keys")
	for _, e := range input {
		if err := ds.Delete(dstore.RawKey(e.Key)); err != nil {
			t.Fatal(err)
		}
	}
}
<commit_msg>test(suite): allow varying the query test size<commit_after>package dstest

import (
	"bytes"
	"fmt"
	"math/rand"
	"reflect"
	"strings"
	"testing"

	dstore "github.com/ipfs/go-datastore"
	dsq "github.com/ipfs/go-datastore/query"
)

func SubtestBasicPutGet(t *testing.T, ds dstore.Datastore) {
	k := dstore.NewKey("foo")
	val := []byte("Hello Datastore!")

	err := ds.Put(k, val)
	if err != nil {
		t.Fatal("error putting to datastore: ", err)
	}

	have, err := ds.Has(k)
	if err != nil {
		t.Fatal("error calling has on key we just put: ", err)
	}

	if !have {
		t.Fatal("should have key foo, has returned false")
	}

	size, err := ds.GetSize(k)
	if err != nil {
		t.Fatal("error getting size after put: ", err)
	}
	if size != len(val) {
		t.Fatalf("incorrect size: expected %d, got %d", len(val), size)
	}

	out, err := ds.Get(k)
	if err != nil {
		t.Fatal("error getting value after put: ", err)
	}

	if !bytes.Equal(out, val) {
		t.Fatal("value received on get wasnt what we expected:", out)
	}

	have, err = ds.Has(k)
	if err != nil {
		t.Fatal("error calling has after get: ", err)
	}

	if !have {
		t.Fatal("should have key foo, has returned false")
	}

	size, err = ds.GetSize(k)
	if err != nil {
		t.Fatal("error getting size after get: ", err)
	}
	if size != len(val) {
		t.Fatalf("incorrect size: expected %d, got %d", len(val), size)
	}

	err = ds.Delete(k)
	if err != nil {
		t.Fatal("error calling delete: ", err)
	}

	have, err = ds.Has(k)
	if err != nil {
		t.Fatal("error calling has after delete: ", err)
	}

	if have {
		t.Fatal("should not have key foo, has returned true")
	}

	size, err = ds.GetSize(k)
	switch err {
	case dstore.ErrNotFound:
	case nil:
		t.Fatal("expected error getting size after delete")
	default:
		t.Fatal("wrong error getting size after delete: ", err)
	}
	if size != -1 {
		t.Fatal("expected missing size to be -1")
	}
}

func SubtestNotFounds(t *testing.T, ds dstore.Datastore) {
	badk := dstore.NewKey("notreal")

	val, err := ds.Get(badk)
	if err != dstore.ErrNotFound {
		t.Fatal("expected ErrNotFound for key that doesnt exist, got: ", err)
	}

	if val != nil {
		t.Fatal("get should always return nil for not found values")
	}

	have, err := ds.Has(badk)
	if err != nil {
		t.Fatal("error calling has on not found key: ", err)
	}
	if have {
		t.Fatal("has returned true for key we don't have")
	}

	size, err := ds.GetSize(badk)
	switch err {
	case dstore.ErrNotFound:
	case nil:
		t.Fatal("expected error getting size after delete")
	default:
		t.Fatal("wrong error getting size after delete: ", err)
	}
	if size != -1 {
		t.Fatal("expected missing size to be -1")
	}
}

func SubtestOrder(t *testing.T, ds dstore.Datastore) {
	test := func(orders ...dsq.Order) {
		var types []string
		for _, o := range orders {
			types = append(types, fmt.Sprintf("%T", o))
		}
		name := strings.Join(types, ">")
		t.Run(name, func(t *testing.T) {
			subtestQuery(t, ds, dsq.Query{
				Orders: orders,
			}, 100)
		})
	}
	test(dsq.OrderByKey{})
	test(new(dsq.OrderByKey))
	test(dsq.OrderByKeyDescending{})
	test(new(dsq.OrderByKeyDescending))
	test(dsq.OrderByValue{})
	test(dsq.OrderByValue{}, dsq.OrderByKey{})
	test(dsq.OrderByFunction(func(a, b dsq.Entry) int {
		return bytes.Compare(a.Value, b.Value)
	}))
}

func SubtestManyKeysAndQuery(t *testing.T, ds dstore.Datastore) {
	subtestQuery(t, ds, dsq.Query{KeysOnly: true}, 100)
}

// need a custom test filter to test the "fallback" filter case for unknown
// filters.
type testFilter struct{}

func (testFilter) Filter(e dsq.Entry) bool {
	return len(e.Key)%2 == 0
}

func SubtestFilter(t *testing.T, ds dstore.Datastore) {
	test := func(filters ...dsq.Filter) {
		var types []string
		for _, o := range filters {
			types = append(types, fmt.Sprintf("%T", o))
		}
		name := strings.Join(types, ">")
		t.Run(name, func(t *testing.T) {
			subtestQuery(t, ds, dsq.Query{
				Filters: filters,
			}, 100)
		})
	}
	test(dsq.FilterKeyCompare{
		Op:  dsq.Equal,
		Key: "/0key0",
	})

	test(dsq.FilterKeyCompare{
		Op:  dsq.LessThan,
		Key: "/2",
	})

	test(&dsq.FilterKeyCompare{
		Op:  dsq.Equal,
		Key: "/0key0",
	})

	test(dsq.FilterKeyPrefix{
		Prefix: "/0key0",
	})

	test(&dsq.FilterKeyPrefix{
		Prefix: "/0key0",
	})

	test(dsq.FilterValueCompare{
		Op:    dsq.LessThan,
		Value: randValue(),
	})

	test(new(testFilter))
}

func randValue() []byte {
	value := make([]byte, 64)
	rand.Read(value)
	return value
}

func subtestQuery(t *testing.T, ds dstore.Datastore, q dsq.Query, count int) {
	var input []dsq.Entry
	for i := 0; i < count; i++ {
		s := fmt.Sprintf("%dkey%d", i, i)
		key := dstore.NewKey(s).String()
		value := randValue()
		input = append(input, dsq.Entry{
			Key:   key,
			Value: value,
		})
	}

	t.Logf("putting %d values", count)
	for i, e := range input {
		err := ds.Put(dstore.RawKey(e.Key), e.Value)
		if err != nil {
			t.Fatalf("error on put[%d]: %s", i, err)
		}
	}

	t.Log("getting values back")
	for i, e := range input {
		val, err := ds.Get(dstore.RawKey(e.Key))
		if err != nil {
			t.Fatalf("error on get[%d]: %s", i, err)
		}

		if !bytes.Equal(val, e.Value) {
			t.Fatal("input value didnt match the one returned from Get")
		}
	}

	t.Log("querying values")
	resp, err := ds.Query(q)
	if err != nil {
		t.Fatal("calling query: ", err)
	}

	if rq := resp.Query(); !reflect.DeepEqual(rq, q) {
		t.Errorf("returned query\n  %s\nexpected query\n  %s", &rq, q)
	}

	t.Log("aggregating query results")
	actual, err := resp.Rest()
	if err != nil {
		t.Fatal("query result error: ", err)
	}

	t.Log("verifying query output")
	expected, err := dsq.NaiveQueryApply(q, dsq.ResultsWithEntries(q, input)).Rest()
	if err != nil {
		t.Fatal("naive query error: ", err)
	}
	if len(actual) != len(expected) {
		t.Fatalf("expected %d results, got %d", len(expected), len(actual))
	}
	if len(q.Orders) == 0 {
		dsq.Sort([]dsq.Order{dsq.OrderByKey{}}, actual)
		dsq.Sort([]dsq.Order{dsq.OrderByKey{}}, expected)
	}
	for i := range actual {
		if actual[i].Key != expected[i].Key {
			t.Errorf("for result %d, expected key %q, got %q", i, expected[i].Key, actual[i].Key)
			continue
		}
		if !q.KeysOnly && !bytes.Equal(actual[i].Value, expected[i].Value) {
			t.Errorf("value mismatch for result %d (key=%q)", i, expected[i].Key)
		}

	}

	t.Log("deleting all keys")
	for _, e := range input {
		if err := ds.Delete(dstore.RawKey(e.Key)); err != nil {
			t.Fatal(err)
		}
	}
}
<|endoftext|>