<commit_before>package landscaper

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	"gopkg.in/yaml.v2"
	"k8s.io/helm/pkg/chartutil"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"k8s.io/helm/pkg/proto/hapi/release"
)

var (
	// ErrNonLandscapeComponent is an error to indicate release is not controlled by landscaper
	ErrNonLandscapeComponent = errors.New("release is not controlled by landscaper")

	// ErrInvalidLandscapeMetadata is an error to indicate a release contains invalid landscaper metadata
	ErrInvalidLandscapeMetadata = errors.New("release contains invalid landscaper metadata")
)

// ComponentProvider can be used to interact with components locally, as well as on the cluster
type ComponentProvider interface {
	Current() ([]*Component, error)
	Desired() ([]*Component, error)
}

type componentProvider struct {
	env             *Environment
	secretsProvider SecretsProvider
}

// NewComponentProvider is a factory method to create a new ComponentProvider
func NewComponentProvider(env *Environment, secretsProvider SecretsProvider) ComponentProvider {
	return &componentProvider{
		env:             env,
		secretsProvider: secretsProvider,
	}
}

// Current returns all Components in the cluster
func (cp *componentProvider) Current() ([]*Component, error) {
	components := []*Component{}

	logrus.Info("Obtain current state Helm Releases (Components) from Tiller")

	// Retrieve the raw Helm release from the tiller
	helmReleases, err := cp.listHelmReleases()
	if err != nil {
		return components, err
	}

	for _, release := range helmReleases {
		cmp, err := newComponentFromHelmRelease(release)
		if err == ErrNonLandscapeComponent {
			continue
		}
		if err != nil {
			return components, err
		}

		secretValues, err := cp.secretsProvider.Read(cmp.Name)
		if err != nil {
			return components, err
		}

		cmp.SecretValues = secretValues
		cmp.Secrets = Secrets{}

		for key := range secretValues {
			cmp.Secrets = append(cmp.Secrets, key)
		}

		components = append(components, cmp)
	}

	logrus.WithFields(logrus.Fields{"totalReleases": len(helmReleases), "landscapedComponents": len(components)}).Info("Retrieved Releases (Components)")

	return components, nil
}

// Desired returns all desired components according to their descriptions
func (cp *componentProvider) Desired() ([]*Component, error) {
	components := []*Component{}

	logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir}).Info("Obtain desired state from directory")

	files, err := ioutil.ReadDir(cp.env.LandscapeDir)
	if err != nil {
		return components, err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		filename := filepath.Join(cp.env.LandscapeDir, file.Name())

		logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir, "file": file.Name()}).Debug("Read desired state from file")
		cmp, err := readComponentFromYAMLFilePath(filename)
		if err != nil {
			return components, err
		}
		cmp.normalizeFromFile(cp.env)

		err = cp.coalesceComponent(cmp)
		if err != nil {
			return components, err
		}

		if len(cmp.Secrets) > 0 {
			readSecretValues(cmp)
		}

		if err := cmp.Validate(); err != nil {
			return nil, fmt.Errorf("failed to validate `%s`: %s", filename, err)
		}

		logrus.Debugf("desired %#v", *cmp)

		components = append(components, cmp)
	}

	if err := validateComponents(components); err != nil {
		return nil, err
	}

	logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir, "components": len(components)}).Debug("Desired state has been read")

	return components, nil
}

// newComponentFromYAML parses a byteslice into a Component instance
func newComponentFromYAML(content []byte) (*Component, error) {
	cmp := &Component{}
	if err := yaml.Unmarshal(content, cmp); err != nil {
		return nil, err
	}

	return NewComponent(cmp.Name, cmp.Release, cmp.Configuration, cmp.Secrets), nil
}

// coalesceComponent takes a component, loads the chart and coalesces the configuration with the default values
func (cp *componentProvider) coalesceComponent(cmp *Component) error {
	logrus.WithFields(logrus.Fields{"chart": cmp.Release.Chart}).Debug("coalesceComponent")
	chartRef, err := cmp.FullChartRef()
	if err != nil {
		return err
	}
	ch, _, err := cp.env.ChartLoader.Load(chartRef)
	if err != nil {
		return err
	}

	raw, err := cmp.Configuration.YAML()
	if err != nil {
		return err
	}

	helmValues, err := chartutil.CoalesceValues(ch, &chart.Config{Raw: raw})
	if err != nil {
		return err
	}

	cmp.Configuration = Configuration(helmValues)

	return nil
}

// listHelmReleases lists all releases that are prefixed with env.LandscapeName
func (cp *componentProvider) listHelmReleases() ([]*release.Release, error) {
	logrus.Debug("listHelmReleases")
	filter := helm.ReleaseListFilter(fmt.Sprintf("^%s.+", cp.env.ReleaseNamePrefix))
	res, err := cp.env.HelmClient().ListReleases(filter)
	if err != nil {
		return nil, err
	}

	return res.Releases, nil
}

// getHelmRelease gets a Release
func (cp *componentProvider) getHelmRelease(releaseName string) (*release.Release, error) {
	logrus.WithFields(logrus.Fields{"releaseName": releaseName}).Debug("getHelmRelease")
	res, err := cp.env.HelmClient().ReleaseContent(releaseName)
	if err != nil {
		return nil, err
	}

	return res.Release, nil
}

// newComponentFromHelmRelease creates a Component from a Release
func newComponentFromHelmRelease(release *release.Release) (*Component, error) {
	cfg, err := getReleaseConfiguration(release)
	if err != nil {
		return nil, err
	}

	if !cfg.HasMetadata() {
		return nil, ErrNonLandscapeComponent
	}

	m, err := cfg.GetMetadata()
	if err != nil {
		return nil, err
	}

	cmp := NewComponent(
		release.Name,
		&Release{
			Chart:   fmt.Sprintf("%s:%s", release.Chart.Metadata.Name, release.Chart.Metadata.Version),
			Version: m.ReleaseVersion,
		},
		cfg,
		Secrets{},
	)

	return cmp, nil
}

// readComponentFromYAMLFilePath reads a yaml file from disk and returns an initialized Component
func readComponentFromYAMLFilePath(filePath string) (*Component, error) {
	cfg, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	return newComponentFromYAML(cfg)
}

// getReleaseConfiguration returns a release's coalesced Cnfiguration (= helm values)
func getReleaseConfiguration(helmRelease *release.Release) (Configuration, error) {
	helmValues, err := chartutil.CoalesceValues(helmRelease.Chart, helmRelease.Config)
	if err != nil {
		return nil, err
	}

	return Configuration(helmValues), nil
}
<commit_msg>Validate input yamls<commit_after>package landscaper

import (
	"errors"
	"fmt"
	"io/ioutil"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	validator "gopkg.in/validator.v2"
	"gopkg.in/yaml.v2"
	"k8s.io/helm/pkg/chartutil"
	"k8s.io/helm/pkg/helm"
	"k8s.io/helm/pkg/proto/hapi/chart"
	"k8s.io/helm/pkg/proto/hapi/release"
)

var (
	// ErrNonLandscapeComponent is an error to indicate release is not controlled by landscaper
	ErrNonLandscapeComponent = errors.New("release is not controlled by landscaper")

	// ErrInvalidLandscapeMetadata is an error to indicate a release contains invalid landscaper metadata
	ErrInvalidLandscapeMetadata = errors.New("release contains invalid landscaper metadata")
)

// ComponentProvider can be used to interact with components locally, as well as on the cluster
type ComponentProvider interface {
	Current() ([]*Component, error)
	Desired() ([]*Component, error)
}

type componentProvider struct {
	env             *Environment
	secretsProvider SecretsProvider
}

// NewComponentProvider is a factory method to create a new ComponentProvider
func NewComponentProvider(env *Environment, secretsProvider SecretsProvider) ComponentProvider {
	return &componentProvider{
		env:             env,
		secretsProvider: secretsProvider,
	}
}

// Current returns all Components in the cluster
func (cp *componentProvider) Current() ([]*Component, error) {
	components := []*Component{}

	logrus.Info("Obtain current state Helm Releases (Components) from Tiller")

	// Retrieve the raw Helm release from the tiller
	helmReleases, err := cp.listHelmReleases()
	if err != nil {
		return components, err
	}

	for _, release := range helmReleases {
		cmp, err := newComponentFromHelmRelease(release)
		if err == ErrNonLandscapeComponent {
			continue
		}
		if err != nil {
			return components, err
		}

		secretValues, err := cp.secretsProvider.Read(cmp.Name)
		if err != nil {
			return components, err
		}

		cmp.SecretValues = secretValues
		cmp.Secrets = Secrets{}

		for key := range secretValues {
			cmp.Secrets = append(cmp.Secrets, key)
		}

		components = append(components, cmp)
	}

	logrus.WithFields(logrus.Fields{"totalReleases": len(helmReleases), "landscapedComponents": len(components)}).Info("Retrieved Releases (Components)")

	return components, nil
}

// Desired returns all desired components according to their descriptions
func (cp *componentProvider) Desired() ([]*Component, error) {
	components := []*Component{}

	logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir}).Info("Obtain desired state from directory")

	files, err := ioutil.ReadDir(cp.env.LandscapeDir)
	if err != nil {
		return components, err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		filename := filepath.Join(cp.env.LandscapeDir, file.Name())

		logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir, "file": file.Name()}).Debug("Read desired state from file")
		cmp, err := readComponentFromYAMLFilePath(filename)
		if err != nil {
			return components, fmt.Errorf("readComponentFromYAMLFilePath file `%s` failed: %s", filename, err)
		}
		cmp.normalizeFromFile(cp.env)

		err = cp.coalesceComponent(cmp)
		if err != nil {
			return components, err
		}

		if len(cmp.Secrets) > 0 {
			readSecretValues(cmp)
		}

		if err := cmp.Validate(); err != nil {
			return nil, fmt.Errorf("failed to validate `%s`: %s", filename, err)
		}

		logrus.Debugf("desired %#v", *cmp)

		components = append(components, cmp)
	}

	if err := validateComponents(components); err != nil {
		return nil, err
	}

	logrus.WithFields(logrus.Fields{"directory": cp.env.LandscapeDir, "components": len(components)}).Debug("Desired state has been read")

	return components, nil
}

// newComponentFromYAML parses a byteslice into a Component instance
func newComponentFromYAML(content []byte) (*Component, error) {
	cmp := &Component{}
	if err := yaml.Unmarshal(content, cmp); err != nil {
		return nil, err
	}

	if cmp.Name == "" {
		return nil, errors.New("invalid input yaml; name missing")
	}

	if cmp.Release == nil {
		return nil, errors.New("invalid input yaml; release missing")
	}

	if err := validator.Validate(cmp.Release); err != nil {
		return nil, err
	}

	return NewComponent(cmp.Name, cmp.Release, cmp.Configuration, cmp.Secrets), nil
}

// coalesceComponent takes a component, loads the chart and coalesces the configuration with the default values
func (cp *componentProvider) coalesceComponent(cmp *Component) error {
	logrus.WithFields(logrus.Fields{"chart": cmp.Release.Chart}).Debug("coalesceComponent")
	chartRef, err := cmp.FullChartRef()
	if err != nil {
		return err
	}
	ch, _, err := cp.env.ChartLoader.Load(chartRef)
	if err != nil {
		return err
	}

	raw, err := cmp.Configuration.YAML()
	if err != nil {
		return err
	}

	helmValues, err := chartutil.CoalesceValues(ch, &chart.Config{Raw: raw})
	if err != nil {
		return err
	}

	cmp.Configuration = Configuration(helmValues)

	return nil
}

// listHelmReleases lists all releases that are prefixed with env.LandscapeName
func (cp *componentProvider) listHelmReleases() ([]*release.Release, error) {
	logrus.Debug("listHelmReleases")
	filter := helm.ReleaseListFilter(fmt.Sprintf("^%s.+", cp.env.ReleaseNamePrefix))
	res, err := cp.env.HelmClient().ListReleases(filter)
	if err != nil {
		return nil, err
	}

	return res.Releases, nil
}

// getHelmRelease gets a Release
func (cp *componentProvider) getHelmRelease(releaseName string) (*release.Release, error) {
	logrus.WithFields(logrus.Fields{"releaseName": releaseName}).Debug("getHelmRelease")
	res, err := cp.env.HelmClient().ReleaseContent(releaseName)
	if err != nil {
		return nil, err
	}

	return res.Release, nil
}

// newComponentFromHelmRelease creates a Component from a Release
func newComponentFromHelmRelease(release *release.Release) (*Component, error) {
	cfg, err := getReleaseConfiguration(release)
	if err != nil {
		return nil, err
	}

	if !cfg.HasMetadata() {
		return nil, ErrNonLandscapeComponent
	}

	m, err := cfg.GetMetadata()
	if err != nil {
		return nil, err
	}

	cmp := NewComponent(
		release.Name,
		&Release{
			Chart:   fmt.Sprintf("%s:%s", release.Chart.Metadata.Name, release.Chart.Metadata.Version),
			Version: m.ReleaseVersion,
		},
		cfg,
		Secrets{},
	)

	return cmp, nil
}

// readComponentFromYAMLFilePath reads a yaml file from disk and returns an initialized Component
func readComponentFromYAMLFilePath(filePath string) (*Component, error) {
	cfg, err := ioutil.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	return newComponentFromYAML(cfg)
}

// getReleaseConfiguration returns a release's coalesced Cnfiguration (= helm values)
func getReleaseConfiguration(helmRelease *release.Release) (Configuration, error) {
	helmValues, err := chartutil.CoalesceValues(helmRelease.Chart, helmRelease.Config)
	if err != nil {
		return nil, err
	}

	return Configuration(helmValues), nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package portworx

import (
	"github.com/golang/glog"
	osdapi "github.com/libopenstorage/openstorage/api"
	osdclient "github.com/libopenstorage/openstorage/api/client"
	volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
	osdspec "github.com/libopenstorage/openstorage/api/spec"
	volumeapi "github.com/libopenstorage/openstorage/volume"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/volume"
)

const (
	osdMgmtPort      = "9001"
	osdDriverVersion = "v1"
	pxdDriverName    = "pxd"
	pvcClaimLabel    = "pvc"
	pxServiceName    = "portworx-service"
)

type PortworxVolumeUtil struct {
	portworxClient *osdclient.Client
}

// CreateVolume creates a Portworx volume.
func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (string, int, map[string]string, error) {
	driver, err := util.getPortworxDriver(p.plugin.host, false /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return "", 0, nil, err
	}

	glog.Infof("Creating Portworx volume for PVC: %v", p.options.PVC.Name)

	capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
	// Portworx Volumes are specified in GB
	requestGB := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024))

	specHandler := osdspec.NewSpecHandler()
	spec, _ := specHandler.SpecFromOpts(p.options.Parameters)
	if spec == nil {
		spec = specHandler.DefaultSpec()
	}

	// Pass all parameters as volume labels for Portworx server-side processing
	spec.VolumeLabels = p.options.Parameters

	spec.Size = uint64(requestGB * 1024 * 1024 * 1024)
	source := osdapi.Source{}
	locator := osdapi.VolumeLocator{
		Name: p.options.PVName,
	}
	// Add claim Name as a part of Portworx Volume Labels
	locator.VolumeLabels = make(map[string]string)
	locator.VolumeLabels[pvcClaimLabel] = p.options.PVC.Name
	volumeID, err := driver.Create(&locator, &source, spec)
	if err != nil {
		glog.Errorf("Error creating Portworx Volume : %v", err)
	}

	glog.Infof("Successfully created Portworx volume for PVC: %v", p.options.PVC.Name)
	return volumeID, requestGB, nil, err
}

// DeleteVolume deletes a Portworx volume
func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error {
	driver, err := util.getPortworxDriver(d.plugin.host, false /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Delete(d.volumeID)
	if err != nil {
		glog.Errorf("Error deleting Portworx Volume (%v): %v", d.volName, err)
		return err
	}
	return nil
}

// AttachVolume attaches a Portworx Volume
func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, error) {
	driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return "", err
	}

	devicePath, err := driver.Attach(m.volName)
	if err != nil {
		glog.Errorf("Error attaching Portworx Volume (%v): %v", m.volName, err)
		return "", err
	}
	return devicePath, nil
}

// DetachVolume detaches a Portworx Volume
func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error {
	driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Detach(u.volName)
	if err != nil {
		glog.Errorf("Error detaching Portworx Volume (%v): %v", u.volName, err)
		return err
	}
	return nil
}

// MountVolume mounts a Portworx Volume on the specified mountPath
func (util *PortworxVolumeUtil) MountVolume(m *portworxVolumeMounter, mountPath string) error {
	driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Mount(m.volName, mountPath)
	if err != nil {
		glog.Errorf("Error mounting Portworx Volume (%v) on Path (%v): %v", m.volName, mountPath, err)
		return err
	}
	return nil
}

// UnmountVolume unmounts a Portworx Volume
func (util *PortworxVolumeUtil) UnmountVolume(u *portworxVolumeUnmounter, mountPath string) error {
	driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Unmount(u.volName, mountPath)
	if err != nil {
		glog.Errorf("Error unmounting Portworx Volume (%v) on Path (%v): %v", u.volName, mountPath, err)
		return err
	}
	return nil
}

func isClientValid(client *osdclient.Client) (bool, error) {
	if client == nil {
		return false, nil
	}

	_, err := client.Versions(osdapi.OsdVolumePath)
	if err != nil {
		glog.Errorf("portworx client failed driver versions check. Err: %v", err)
		return false, err
	}

	return true, nil
}

func createDriverClient(hostname string) (*osdclient.Client, error) {
	client, err := volumeclient.NewDriverClient("http://"+hostname+":"+osdMgmtPort,
		pxdDriverName, osdDriverVersion)
	if err != nil {
		return nil, err
	}

	if isValid, err := isClientValid(client); isValid {
		return client, nil
	} else {
		return nil, err
	}
}

// getPortworxDriver() returns a Portworx volume driver which can be used for volume operations
// localOnly: If true, the returned driver will be connected to Portworx API server on volume host.
//            If false, driver will be connected to API server on volume host or Portworx k8s service cluster IP
//            This flag is required to explicitly force certain operations (mount, unmount, detach, attach) to
//            go to the volume host instead of the k8s service which might route it to any host. This pertains to how
//            Portworx mounts and attaches a volume to the running container. The node getting these requests needs to
//            see the pod container mounts (specifically /var/lib/kubelet/pods/<pod_id>)
//            Operations like create and delete volume don't need to be restricted to local volume host since
//            any node in the Portworx cluster can co-ordinate the create/delete request and forward the operations to
//            the Portworx node that will own/owns the data.
func (util *PortworxVolumeUtil) getPortworxDriver(volumeHost volume.VolumeHost, localOnly bool) (volumeapi.VolumeDriver, error) {
	var err error
	if localOnly {
		util.portworxClient, err = createDriverClient(volumeHost.GetHostName())
		if err != nil {
			return nil, err
		} else {
			glog.V(4).Infof("Using portworx local service at: %v as api endpoint", volumeHost.GetHostName())
			return volumeclient.VolumeDriver(util.portworxClient), nil
		}
	}

	// check if existing saved client is valid
	if isValid, _ := isClientValid(util.portworxClient); isValid {
		return volumeclient.VolumeDriver(util.portworxClient), nil
	}

	// create new client
	util.portworxClient, err = createDriverClient(volumeHost.GetHostName()) // for backward compatibility
	if err != nil || util.portworxClient == nil {
		// Create client from portworx service
		kubeClient := volumeHost.GetKubeClient()
		if kubeClient == nil {
			glog.Error("Failed to get kubeclient when creating portworx client")
			return nil, nil
		}

		opts := metav1.GetOptions{}
		svc, err := kubeClient.CoreV1().Services(api.NamespaceSystem).Get(pxServiceName, opts)
		if err != nil {
			glog.Errorf("Failed to get service. Err: %v", err)
			return nil, err
		}

		if svc == nil {
			glog.Errorf("Service: %v not found. Consult Portworx docs to deploy it.", pxServiceName)
			return nil, err
		}

		util.portworxClient, err = createDriverClient(svc.Spec.ClusterIP)
		if err != nil || util.portworxClient == nil {
			glog.Errorf("Failed to connect to portworx service. Err: %v", err)
			return nil, err
		}

		glog.Infof("Using portworx cluster service at: %v as api endpoint", svc.Spec.ClusterIP)
	} else {
		glog.Infof("Using portworx service at: %v as api endpoint", volumeHost.GetHostName())
	}

	return volumeclient.VolumeDriver(util.portworxClient), nil
}
<commit_msg>Add comment for parameter parsing logic in Portworx volume create<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package portworx

import (
	"github.com/golang/glog"
	osdapi "github.com/libopenstorage/openstorage/api"
	osdclient "github.com/libopenstorage/openstorage/api/client"
	volumeclient "github.com/libopenstorage/openstorage/api/client/volume"
	osdspec "github.com/libopenstorage/openstorage/api/spec"
	volumeapi "github.com/libopenstorage/openstorage/volume"
	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/volume"
)

const (
	osdMgmtPort      = "9001"
	osdDriverVersion = "v1"
	pxdDriverName    = "pxd"
	pvcClaimLabel    = "pvc"
	pxServiceName    = "portworx-service"
)

type PortworxVolumeUtil struct {
	portworxClient *osdclient.Client
}

// CreateVolume creates a Portworx volume.
func (util *PortworxVolumeUtil) CreateVolume(p *portworxVolumeProvisioner) (string, int, map[string]string, error) {
	driver, err := util.getPortworxDriver(p.plugin.host, false /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return "", 0, nil, err
	}

	glog.Infof("Creating Portworx volume for PVC: %v", p.options.PVC.Name)

	capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
	// Portworx Volumes are specified in GB
	requestGB := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024))

	// Perform a best-effort parsing of parameters. Portworx 1.2.9 and later parses volume parameters from
	// spec.VolumeLabels. So even if below SpecFromOpts() fails to parse certain parameters or
	// doesn't support new parameters, the server-side processing will parse it correctly.
	// We still need to call SpecFromOpts() here to handle cases where someone is running Portworx 1.2.8 and lower.
	specHandler := osdspec.NewSpecHandler()
	spec, _ := specHandler.SpecFromOpts(p.options.Parameters)
	if spec == nil {
		spec = specHandler.DefaultSpec()
	}

	// Pass all parameters as volume labels for Portworx server-side processing.
	spec.VolumeLabels = p.options.Parameters

	spec.Size = uint64(requestGB * 1024 * 1024 * 1024)
	source := osdapi.Source{}
	locator := osdapi.VolumeLocator{
		Name: p.options.PVName,
	}
	// Add claim Name as a part of Portworx Volume Labels
	locator.VolumeLabels = make(map[string]string)
	locator.VolumeLabels[pvcClaimLabel] = p.options.PVC.Name
	volumeID, err := driver.Create(&locator, &source, spec)
	if err != nil {
		glog.Errorf("Error creating Portworx Volume : %v", err)
	}

	glog.Infof("Successfully created Portworx volume for PVC: %v", p.options.PVC.Name)
	return volumeID, requestGB, nil, err
}

// DeleteVolume deletes a Portworx volume
func (util *PortworxVolumeUtil) DeleteVolume(d *portworxVolumeDeleter) error {
	driver, err := util.getPortworxDriver(d.plugin.host, false /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Delete(d.volumeID)
	if err != nil {
		glog.Errorf("Error deleting Portworx Volume (%v): %v", d.volName, err)
		return err
	}
	return nil
}

// AttachVolume attaches a Portworx Volume
func (util *PortworxVolumeUtil) AttachVolume(m *portworxVolumeMounter) (string, error) {
	driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return "", err
	}

	devicePath, err := driver.Attach(m.volName)
	if err != nil {
		glog.Errorf("Error attaching Portworx Volume (%v): %v", m.volName, err)
		return "", err
	}
	return devicePath, nil
}

// DetachVolume detaches a Portworx Volume
func (util *PortworxVolumeUtil) DetachVolume(u *portworxVolumeUnmounter) error {
	driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Detach(u.volName)
	if err != nil {
		glog.Errorf("Error detaching Portworx Volume (%v): %v", u.volName, err)
		return err
	}
	return nil
}

// MountVolume mounts a Portworx Volume on the specified mountPath
func (util *PortworxVolumeUtil) MountVolume(m *portworxVolumeMounter, mountPath string) error {
	driver, err := util.getPortworxDriver(m.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Mount(m.volName, mountPath)
	if err != nil {
		glog.Errorf("Error mounting Portworx Volume (%v) on Path (%v): %v", m.volName, mountPath, err)
		return err
	}
	return nil
}

// UnmountVolume unmounts a Portworx Volume
func (util *PortworxVolumeUtil) UnmountVolume(u *portworxVolumeUnmounter, mountPath string) error {
	driver, err := util.getPortworxDriver(u.plugin.host, true /*localOnly*/)
	if err != nil || driver == nil {
		glog.Errorf("Failed to get portworx driver. Err: %v", err)
		return err
	}

	err = driver.Unmount(u.volName, mountPath)
	if err != nil {
		glog.Errorf("Error unmounting Portworx Volume (%v) on Path (%v): %v", u.volName, mountPath, err)
		return err
	}
	return nil
}

func isClientValid(client *osdclient.Client) (bool, error) {
	if client == nil {
		return false, nil
	}

	_, err := client.Versions(osdapi.OsdVolumePath)
	if err != nil {
		glog.Errorf("portworx client failed driver versions check. Err: %v", err)
		return false, err
	}

	return true, nil
}

func createDriverClient(hostname string) (*osdclient.Client, error) {
	client, err := volumeclient.NewDriverClient("http://"+hostname+":"+osdMgmtPort,
		pxdDriverName, osdDriverVersion)
	if err != nil {
		return nil, err
	}

	if isValid, err := isClientValid(client); isValid {
		return client, nil
	} else {
		return nil, err
	}
}

// getPortworxDriver() returns a Portworx volume driver which can be used for volume operations
// localOnly: If true, the returned driver will be connected to Portworx API server on volume host.
//            If false, driver will be connected to API server on volume host or Portworx k8s service cluster IP
//            This flag is required to explicitly force certain operations (mount, unmount, detach, attach) to
//            go to the volume host instead of the k8s service which might route it to any host. This pertains to how
//            Portworx mounts and attaches a volume to the running container. The node getting these requests needs to
//            see the pod container mounts (specifically /var/lib/kubelet/pods/<pod_id>)
//            Operations like create and delete volume don't need to be restricted to local volume host since
//            any node in the Portworx cluster can co-ordinate the create/delete request and forward the operations to
//            the Portworx node that will own/owns the data.
func (util *PortworxVolumeUtil) getPortworxDriver(volumeHost volume.VolumeHost, localOnly bool) (volumeapi.VolumeDriver, error) {
	var err error
	if localOnly {
		util.portworxClient, err = createDriverClient(volumeHost.GetHostName())
		if err != nil {
			return nil, err
		} else {
			glog.V(4).Infof("Using portworx local service at: %v as api endpoint", volumeHost.GetHostName())
			return volumeclient.VolumeDriver(util.portworxClient), nil
		}
	}

	// check if existing saved client is valid
	if isValid, _ := isClientValid(util.portworxClient); isValid {
		return volumeclient.VolumeDriver(util.portworxClient), nil
	}

	// create new client
	util.portworxClient, err = createDriverClient(volumeHost.GetHostName()) // for backward compatibility
	if err != nil || util.portworxClient == nil {
		// Create client from portworx service
		kubeClient := volumeHost.GetKubeClient()
		if kubeClient == nil {
			glog.Error("Failed to get kubeclient when creating portworx client")
			return nil, nil
		}

		opts := metav1.GetOptions{}
		svc, err := kubeClient.CoreV1().Services(api.NamespaceSystem).Get(pxServiceName, opts)
		if err != nil {
			glog.Errorf("Failed to get service. Err: %v", err)
			return nil, err
		}

		if svc == nil {
			glog.Errorf("Service: %v not found. Consult Portworx docs to deploy it.", pxServiceName)
			return nil, err
		}

		util.portworxClient, err = createDriverClient(svc.Spec.ClusterIP)
		if err != nil || util.portworxClient == nil {
			glog.Errorf("Failed to connect to portworx service. Err: %v", err)
			return nil, err
		}

		glog.Infof("Using portworx cluster service at: %v as api endpoint", svc.Spec.ClusterIP)
	} else {
		glog.Infof("Using portworx service at: %v as api endpoint", volumeHost.GetHostName())
	}

	return volumeclient.VolumeDriver(util.portworxClient), nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/epeli/dyntftp/tftp"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var root = flag.String("root", "/var/lib/tftpboot/", "Serve files from")
var port = flag.String("port", "69", "Port to listen")
var badinternet = flag.Bool("simulate-bad-internet", false, "Simulate bad internet connection for testing purposes")
var configPath = flag.String("config", "/etc/dyntftp.json", "Config file")
var config *Config

func handleRRQ(res *tftp.RRQresponse) {
	path := filepath.Join(*root, res.Request.Path)

	started := time.Now()

	path, err := filepath.Abs(path)

	if err != nil {
		fmt.Println("Bad path", err)
		res.WriteError(tftp.UNKNOWN_ERROR, "Invalid file path:"+err.Error())
		return
	}

	fmt.Println("GET", path, "blocksize", res.Request.Blocksize)

	if !strings.HasPrefix(path, *root) {
		fmt.Println("Path access violation", path)
		res.WriteError(tftp.ACCESS_VIOLATION, "Path access violation")
		return
	}

	if err := res.WriteOACK(); err != nil {
		fmt.Println("Failed to write OACK", err)
		return
	}

	for _, hook := range config.Hooks {
		if hook.Regexp.MatchString(path) {
			// TODO: execute command
			res.Write([]byte("customdata"))
			res.End()
			return
		}
	}

	file, err := os.Open(path)
	if err != nil {
		fmt.Println("Failed to open file", path, err)
		res.WriteError(tftp.NOT_FOUND, err.Error())
		return
	}

	defer file.Close()

	b := make([]byte, res.Request.Blocksize)

	totalBytes := 0

	for {
		bytesRead, err := file.Read(b)
		totalBytes += bytesRead

		if err == io.EOF {
			if _, err := res.Write(b[:bytesRead]); err != nil {
				fmt.Println("Failed to write last bytes of the file", err)
				return
			}
			res.End()
			break
		} else if err != nil {
			fmt.Println("Error while reading", file, err)
			res.WriteError(tftp.UNKNOWN_ERROR, err.Error())
			return
		}

		if _, err := res.Write(b[:bytesRead]); err != nil {
			fmt.Println("Failed to write bytes for", path, err)
			return
		}
	}

	took := time.Since(started)

	speed := float64(totalBytes) / took.Seconds() / 1024 / 1024

	fmt.Printf("Sent %v bytes in %v %f MB/s\n", totalBytes, took, speed)
}

func main() {
	flag.Parse()
	*root, _ = filepath.Abs(*root)
	var err error
	config, err = ParseConfigFile(*configPath)
	if err != nil {
		fmt.Println("Failed to parse", *configPath, err)
		return
	}

	fmt.Println("flags", *root, *port)
	addr, err := net.ResolveUDPAddr("udp", ":"+*port)
	if err != nil {
		fmt.Println("Failed to resolve address", err)
		return
	}

	server, err := tftp.NewTFTPServer(addr)
	if err != nil {
		fmt.Println("Failed to listen", err)
		return
	}

	for {
		res, err := server.Accept()
		if err != nil {
			fmt.Println("Bad tftp request", err)
			continue
		}

		go handleRRQ(res)
	}

}
<commit_msg>use new hook system<commit_after>package main

import (
	"github.com/epeli/dyntftp/tftp"
	"github.com/epeli/dyntftp/config"
	"github.com/epeli/dyntftp/hooks"
	"io/ioutil"
	"fmt"
	"io"
	"net"
	"time"
)

var HOOKS []hooks.Hook

func handleRRQ(res *tftp.RRQresponse) {

	started := time.Now()

	path := res.Request.Path

	fmt.Println("GET", path, "blocksize", res.Request.Blocksize)

	if err := res.WriteOACK(); err != nil {
		fmt.Println("Failed to write OACK", err)
		return
	}

	var reader io.Reader
	for _, hook := range HOOKS {
		var err error
		reader, err = hook(res.Request.Path)
		if err == hooks.NO_MATCH {
			continue
		} else if err != nil {
			fmt.Printf("Failed to execute hook for '%v' error: %v", res.Request.Path, err)
			res.WriteError(tftp.UNKNOWN_ERROR, "Hook exec failed")
			return
		}
		break
	}

	if reader == nil {
		res.WriteError(tftp.NOT_FOUND, "No hook matches")
		return
	}

	// TODO: close!!

	b := make([]byte, res.Request.Blocksize)

	totalBytes := 0

	for {
		bytesRead, err := reader.Read(b)
		totalBytes += bytesRead

		if err == io.EOF {
			if _, err := res.Write(b[:bytesRead]); err != nil {
				fmt.Println("Failed to write last bytes of the reader", err)
				return
			}
			res.End()
			break
		} else if err != nil {
			fmt.Println("Error while reading", reader, err)
			res.WriteError(tftp.UNKNOWN_ERROR, err.Error())
			return
		}

		if _, err := res.Write(b[:bytesRead]); err != nil {
			fmt.Println("Failed to write bytes for", path, err)
			return
		}
	}

	took := time.Since(started)

	speed := float64(totalBytes) / took.Seconds() / 1024 / 1024

	fmt.Printf("Sent %v bytes in %v %f MB/s\n", totalBytes, took, speed)
}

func main() {

	configData, err := ioutil.ReadFile("./config_test.yml")
	if err != nil {
		fmt.Println("Failed to read config", err)
		return
	}

	conf, err := config.ParseYaml(configData)
	if err != nil {
		fmt.Println("Failed to parse config", err)
		return
	}

	for _, hookDef := range conf.HookDefs {
		fmt.Println("Compiling hook", hookDef)
		hook, err := hooks.CompileHook(&hookDef)
		if err != nil {
			fmt.Println("Failed to compile hook", hookDef, err)
			return
		}
		HOOKS = append(HOOKS, hook)
	}

	addr, err := net.ResolveUDPAddr("udp", ":"+conf.Port)
	if err != nil {
		fmt.Println("Failed to resolve address", err)
		return
	}

	server, err := tftp.NewTFTPServer(addr)
	if err != nil {
		fmt.Println("Failed to listen", err)
		return
	}

	for {
		res, err := server.Accept()
		if err != nil {
			fmt.Println("Bad tftp request", err)
			continue
		}

		go handleRRQ(res)
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goga

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/la"
	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/rnd"
	"github.com/cpmech/gosl/utl"
)

// Evolver realises the evolutionary process
type Evolver struct {

	// data
	C       *ConfParams // configuration parameters
	Islands []*Island   // islands

	// migration
	OvaMin []float64     // min ova
	OvaMax []float64     // max ova
	Mdist  [][]float64   // match distances
	Match  graph.Munkres // matches
}

// NewEvolverPop creates a new evolver based on given populations
func NewEvolver(C *ConfParams) (o *Evolver) {

	// check input
	C.check_input()

	// data
	o = new(Evolver)
	o.C = C
	o.Islands = make([]*Island, o.C.Nisl)
	if o.C.Pll {
		done := make(chan int, o.C.Nisl)
		for i := 0; i < o.C.Nisl; i++ {
			go func(idx int) {
				o.Islands[idx] = NewIsland(idx, o.C)
				done <- 1
			}(i)
		}
		for i := 0; i < o.C.Nisl; i++ {
			<-done
		}
	} else {
		for i := 0; i < o.C.Nisl; i++ {
			o.Islands[i] = NewIsland(i, o.C)
		}
	}

	// migration
	o.OvaMin = make([]float64, o.C.Nova)
	o.OvaMax = make([]float64, o.C.Nova)
	o.Mdist = la.MatAlloc(o.C.Nimig, o.C.Nimig)
	o.Match.Init(o.C.Nimig, o.C.Nimig)
	return
}

// Run runs the evolution process
func (o *Evolver) Run() {

	// first output
	t := 0
	if o.C.Verbose {
		o.print_legend()
		io.Pf("\nrunning ...\n")
	}

	// time loop
	t = 1
	tmig := o.C.Dtmig
	nomig := false
	if tmig > o.C.Tf {
		tmig = o.C.Tf
		nomig = true
	}
	done := make(chan int, o.C.Nisl)
	for t < o.C.Tf {

		// evolve up to migration time
		if o.C.Pll {
			for i := 0; i < o.C.Nisl; i++ {
				go func(isl *Island) {
					for time := t; time < tmig; time++ {
						isl.Run(time)
						o.print_time(time, isl.Id)
					}
					Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
					done <- 1
				}(o.Islands[i])
			}
			for i := 0; i < o.C.Nisl; i++ {
				<-done
			}
		} else {
			for _, isl := range o.Islands {
				for time := t; time < tmig; time++ {
					isl.Run(time)
					o.print_time(time, isl.Id)
				}
				Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
			}
		}

		// update time
		t = tmig
		tmig += o.C.Dtmig
		if tmig > o.C.Tf {
			tmig = o.C.Tf
			nomig = true
		}

		// migration
		if nomig {
			continue
		}
		if o.C.Verbose {
			io.Pfyel(" %d", t)
		}
		o.migration(t)
	}

	// message
	if o.C.Verbose {
		io.Pfgrey(" %d", t)
		io.Pf("\n... end\n\n")
	}
	return
}

// post-processing methods /////////////////////////////////////////////////////////////////////////

// GetFeasible returns all feasible individuals from all islands
func (o *Evolver) GetFeasible() (feasible []*Individual) {
	for _, isl := range o.Islands {
		for _, ind := range isl.Pop {
			if ind.Feasible() {
				feasible = append(feasible, ind)
			}
		}
	}
	return
}

// GetResults returns all ovas and oors from a subset of individuals
//  Output:
//   ovas -- [len(subset)][nova] objective values
//   oors -- [len(subset)][noor] out-of-range values
func (o *Evolver) GetResults(subset []*Individual) (ovas, oors [][]float64) {
	ninds := len(subset)
	ovas = utl.DblsAlloc(ninds, o.C.Nova)
	oors = utl.DblsAlloc(ninds, o.C.Noor)
	for i, ind := range subset {
		for j := 0; j < o.C.Nova; j++ {
			ovas[i][j] = ind.Ovas[j]
		}
		for j := 0; j < o.C.Noor; j++ {
			oors[i][j] = ind.Oors[j]
		}
	}
	return
}

// GetParetoFront returns all feasible individuals on the Pareto front
// Note: input data can be obtained from GetFeasible and GetResults
func (o *Evolver) GetParetoFront(feasible []*Individual, ovas, oors [][]float64) (ovafront, oorfront []*Individual) {
	chk.IntAssert(len(feasible), len(ovas))
	ovaf := utl.ParetoFront(ovas)
	ovafront = make([]*Individual, len(ovaf))
	for i, id := range ovaf {
		ovafront[i] = feasible[id]
	}
	if len(oors) > 0 {
		chk.IntAssert(len(feasible), len(oors))
		oorf := utl.ParetoFront(oors)
		oorfront = make([]*Individual, len(oorf))
		for i, id := range oorf {
			oorfront[i] = feasible[id]
		}
	}
	return
}

// GetFrontOvas collects 2 ova results from Pareto front
//  Input:
//   r and s -- 2 selected objective functions; e.g. r=0 and s=1 for 2D problems
func (o *Evolver) GetFrontOvas(r, s int, front []*Individual) (x, y []float64) {
	x = make([]float64, len(front))
	y = make([]float64, len(front))
	for i, ind := range front {
		x[i] = ind.Ovas[r]
		y[i] = ind.Ovas[s]
	}
	return
}

// GetPopulations returns all populations from all islands
func (o *Evolver) GetPopulations() (pops []Population) {
	pops = make([]Population, o.C.Nisl)
	for i, isl := range o.Islands {
		pops[i] = isl.Pop.GetCopy()
	}
	return
}

// PlotPareto plots pareto front for i and j objectives
func (o *Evolver) PlotPareto(i, j int) {
	feasible := o.GetFeasible()
	ovas, _ := o.GetResults(feasible)
	ovafront, _ := o.GetParetoFront(feasible, ovas, nil)
	f0front, f1front := o.GetFrontOvas(i, j, ovafront)
	f0fin := utl.DblsGetColumn(i, ovas)
	f1fin := utl.DblsGetColumn(j, ovas)
	plt.Plot(f0fin, f1fin, "'r.', clip_on=0, ms=3")
	plt.Plot(f0front, f1front, "'ko',markerfacecolor='none',ms=4, clip_on=0")
}

// GetNfeval returns the number of evaluations
func (o *Evolver) GetNfeval() (nfeval int) {
	for _, isl := range o.Islands {
		nfeval += isl.Nfeval
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

func (o *Evolver) migration_(t int) {
	for i := 0; i < o.C.Nisl; i++ {
		for j := i + 1; j < o.C.Nisl; j++ {
			selA := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			selB := rnd.IntGetUniqueN(0, o.C.Ninds, o.C.Nimig)
			for _, m := range selA {
				A := o.Islands[i].Pop[m]
				for _, n := range selB {
					B := o.Islands[j].Pop[n]
					if A.Fight(B) {
						A.CopyInto(B)
					} else {
						B.CopyInto(A)
					}
				}
			}
		}
	}
}

func (o *Evolver) migration__(t int) {
	B_cpy := o.Islands[0].Pop[0].GetCopy()
	count := make([]int, o.C.Nisl)
	l := o.C.Ninds - o.C.Nimig
	for m := 0; m < o.C.Nimig; m++ {
		for i := 0; i < o.C.Nisl; i++ {
			I := count[i]
			if I >= l {
				continue
			}
			A := o.Islands[i].Pop[I]
			for j := i + 1; j < o.C.Nisl; j++ {
				J := count[j]
				if J >= l {
					continue
				}
				B := o.Islands[j].Pop[J]
				B.CopyInto(B_cpy)
				A.CopyInto(B)
				B_cpy.CopyInto(A)
				count[i]++
				count[j]++
			}
		}
	}
}

func (o *Evolver) migration(t int) {

	// compute metrics in each island and compute global ova range
	for i, isl := range o.Islands {
		isl.Pop.SortByRank()
		if i == 0 {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = isl.OvaMin[j]
				o.OvaMax[j] = isl.OvaMax[j]
			}
		} else {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = utl.Min(o.OvaMin[j], isl.OvaMin[j])
				o.OvaMax[j] = utl.Max(o.OvaMax[j], isl.OvaMax[j])
			}
		}
	}

	// loop over pair of islands
	l := o.C.Ninds - o.C.Nimig
	for I := 0; I < o.C.Nisl; I++ {
		Pbest := o.Islands[I].Pop[:o.C.Nimig]
		Pwors := o.Islands[I].Pop[l:]
		for J := I + 1; J < o.C.Nisl; J++ {
			Qbest := o.Islands[J].Pop[:o.C.Nimig]
			Qwors := o.Islands[J].Pop[l:]

			// compute match distances
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				for j := 0; j < o.C.Nimig; j++ {
					B := Qbest[j]
					o.Mdist[i][j] = IndDistance(A, B, o.OvaMin, o.OvaMax)
				}
			}

			// match competitors
			o.Match.SetCostMatrix(o.Mdist)
			o.Match.Run()

			// matches
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				B := Qbest[o.Match.Links[i]]
				if A.Fight(B) {
					A.CopyInto(Qwors[i])
				} else {
					B.CopyInto(Pwors[i])
				}
			}
		}
	}
}

func (o Evolver) print_legend() {
	io.Pf("\nLEGEND\n")
	io.Pfgrey(" 00 -- generation number (time)\n")
	io.Pfblue(" 00 -- reporting time\n")
	io.Pfyel(" 00 -- migration time\n")
}

func (o Evolver) print_time(time, isl int) {
	if o.C.Verbose && isl == 0 {
		io.Pf(" ")
		if time%o.C.Dtout == 0 {
			io.Pfblue("%v", time)
			return
		}
		io.Pfgrey("%v", time)
	}
}
<commit_msg>non-opt migration removed<commit_after>// Copyright 2015 Dorival de Moraes Pedroso. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package goga

import (
	"github.com/cpmech/gosl/chk"
	"github.com/cpmech/gosl/graph"
	"github.com/cpmech/gosl/io"
	"github.com/cpmech/gosl/la"
	"github.com/cpmech/gosl/plt"
	"github.com/cpmech/gosl/utl"
)

// Evolver realises the evolutionary process
type Evolver struct {

	// data
	C       *ConfParams // configuration parameters
	Islands []*Island   // islands

	// migration
	OvaMin []float64     // min ova
	OvaMax []float64     // max ova
	Mdist  [][]float64   // match distances
	Match  graph.Munkres // matches
}

// NewEvolverPop creates a new evolver based on given populations
func NewEvolver(C *ConfParams) (o *Evolver) {

	// check input
	C.check_input()

	// data
	o = new(Evolver)
	o.C = C
	o.Islands = make([]*Island, o.C.Nisl)
	if o.C.Pll {
		done := make(chan int, o.C.Nisl)
		for i := 0; i < o.C.Nisl; i++ {
			go func(idx int) {
				o.Islands[idx] = NewIsland(idx, o.C)
				done <- 1
			}(i)
		}
		for i := 0; i < o.C.Nisl; i++ {
			<-done
		}
	} else {
		for i := 0; i < o.C.Nisl; i++ {
			o.Islands[i] = NewIsland(i, o.C)
		}
	}

	// migration
	o.OvaMin = make([]float64, o.C.Nova)
	o.OvaMax = make([]float64, o.C.Nova)
	o.Mdist = la.MatAlloc(o.C.Nimig, o.C.Nimig)
	o.Match.Init(o.C.Nimig, o.C.Nimig)
	return
}

// Run runs the evolution process
func (o *Evolver) Run() {

	// first output
	t := 0
	if o.C.Verbose {
		o.print_legend()
		io.Pf("\nrunning ...\n")
	}

	// time loop
	t = 1
	tmig := o.C.Dtmig
	nomig := false
	if tmig > o.C.Tf {
		tmig = o.C.Tf
		nomig = true
	}
	done := make(chan int, o.C.Nisl)
	for t < o.C.Tf {

		// evolve up to migration time
		if o.C.Pll {
			for i := 0; i < o.C.Nisl; i++ {
				go func(isl *Island) {
					for time := t; time < tmig; time++ {
						isl.Run(time)
						o.print_time(time, isl.Id)
					}
					Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
					done <- 1
				}(o.Islands[i])
			}
			for i := 0; i < o.C.Nisl; i++ {
				<-done
			}
		} else {
			for _, isl := range o.Islands {
				for time := t; time < tmig; time++ {
					isl.Run(time)
					o.print_time(time, isl.Id)
				}
				Metrics(isl.OvaMin, isl.OvaMax, isl.Fsizes, isl.Fronts, isl.Pop)
			}
		}

		// update time
		t = tmig
		tmig += o.C.Dtmig
		if tmig > o.C.Tf {
			tmig = o.C.Tf
			nomig = true
		}

		// migration
		if nomig {
			continue
		}
		if o.C.Verbose {
			io.Pfyel(" %d", t)
		}
		o.migration(t)
	}

	// message
	if o.C.Verbose {
		io.Pfgrey(" %d", t)
		io.Pf("\n... end\n\n")
	}
	return
}

// post-processing methods /////////////////////////////////////////////////////////////////////////

// GetFeasible returns all feasible individuals from all islands
func (o *Evolver) GetFeasible() (feasible []*Individual) {
	for _, isl := range o.Islands {
		for _, ind := range isl.Pop {
			if ind.Feasible() {
				feasible = append(feasible, ind)
			}
		}
	}
	return
}

// GetResults returns all ovas and oors from a subset of individuals
//  Output:
//   ovas -- [len(subset)][nova] objective values
//   oors -- [len(subset)][noor] out-of-range values
func (o *Evolver) GetResults(subset []*Individual) (ovas, oors [][]float64) {
	ninds := len(subset)
	ovas = utl.DblsAlloc(ninds, o.C.Nova)
	oors = utl.DblsAlloc(ninds, o.C.Noor)
	for i, ind := range subset {
		for j := 0; j < o.C.Nova; j++ {
			ovas[i][j] = ind.Ovas[j]
		}
		for j := 0; j < o.C.Noor; j++ {
			oors[i][j] = ind.Oors[j]
		}
	}
	return
}

// GetParetoFront returns all feasible individuals on the Pareto front
// Note: input data can be obtained from GetFeasible and GetResults
func (o *Evolver) GetParetoFront(feasible []*Individual, ovas, oors [][]float64) (ovafront, oorfront []*Individual) {
	chk.IntAssert(len(feasible), len(ovas))
	ovaf := utl.ParetoFront(ovas)
	ovafront = make([]*Individual, len(ovaf))
	for i, id := range ovaf {
		ovafront[i] = feasible[id]
	}
	if len(oors) > 0 {
		chk.IntAssert(len(feasible), len(oors))
		oorf := utl.ParetoFront(oors)
		oorfront = make([]*Individual, len(oorf))
		for i, id := range oorf {
			oorfront[i] = feasible[id]
		}
	}
	return
}

// GetFrontOvas collects 2 ova results from Pareto front
//  Input:
//   r and s -- 2 selected objective functions; e.g. r=0 and s=1 for 2D problems
func (o *Evolver) GetFrontOvas(r, s int, front []*Individual) (x, y []float64) {
	x = make([]float64, len(front))
	y = make([]float64, len(front))
	for i, ind := range front {
		x[i] = ind.Ovas[r]
		y[i] = ind.Ovas[s]
	}
	return
}

// GetPopulations returns all populations from all islands
func (o *Evolver) GetPopulations() (pops []Population) {
	pops = make([]Population, o.C.Nisl)
	for i, isl := range o.Islands {
		pops[i] = isl.Pop.GetCopy()
	}
	return
}

// PlotPareto plots pareto front for i and j objectives
func (o *Evolver) PlotPareto(i, j int) {
	feasible := o.GetFeasible()
	ovas, _ := o.GetResults(feasible)
	ovafront, _ := o.GetParetoFront(feasible, ovas, nil)
	f0front, f1front := o.GetFrontOvas(i, j, ovafront)
	f0fin := utl.DblsGetColumn(i, ovas)
	f1fin := utl.DblsGetColumn(j, ovas)
	plt.Plot(f0fin, f1fin, "'r.', clip_on=0, ms=3")
	plt.Plot(f0front, f1front, "'ko',markerfacecolor='none',ms=4, clip_on=0")
}

// GetNfeval returns the number of evaluations
func (o *Evolver) GetNfeval() (nfeval int) {
	for _, isl := range o.Islands {
		nfeval += isl.Nfeval
	}
	return
}

// auxiliary //////////////////////////////////////////////////////////////////////////////////////

func (o *Evolver) migration(t int) {

	// compute metrics in each island and compute global ova range
	for i, isl := range o.Islands {
		isl.Pop.SortByRank()
		if i == 0 {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = isl.OvaMin[j]
				o.OvaMax[j] = isl.OvaMax[j]
			}
		} else {
			for j := 0; j < o.C.Nova; j++ {
				o.OvaMin[j] = utl.Min(o.OvaMin[j], isl.OvaMin[j])
				o.OvaMax[j] = utl.Max(o.OvaMax[j], isl.OvaMax[j])
			}
		}
	}

	// loop over pair of islands
	l := o.C.Ninds - o.C.Nimig
	for I := 0; I < o.C.Nisl; I++ {
		Pbest := o.Islands[I].Pop[:o.C.Nimig]
		Pwors := o.Islands[I].Pop[l:]
		for J := I + 1; J < o.C.Nisl; J++ {
			Qbest := o.Islands[J].Pop[:o.C.Nimig]
			Qwors := o.Islands[J].Pop[l:]

			// compute match distances
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				for j := 0; j < o.C.Nimig; j++ {
					B := Qbest[j]
					o.Mdist[i][j] = IndDistance(A, B, o.OvaMin, o.OvaMax)
				}
			}

			// match competitors
			o.Match.SetCostMatrix(o.Mdist)
			o.Match.Run()

			// matches
			for i := 0; i < o.C.Nimig; i++ {
				A := Pbest[i]
				B := Qbest[o.Match.Links[i]]
				if A.Fight(B) {
					A.CopyInto(Qwors[i])
				} else {
					B.CopyInto(Pwors[i])
				}
			}
		}
	}
}

func (o Evolver) print_legend() {
	io.Pf("\nLEGEND\n")
	io.Pfgrey(" 00 -- generation number (time)\n")
	io.Pfblue(" 00 -- reporting time\n")
	io.Pfyel(" 00 -- migration time\n")
}

func (o Evolver) print_time(time, isl int) {
	if o.C.Verbose && isl == 0 {
		io.Pf(" ")
		if time%o.C.Dtout == 0 {
			io.Pfblue("%v", time)
			return
		}
		io.Pfgrey("%v", time)
	}
}
<|endoftext|>


<commit_before>package eventemitter

import (
	"sync"
)

type Emitter struct {
	async         bool
	stopOnError   bool
	capturers     []*Capturer
	listeners     map[EventType][]*Listener
	listenerMutex sync.Mutex
}

// NewEmitter creates a new event emitter that implements the Observable interface.
// Async determines whether events listeners fire in separate goroutines or not.
func NewEmitter(async bool) (em *Emitter) {
	em = &Emitter{
		async:       async,
		listeners:   make(map[EventType][]*Listener),
	}
	return em
}

// EmitEvent emits the given event to all listeners and capturers
func (em *Emitter) EmitEvent(event EventType, arguments ...interface{}) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	removed := 0
	var adjustedIndex int
	for index := range em.listeners[event] {
		adjustedIndex = index - removed

		if em.async {
			go em.listeners[event][adjustedIndex].handler(arguments...)
		} else {
			em.listeners[event][adjustedIndex].handler(arguments...)
		}

		if em.listeners[event][adjustedIndex].once {
			em.removeListenerAtIndex(event, adjustedIndex)
			removed++
		}
	}

	removed = 0
	for index := range em.capturers {
		adjustedIndex = index - removed

		if em.async {
			go em.capturers[adjustedIndex].handler(event, arguments...)
		} else {
			em.capturers[adjustedIndex].handler(event, arguments...)
		}

		if em.capturers[adjustedIndex].once {
			em.removeCapturerAtIndex(adjustedIndex)
			removed++
		}
	}
}

// AddListener adds a listener for the given event type
func (em *Emitter) AddListener(event EventType, handler HandleFunc) (listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	listener = &Listener{
		handler: handler,
		once:    false,
	}
	em.listeners[event] = append(em.listeners[event], listener)
	return listener
}

// ListenOnce adds a listener for the given event type that removes itself after it has been fired once
func (em *Emitter) ListenOnce(event EventType, handler HandleFunc) (listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	listener = &Listener{
		handler: handler,
		once:    true,
	}
	em.listeners[event] = append(em.listeners[event], listener)
	return listener
}

// AddCapturer adds an event capturer for all events
func (em *Emitter) AddCapturer(handler CaptureFunc) (capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	capturer = &Capturer{
		handler: handler,
		once:    false,
	}
	em.capturers = append(em.capturers, capturer)
	return capturer
}

// CaptureOnce adds an event capturer for all events that removes itself after it has been fired once
func (em *Emitter) CaptureOnce(handler CaptureFunc) (capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	capturer = &Capturer{
		handler: handler,
		once:    true,
	}
	em.capturers = append(em.capturers, capturer)
	return capturer
}

// RemoveListener removes the registered given listener for the given event
func (em *Emitter) RemoveListener(event EventType, listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	for index, list := range em.listeners[event] {
		if list == listener {
			em.removeListenerAtIndex(event, index)
			return
		}
	}
}

// RemoveAllListenersForEvent removes all registered listeners for a given event type
func (em *Emitter) RemoveAllListenersForEvent(event EventType) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.listeners[event] = make([]*Listener, 0)
}

// RemoveAllListeners removes all registered listeners for all event types
func (em *Emitter) RemoveAllListeners() {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.listeners = make(map[EventType][]*Listener)
}

// RemoveCapturer removes the given capturer
func (em *Emitter) RemoveCapturer(capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	for index, capt := range em.capturers {
		if capt == capturer {
			em.removeCapturerAtIndex(index)
			return
		}
	}
}

// RemoveAllCapturers removes all registered capturers
func (em *Emitter) RemoveAllCapturers() {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.capturers = make([]*Capturer, 0)
}

func (em *Emitter) removeListenerAtIndex(event EventType, index int) {
	copy(em.listeners[event][index:], em.listeners[event][index+1:])
	em.listeners[event][len(em.listeners[event])-1] = nil
	em.listeners[event] = em.listeners[event][:len(em.listeners[event])-1]
}

func (em *Emitter) removeCapturerAtIndex(index int) {
	copy(em.capturers[index:], em.capturers[index+1:])
	em.capturers[len(em.capturers)-1] = nil
	em.capturers = em.capturers[:len(em.capturers)-1]
}
<commit_msg>Remove unused property<commit_after>package eventemitter

import (
	"sync"
)

type Emitter struct {
	async         bool
	capturers     []*Capturer
	listeners     map[EventType][]*Listener
	listenerMutex sync.Mutex
}

// NewEmitter creates a new event emitter that implements the Observable interface.
// Async determines whether events listeners fire in separate goroutines or not.
func NewEmitter(async bool) (em *Emitter) {
	em = &Emitter{
		async:     async,
		listeners: make(map[EventType][]*Listener),
	}
	return em
}

// EmitEvent emits the given event to all listeners and capturers
func (em *Emitter) EmitEvent(event EventType, arguments ...interface{}) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	removed := 0
	var adjustedIndex int
	for index := range em.listeners[event] {
		adjustedIndex = index - removed

		if em.async {
			go em.listeners[event][adjustedIndex].handler(arguments...)
		} else {
			em.listeners[event][adjustedIndex].handler(arguments...)
		}

		if em.listeners[event][adjustedIndex].once {
			em.removeListenerAtIndex(event, adjustedIndex)
			removed++
		}
	}

	removed = 0
	for index := range em.capturers {
		adjustedIndex = index - removed

		if em.async {
			go em.capturers[adjustedIndex].handler(event, arguments...)
		} else {
			em.capturers[adjustedIndex].handler(event, arguments...)
		}

		if em.capturers[adjustedIndex].once {
			em.removeCapturerAtIndex(adjustedIndex)
			removed++
		}
	}
}

// AddListener adds a listener for the given event type
func (em *Emitter) AddListener(event EventType, handler HandleFunc) (listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	listener = &Listener{
		handler: handler,
		once:    false,
	}
	em.listeners[event] = append(em.listeners[event], listener)
	return listener
}

// ListenOnce adds a listener for the given event type that removes itself after it has been fired once
func (em *Emitter) ListenOnce(event EventType, handler HandleFunc) (listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	listener = &Listener{
		handler: handler,
		once:    true,
	}
	em.listeners[event] = append(em.listeners[event], listener)
	return listener
}

// AddCapturer adds an event capturer for all events
func (em *Emitter) AddCapturer(handler CaptureFunc) (capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	capturer = &Capturer{
		handler: handler,
		once:    false,
	}
	em.capturers = append(em.capturers, capturer)
	return capturer
}

// CaptureOnce adds an event capturer for all events that removes itself after it has been fired once
func (em *Emitter) CaptureOnce(handler CaptureFunc) (capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	capturer = &Capturer{
		handler: handler,
		once:    true,
	}
	em.capturers = append(em.capturers, capturer)
	return capturer
}

// RemoveListener removes the registered given listener for the given event
func (em *Emitter) RemoveListener(event EventType, listener *Listener) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	for index, list := range em.listeners[event] {
		if list == listener {
			em.removeListenerAtIndex(event, index)
			return
		}
	}
}

// RemoveAllListenersForEvent removes all registered listeners for a given event type
func (em *Emitter) RemoveAllListenersForEvent(event EventType) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.listeners[event] = make([]*Listener, 0)
}

// RemoveAllListeners removes all registered listeners for all event types
func (em *Emitter) RemoveAllListeners() {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.listeners = make(map[EventType][]*Listener)
}

// RemoveCapturer removes the given capturer
func (em *Emitter) RemoveCapturer(capturer *Capturer) {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	for index, capt := range em.capturers {
		if capt == capturer {
			em.removeCapturerAtIndex(index)
			return
		}
	}
}

// RemoveAllCapturers removes all registered capturers
func (em *Emitter) RemoveAllCapturers() {
	em.listenerMutex.Lock()
	defer em.listenerMutex.Unlock()

	em.capturers = make([]*Capturer, 0)
}

func (em *Emitter) removeListenerAtIndex(event EventType, index int) {
	copy(em.listeners[event][index:], em.listeners[event][index+1:])
	em.listeners[event][len(em.listeners[event])-1] = nil
	em.listeners[event] = em.listeners[event][:len(em.listeners[event])-1]
}

func (em *Emitter) removeCapturerAtIndex(index int) {
	copy(em.capturers[index:], em.capturers[index+1:])
	em.capturers[len(em.capturers)-1] = nil
	em.capturers = em.capturers[:len(em.capturers)-1]
}
<|endoftext|>


<commit_before>package id3

import (
	"io"
	"time"
)

func generateHeader(size int) []byte {
	size = synchsafeInt(size)

	b1 := id3byte
	b2 := versionByte
	b3 := nul // TODO flags
	b4 := intToBytes(size)
	var b5 []byte
	b5 = append(b5, b1...)
	b5 = append(b5, b2...)
	b5 = append(b5, b3...)
	b5 = append(b5, b4...)

	return b5
}

type Encoder struct {
	w io.Writer
	// The amount of padding that will be added after the last frame.
	Padding int
}

func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{
		w:       w,
		Padding: 1024,
	}
}

func (e *Encoder) WriteHeader(size int) error {
	h := generateHeader(size)
	_, err := e.Write(h)
	return err
}

func (e *Encoder) WriteFrame(f Frame) error {
	b := f.Header().serialize(f.size() - frameLength)
	_, err := e.Write(b)
	if err != nil {
		return err
	}
	b = f.Encode()
	_, err = e.Write(b)
	return err
}

func (e *Encoder) WritePadding() error {
	_, err := e.Write(make([]byte, e.Padding))
	return err
}

func (e *Encoder) Write(b []byte) (n int, err error) {
	return e.w.Write(b)
}

func (e *Encoder) WriteTag(t *Tag) error {
	t.SetTextFrameTime("TDTG", time.Now().UTC())
	err := e.WriteHeader(t.Frames.size() + e.Padding)
	if err != nil {
		return err
	}

	// TODO write important frames first
	for _, frames := range t.Frames {
		for _, frame := range frames {
			err := e.WriteFrame(frame)
			if err != nil {
				return err
			}
		}
	}

	return e.WritePadding()
}
<commit_msg>remove Encoder.Write<commit_after>package id3

import (
	"io"
	"time"
)

func generateHeader(size int) []byte {
	size = synchsafeInt(size)

	b1 := id3byte
	b2 := versionByte
	b3 := nul // TODO flags
	b4 := intToBytes(size)
	var b5 []byte
	b5 = append(b5, b1...)
	b5 = append(b5, b2...)
	b5 = append(b5, b3...)
	b5 = append(b5, b4...)

	return b5
}

type Encoder struct {
	w io.Writer
	// The amount of padding that will be added after the last frame.
	Padding int
}

func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{
		w:       w,
		Padding: 1024,
	}
}

func (e *Encoder) WriteHeader(size int) error {
	h := generateHeader(size)
	_, err := e.w.Write(h)
	return err
}

func (e *Encoder) WriteFrame(f Frame) error {
	b := f.Header().serialize(f.size() - frameLength)
	_, err := e.w.Write(b)
	if err != nil {
		return err
	}
	b = f.Encode()
	_, err = e.w.Write(b)
	return err
}

func (e *Encoder) WritePadding() error {
	_, err := e.w.Write(make([]byte, e.Padding))
	return err
}

func (e *Encoder) WriteTag(t *Tag) error {
	t.SetTextFrameTime("TDTG", time.Now().UTC())
	err := e.WriteHeader(t.Frames.size() + e.Padding)
	if err != nil {
		return err
	}

	// TODO write important frames first
	for _, frames := range t.Frames {
		for _, frame := range frames {
			err := e.WriteFrame(frame)
			if err != nil {
				return err
			}
		}
	}

	return e.WritePadding()
}
<|endoftext|>


<commit_before>package ginkgo

import (
	"fmt"
	"math"
	"time"
)

type example struct {
	subject exampleSubject
	focused bool

	containers []*containerNode

	state               ExampleState
	runTime             time.Duration
	sampleRunTimes      []time.Duration
	failure             ExampleFailure
	didInterceptFailure bool
	interceptedFailure  failureData
}

func newExample(subject exampleSubject) *example {
	ex := &example{
		subject: subject,
		focused: subject.getFlag() == flagTypeFocused,
	}

	if subject.getFlag() == flagTypePending {
		ex.state = ExampleStatePending
	}

	return ex
}

func (ex *example) addContainerNode(container *containerNode) {
	ex.containers = append([]*containerNode{container}, ex.containers...)
	if container.flag == flagTypeFocused {
		ex.focused = true
	} else if container.flag == flagTypePending {
		ex.state = ExampleStatePending
	}
}

func (ex *example) fail(failure failureData) {
	if !ex.didInterceptFailure {
		ex.interceptedFailure = failure
		ex.didInterceptFailure = true
	}
}

func (ex *example) skip() {
	ex.state = ExampleStateSkipped
}

func (ex *example) subjectComponentType() ExampleComponentType {
	if ex.subject.nodeType() == nodeTypeBenchmark {
		return ExampleComponentTypeBenchmark
	} else {
		return ExampleComponentTypeIt
	}
}

func (ex *example) desiredNumberOfSamples() int {
	if ex.subject.nodeType() == nodeTypeBenchmark {
		return ex.subject.(*benchmarkNode).samples
	}

	return 1
}

func (ex *example) failed() bool {
	return ex.state == ExampleStateFailed || ex.state == ExampleStatePanicked || ex.state == ExampleStateTimedOut
}

func (ex *example) skippedOrPending() bool {
	return ex.state == ExampleStateSkipped || ex.state == ExampleStatePending
}

func (ex *example) pending() bool {
	return ex.state == ExampleStatePending
}

func (ex *example) run() {
	startTime := time.Now()
	defer func() {
		ex.runTime = time.Since(startTime)
	}()

	ex.sampleRunTimes = make([]time.Duration, ex.desiredNumberOfSamples())

	for sample := 0; sample < ex.desiredNumberOfSamples(); sample++ {
		ex.state, ex.failure = ex.runSample(sample)

		if ex.state != ExampleStatePassed {
			return
		}
	}
}

func (ex *example) runSample(sample int) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleState = ExampleStatePassed
	exampleFailure = ExampleFailure{}
	innerMostContainerIndexToUnwind := 0

	defer func() {
		if len(ex.containers) > 0 {
			for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
				container := ex.containers[i]
				for _, afterEach := range container.afterEachNodes {
					outcome, failure := afterEach.run()
					afterEachState, afterEachFailure := ex.processOutcomeAndFailure(i, ExampleComponentTypeAfterEach, afterEach.codeLocation, outcome, failure)
					if afterEachState != ExampleStatePassed && exampleState == ExampleStatePassed {
						exampleState = afterEachState
						exampleFailure = afterEachFailure
					}
				}
			}
		}
	}()

	for i, container := range ex.containers {
		innerMostContainerIndexToUnwind = i
		for _, beforeEach := range container.beforeEachNodes {
			outcome, failure := beforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, ExampleComponentTypeBeforeEach, beforeEach.codeLocation, outcome, failure)
			if exampleState != ExampleStatePassed {
				return
			}
		}
	}

	for i, container := range ex.containers {
		for _, justBeforeEach := range container.justBeforeEachNodes {
			outcome, failure := justBeforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, ExampleComponentTypeJustBeforeEach, justBeforeEach.codeLocation, outcome, failure)
			if exampleState != ExampleStatePassed {
				return
			}
		}
	}

	sampleTime := time.Now()
	outcome, failure := ex.subject.run()
	ex.sampleRunTimes[sample] = time.Since(sampleTime)

	exampleState, exampleFailure = ex.processOutcomeAndFailure(len(ex.containers), ex.subjectComponentType(), ex.subject.getCodeLocation(), outcome, failure)
	if exampleState != ExampleStatePassed {
		return
	}

	if ex.subject.nodeType() == nodeTypeBenchmark {
		exampleState, exampleFailure = ex.processBenchmark(ex.sampleRunTimes[sample])
	}

	return
}

func (ex *example) processOutcomeAndFailure(containerIndex int, componentType ExampleComponentType, codeLocation CodeLocation, outcome runOutcome, failure failureData) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleFailure = ExampleFailure{}
	exampleState = ExampleStatePassed

	if ex.didInterceptFailure {
		exampleState = ExampleStateFailed
		failure = ex.interceptedFailure
	} else if outcome == runOutcomePanicked {
		exampleState = ExampleStatePanicked
	} else if outcome == runOutcomeTimedOut {
		exampleState = ExampleStateTimedOut
	} else {
		return
	}

	exampleFailure = ExampleFailure{
		Message:               failure.message,
		Location:              failure.codeLocation,
		ForwardedPanic:        failure.forwardedPanic,
		ComponentIndex:        containerIndex,
		ComponentType:         componentType,
		ComponentCodeLocation: codeLocation,
	}

	return
}

func (ex *example) processBenchmark(sampleTime time.Duration) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleFailure = ExampleFailure{}
	exampleState = ExampleStatePassed

	node := ex.subject.(*benchmarkNode)
	if sampleTime < node.maximumTime {
		return
	}

	exampleState = ExampleStateFailed
	message := fmt.Sprintf("Benchmark sample took: %.4fs\nThis exceeds the allowed maximum: %.4fs", sampleTime.Seconds(), node.maximumTime.Seconds())

	exampleFailure = ExampleFailure{
		Message:               message,
		Location:              node.getCodeLocation(),
		ComponentIndex:        len(ex.containers),
		ComponentType:         ExampleComponentTypeBenchmark,
		ComponentCodeLocation: node.getCodeLocation(),
	}

	return
}

func (ex *example) summary() *ExampleSummary {
	componentTexts := make([]string, len(ex.containers)+1)
	componentCodeLocations := make([]CodeLocation, len(ex.containers)+1)

	for i, container := range ex.containers {
		componentTexts[i] = container.text
		componentCodeLocations[i] = container.codeLocation
	}

	componentTexts[len(ex.containers)] = ex.subject.getText()
	componentCodeLocations[len(ex.containers)] = ex.subject.getCodeLocation()

	return &ExampleSummary{
		ComponentTexts:         componentTexts,
		ComponentCodeLocations: componentCodeLocations,
		State:     ex.state,
		RunTime:   ex.runTime,
		Failure:   ex.failure,
		Benchmark: ex.benchmarkReport(),
	}
}

func (ex *example) benchmarkReport() ExampleBenchmark {
	if ex.subject.nodeType() != nodeTypeBenchmark {
		return ExampleBenchmark{}
	}

	if ex.failed() {
		return ExampleBenchmark{
			IsBenchmark:     true,
			NumberOfSamples: len(ex.sampleRunTimes),
		}
	}

	max := time.Duration(math.MinInt64)
	min := time.Duration(math.MaxInt64)
	sum := time.Duration(0)
	sumOfSquares := time.Duration(0)

	for _, sample := range ex.sampleRunTimes {
		if sample > max {
			max = sample
		}
		if sample < min {
			min = sample
		}
		sum += sample
		sumOfSquares += sample * sample
	}

	n := float64(len(ex.sampleRunTimes))
	mean := time.Duration(float64(sum) / n)
	stdDev := time.Duration(math.Sqrt(float64(sumOfSquares)/n - float64(mean*mean)))

	return ExampleBenchmark{
		IsBenchmark:     true,
		NumberOfSamples: len(ex.sampleRunTimes),
		FastestTime:     min,
		SlowestTime:     max,
		AverageTime:     mean,
		StdDeviation:    stdDev,
	}
}

func (ex *example) concatenatedString() string {
	s := ""
	for _, container := range ex.containers {
		s += container.text + " "
	}

	return s + ex.subject.getText()
}
<commit_msg>fix terrible int64 overflow in benchmark report<commit_after>package ginkgo

import (
	"fmt"
	"math"
	"time"
)

type example struct {
	subject exampleSubject
	focused bool

	containers []*containerNode

	state               ExampleState
	runTime             time.Duration
	sampleRunTimes      []time.Duration
	failure             ExampleFailure
	didInterceptFailure bool
	interceptedFailure  failureData
}

func newExample(subject exampleSubject) *example {
	ex := &example{
		subject: subject,
		focused: subject.getFlag() == flagTypeFocused,
	}

	if subject.getFlag() == flagTypePending {
		ex.state = ExampleStatePending
	}

	return ex
}

func (ex *example) addContainerNode(container *containerNode) {
	ex.containers = append([]*containerNode{container}, ex.containers...)
	if container.flag == flagTypeFocused {
		ex.focused = true
	} else if container.flag == flagTypePending {
		ex.state = ExampleStatePending
	}
}

func (ex *example) fail(failure failureData) {
	if !ex.didInterceptFailure {
		ex.interceptedFailure = failure
		ex.didInterceptFailure = true
	}
}

func (ex *example) skip() {
	ex.state = ExampleStateSkipped
}

func (ex *example) subjectComponentType() ExampleComponentType {
	if ex.subject.nodeType() == nodeTypeBenchmark {
		return ExampleComponentTypeBenchmark
	} else {
		return ExampleComponentTypeIt
	}
}

func (ex *example) desiredNumberOfSamples() int {
	if ex.subject.nodeType() == nodeTypeBenchmark {
		return ex.subject.(*benchmarkNode).samples
	}

	return 1
}

func (ex *example) failed() bool {
	return ex.state == ExampleStateFailed || ex.state == ExampleStatePanicked || ex.state == ExampleStateTimedOut
}

func (ex *example) skippedOrPending() bool {
	return ex.state == ExampleStateSkipped || ex.state == ExampleStatePending
}

func (ex *example) pending() bool {
	return ex.state == ExampleStatePending
}

func (ex *example) run() {
	startTime := time.Now()
	defer func() {
		ex.runTime = time.Since(startTime)
	}()

	ex.sampleRunTimes = make([]time.Duration, ex.desiredNumberOfSamples())

	for sample := 0; sample < ex.desiredNumberOfSamples(); sample++ {
		ex.state, ex.failure = ex.runSample(sample)

		if ex.state != ExampleStatePassed {
			return
		}
	}
}

func (ex *example) runSample(sample int) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleState = ExampleStatePassed
	exampleFailure = ExampleFailure{}
	innerMostContainerIndexToUnwind := 0

	defer func() {
		if len(ex.containers) > 0 {
			for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
				container := ex.containers[i]
				for _, afterEach := range container.afterEachNodes {
					outcome, failure := afterEach.run()
					afterEachState, afterEachFailure := ex.processOutcomeAndFailure(i, ExampleComponentTypeAfterEach, afterEach.codeLocation, outcome, failure)
					if afterEachState != ExampleStatePassed && exampleState == ExampleStatePassed {
						exampleState = afterEachState
						exampleFailure = afterEachFailure
					}
				}
			}
		}
	}()

	for i, container := range ex.containers {
		innerMostContainerIndexToUnwind = i
		for _, beforeEach := range container.beforeEachNodes {
			outcome, failure := beforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, ExampleComponentTypeBeforeEach, beforeEach.codeLocation, outcome, failure)
			if exampleState != ExampleStatePassed {
				return
			}
		}
	}

	for i, container := range ex.containers {
		for _, justBeforeEach := range container.justBeforeEachNodes {
			outcome, failure := justBeforeEach.run()
			exampleState, exampleFailure = ex.processOutcomeAndFailure(i, ExampleComponentTypeJustBeforeEach, justBeforeEach.codeLocation, outcome, failure)
			if exampleState != ExampleStatePassed {
				return
			}
		}
	}

	sampleTime := time.Now()
	outcome, failure := ex.subject.run()
	ex.sampleRunTimes[sample] = time.Since(sampleTime)

	exampleState, exampleFailure = ex.processOutcomeAndFailure(len(ex.containers), ex.subjectComponentType(), ex.subject.getCodeLocation(), outcome, failure)
	if exampleState != ExampleStatePassed {
		return
	}

	if ex.subject.nodeType() == nodeTypeBenchmark {
		exampleState, exampleFailure = ex.processBenchmark(ex.sampleRunTimes[sample])
	}

	return
}

func (ex *example) processOutcomeAndFailure(containerIndex int, componentType ExampleComponentType, codeLocation CodeLocation, outcome runOutcome, failure failureData) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleFailure = ExampleFailure{}
	exampleState = ExampleStatePassed

	if ex.didInterceptFailure {
		exampleState = ExampleStateFailed
		failure = ex.interceptedFailure
	} else if outcome == runOutcomePanicked {
		exampleState = ExampleStatePanicked
	} else if outcome == runOutcomeTimedOut {
		exampleState = ExampleStateTimedOut
	} else {
		return
	}

	exampleFailure = ExampleFailure{
		Message:               failure.message,
		Location:              failure.codeLocation,
		ForwardedPanic:        failure.forwardedPanic,
		ComponentIndex:        containerIndex,
		ComponentType:         componentType,
		ComponentCodeLocation: codeLocation,
	}

	return
}

func (ex *example) processBenchmark(sampleTime time.Duration) (exampleState ExampleState, exampleFailure ExampleFailure) {
	exampleFailure = ExampleFailure{}
	exampleState = ExampleStatePassed

	node := ex.subject.(*benchmarkNode)
	if sampleTime < node.maximumTime {
		return
	}

	exampleState = ExampleStateFailed
	message := fmt.Sprintf("Benchmark sample took: %.4fs\nThis exceeds the allowed maximum: %.4fs", sampleTime.Seconds(), node.maximumTime.Seconds())

	exampleFailure = ExampleFailure{
		Message:               message,
		Location:              node.getCodeLocation(),
		ComponentIndex:        len(ex.containers),
		ComponentType:         ExampleComponentTypeBenchmark,
		ComponentCodeLocation: node.getCodeLocation(),
	}

	return
}

func (ex *example) summary() *ExampleSummary {
	componentTexts := make([]string, len(ex.containers)+1)
	componentCodeLocations := make([]CodeLocation, len(ex.containers)+1)

	for i, container := range ex.containers {
		componentTexts[i] = container.text
		componentCodeLocations[i] = container.codeLocation
	}

	componentTexts[len(ex.containers)] = ex.subject.getText()
	componentCodeLocations[len(ex.containers)] = ex.subject.getCodeLocation()

	return &ExampleSummary{
		ComponentTexts:         componentTexts,
		ComponentCodeLocations: componentCodeLocations,
		State:     ex.state,
		RunTime:   ex.runTime,
		Failure:   ex.failure,
		Benchmark: ex.benchmarkReport(),
	}
}

func (ex *example) benchmarkReport() ExampleBenchmark {
	if ex.subject.nodeType() != nodeTypeBenchmark {
		return ExampleBenchmark{}
	}

	if ex.failed() {
		return ExampleBenchmark{
			IsBenchmark:     true,
			NumberOfSamples: len(ex.sampleRunTimes),
		}
	}

	max := time.Duration(math.MinInt64)
	min := time.Duration(math.MaxInt64)
	sum := float64(0)
	sumOfSquares := float64(0)

	for _, sample := range ex.sampleRunTimes {
		if sample > max {
			max = sample
		}
		if sample < min {
			min = sample
		}
		sum += sample.Seconds()
		sumOfSquares += sample.Seconds() * sample.Seconds()
	}

	n := float64(len(ex.sampleRunTimes))
	mean := time.Duration((sum / n) * float64(time.Second))
	stdDev := time.Duration(math.Sqrt(sumOfSquares/n-float64(sum*sum/n/n)) * float64(time.Second))

	return ExampleBenchmark{
		IsBenchmark:     true,
		NumberOfSamples: len(ex.sampleRunTimes),
		FastestTime:     min,
		SlowestTime:     max,
		AverageTime:     mean,
		StdDeviation:    stdDev,
	}
}

func (ex *example) concatenatedString() string {
	s := ""
	for _, container := range ex.containers {
		s += container.text + " "
	}

	return s + ex.subject.getText()
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 Go Fightclub Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx

    header := afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- header

    retval := self.prepare()
    return retval
}

func (self *AlsaSource) Start() {
    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    self.header = <-self.ctx.HeaderSource
    retval := self.prepare()
    return retval
}

func (self *AlsaSink) Start() {
    for buffer := range self.ctx.Source { //reading a [][]float32
        cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
        length := len(buffer)
        chans := int(self.header.Channels)

        //interleave the channels
        for i := 0; i < length; i += chans {
            for j := 0; j < chans; j++ {
                cbuf[i+j] = buffer[i / chans][j]
            }
        }

        //write some data to alsa
        written := C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))

        if int(written) < length {
            //not all the data was written
            panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: ", written))
        }
    }

    return
}

// Ugly bastardized C code follows
func (self *AlsaSink) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.playback, C.CString("default"), C.SND_PCM_STREAM_PLAYBACK, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    defer C.snd_pcm_close(self.playback)

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.playback, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access type. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.playback, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.playback, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.playback, self.params, C.uint(self.header.Channels)); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set hardware parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.playback); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio device for use. Error %d", errno) )
    }

    return nil
}

//this one is slightly different
//note the change in scope
func (self *AlsaSource) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.capture, C.CString("default"), C.SND_PCM_STREAM_CAPTURE, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    defer C.snd_pcm_close(self.capture)

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameters. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.capture, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.capture, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.capture, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.capture, self.params, 1); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.capture); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio interface for use. Error %d", errno) )
    }

    return nil
}
<commit_msg>Cleaning up after vimdiff fail<commit_after>// Copyright (c) 2010 Go Fightclub Authors

package alsa

import (
  "fmt"
  "unsafe"
  "afp"
  "os"
)

// #include <alsa/asoundlib.h>
import "C"

/////
// Alsa Source
// Listens to a microphone
type AlsaSource struct {
    ctx *afp.Context
    header afp.StreamHeader
    capture *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t
}

func (self *AlsaSource) GetType() int {
    return afp.PIPE_SOURCE
}

func (self *AlsaSource) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx

    header := afp.StreamHeader {
        Version: 1,
        Channels: 1,
        SampleSize: 32,
        SampleRate: 44100,
        FrameSize: 4096,
    }

    self.ctx.HeaderSink <- header

    retval := self.prepare()
    return retval
}

func (self *AlsaSource) Start() {
    for {
		cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
		buff := make([][]float32, self.header.FrameSize)
        length := len(cbuf)

        //first off, grab some data from alsa
        read := C.snd_pcm_readi(self.capture, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))
        if read < C.snd_pcm_sframes_t(length) {
            errno := C.snd_pcm_recover(self.capture, C.int(read), 0)
            if errno < 0 {
                panic(fmt.Sprint( "While reading from ALSA device, failed to recover from error: ", errno))
            }
        }

        // snd_pcm_readi gives us a one dimensional array of interleaved data
        // but what we want is a two dimensional array of samples
        chans := int(self.header.Channels)
		for slice, i := 0, 0; i < length; slice, i = slice + 1, i + chans {
			buff[slice] = make([]float32, chans)
			buff[slice] = cbuf[i : i + chans]
        }

        //send it on down the line
        self.ctx.Sink <- buff
    }

}

/////
// Alsa Sink
// Outputs to speakers via ALSA
type AlsaSink struct {
    ctx *afp.Context
    header afp.StreamHeader
    playback *C.snd_pcm_t
    params *C.snd_pcm_hw_params_t

}

func (self *AlsaSink) GetType() int {
    return afp.PIPE_SINK
}

func (self *AlsaSink) Init(ctx *afp.Context, args []string) os.Error {
    self.ctx = ctx
    self.header = <-self.ctx.HeaderSource
    retval := self.prepare()
    return retval
}

func (self *AlsaSink) Start() {
    for buffer := range self.ctx.Source { //reading a [][]float32
        cbuf := make([]float32, int32(self.header.Channels) * self.header.FrameSize)
        length := len(buffer)
        chans := int(self.header.Channels)

        //interleave the channels
        for i := 0; i < length; i += chans {
            for j := 0; j < chans; j++ {
                cbuf[i+j] = buffer[i / chans][j]
            }
        }

        //write some data to alsa
        written := C.snd_pcm_writei(self.playback, unsafe.Pointer(&cbuf[0]), C.snd_pcm_uframes_t(length))

        if int(written) < length {
            //not all the data was written
            panic(fmt.Sprintf("Could not write all data to ALSA device, wrote: ", written))
        }
    }

    return
}

// Ugly bastardized C code follows
func (self *AlsaSink) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.playback, C.CString("default"), C.SND_PCM_STREAM_PLAYBACK, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    defer C.snd_pcm_close(self.playback)

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.playback, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access type. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.playback, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.playback, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.playback, self.params, C.uint(self.header.Channels)); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.playback, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set hardware parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.playback); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio device for use. Error %d", errno) )
    }

    return nil
}

//this one is slightly different
//note the change in scope
func (self *AlsaSource) prepare() os.Error {

    if errno := C.snd_pcm_open(&self.capture, C.CString("default"), C.SND_PCM_STREAM_CAPTURE, 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not open device. Error %d", errno) )
    }

    defer C.snd_pcm_close(self.capture)

    if errno := C.snd_pcm_hw_params_malloc(&self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not allocate hardware parameters. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_any(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not initialize hardware parameter structure. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_access(self.capture, self.params, C.SND_PCM_ACCESS_RW_INTERLEAVED); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set access. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_format(self.capture, self.params, C.SND_PCM_FORMAT_FLOAT); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample format. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_rate(self.capture, self.params, C.uint(self.header.SampleRate), 0); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set sample rate. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params_set_channels(self.capture, self.params, 1); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set channel count. Error %d", errno) )
    }

    if errno := C.snd_pcm_hw_params(self.capture, self.params); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not set parameters. Error %d", errno) )
    }

    C.snd_pcm_hw_params_free(self.params)

    if errno := C.snd_pcm_prepare(self.capture); errno < 0 {
        return os.NewError( fmt.Sprintf("Could not prepare audio interface for use. Error %d", errno) )
    }

    return nil
}
<|endoftext|>