<commit_before>package app

import (
	"errors"
	"fmt"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"github.com/Sirupsen/logrus"
	"github.com/casualjim/go-app/logging"
	"github.com/casualjim/go-app/tracing"
	cjm "github.com/casualjim/middlewares"
	"github.com/fsnotify/fsnotify"
	"github.com/kardianos/osext"
	"github.com/spf13/viper"

	// we enable remote config providers by default
	_ "github.com/spf13/viper/remote"
)

var (
	// ErrModuleUnknown returned when no module can be found for the specified key
	ErrModuleUnknown error

	execName func() (string, error)

	// Version of the application
	Version string
)

func init() {
	ErrModuleUnknown = errors.New("unknown module")
	execName = osext.Executable
	log.SetOutput(logrus.StandardLogger().Writer())
	log.SetFlags(0)
}

// A Key represents a key for a module.
// Users of this package can define their own keys, this is just the type definition.
type Key string

// Application is an application level context package
// It can be used as a kind of dependency injection container
type Application interface {
	// Add modules to the application context
	Add(...Module) error

	// Get the module at the specified key, thread-safe
	Get(Key) interface{}

	// Get the module at the specified key, thread-safe
	GetOK(Key) (interface{}, bool)

	// Set the module at the specified key, this should be safe across multiple threads
	Set(Key, interface{}) error

	// Logger gets the root logger for this application
	Logger() logrus.FieldLogger

	// NewLogger creates a new named logger for this application
	NewLogger(string, logrus.Fields) logrus.FieldLogger

	// Tracer returns the root
	Tracer() tracing.Tracer

	// Config returns the viper config for this application
	Config() *viper.Viper

	// Info returns the app info object for this application
	Info() cjm.AppInfo

	// Init the application and its modules with the config.
	Init() error

	// Start the application an its enabled modules
	Start() error

	// Stop the application an its enabled modules
	Stop() error
}

func addDefaultConfigPaths(v *viper.Viper, name string) {
	v.SetConfigName("config")
	norm := strings.ToLower(name)
	paths := filepath.Join(os.Getenv("HOME"), ".config", norm) + ":" + filepath.Join("/etc", norm) + ":etc:."
	if os.Getenv("CONFIG_PATH") != "" {
		paths = os.Getenv("CONFIG_PATH")
	}
	for _, path := range filepath.SplitList(paths) {
		v.AddConfigPath(path)
	}
}

var viperLock *sync.Mutex

func init() {
	viperLock = new(sync.Mutex)
}

func createViper(name string, configPath string) (*viper.Viper, error) {
	viperLock.Lock()
	defer viperLock.Unlock()
	v := viper.New()
	if configPath == "" {
		addDefaultConfigPaths(v, name)
	} else {
		if _, err := os.Stat(configPath); os.IsNotExist(err) {
			return nil, fmt.Errorf("No config file found at %s", configPath)
		}
		dir, fname := filepath.Split(configPath)
		// viper wants the file name without extention...
		suffixes := []string{".json", ".yml", ".yaml", ".hcl", ".toml"}
		for _, suffix := range suffixes {
			if strings.HasSuffix(fname, suffix) {
				fname = strings.Split(fname, suffix)[0]
				break
			}
		}
		v.SetConfigName(fname)
		v.AddConfigPath(dir)
	}

	if err := addViperRemoteConfig(v); err != nil {
		return nil, err
	}

	if err := v.ReadInConfig(); err != nil {
		if _, ok := err.(viper.UnsupportedConfigError); !ok && v.ConfigFileUsed() != "" {
			return nil, err
		}
	}
	v.SetEnvPrefix(name)
	v.AutomaticEnv()

	addViperDefaults(v)

	return v, nil
}

func addViperRemoteConfig(v *viper.Viper) error {
	// check if encryption is required CONFIG_KEYRING
	keyring := os.Getenv("CONFIG_KEYRING")

	// check for etcd env vars CONFIG_REMOTE_URL, eg:
	// etcd://localhost:2379/[app-name]/config.[type]
	// consul://localhost:8500/[app-name]/config.[type]
	remURL := os.Getenv("CONFIG_REMOTE_URL")
	if remURL == "" {
		return nil
	}
	var provider, host, path, tpe string
	u, err := url.Parse(remURL)
	if err != nil {
		return err
	}
	provider = strings.ToLower(u.Scheme)
	host = u.Host
	if provider == "etcd" {
		host = "http://" + host
	}
	path = u.Path
	tpe = strings.ToLower(strings.TrimLeft(filepath.Ext(path), "."))
	if tpe == "" {
		tpe = "json"
	}

	v.SetConfigType(tpe)
	if keyring != "" {
		if err := v.AddSecureRemoteProvider(provider, host, path, keyring); err != nil {
			return err
		}
	} else {

		if err := v.AddRemoteProvider(provider, host, path); err != nil {
			return err
		}
	}

	if err := v.ReadRemoteConfig(); err != nil {
		return fmt.Errorf("config is invalid as %s", tpe)
	}

	return nil
}

func addViperDefaults(v *viper.Viper) {
	v.SetDefault("tracer", map[interface{}]interface{}{"enable": true})
	v.SetDefault("logging", map[interface{}]interface{}{"root": map[interface{}]interface{}{"level": "info"}})
}

func ensureDefaults(name string) (string, string, error) {
	// configure version defaults
	version := "dev"
	if Version != "" {
		version = Version
	}

	// configure name defaults
	if name == "" {
		name = os.Getenv("APP_NAME")
		if name == "" {
			exe, err := execName()
			if err != nil {
				return "", "", err
			}
			name = filepath.Base(exe)
		}
	}

	return name, version, nil
}

func newWithCallback(nme string, configPath string, reload func(fsnotify.Event)) (Application, error) {
	name, version, err := ensureDefaults(nme)
	if err != nil {
		return nil, err
	}
	appInfo := cjm.AppInfo{
		Name:     name,
		BasePath: "/",
		Version:  version,
		Pid:      os.Getpid(),
	}

	cfg, err := createViper(name, configPath)
	if err != nil {
		return nil, err
	}

	allLoggers := logging.NewRegistry(cfg, logrus.Fields{"app": appInfo.Name})

	log.SetOutput(allLoggers.Writer())

	tracer := allLoggers.Root().WithField("module", "trace")
	trace := tracing.New("", tracer, nil)

	app := &defaultApplication{
		appInfo:    appInfo,
		allLoggers: allLoggers,
		rootTracer: trace,
		config:     cfg,
		registry:   make(map[Key]interface{}, 100),
		regLock:    new(sync.Mutex),
	}
	app.watchConfigurations(func(in fsnotify.Event) {
		if reload != nil {
			reload(in)
		}
		allLoggers.Reload()
		for _, mod := range app.modules {
			if err := mod.Reload(app); err != nil {
				allLoggers.Root().Errorf("reload config: %v", err)
			}
		}
		allLoggers.Root().Infoln("config file changed:", in.Name)
	})
	return app, nil
}

// New application with the specified name, at the specified basepath
func New(nme string) (Application, error) {
	return newWithCallback(nme, "", nil)
}

// NewWithConfig application with the specified name, with a specific config file path
func NewWithConfig(nme string, configPath string) (Application, error) {
	return newWithCallback(nme, configPath, nil)
}

type defaultApplication struct {
	appInfo    cjm.AppInfo
	allLoggers *logging.Registry
	rootTracer tracing.Tracer
	config     *viper.Viper
	modules    []Module

	registry map[Key]interface{}
	regLock  *sync.Mutex
}

func (d *defaultApplication) watchConfigurations(reload func(fsnotify.Event)) {
	viperLock.Lock()
	defer viperLock.Unlock()
	d.config.WatchConfig()
	d.config.OnConfigChange(reload)

	// we made it this far, it's clear the url means we're also connecting remotely
	if os.Getenv("CONFIG_REMOTE_URL") != "" {
		go func() {
			for {
				err := d.config.WatchRemoteConfig()
				if err != nil {
					d.Logger().Errorf("watching remote config: %v", err)
					continue
				}
				reload(fsnotify.Event{Name: os.Getenv("CONFIG_REMOTE_URL"), Op: fsnotify.Write})
			}
		}()
	}
}

func (d *defaultApplication) Add(modules ...Module) error {
	if len(modules) > 0 {
		d.modules = append(d.modules, modules...)
	}
	return nil
}

// Get the module at the specified key, return nil when the component doesn't exist
func (d *defaultApplication) Get(key Key) interface{} {
	mod, _ := d.GetOK(key)
	return mod
}

// Get the module at the specified key, return false when the component doesn't exist
func (d *defaultApplication) GetOK(key Key) (interface{}, bool) {
	d.regLock.Lock()
	defer d.regLock.Unlock()

	mod, ok := d.registry[key]
	if !ok {
		return nil, ok
	}
	return mod, ok
}

func (d *defaultApplication) Set(key Key, module interface{}) error {
	d.regLock.Lock()
	d.registry[key] = module
	d.regLock.Unlock()
	return nil
}

func (d *defaultApplication) Logger() logrus.FieldLogger {
	return d.allLoggers.Root()
}

func (d *defaultApplication) NewLogger(name string, ctx logrus.Fields) logrus.FieldLogger {
	return d.allLoggers.Root().New(name, ctx)
}

func (d *defaultApplication) Tracer() tracing.Tracer {
	return d.rootTracer
}

func (d *defaultApplication) Config() *viper.Viper {
	return d.config
}

func (d *defaultApplication) Info() cjm.AppInfo {
	return d.appInfo
}

func (d *defaultApplication) Init() error {
	for _, mod := range d.modules {
		if err := mod.Init(d); err != nil {
			return err
		}
	}
	return nil
}

func (d *defaultApplication) Start() error {
	for _, mod := range d.modules {
		if err := mod.Start(d); err != nil {
			return err
		}
	}
	return nil
}

func (d *defaultApplication) Stop() error {
	for _, mod := range d.modules {
		if err := mod.Stop(d); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>add goroutine dump for SIGQUIT<commit_after>package app

import (
	"errors"
	"fmt"
	"log"
	"net/url"
	"os"
	"os/signal"
	"path/filepath"
	goruntime "runtime"
	"strings"
	"sync"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/casualjim/go-app/logging"
	"github.com/casualjim/go-app/tracing"
	cjm "github.com/casualjim/middlewares"
	"github.com/fsnotify/fsnotify"
	"github.com/kardianos/osext"
	"github.com/spf13/viper"

	// we enable remote config providers by default
	_ "github.com/spf13/viper/remote"
)

var (
	// ErrModuleUnknown returned when no module can be found for the specified key
	ErrModuleUnknown error

	execName func() (string, error)

	// Version of the application
	Version string
)

func init() {
	ErrModuleUnknown = errors.New("unknown module")
	execName = osext.Executable
	log.SetOutput(logrus.StandardLogger().Writer())
	log.SetFlags(0)
}

// A Key represents a key for a module.
// Users of this package can define their own keys, this is just the type definition.
type Key string

// Application is an application level context package
// It can be used as a kind of dependency injection container
type Application interface {
	// Add modules to the application context
	Add(...Module) error

	// Get the module at the specified key, thread-safe
	Get(Key) interface{}

	// Get the module at the specified key, thread-safe
	GetOK(Key) (interface{}, bool)

	// Set the module at the specified key, this should be safe across multiple threads
	Set(Key, interface{}) error

	// Logger gets the root logger for this application
	Logger() logrus.FieldLogger

	// NewLogger creates a new named logger for this application
	NewLogger(string, logrus.Fields) logrus.FieldLogger

	// Tracer returns the root
	Tracer() tracing.Tracer

	// Config returns the viper config for this application
	Config() *viper.Viper

	// Info returns the app info object for this application
	Info() cjm.AppInfo

	// Init the application and its modules with the config.
	Init() error

	// Start the application an its enabled modules
	Start() error

	// Stop the application an its enabled modules
	Stop() error
}

func addDefaultConfigPaths(v *viper.Viper, name string) {
	v.SetConfigName("config")
	norm := strings.ToLower(name)
	paths := filepath.Join(os.Getenv("HOME"), ".config", norm) + ":" + filepath.Join("/etc", norm) + ":etc:."
	if os.Getenv("CONFIG_PATH") != "" {
		paths = os.Getenv("CONFIG_PATH")
	}
	for _, path := range filepath.SplitList(paths) {
		v.AddConfigPath(path)
	}
}

var viperLock *sync.Mutex

func init() {
	viperLock = new(sync.Mutex)
}

func createViper(name string, configPath string) (*viper.Viper, error) {
	viperLock.Lock()
	defer viperLock.Unlock()
	v := viper.New()
	if configPath == "" {
		addDefaultConfigPaths(v, name)
	} else {
		if _, err := os.Stat(configPath); os.IsNotExist(err) {
			return nil, fmt.Errorf("No config file found at %s", configPath)
		}
		dir, fname := filepath.Split(configPath)
		// viper wants the file name without extention...
		suffixes := []string{".json", ".yml", ".yaml", ".hcl", ".toml"}
		for _, suffix := range suffixes {
			if strings.HasSuffix(fname, suffix) {
				fname = strings.Split(fname, suffix)[0]
				break
			}
		}
		v.SetConfigName(fname)
		v.AddConfigPath(dir)
	}

	if err := addViperRemoteConfig(v); err != nil {
		return nil, err
	}

	if err := v.ReadInConfig(); err != nil {
		if _, ok := err.(viper.UnsupportedConfigError); !ok && v.ConfigFileUsed() != "" {
			return nil, err
		}
	}
	v.SetEnvPrefix(name)
	v.AutomaticEnv()

	addViperDefaults(v)

	return v, nil
}

func addViperRemoteConfig(v *viper.Viper) error {
	// check if encryption is required CONFIG_KEYRING
	keyring := os.Getenv("CONFIG_KEYRING")

	// check for etcd env vars CONFIG_REMOTE_URL, eg:
	// etcd://localhost:2379/[app-name]/config.[type]
	// consul://localhost:8500/[app-name]/config.[type]
	remURL := os.Getenv("CONFIG_REMOTE_URL")
	if remURL == "" {
		return nil
	}
	var provider, host, path, tpe string
	u, err := url.Parse(remURL)
	if err != nil {
		return err
	}
	provider = strings.ToLower(u.Scheme)
	host = u.Host
	if provider == "etcd" {
		host = "http://" + host
	}
	path = u.Path
	tpe = strings.ToLower(strings.TrimLeft(filepath.Ext(path), "."))
	if tpe == "" {
		tpe = "json"
	}

	v.SetConfigType(tpe)
	if keyring != "" {
		if err := v.AddSecureRemoteProvider(provider, host, path, keyring); err != nil {
			return err
		}
	} else {

		if err := v.AddRemoteProvider(provider, host, path); err != nil {
			return err
		}
	}

	if err := v.ReadRemoteConfig(); err != nil {
		return fmt.Errorf("config is invalid as %s", tpe)
	}

	return nil
}

func addViperDefaults(v *viper.Viper) {
	v.SetDefault("tracer", map[interface{}]interface{}{"enable": true})
	v.SetDefault("logging", map[interface{}]interface{}{"root": map[interface{}]interface{}{"level": "info"}})
}

func ensureDefaults(name string) (string, string, error) {
	// configure version defaults
	version := "dev"
	if Version != "" {
		version = Version
	}

	// configure name defaults
	if name == "" {
		name = os.Getenv("APP_NAME")
		if name == "" {
			exe, err := execName()
			if err != nil {
				return "", "", err
			}
			name = filepath.Base(exe)
		}
	}

	return name, version, nil
}

func newWithCallback(nme string, configPath string, reload func(fsnotify.Event)) (Application, error) {
	name, version, err := ensureDefaults(nme)
	if err != nil {
		return nil, err
	}
	appInfo := cjm.AppInfo{
		Name:     name,
		BasePath: "/",
		Version:  version,
		Pid:      os.Getpid(),
	}

	cfg, err := createViper(name, configPath)
	if err != nil {
		return nil, err
	}

	allLoggers := logging.NewRegistry(cfg, logrus.Fields{"app": appInfo.Name})

	log.SetOutput(allLoggers.Writer())

	tracer := allLoggers.Root().WithField("module", "trace")
	trace := tracing.New("", tracer, nil)

	go func() {
		sigs := make(chan os.Signal, 1)
		signal.Notify(sigs, syscall.SIGQUIT)
		buf := make([]byte, 1<<20)

		for {
			<-sigs
			ln := goruntime.Stack(buf, true)
			allLoggers.Root().Println(string(buf[:ln]))
		}
	}()

	app := &defaultApplication{
		appInfo:    appInfo,
		allLoggers: allLoggers,
		rootTracer: trace,
		config:     cfg,
		registry:   make(map[Key]interface{}, 100),
		regLock:    new(sync.Mutex),
	}
	app.watchConfigurations(func(in fsnotify.Event) {
		if reload != nil {
			reload(in)
		}
		allLoggers.Reload()
		for _, mod := range app.modules {
			if err := mod.Reload(app); err != nil {
				allLoggers.Root().Errorf("reload config: %v", err)
			}
		}
		allLoggers.Root().Infoln("config file changed:", in.Name)
	})
	return app, nil
}

// New application with the specified name, at the specified basepath
func New(nme string) (Application, error) {
	return newWithCallback(nme, "", nil)
}

// NewWithConfig application with the specified name, with a specific config file path
func NewWithConfig(nme string, configPath string) (Application, error) {
	return newWithCallback(nme, configPath, nil)
}

type defaultApplication struct {
	appInfo    cjm.AppInfo
	allLoggers *logging.Registry
	rootTracer tracing.Tracer
	config     *viper.Viper
	modules    []Module

	registry map[Key]interface{}
	regLock  *sync.Mutex
}

func (d *defaultApplication) watchConfigurations(reload func(fsnotify.Event)) {
	viperLock.Lock()
	defer viperLock.Unlock()
	d.config.WatchConfig()
	d.config.OnConfigChange(reload)

	// we made it this far, it's clear the url means we're also connecting remotely
	if os.Getenv("CONFIG_REMOTE_URL") != "" {
		go func() {
			for {
				err := d.config.WatchRemoteConfig()
				if err != nil {
					d.Logger().Errorf("watching remote config: %v", err)
					continue
				}
				reload(fsnotify.Event{Name: os.Getenv("CONFIG_REMOTE_URL"), Op: fsnotify.Write})
			}
		}()
	}
}

func (d *defaultApplication) Add(modules ...Module) error {
	if len(modules) > 0 {
		d.modules = append(d.modules, modules...)
	}
	return nil
}

// Get the module at the specified key, return nil when the component doesn't exist
func (d *defaultApplication) Get(key Key) interface{} {
	mod, _ := d.GetOK(key)
	return mod
}

// Get the module at the specified key, return false when the component doesn't exist
func (d *defaultApplication) GetOK(key Key) (interface{}, bool) {
	d.regLock.Lock()
	defer d.regLock.Unlock()

	mod, ok := d.registry[key]
	if !ok {
		return nil, ok
	}
	return mod, ok
}

func (d *defaultApplication) Set(key Key, module interface{}) error {
	d.regLock.Lock()
	d.registry[key] = module
	d.regLock.Unlock()
	return nil
}

func (d *defaultApplication) Logger() logrus.FieldLogger {
	return d.allLoggers.Root()
}

func (d *defaultApplication) NewLogger(name string, ctx logrus.Fields) logrus.FieldLogger {
	return d.allLoggers.Root().New(name, ctx)
}

func (d *defaultApplication) Tracer() tracing.Tracer {
	return d.rootTracer
}

func (d *defaultApplication) Config() *viper.Viper {
	return d.config
}

func (d *defaultApplication) Info() cjm.AppInfo {
	return d.appInfo
}

func (d *defaultApplication) Init() error {
	for _, mod := range d.modules {
		if err := mod.Init(d); err != nil {
			return err
		}
	}
	return nil
}

func (d *defaultApplication) Start() error {
	for _, mod := range d.modules {
		if err := mod.Start(d); err != nil {
			return err
		}
	}
	return nil
}

func (d *defaultApplication) Stop() error {
	for _, mod := range d.modules {
		if err := mod.Stop(d); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package openapi3

import (
	"reflect"
	"regexp"

	oas3 "github.com/getkin/kin-openapi/openapi3"
	"github.com/grokify/gocharts/data/table"
)

type CollisionCheckResult int

const (
	CollisionCheckSame CollisionCheckResult = iota
	CollisionCheckOverwrite
	CollisionCheckError
	CollisionCheckSkip
)

type MergeOptions struct {
	FileRx               *regexp.Regexp
	SchemaFunc           func(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult
	CollisionCheckResult CollisionCheckResult
	ValidateEach         bool
	ValidateFinal        bool
	TableColumns         *table.ColumnSet
	TableOpFilterFunc    func(path, method string, op *oas3.Operation) bool
}

func NewMergeOptionsSkip() *MergeOptions {
	return &MergeOptions{
		SchemaFunc: SchemaCheckCollisionSkip}
}

func (mo *MergeOptions) CheckSchemaCollision(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult {
	if mo.CollisionCheckResult == CollisionCheckSkip {
		mo.SchemaFunc = SchemaCheckCollisionSkip
	} else if mo.SchemaFunc == nil {
		mo.SchemaFunc = SchemaCheckCollisionDefault
	}
	return mo.SchemaFunc(schemaName, sch1, sch2, hint2)
}

func SchemaCheckCollisionDefault(schemaName string, item1, item2 interface{}, item2Note string) CollisionCheckResult {
	if reflect.DeepEqual(item1, item2) {
		return CollisionCheckSame
	}
	return CollisionCheckError
}

func SchemaCheckCollisionSkip(schemaName string, item1, item2 interface{}, item2Note string) CollisionCheckResult {
	if reflect.DeepEqual(item1, item2) {
		return CollisionCheckSame
	}
	return CollisionCheckSkip
}
<commit_msg>enhance: openapi3: update `NewMergeOptionsSkip()`<commit_after>package openapi3

import (
	"reflect"
	"regexp"

	oas3 "github.com/getkin/kin-openapi/openapi3"
	"github.com/grokify/gocharts/data/table"
)

type CollisionCheckResult int

const (
	CollisionCheckSame CollisionCheckResult = iota
	CollisionCheckOverwrite
	CollisionCheckError
	CollisionCheckSkip
)

type MergeOptions struct {
	FileRx               *regexp.Regexp
	SchemaFunc           func(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult
	CollisionCheckResult CollisionCheckResult
	ValidateEach         bool
	ValidateFinal        bool
	TableColumns         *table.ColumnSet
	TableOpFilterFunc    func(path, method string, op *oas3.Operation) bool
}

func NewMergeOptionsSkip() *MergeOptions {
	return &MergeOptions{
		CollisionCheckResult: CollisionCheckSkip,
		SchemaFunc:           SchemaCheckCollisionSkip}
}

func (mo *MergeOptions) CheckSchemaCollision(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult {
	if mo.CollisionCheckResult == CollisionCheckSkip {
		mo.SchemaFunc = SchemaCheckCollisionSkip
	} else if mo.SchemaFunc == nil {
		mo.SchemaFunc = SchemaCheckCollisionDefault
	}
	return mo.SchemaFunc(schemaName, sch1, sch2, hint2)
}

func SchemaCheckCollisionDefault(schemaName string, item1, item2 interface{}, item2Note string) CollisionCheckResult {
	if reflect.DeepEqual(item1, item2) {
		return CollisionCheckSame
	}
	return CollisionCheckError
}

func SchemaCheckCollisionSkip(schemaName string, item1, item2 interface{}, item2Note string) CollisionCheckResult {
	if reflect.DeepEqual(item1, item2) {
		return CollisionCheckSame
	}
	return CollisionCheckSkip
}
<|endoftext|>


<commit_before>package experiments

import (
	"time"
	"sort"
	"github.com/yaricom/goNEAT/neat/genetics"
	"io"
	"encoding/gob"
	"fmt"
)

// An Experiment is a collection of trials for one experiment. It's useful for statistical analysis of a series of
// experiments
type Experiment struct {
	Id   int
	Name string
	Trials
}

// Calculates average duration of experiment's trial
// Note, that most trials finish after solution solved, so this metric can be used to represent how efficient the solvers
// was generated
func (e *Experiment) AvgTrialDuration() time.Duration {
	total := time.Duration(0)
	for _, t := range e.Trials {
		total += t.Duration
	}
	return total / time.Duration(len(e.Trials))
}

// Calculates average duration of evaluations among all generations of organism populations in this experiment
func (e *Experiment) AvgEpochDuration() time.Duration {
	total := time.Duration(0)
	for _, t := range e.Trials {
		total += t.AvgEpochDuration()
	}
	return total / time.Duration(len(e.Trials))
}

// Calculates average number of generations evaluated per trial during this experiment. This can be helpful when estimating
// algorithm efficiency, because when winner organism is found the trial is terminated, i.e. less evaluations - more fast
// convergence.
func (e *Experiment) AvgGenerationsPerTrial() int {
	total := 0
	for _, t := range e.Trials {
		total += len(t.Generations)
	}
	return total / len(e.Trials)
}

// Returns time of last trial's execution
func (e *Experiment) LastExecuted() time.Time {
	var u time.Time
	for _, e := range e.Trials {
		ut := e.LastExecuted()
		if u.Before(ut) {
			u = ut
		}
	}
	return u
}

// Finds the most fit organism among all epochs in this trial. It's also possible to get the best organism only among the ones
// which was able to solve the experiment's problem. Returns the best fit organism in this experiment among with ID of trial
// where it was found and boolean value to indicate if search was successful.
func (e *Experiment) BestOrganism(onlySolvers bool) (*genetics.Organism, int, bool) {
	var orgs = make(genetics.Organisms, 0, len(e.Trials))
	for i, t := range e.Trials {
		org, found := t.BestOrganism(onlySolvers)
		if found {
			orgs = append(orgs, org)
			org.Flag = i
		}

	}
	if len(orgs) > 0 {
		sort.Sort(sort.Reverse(orgs))
		return orgs[0], orgs[0].Flag, true
	} else {
		return nil, -1, false
	}

}

func (e *Experiment) Solved() bool {
	for _, t := range e.Trials {
		if t.Solved() {
			return true
		}
	}
	return false
}

// The fitness values of the best organisms for each trial
func (e *Experiment) BestFitness() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = org.Fitness
		}
	}
	return x
}

// The age values of the organisms for each trial
func (e *Experiment) BestAge() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Species.Age)
		}
	}
	return x
}

// The complexity values of the best organisms for each trial
func (e *Experiment) BestComplexity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Phenotype.Complexity())
		}
	}
	return x
}

// Diversity returns the average number of species in each trial
func (e *Experiment) Diversity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = t.Diversity().Mean()
	}
	return x
}

// Trials returns the number of epochs in each trial
func (e *Experiment) Epochs() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = float64(len(t.Generations))
	}
	return x
}

// The number of trials solved
func (e *Experiment) TrialsSolved() int {
	count := 0
	for _, t := range e.Trials {
		if t.Solved() {
			count++
		}
	}
	return count
}

// Returns average number of nodes, genes, organisms evaluations, and species diversity of winner genomes among all
// trials, i.e. for all trials where winning solution was found
func (e *Experiment) AvgWinner() (avg_nodes, avg_genes, avg_evals, avg_diversity float64) {
	total_nodes, total_genes, total_evals, total_diversity := 0, 0, 0, 0
	count := 0
	for i := 0; i < len(e.Trials); i++ {
		t := e.Trials[i]
		if t.Solved() {
			nodes, genes, evals, diversity := t.Winner()
			total_nodes += nodes
			total_genes += genes
			total_evals += evals
			total_diversity += diversity

			count++
		}
	}
	avg_nodes = float64(total_nodes) / float64(count)
	avg_genes = float64(total_genes) / float64(count)
	avg_evals = float64(total_evals) / float64(count)
	avg_diversity = float64(total_diversity) / float64(count)
	return avg_nodes, avg_genes, avg_evals, avg_diversity
}

// Prints experiment statistics
func (ex *Experiment) PrintStatistics() {
	fmt.Printf("\n+++ Solved %d trials from %d +++\n", ex.TrialsSolved(), len(ex.Trials))
	fmt.Printf("Average\n\ttrial duration:\t\t%s\n\tepoch duration:\t\t%s\n\tgenerations/trial:\t%d\n",
		ex.AvgTrialDuration(), ex.AvgEpochDuration(), ex.AvgGenerationsPerTrial())
	// Print absolute champion statistics
	if org, trid, found := ex.BestOrganism(true); found {
		nodes, genes, evals, divers := ex.Trials[trid].Winner()
		fmt.Printf("\nChampion found in %d trial run\n\tWinner Nodes:\t%d\n\tWinner Genes:\t%d\n\tWinner Evals:\t%d\n\n\tDiversity:\t%d",
			trid, nodes, genes, evals, divers)
		fmt.Printf("\n\tComplexity:\t%d\n\tAge:\t\t%d\n\tFitness:\t%.1f\n",
			org.Phenotype.Complexity(), org.Species.Age, org.Fitness)
	} else {
		fmt.Println("\nNo winner found in the experiment!!!")
	}

	// Print average winner statistics
	mean_complexity, mean_diversity, mean_age, mean_fitness := 0.0, 0.0, 0.0, 0.0
	if len(ex.Trials) > 1 {
		avg_nodes, avg_genes, avg_evals, avg_divers := 0.0, 0.0, 0.0, 0.0
		count := 0.0
		for i := 0; i < len(ex.Trials); i++ {
			t := ex.Trials[i]
			if t.Solved() {
				nodes, genes, evals, diversity := t.Winner()
				avg_nodes += float64(nodes)
				avg_genes += float64(genes)
				avg_evals += float64(evals)
				avg_divers += float64(diversity)

				mean_complexity += float64(t.WinnerGeneration.Best.Phenotype.Complexity())
				mean_age += float64(t.WinnerGeneration.Best.Species.Age)
				mean_fitness += t.WinnerGeneration.Best.Fitness

				count++
			}
		}
		avg_nodes /= count
		avg_genes /= count
		avg_evals /= count
		avg_divers /= count
		fmt.Printf("\nAverage among winners\n\tWinner Nodes:\t%.1f\n\tWinner Genes:\t%.1f\n\tWinner Evals:\t%.1f\n\n\tDiversity:\t%.1f\n",
			avg_nodes, avg_genes, avg_evals, avg_divers)

		mean_complexity /= count
		mean_age /= count
		mean_fitness /=count
		fmt.Printf("\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n",
			mean_complexity, mean_age, mean_fitness)
	}

	// Print the average values for each population of organisms evaluated
	count := float64(len(ex.Trials))
	for _, t := range ex.Trials {
		fitness, age, complexity := t.Average()

		mean_complexity += complexity.Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += age.Mean()
		mean_fitness += fitness.Mean()
	}
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	mean_fitness /=count
	fmt.Printf("\nAverages for all organisms evaluated during experiment\n\tDiversity:\t%.1f\n\tComplexity:\t%.1f\n\tAge:\t\t%.1f\n\tFitness:\t%.1f\n\n",
		mean_diversity, mean_complexity, mean_age, mean_fitness)

}

// Encodes experiment and writes to provided writer
func (ex *Experiment) Write(w io.Writer) error {
	enc := gob.NewEncoder(w)
	return ex.Encode(enc)
}

// Encodes experiment with GOB encoding
func (ex *Experiment) Encode(enc *gob.Encoder) error {
	err := enc.Encode(ex.Id)
	err = enc.Encode(ex.Name)

	// encode trials
	err = enc.Encode(len(ex.Trials))
	for _, t := range ex.Trials {
		err = t.Encode(enc)
		if err != nil {
			return err
		}
	}
	return err
}

// Reads experiment data from provided reader and decodes it
func (ex *Experiment) Read(r io.Reader) error {
	dec := gob.NewDecoder(r)
	return ex.Decode(dec)
}

// Decodes experiment data
func (ex *Experiment) Decode(dec *gob.Decoder) error {
	err := dec.Decode(&ex.Id)
	err = dec.Decode(&ex.Name)

	// decode Trials
	var t_num int
	err = dec.Decode(&t_num)
	if err != nil {
		return err
	}

	ex.Trials = make([]Trial, t_num)
	for i := 0; i < t_num; i++ {
		trial := Trial{}
		err = trial.Decode(dec)
		ex.Trials[i] = trial
	}
	return err
}

// Experiments is a sortable list of experiments by execution time and Id
type Experiments []Experiment

func (es Experiments) Len() int {
	return len(es)
}
func (es Experiments) Swap(i, j int) {
	es[i], es[j] = es[j], es[i]
}
func (es Experiments) Less(i, j int) bool {
	ui := es[i].LastExecuted()
	uj := es[j].LastExecuted()
	if ui.Equal(uj) {
		return es[i].Id < es[j].Id
	}
	return ui.Before(uj)
}<commit_msg>Adjusted statistics precision and format<commit_after>package experiments

import (
	"time"
	"sort"
	"github.com/yaricom/goNEAT/neat/genetics"
	"io"
	"encoding/gob"
	"fmt"
)

// An Experiment is a collection of trials for one experiment. It's useful for statistical analysis of a series of
// experiments
type Experiment struct {
	Id   int
	Name string
	Trials
}

// Calculates average duration of experiment's trial
// Note, that most trials finish after solution solved, so this metric can be used to represent how efficient the solvers
// was generated
func (e *Experiment) AvgTrialDuration() time.Duration {
	total := time.Duration(0)
	for _, t := range e.Trials {
		total += t.Duration
	}
	return total / time.Duration(len(e.Trials))
}

// Calculates average duration of evaluations among all generations of organism populations in this experiment
func (e *Experiment) AvgEpochDuration() time.Duration {
	total := time.Duration(0)
	for _, t := range e.Trials {
		total += t.AvgEpochDuration()
	}
	return total / time.Duration(len(e.Trials))
}

// Calculates average number of generations evaluated per trial during this experiment. This can be helpful when estimating
// algorithm efficiency, because when winner organism is found the trial is terminated, i.e. less evaluations - more fast
// convergence.
func (e *Experiment) AvgGenerationsPerTrial() float64 {
	total := 0.0
	for _, t := range e.Trials {
		total += float64(len(t.Generations))
	}
	return total / float64(len(e.Trials))
}

// Returns time of last trial's execution
func (e *Experiment) LastExecuted() time.Time {
	var u time.Time
	for _, e := range e.Trials {
		ut := e.LastExecuted()
		if u.Before(ut) {
			u = ut
		}
	}
	return u
}

// Finds the most fit organism among all epochs in this trial. It's also possible to get the best organism only among the ones
// which was able to solve the experiment's problem. Returns the best fit organism in this experiment among with ID of trial
// where it was found and boolean value to indicate if search was successful.
func (e *Experiment) BestOrganism(onlySolvers bool) (*genetics.Organism, int, bool) {
	var orgs = make(genetics.Organisms, 0, len(e.Trials))
	for i, t := range e.Trials {
		org, found := t.BestOrganism(onlySolvers)
		if found {
			orgs = append(orgs, org)
			org.Flag = i
		}

	}
	if len(orgs) > 0 {
		sort.Sort(sort.Reverse(orgs))
		return orgs[0], orgs[0].Flag, true
	} else {
		return nil, -1, false
	}

}

func (e *Experiment) Solved() bool {
	for _, t := range e.Trials {
		if t.Solved() {
			return true
		}
	}
	return false
}

// The fitness values of the best organisms for each trial
func (e *Experiment) BestFitness() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = org.Fitness
		}
	}
	return x
}

// The age values of the organisms for each trial
func (e *Experiment) BestAge() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Species.Age)
		}
	}
	return x
}

// The complexity values of the best organisms for each trial
func (e *Experiment) BestComplexity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		if org, ok := t.BestOrganism(false); ok {
			x[i] = float64(org.Phenotype.Complexity())
		}
	}
	return x
}

// Diversity returns the average number of species in each trial
func (e *Experiment) Diversity() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = t.Diversity().Mean()
	}
	return x
}

// Trials returns the number of epochs in each trial
func (e *Experiment) Epochs() Floats {
	var x Floats = make([]float64, len(e.Trials))
	for i, t := range e.Trials {
		x[i] = float64(len(t.Generations))
	}
	return x
}

// The number of trials solved
func (e *Experiment) TrialsSolved() int {
	count := 0
	for _, t := range e.Trials {
		if t.Solved() {
			count++
		}
	}
	return count
}

// The success rate
func (e *Experiment) SuccessRate() float64 {
	soved := float64(e.TrialsSolved())
	return soved / float64(len(e.Trials))
}

// Returns average number of nodes, genes, organisms evaluations, and species diversity of winner genomes among all
// trials, i.e. for all trials where winning solution was found
func (e *Experiment) AvgWinner() (avg_nodes, avg_genes, avg_evals, avg_diversity float64) {
	total_nodes, total_genes, total_evals, total_diversity := 0, 0, 0, 0
	count := 0
	for i := 0; i < len(e.Trials); i++ {
		t := e.Trials[i]
		if t.Solved() {
			nodes, genes, evals, diversity := t.Winner()
			total_nodes += nodes
			total_genes += genes
			total_evals += evals
			total_diversity += diversity

			count++
		}
	}
	avg_nodes = float64(total_nodes) / float64(count)
	avg_genes = float64(total_genes) / float64(count)
	avg_evals = float64(total_evals) / float64(count)
	avg_diversity = float64(total_diversity) / float64(count)
	return avg_nodes, avg_genes, avg_evals, avg_diversity
}

// Prints experiment statistics
func (ex *Experiment) PrintStatistics() {
	fmt.Printf("\nSolved %d trials from %d, success rate: %f\n", ex.TrialsSolved(), len(ex.Trials), ex.SuccessRate())
	fmt.Printf("Average\n\tTrial duration:\t\t%s\n\tEpoch duration:\t\t%s\n\tGenerations/trial:\t%.1f\n",
		ex.AvgTrialDuration(), ex.AvgEpochDuration(), ex.AvgGenerationsPerTrial())
	// Print absolute champion statistics
	if org, trid, found := ex.BestOrganism(true); found {
		nodes, genes, evals, divers := ex.Trials[trid].Winner()
		fmt.Printf("\nChampion found in %d trial run\n\tWinner Nodes:\t\t%d\n\tWinner Genes:\t\t%d\n\tWinner Evals:\t\t%d\n\n\tDiversity:\t\t%d",
			trid, nodes, genes, evals, divers)
		fmt.Printf("\n\tComplexity:\t\t%d\n\tAge:\t\t\t%d\n\tFitness:\t\t%f\n",
			org.Phenotype.Complexity(), org.Species.Age, org.Fitness)
	} else {
		fmt.Println("\nNo winner found in the experiment!!!")
	}

	// Print average winner statistics
	mean_complexity, mean_diversity, mean_age, mean_fitness := 0.0, 0.0, 0.0, 0.0
	if len(ex.Trials) > 1 {
		avg_nodes, avg_genes, avg_evals, avg_divers, avg_generations := 0.0, 0.0, 0.0, 0.0, 0.0
		count := 0.0
		for i := 0; i < len(ex.Trials); i++ {
			t := ex.Trials[i]
			if t.Solved() {
				nodes, genes, evals, diversity := t.Winner()
				avg_nodes += float64(nodes)
				avg_genes += float64(genes)
				avg_evals += float64(evals)
				avg_divers += float64(diversity)
				avg_generations += float64(len(t.Generations))

				mean_complexity += float64(t.WinnerGeneration.Best.Phenotype.Complexity())
				mean_age += float64(t.WinnerGeneration.Best.Species.Age)
				mean_fitness += t.WinnerGeneration.Best.Fitness

				count++
			}
		}
		avg_nodes /= count
		avg_genes /= count
		avg_evals /= count
		avg_divers /= count
		avg_generations /= count
		fmt.Printf("\nAverage among winners\n\tWinner Nodes:\t\t%.1f\n\tWinner Genes:\t\t%.1f\n\tWinner Evals:\t\t%.1f\n\tGenerations/trial:\t%.1f\n\n\tDiversity:\t\t%f\n",
			avg_nodes, avg_genes, avg_evals, avg_generations, avg_divers)

		mean_complexity /= count
		mean_age /= count
		mean_fitness /=count
		fmt.Printf("\tComplexity:\t\t%f\n\tAge:\t\t\t%f\n\tFitness:\t\t%f\n",
			mean_complexity, mean_age, mean_fitness)
	}

	// Print the average values for each population of organisms evaluated
	count := float64(len(ex.Trials))
	for _, t := range ex.Trials {
		fitness, age, complexity := t.Average()

		mean_complexity += complexity.Mean()
		mean_diversity += t.Diversity().Mean()
		mean_age += age.Mean()
		mean_fitness += fitness.Mean()
	}
	mean_complexity /= count
	mean_diversity /= count
	mean_age /= count
	mean_fitness /=count
	fmt.Printf("\nAverages for all organisms evaluated during experiment\n\tDiversity:\t\t%f\n\tComplexity:\t\t%f\n\tAge:\t\t\t%f\n\tFitness:\t\t%f\n\n",
		mean_diversity, mean_complexity, mean_age, mean_fitness)

}

// Encodes experiment and writes to provided writer
func (ex *Experiment) Write(w io.Writer) error {
	enc := gob.NewEncoder(w)
	return ex.Encode(enc)
}

// Encodes experiment with GOB encoding
func (ex *Experiment) Encode(enc *gob.Encoder) error {
	err := enc.Encode(ex.Id)
	err = enc.Encode(ex.Name)

	// encode trials
	err = enc.Encode(len(ex.Trials))
	for _, t := range ex.Trials {
		err = t.Encode(enc)
		if err != nil {
			return err
		}
	}
	return err
}

// Reads experiment data from provided reader and decodes it
func (ex *Experiment) Read(r io.Reader) error {
	dec := gob.NewDecoder(r)
	return ex.Decode(dec)
}

// Decodes experiment data
func (ex *Experiment) Decode(dec *gob.Decoder) error {
	err := dec.Decode(&ex.Id)
	err = dec.Decode(&ex.Name)

	// decode Trials
	var t_num int
	err = dec.Decode(&t_num)
	if err != nil {
		return err
	}

	ex.Trials = make([]Trial, t_num)
	for i := 0; i < t_num; i++ {
		trial := Trial{}
		err = trial.Decode(dec)
		ex.Trials[i] = trial
	}
	return err
}

// Experiments is a sortable list of experiments by execution time and Id
type Experiments []Experiment

func (es Experiments) Len() int {
	return len(es)
}
func (es Experiments) Swap(i, j int) {
	es[i], es[j] = es[j], es[i]
}
func (es Experiments) Less(i, j int) bool {
	ui := es[i].LastExecuted()
	uj := es[j].LastExecuted()
	if ui.Equal(uj) {
		return es[i].Id < es[j].Id
	}
	return ui.Before(uj)
}<|endoftext|>


<commit_before>package form

import (
	"testing"

	. "gopkg.in/go-playground/assert.v1"
)

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
//
// go test -cpuprofile cpu.out
// ./validator.test -test.bench=. -test.cpuprofile=cpu.prof
// go tool pprof validator.test cpu.prof
//
//
// go test -memprofile mem.out

func TestEncoderInt(t *testing.T) {

	type TestInt struct {
		Int              int
		Int8             int8
		Int16            int16
		Int32            int32
		Int64            int64
		IntPtr           *int
		Int8Ptr          *int8
		Int16Ptr         *int16
		Int32Ptr         *int32
		Int64Ptr         *int64
		IntArray         []int
		IntPtrArray      []*int
		IntArrayArray    [][]int
		IntPtrArrayArray [][]*int
		IntMap           map[int]int
		IntPtrMap        map[*int]*int
		NoValue          int
		NoPtrValue       *int
	}

	i := int(3)
	i8 := int8(3)
	i16 := int16(3)
	i32 := int32(3)
	i64 := int64(3)

	zero := int(0)
	one := int(1)
	two := int(2)
	three := int(3)

	test := TestInt{
		Int:              i,
		Int8:             i8,
		Int16:            i16,
		Int32:            i32,
		Int64:            i64,
		IntPtr:           &i,
		Int8Ptr:          &i8,
		Int16Ptr:         &i16,
		Int32Ptr:         &i32,
		Int64Ptr:         &i64,
		IntArray:         []int{one, two, three},
		IntPtrArray:      []*int{&one, &two, &three},
		IntArrayArray:    [][]int{{one, zero, three}},
		IntPtrArrayArray: [][]*int{{&one, &zero, &three}},
		IntMap:           map[int]int{one: three, zero: two},
		IntPtrMap:        map[*int]*int{&one: &three, &zero: &two},
	}

	encoder := NewEncoder()
	values, errs := encoder.Encode(test)

	Equal(t, errs, nil)
	Equal(t, len(values), 25)

	val, ok := values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int16"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int32"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int64"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int16Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int32Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int64Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntArray"]
	Equal(t, ok, true)
	Equal(t, len(val), 3)
	Equal(t, val[0], "1")
	Equal(t, val[1], "2")
	Equal(t, val[2], "3")

	val, ok = values["IntPtrArray[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntPtrArray[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntPtrArray[2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["IntArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntPtrArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntPtrArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["IntPtrArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntPtrMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntPtrMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["NoValue"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["NoPtrValue"]
	Equal(t, ok, false)
}
<commit_msg>add uint & string tests<commit_after>package form

import (
	"testing"

	. "gopkg.in/go-playground/assert.v1"
)

// NOTES:
// - Run "go test" to run tests
// - Run "gocov test | gocov report" to report on test converage by file
// - Run "gocov test | gocov annotate -" to report on all code and functions, those ,marked with "MISS" were never called
//
// or
//
// -- may be a good idea to change to output path to somewherelike /tmp
// go test -coverprofile cover.out && go tool cover -html=cover.out -o cover.html
//
//
// go test -cpuprofile cpu.out
// ./validator.test -test.bench=. -test.cpuprofile=cpu.prof
// go tool pprof validator.test cpu.prof
//
//
// go test -memprofile mem.out

func TestEncoderInt(t *testing.T) {

	type TestInt struct {
		Int              int
		Int8             int8
		Int16            int16
		Int32            int32
		Int64            int64
		IntPtr           *int
		Int8Ptr          *int8
		Int16Ptr         *int16
		Int32Ptr         *int32
		Int64Ptr         *int64
		IntArray         []int
		IntPtrArray      []*int
		IntArrayArray    [][]int
		IntPtrArrayArray [][]*int
		IntMap           map[int]int
		IntPtrMap        map[*int]*int
		NoValue          int
		NoPtrValue       *int
	}

	i := int(3)
	i8 := int8(3)
	i16 := int16(3)
	i32 := int32(3)
	i64 := int64(3)

	zero := int(0)
	one := int(1)
	two := int(2)
	three := int(3)

	test := TestInt{
		Int:              i,
		Int8:             i8,
		Int16:            i16,
		Int32:            i32,
		Int64:            i64,
		IntPtr:           &i,
		Int8Ptr:          &i8,
		Int16Ptr:         &i16,
		Int32Ptr:         &i32,
		Int64Ptr:         &i64,
		IntArray:         []int{one, two, three},
		IntPtrArray:      []*int{&one, &two, &three},
		IntArrayArray:    [][]int{{one, zero, three}},
		IntPtrArrayArray: [][]*int{{&one, &zero, &three}},
		IntMap:           map[int]int{one: three, zero: two},
		IntPtrMap:        map[*int]*int{&one: &three, &zero: &two},
	}

	encoder := NewEncoder()
	values, errs := encoder.Encode(test)

	Equal(t, errs, nil)
	Equal(t, len(values), 25)

	val, ok := values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int16"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int32"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int64"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int8Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int16Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int32Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Int64Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntArray"]
	Equal(t, ok, true)
	Equal(t, len(val), 3)
	Equal(t, val[0], "1")
	Equal(t, val[1], "2")
	Equal(t, val[2], "3")

	val, ok = values["IntPtrArray[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntPtrArray[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntPtrArray[2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["IntArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntPtrArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["IntPtrArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["IntPtrArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["IntPtrMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["IntPtrMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["NoValue"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["NoPtrValue"]
	Equal(t, ok, false)
}

func TestEncoderUint(t *testing.T) {

	type TestUint struct {
		Uint              uint
		Uint8             uint8
		Uint16            uint16
		Uint32            uint32
		Uint64            uint64
		UintPtr           *uint
		Uint8Ptr          *uint8
		Uint16Ptr         *uint16
		Uint32Ptr         *uint32
		Uint64Ptr         *uint64
		UintArray         []uint
		UintPtrArray      []*uint
		UintArrayArray    [][]uint
		UintPtrArrayArray [][]*uint
		UintMap           map[uint]uint
		UintPtrMap        map[*uint]*uint
		NoValue           uint
		NoPtrValue        *uint
	}

	i := uint(3)
	i8 := uint8(3)
	i16 := uint16(3)
	i32 := uint32(3)
	i64 := uint64(3)

	zero := uint(0)
	one := uint(1)
	two := uint(2)
	three := uint(3)

	test := TestUint{
		Uint:              i,
		Uint8:             i8,
		Uint16:            i16,
		Uint32:            i32,
		Uint64:            i64,
		UintPtr:           &i,
		Uint8Ptr:          &i8,
		Uint16Ptr:         &i16,
		Uint32Ptr:         &i32,
		Uint64Ptr:         &i64,
		UintArray:         []uint{one, two, three},
		UintPtrArray:      []*uint{&one, &two, &three},
		UintArrayArray:    [][]uint{{one, zero, three}},
		UintPtrArrayArray: [][]*uint{{&one, &zero, &three}},
		UintMap:           map[uint]uint{one: three, zero: two},
		UintPtrMap:        map[*uint]*uint{&one: &three, &zero: &two},
	}

	encoder := NewEncoder()
	values, errs := encoder.Encode(test)

	Equal(t, errs, nil)
	Equal(t, len(values), 25)

	val, ok := values["Uint8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint16"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint32"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint64"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint8"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint8Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint16Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint32Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["Uint64Ptr"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["UintArray"]
	Equal(t, ok, true)
	Equal(t, len(val), 3)
	Equal(t, val[0], "1")
	Equal(t, val[1], "2")
	Equal(t, val[2], "3")

	val, ok = values["UintPtrArray[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["UintPtrArray[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["UintPtrArray[2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["UintArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["UintArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["UintArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["UintPtrArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["UintPtrArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["UintPtrArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["UintMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["UintMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["UintPtrMap[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["UintPtrMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["NoValue"]
	Equal(t, ok, true)
	Equal(t, val[0], "0")

	val, ok = values["NoPtrValue"]
	Equal(t, ok, false)
}

func TestEncoderString(t *testing.T) {

	type TestString struct {
		String              string
		StringPtr           *string
		StringArray         []string
		StringPtrArray      []*string
		StringArrayArray    [][]string
		StringPtrArrayArray [][]*string
		StringMap           map[string]string
		StringPtrMap        map[*string]*string
		NoValue             string
	}

	one := "1"
	two := "2"
	three := "3"

	test := TestString{
		String:              three,
		StringPtr:           &two,
		StringArray:         []string{one, "", three},
		StringPtrArray:      []*string{&one, nil, &three},
		StringArrayArray:    [][]string{{one, "", three}, nil, {one}},
		StringPtrArrayArray: [][]*string{{&one, nil, &three}, nil, {&one}},
		StringMap:           map[string]string{one: three, three: two},
		StringPtrMap:        map[*string]*string{&one: &three, &three: &two},
	}

	encoder := NewEncoder()
	values, errs := encoder.Encode(test)

	Equal(t, errs, nil)
	Equal(t, len(values), 17)

	val, ok := values["String"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringPtr"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["StringArray"]
	Equal(t, ok, true)
	Equal(t, len(val), 3)
	Equal(t, val[0], "1")
	Equal(t, val[1], "")
	Equal(t, val[2], "3")

	val, ok = values["StringPtr"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["StringPtrArray[0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["StringPtrArray[1]"]
	Equal(t, ok, false)

	val, ok = values["StringPtrArray[2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringPtrArray[2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["StringArrayArray[0][1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "")

	val, ok = values["StringArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringArrayArray[1][1]"]
	Equal(t, ok, false)

	val, ok = values["StringArrayArray[2][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["StringPtrArrayArray[0][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["StringPtrArrayArray[0][1]"]
	Equal(t, ok, false)

	val, ok = values["StringPtrArrayArray[0][2]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringPtrArrayArray[1][1]"]
	Equal(t, ok, false)

	val, ok = values["StringPtrArrayArray[2][0]"]
	Equal(t, ok, true)
	Equal(t, val[0], "1")

	val, ok = values["StringMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringMap[3]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["StringPtrMap[1]"]
	Equal(t, ok, true)
	Equal(t, val[0], "3")

	val, ok = values["StringPtrMap[3]"]
	Equal(t, ok, true)
	Equal(t, val[0], "2")

	val, ok = values["NoValue"]
	Equal(t, ok, true)
	Equal(t, val[0], "")
}
<|endoftext|>


<commit_before>// +build linux

/*
http://www.apache.org/licenses/LICENSE-2.0.txt
Copyright 2016 Intel Corporation
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 influxdb

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/control/plugin/cpolicy"

	"github.com/intelsdi-x/snap-plugin-collector-influxdb/influxdb/dtype"
	"github.com/intelsdi-x/snap-plugin-collector-influxdb/influxdb/monitor"
	"github.com/intelsdi-x/snap-plugin-utilities/config"
)

const (
	// Name of plugin
	Name = "influxdb"
	// Version of plugin
	Version = 2
	// Type of plugin
	Type = plugin.CollectorPluginType

	nsVendor = "intel"
	nsClass  = "influxdb"

	nsTypeStats = "stat"
	nsTypeDiagn = "diagn"
)

const (
	typeUnknown = iota
	typeStats
	typeDiagn
)

// prefix in metric namespace
var prefix = []string{nsVendor, nsClass}

// InfluxdbCollector holds data retrived from influxDB system monitoring
type InfluxdbCollector struct {
	data        map[string]datum
	service     monitor.Monitoring
	initialized bool
}

type datum struct {
	value interface{}
	tags  map[string]string
}

// New returns new instance of snap-plugin-collector-influxdb
func New() *InfluxdbCollector {
	return &InfluxdbCollector{initialized: false, service: &monitor.Monitor{}, data: map[string]datum{}}
}

// GetConfigPolicy returns a ConfigPolicy
func (ic *InfluxdbCollector) GetConfigPolicy() (*cpolicy.ConfigPolicy, error) {
	return cpolicy.New(), nil
}

// GetMetricTypes returns list of metrics based on influxDB system monitoring
func (ic *InfluxdbCollector) GetMetricTypes(cfg plugin.PluginConfigType) ([]plugin.PluginMetricType, error) {
	mts := []plugin.PluginMetricType{}

	ic.init(cfg)
	ic.getStatistics()  // get statistical information about influxDB
	ic.getDiagnostics() // get diagnostic information about influxDB

	for ns, dat := range ic.data {
		mts = append(mts, plugin.PluginMetricType{Namespace_: splitNamespace(ns), Tags_: dat.tags})
	}

	return mts, nil
}

// CollectMetrics collects given metrics
func (ic *InfluxdbCollector) CollectMetrics(mts []plugin.PluginMetricType) ([]plugin.PluginMetricType, error) {
	metrics := []plugin.PluginMetricType{}
	hostname, _ := os.Hostname()

	if !ic.initialized {
		ic.init(mts[0])     // if CollectMetrics() is called, mts has one item at least
		ic.getDiagnostics() // get diagnostic information (once only)
	}

	ic.getStatistics() // get statistical information

	for _, m := range mts {
		if dat, ok := ic.data[joinNamespace(m.Namespace())]; ok {
			metric := plugin.PluginMetricType{
				Namespace_: m.Namespace(),
				Data_:      dat.value,
				Source_:    hostname,
				Timestamp_: time.Now(),
				Tags_:      dat.tags,
			}

			metrics = append(metrics, metric)
		}
	}

	return metrics, nil
}

// init initializes InfluxdbCollector instance based on config `cfg`
func (ic *InfluxdbCollector) init(cfg interface{}) {
	items := []string{"host", "port", "user", "password"}
	settings, err := config.GetConfigItems(cfg, items)
	handleErr(err)

	err = ic.service.InitURLs(settings)
	handleErr(err)

	ic.initialized = true
}

// getDiagnostics executes the command "SHOW DIAGNOSTICS" (indirectly)
func (ic *InfluxdbCollector) getDiagnostics() {
	err := ic.getData(typeDiagn)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot get influxdb diagnostic information, err=", err)
	}
}

// getStatistics executes the command "SHOW STATS" (indirectly)
func (ic *InfluxdbCollector) getStatistics() {

	err := ic.getData(typeStats)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot get influxdb internal statistics, err=", err)
	}
}

// getData executes a command specified by given `type` of desired data
// and assignes its results to InfluxdbCollector structure item `data`
func (ic *InfluxdbCollector) getData(kind int) error {
	var results dtype.Results
	var err error
	var nsType string

	switch kind {
	case typeStats:
		nsType = nsTypeStats
		results, err = ic.service.GetStatistics()

	case typeDiagn:
		nsType = nsTypeDiagn
		results, err = ic.service.GetDiagnostics()

	default:
		err = errors.New("Inalid type of monitoring service")
	}

	if err != nil {
		return err
	}

	for seriesName, series := range results {
		for columnName := range series.Data {
			key := createNamespace(nsType, seriesName, columnName)
			ic.data[key] = datum{
				value: series.Data[columnName],
				tags:  series.Tags,
			}

		}
	}

	return nil
}

// handleErr handles critical error indicated with an abnormal state of plugin
func handleErr(err error) {
	if err != nil {
		panic(err)
	}
}

// createNamespace returns namespace composed from prefix, type of metric and metric name's components (the elements are joined to a single string)
func createNamespace(nsType, seriesName, columnName string) string {
	ns := append(prefix, nsType)
	ns = append(ns, seriesName)
	ns = append(ns, columnName)
	return strings.Join(ns, "/")

}

// joinNamespace concatenates the elements of `ns` to create a single string combined by slash
func joinNamespace(ns []string) string {
	return strings.Join(ns, "/")
}

//splitNamespace splits namespace (repesented by single string `s`) and returns  a slice of the substrings beetween slash separator
func splitNamespace(ns string) []string {
	return strings.Split(ns, "/")
}
<commit_msg>Typo in error message<commit_after>// +build linux

/*
http://www.apache.org/licenses/LICENSE-2.0.txt
Copyright 2016 Intel Corporation
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 influxdb

import (
	"errors"
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/control/plugin/cpolicy"

	"github.com/intelsdi-x/snap-plugin-collector-influxdb/influxdb/dtype"
	"github.com/intelsdi-x/snap-plugin-collector-influxdb/influxdb/monitor"
	"github.com/intelsdi-x/snap-plugin-utilities/config"
)

const (
	// Name of plugin
	Name = "influxdb"
	// Version of plugin
	Version = 2
	// Type of plugin
	Type = plugin.CollectorPluginType

	nsVendor = "intel"
	nsClass  = "influxdb"

	nsTypeStats = "stat"
	nsTypeDiagn = "diagn"
)

const (
	typeUnknown = iota
	typeStats
	typeDiagn
)

// prefix in metric namespace
var prefix = []string{nsVendor, nsClass}

// InfluxdbCollector holds data retrived from influxDB system monitoring
type InfluxdbCollector struct {
	data        map[string]datum
	service     monitor.Monitoring
	initialized bool
}

type datum struct {
	value interface{}
	tags  map[string]string
}

// New returns new instance of snap-plugin-collector-influxdb
func New() *InfluxdbCollector {
	return &InfluxdbCollector{initialized: false, service: &monitor.Monitor{}, data: map[string]datum{}}
}

// GetConfigPolicy returns a ConfigPolicy
func (ic *InfluxdbCollector) GetConfigPolicy() (*cpolicy.ConfigPolicy, error) {
	return cpolicy.New(), nil
}

// GetMetricTypes returns list of metrics based on influxDB system monitoring
func (ic *InfluxdbCollector) GetMetricTypes(cfg plugin.PluginConfigType) ([]plugin.PluginMetricType, error) {
	mts := []plugin.PluginMetricType{}

	ic.init(cfg)
	ic.getStatistics()  // get statistical information about influxDB
	ic.getDiagnostics() // get diagnostic information about influxDB

	for ns, dat := range ic.data {
		mts = append(mts, plugin.PluginMetricType{Namespace_: splitNamespace(ns), Tags_: dat.tags})
	}

	return mts, nil
}

// CollectMetrics collects given metrics
func (ic *InfluxdbCollector) CollectMetrics(mts []plugin.PluginMetricType) ([]plugin.PluginMetricType, error) {
	metrics := []plugin.PluginMetricType{}
	hostname, _ := os.Hostname()

	if !ic.initialized {
		ic.init(mts[0])     // if CollectMetrics() is called, mts has one item at least
		ic.getDiagnostics() // get diagnostic information (once only)
	}

	ic.getStatistics() // get statistical information

	for _, m := range mts {
		if dat, ok := ic.data[joinNamespace(m.Namespace())]; ok {
			metric := plugin.PluginMetricType{
				Namespace_: m.Namespace(),
				Data_:      dat.value,
				Source_:    hostname,
				Timestamp_: time.Now(),
				Tags_:      dat.tags,
			}

			metrics = append(metrics, metric)
		}
	}

	return metrics, nil
}

// init initializes InfluxdbCollector instance based on config `cfg`
func (ic *InfluxdbCollector) init(cfg interface{}) {
	items := []string{"host", "port", "user", "password"}
	settings, err := config.GetConfigItems(cfg, items)
	handleErr(err)

	err = ic.service.InitURLs(settings)
	handleErr(err)

	ic.initialized = true
}

// getDiagnostics executes the command "SHOW DIAGNOSTICS" (indirectly)
func (ic *InfluxdbCollector) getDiagnostics() {
	err := ic.getData(typeDiagn)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot get influxdb diagnostic information, err=", err)
	}
}

// getStatistics executes the command "SHOW STATS" (indirectly)
func (ic *InfluxdbCollector) getStatistics() {

	err := ic.getData(typeStats)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Cannot get influxdb internal statistics, err=", err)
	}
}

// getData executes a command specified by given `type` of desired data
// and assigns its results to InfluxdbCollector structure item `data`
func (ic *InfluxdbCollector) getData(kind int) error {
	var results dtype.Results
	var err error
	var nsType string

	switch kind {
	case typeStats:
		nsType = nsTypeStats
		results, err = ic.service.GetStatistics()

	case typeDiagn:
		nsType = nsTypeDiagn
		results, err = ic.service.GetDiagnostics()

	default:
		err = errors.New("Invalid type of monitoring service")
	}

	if err != nil {
		return err
	}

	for seriesName, series := range results {
		for columnName := range series.Data {
			key := createNamespace(nsType, seriesName, columnName)
			ic.data[key] = datum{
				value: series.Data[columnName],
				tags:  series.Tags,
			}

		}
	}

	return nil
}

// handleErr handles critical error indicated with an abnormal state of plugin
func handleErr(err error) {
	if err != nil {
		panic(err)
	}
}

// createNamespace returns namespace composed from prefix, type of metric and metric name's components (the elements are joined to a single string)
func createNamespace(nsType, seriesName, columnName string) string {
	ns := append(prefix, nsType)
	ns = append(ns, seriesName)
	ns = append(ns, columnName)
	return strings.Join(ns, "/")

}

// joinNamespace concatenates the elements of `ns` to create a single string combined by slash
func joinNamespace(ns []string) string {
	return strings.Join(ns, "/")
}

//splitNamespace splits namespace (repesented by single string `s`) and returns  a slice of the substrings between slash separator
func splitNamespace(ns string) []string {
	return strings.Split(ns, "/")
}
<|endoftext|>


<commit_before>package machine

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"os"
	"time"
)

type machinesData struct {
	Runner   string
	Acquired int
	Creating int
	Idle     int
	Used     int
	Removing int
}

func (d *machinesData) Available() int {
	return d.Acquired + d.Creating + d.Idle
}

func (d *machinesData) Total() int {
	return d.Acquired + d.Creating + d.Idle + d.Used
}

func (d *machinesData) Add(state machineState) {
	switch state {
	case machineStateIdle:
		d.Idle++

	case machineStateCreating:
		d.Creating++

	case machineStateAcquired:
		d.Acquired++

	case machineStateUsed:
		d.Used++

	case machineStateRemoving:
		d.Removing++
	}
}

func (d *machinesData) Fields() logrus.Fields {
	return logrus.Fields{
		"used":     d.Used,
		"idle":     d.Idle,
		"total":    d.Total(),
		"creating": d.Creating,
		"removing": d.Removing,
	}
}

func (d *machinesData) writeDebugInformation() {
	if logrus.GetLevel() < logrus.DebugLevel {
		return
	}

	file, err := os.OpenFile("machines.csv", os.O_RDWR|os.O_APPEND, 0600)
	if err != nil {
		return
	}
	defer file.Close()
	fmt.Fprintln(file,
		"time", time.Now(),
		"acquired", d.Acquired,
		"creating", d.Creating,
		"idle", d.Idle,
		"used", d.Used,
		"removing", d.Removing)
}
<commit_msg>Log the runner in debug messages for machine<commit_after>package machine

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"os"
	"time"
)

type machinesData struct {
	Runner   string
	Acquired int
	Creating int
	Idle     int
	Used     int
	Removing int
}

func (d *machinesData) Available() int {
	return d.Acquired + d.Creating + d.Idle
}

func (d *machinesData) Total() int {
	return d.Acquired + d.Creating + d.Idle + d.Used
}

func (d *machinesData) Add(state machineState) {
	switch state {
	case machineStateIdle:
		d.Idle++

	case machineStateCreating:
		d.Creating++

	case machineStateAcquired:
		d.Acquired++

	case machineStateUsed:
		d.Used++

	case machineStateRemoving:
		d.Removing++
	}
}

func (d *machinesData) Fields() logrus.Fields {
	return logrus.Fields{
		"runner":   d.Runner,
		"used":     d.Used,
		"idle":     d.Idle,
		"total":    d.Total(),
		"creating": d.Creating,
		"removing": d.Removing,
	}
}

func (d *machinesData) writeDebugInformation() {
	if logrus.GetLevel() < logrus.DebugLevel {
		return
	}

	file, err := os.OpenFile("machines.csv", os.O_RDWR|os.O_APPEND, 0600)
	if err != nil {
		return
	}
	defer file.Close()
	fmt.Fprintln(file,
		"time", time.Now(),
		"runner", d.Runner,
		"acquired", d.Acquired,
		"creating", d.Creating,
		"idle", d.Idle,
		"used", d.Used,
		"removing", d.Removing)
}
<|endoftext|>


<commit_before>// Package eval handles evaluation of nodes and consists the runtime of the
// shell.
package eval

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"syscall"
	"unicode/utf8"

	"github.com/elves/elvish/errutil"
	"github.com/elves/elvish/logutil"
	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/store"
)

var Logger = logutil.Discard

// FnPrefix is the prefix for the variable names of functions. Defining a
// function "foo" is equivalent to setting a variable named FnPrefix + "foo".
const FnPrefix = "&"

// ns is a namespace.
type ns map[string]Variable

// Evaler is used to evaluate elvish sources. It maintains runtime context
// shared among all evalCtx instances.
type Evaler struct {
	global      ns
	mod         map[string]ns
	searchPaths []string
	store       *store.Store
	Editor      Editor
}

// evalCtx maintains an Evaler along with its runtime context. After creation
// an evalCtx is not modified, and new instances are created when needed.
type evalCtx struct {
	*Evaler
	name, text, context string

	local, up ns
	ports     []*Port
}

// NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler {
	// Construct searchPaths
	var searchPaths []string
	if path := os.Getenv("PATH"); path != "" {
		searchPaths = strings.Split(path, ":")
	} else {
		searchPaths = []string{"/bin"}
	}

	// Construct initial global namespace
	pid := String(strconv.Itoa(syscall.Getpid()))
	paths := NewList()
	paths.appendStrings(searchPaths)
	global := ns{
		"pid":   newPtrVariable(pid),
		"ok":    newPtrVariable(OK),
		"true":  newPtrVariable(Bool(true)),
		"false": newPtrVariable(Bool(false)),
		"paths": newPtrVariable(paths),
	}
	for _, b := range builtinFns {
		global[FnPrefix+b.Name] = newPtrVariable(b)
	}

	return &Evaler{global, map[string]ns{}, searchPaths, st, nil}
}

// PprintError pretty prints an error. It understands specialized error types
// defined in this package.
func PprintError(e error) {
	switch e := e.(type) {
	case nil:
		fmt.Print("\033[32mok\033[m")
	case multiError:
		fmt.Print("(")
		for i, c := range e.errors {
			if i > 0 {
				fmt.Print(" | ")
			}
			PprintError(c.inner)
		}
		fmt.Print(")")
	case flow:
		fmt.Print("\033[33m" + e.Error() + "\033[m")
	default:
		fmt.Print("\033[31;1m" + e.Error() + "\033[m")
	}
}

const (
	outChanSize   = 32
	outChanLeader = "▶ "
)

// NewTopEvalCtx creates a top-level evalCtx.
func NewTopEvalCtx(ev *Evaler, name, text string, ports []*Port) *evalCtx {
	return &evalCtx{
		ev,
		name, text, "top",
		ev.global, ns{},
		ports,
	}
}

// fork returns a modified copy of ec. The ports are forked, and the context is
// changed to the given value. Other fields are copied shallowly.
func (ec *evalCtx) fork(newContext string) *evalCtx {
	newPorts := make([]*Port, len(ec.ports))
	for i, p := range ec.ports {
		newPorts[i] = p.Fork()
	}
	return &evalCtx{
		ec.Evaler,
		ec.name, ec.text, newContext,
		ec.local, ec.up,
		newPorts,
	}
}

// port returns ec.ports[i] or nil if i is out of range. This makes it possible
// to treat ec.ports as if it has an infinite tail of nil's.
func (ec *evalCtx) port(i int) *Port {
	if i >= len(ec.ports) {
		return nil
	}
	return ec.ports[i]
}

// growPorts makes the size of ec.ports at least n, adding nil's if necessary.
func (ec *evalCtx) growPorts(n int) {
	if len(ec.ports) >= n {
		return
	}
	ports := ec.ports
	ec.ports = make([]*Port, n)
	copy(ec.ports, ports)
}

func makeScope(s ns) scope {
	sc := scope{}
	for name := range s {
		sc[name] = true
	}
	return sc
}

// Eval evaluates a chunk node n. The supplied name and text are used in
// diagnostic messages.
func (ev *Evaler) Eval(name, text string, n *parse.Chunk, ports []*Port) error {
	op, err := ev.Compile(name, text, n)
	if err != nil {
		return err
	}
	ec := NewTopEvalCtx(ev, name, text, ports)
	return ec.PEval(op)
}

func (ev *Evaler) EvalInteractive(text string, n *parse.Chunk) error {
	inCh := make(chan Value)
	close(inCh)

	outCh := make(chan Value, outChanSize)
	outDone := make(chan struct{})
	go func() {
		for v := range outCh {
			fmt.Printf("%s%s\n", outChanLeader, v.Repr())
		}
		close(outDone)
	}()

	ports := []*Port{
		{File: os.Stdin, Chan: inCh},
		{File: os.Stdout, Chan: outCh},
		{File: os.Stderr},
	}

	err := ev.Eval("[interactive]", text, n, ports)
	close(outCh)
	<-outDone
	return err
}

// Compile compiles elvish code in the global scope.
func (ev *Evaler) Compile(name, text string, n *parse.Chunk) (Op, error) {
	return compile(name, text, makeScope(ev.global), n)
}

// PEval evaluates an op in a protected environment so that calls to errorf are
// wrapped in an Error.
func (ec *evalCtx) PEval(op Op) (ex error) {
	defer errutil.Catch(&ex)
	op(ec)
	return nil
}

// errorf stops the ec.eval immediately by panicking with a diagnostic message.
// The panic is supposed to be caught by ec.eval.
func (ec *evalCtx) errorf(p int, format string, args ...interface{}) {
	throw(errutil.NewContextualError(
		fmt.Sprintf("%s (%s)", ec.name, ec.context), "error",
		ec.text, p, format, args...))
}

// mustSingleString returns a String if that is the only element of vs.
// Otherwise it errors.
func (ec *evalCtx) mustSingleString(vs []Value, what string, p int) String {
	if len(vs) != 1 {
		ec.errorf(p, "Expect exactly one word for %s, got %d", what, len(vs))
	}
	v, ok := vs[0].(String)
	if !ok {
		ec.errorf(p, "Expect string for %s, got %s", what, vs[0])
	}
	return v
}

// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(src string) error {
	n, err := parse.Parse(src)
	if err != nil {
		return err
	}
	return ev.EvalInteractive(src, n)
}

func readFileUTF8(fname string) (string, error) {
	bytes, err := ioutil.ReadFile(fname)
	if err != nil {
		return "", err
	}
	if !utf8.Valid(bytes) {
		return "", fmt.Errorf("%s: source is not valid UTF-8", fname)
	}
	return string(bytes), nil
}

// Source evaluates the content of a file.
func (ev *Evaler) Source(fname string) error {
	src, err := readFileUTF8(fname)
	if err != nil {
		return err
	}
	return ev.SourceText(src)
}

// Global returns the global namespace.
func (ev *Evaler) Global() map[string]Variable {
	return map[string]Variable(ev.global)
}

// ResolveVar resolves a variable. When the variable cannot be found, nil is
// returned.
func (ec *evalCtx) ResolveVar(ns, name string) Variable {
	if ns == "env" {
		return newEnvVariable(name)
	}
	if mod, ok := ec.mod[ns]; ok {
		return mod[name]
	}

	may := func(n string) bool {
		return ns == "" || ns == n
	}
	if may("local") {
		if v, ok := ec.local[name]; ok {
			return v
		}
	}
	if may("up") {
		if v, ok := ec.up[name]; ok {
			return v
		}
	}
	return nil
}
<commit_msg>eval: ns -> Namespace.<commit_after>// Package eval handles evaluation of nodes and consists the runtime of the
// shell.
package eval

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"syscall"
	"unicode/utf8"

	"github.com/elves/elvish/errutil"
	"github.com/elves/elvish/logutil"
	"github.com/elves/elvish/parse"
	"github.com/elves/elvish/store"
)

var Logger = logutil.Discard

// FnPrefix is the prefix for the variable names of functions. Defining a
// function "foo" is equivalent to setting a variable named FnPrefix + "foo".
const FnPrefix = "&"

// Namespace is a map from name to variables.
type Namespace map[string]Variable

// Evaler is used to evaluate elvish sources. It maintains runtime context
// shared among all evalCtx instances.
type Evaler struct {
	global      Namespace
	mod         map[string]Namespace
	searchPaths []string
	store       *store.Store
	Editor      Editor
}

// evalCtx maintains an Evaler along with its runtime context. After creation
// an evalCtx is not modified, and new instances are created when needed.
type evalCtx struct {
	*Evaler
	name, text, context string

	local, up Namespace
	ports     []*Port
}

// NewEvaler creates a new Evaler.
func NewEvaler(st *store.Store) *Evaler {
	// Construct searchPaths
	var searchPaths []string
	if path := os.Getenv("PATH"); path != "" {
		searchPaths = strings.Split(path, ":")
	} else {
		searchPaths = []string{"/bin"}
	}

	// Construct initial global namespace
	pid := String(strconv.Itoa(syscall.Getpid()))
	paths := NewList()
	paths.appendStrings(searchPaths)
	global := Namespace{
		"pid":   newPtrVariable(pid),
		"ok":    newPtrVariable(OK),
		"true":  newPtrVariable(Bool(true)),
		"false": newPtrVariable(Bool(false)),
		"paths": newPtrVariable(paths),
	}
	for _, b := range builtinFns {
		global[FnPrefix+b.Name] = newPtrVariable(b)
	}

	return &Evaler{global, map[string]Namespace{}, searchPaths, st, nil}
}

// PprintError pretty prints an error. It understands specialized error types
// defined in this package.
func PprintError(e error) {
	switch e := e.(type) {
	case nil:
		fmt.Print("\033[32mok\033[m")
	case multiError:
		fmt.Print("(")
		for i, c := range e.errors {
			if i > 0 {
				fmt.Print(" | ")
			}
			PprintError(c.inner)
		}
		fmt.Print(")")
	case flow:
		fmt.Print("\033[33m" + e.Error() + "\033[m")
	default:
		fmt.Print("\033[31;1m" + e.Error() + "\033[m")
	}
}

const (
	outChanSize   = 32
	outChanLeader = "▶ "
)

// NewTopEvalCtx creates a top-level evalCtx.
func NewTopEvalCtx(ev *Evaler, name, text string, ports []*Port) *evalCtx {
	return &evalCtx{
		ev,
		name, text, "top",
		ev.global, Namespace{},
		ports,
	}
}

// fork returns a modified copy of ec. The ports are forked, and the context is
// changed to the given value. Other fields are copied shallowly.
func (ec *evalCtx) fork(newContext string) *evalCtx {
	newPorts := make([]*Port, len(ec.ports))
	for i, p := range ec.ports {
		newPorts[i] = p.Fork()
	}
	return &evalCtx{
		ec.Evaler,
		ec.name, ec.text, newContext,
		ec.local, ec.up,
		newPorts,
	}
}

// port returns ec.ports[i] or nil if i is out of range. This makes it possible
// to treat ec.ports as if it has an infinite tail of nil's.
func (ec *evalCtx) port(i int) *Port {
	if i >= len(ec.ports) {
		return nil
	}
	return ec.ports[i]
}

// growPorts makes the size of ec.ports at least n, adding nil's if necessary.
func (ec *evalCtx) growPorts(n int) {
	if len(ec.ports) >= n {
		return
	}
	ports := ec.ports
	ec.ports = make([]*Port, n)
	copy(ec.ports, ports)
}

func makeScope(s Namespace) scope {
	sc := scope{}
	for name := range s {
		sc[name] = true
	}
	return sc
}

// Eval evaluates a chunk node n. The supplied name and text are used in
// diagnostic messages.
func (ev *Evaler) Eval(name, text string, n *parse.Chunk, ports []*Port) error {
	op, err := ev.Compile(name, text, n)
	if err != nil {
		return err
	}
	ec := NewTopEvalCtx(ev, name, text, ports)
	return ec.PEval(op)
}

func (ev *Evaler) EvalInteractive(text string, n *parse.Chunk) error {
	inCh := make(chan Value)
	close(inCh)

	outCh := make(chan Value, outChanSize)
	outDone := make(chan struct{})
	go func() {
		for v := range outCh {
			fmt.Printf("%s%s\n", outChanLeader, v.Repr())
		}
		close(outDone)
	}()

	ports := []*Port{
		{File: os.Stdin, Chan: inCh},
		{File: os.Stdout, Chan: outCh},
		{File: os.Stderr},
	}

	err := ev.Eval("[interactive]", text, n, ports)
	close(outCh)
	<-outDone
	return err
}

// Compile compiles elvish code in the global scope.
func (ev *Evaler) Compile(name, text string, n *parse.Chunk) (Op, error) {
	return compile(name, text, makeScope(ev.global), n)
}

// PEval evaluates an op in a protected environment so that calls to errorf are
// wrapped in an Error.
func (ec *evalCtx) PEval(op Op) (ex error) {
	defer errutil.Catch(&ex)
	op(ec)
	return nil
}

// errorf stops the ec.eval immediately by panicking with a diagnostic message.
// The panic is supposed to be caught by ec.eval.
func (ec *evalCtx) errorf(p int, format string, args ...interface{}) {
	throw(errutil.NewContextualError(
		fmt.Sprintf("%s (%s)", ec.name, ec.context), "error",
		ec.text, p, format, args...))
}

// mustSingleString returns a String if that is the only element of vs.
// Otherwise it errors.
func (ec *evalCtx) mustSingleString(vs []Value, what string, p int) String {
	if len(vs) != 1 {
		ec.errorf(p, "Expect exactly one word for %s, got %d", what, len(vs))
	}
	v, ok := vs[0].(String)
	if !ok {
		ec.errorf(p, "Expect string for %s, got %s", what, vs[0])
	}
	return v
}

// SourceText evaluates a chunk of elvish source.
func (ev *Evaler) SourceText(src string) error {
	n, err := parse.Parse(src)
	if err != nil {
		return err
	}
	return ev.EvalInteractive(src, n)
}

func readFileUTF8(fname string) (string, error) {
	bytes, err := ioutil.ReadFile(fname)
	if err != nil {
		return "", err
	}
	if !utf8.Valid(bytes) {
		return "", fmt.Errorf("%s: source is not valid UTF-8", fname)
	}
	return string(bytes), nil
}

// Source evaluates the content of a file.
func (ev *Evaler) Source(fname string) error {
	src, err := readFileUTF8(fname)
	if err != nil {
		return err
	}
	return ev.SourceText(src)
}

// Global returns the global namespace.
func (ev *Evaler) Global() map[string]Variable {
	return map[string]Variable(ev.global)
}

// ResolveVar resolves a variable. When the variable cannot be found, nil is
// returned.
func (ec *evalCtx) ResolveVar(ns, name string) Variable {
	if ns == "env" {
		return newEnvVariable(name)
	}
	if mod, ok := ec.mod[ns]; ok {
		return mod[name]
	}

	may := func(n string) bool {
		return ns == "" || ns == n
	}
	if may("local") {
		if v, ok := ec.local[name]; ok {
			return v
		}
	}
	if may("up") {
		if v, ok := ec.up[name]; ok {
			return v
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package eval

import (
	"os"
	"fmt"
	"strings"
	"syscall"
	"../parse"
)

const (
	FILE_CLOSE uintptr = ^uintptr(0)
)

// TODO return a separate error
func isExecutable(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return false
	}
	fm := fi.Mode()
	return !fm.IsDir() && (fm & 0111 != 0)
}

// Search for executable `exe`.
// TODO return a separate error
func search(exe string) string {
	for _, p := range []string{"/", "./", "../"} {
		if strings.HasPrefix(exe, p) {
			return exe
		}
	}
	for _, p := range search_paths {
		full := p + "/" + exe
		if isExecutable(full) {
			return full
		}
	}
	return ""
}

func envAsSlice(env map[string]string) (s []string) {
	s = make([]string, len(env))
	for k, v := range env {
		s = append(s, fmt.Sprintf("%s=%s", k, v))
	}
	return
}

func evalTerm(n parse.Node) string {
	return n.(*parse.StringNode).Text
}

func evalCommandArgs(n *parse.CommandNode) (args []string) {
	args = make([]string, 0, len(n.Nodes))
	for _, w := range n.Nodes {
		args = append(args, evalTerm(w))
	}
	return
}

// ExecCommand executes a command.
func ExecCommand(cmd *parse.CommandNode) (pid int, err error) {
	args := evalCommandArgs(cmd)
	if len(args) == 0 {
		return 0, fmt.Errorf("empty command")
	}
	full := search(args[0])
	if len(full) == 0 {
		return 0, fmt.Errorf("command not found: %s", args[0])
	}
	args[0] = full

	files := []uintptr{0, 1, 2}

	for _, r := range cmd.Redirs {
		fd := r.Fd()

		if fd > 2 {
			return 0, fmt.Errorf("redir on fd > 2 not yet supported")
		}

		switch r := r.(type) {
		case *parse.FdRedir:
			oldFd := r.OldFd
			if oldFd > 2 {
				return 0, fmt.Errorf("fd redir from fd > 2 not yet supported")
			}
			files[fd] = files[oldFd]
		case *parse.CloseRedir:
			files[fd] = FILE_CLOSE
		case *parse.FilenameRedir:
			// TODO haz hardcoded permbits now
			fname := evalTerm(r.Filename)
			oldFd, err := syscall.Open(fname, r.Flag, 0644)
			if err != nil {
				return 0, fmt.Errorf("failed to open file %q: %s",
				                     r.Filename, err)
			} else {
				files[fd] = uintptr(oldFd)
				defer syscall.Close(oldFd)
			}
		default:
			panic("unreachable")
		}
	}

	sys := syscall.SysProcAttr{}
	attr := syscall.ProcAttr{Env: envAsSlice(env), Files: files, Sys: &sys}
	return syscall.ForkExec(full, args, &attr)
}
<commit_msg>eval: Little cleanup<commit_after>package eval

import (
	"os"
	"fmt"
	"strings"
	"syscall"
	"../parse"
)

const (
	FILE_CLOSE uintptr = ^uintptr(0)
)

// TODO return a separate error
func isExecutable(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	defer f.Close()

	fi, err := f.Stat()
	if err != nil {
		return false
	}
	fm := fi.Mode()
	return !fm.IsDir() && (fm & 0111 != 0)
}

// Search for executable `exe`.
// TODO return a separate error
func search(exe string) string {
	for _, p := range []string{"/", "./", "../"} {
		if strings.HasPrefix(exe, p) {
			return exe
		}
	}
	for _, p := range search_paths {
		full := p + "/" + exe
		if isExecutable(full) {
			return full
		}
	}
	return ""
}

func envAsSlice(env map[string]string) (s []string) {
	s = make([]string, len(env))
	for k, v := range env {
		s = append(s, fmt.Sprintf("%s=%s", k, v))
	}
	return
}

func evalTerm(n parse.Node) string {
	return n.(*parse.StringNode).Text
}

func evalCommandArgs(n *parse.CommandNode) (args []string) {
	args = make([]string, 0, len(n.Nodes))
	for _, w := range n.Nodes {
		args = append(args, evalTerm(w))
	}
	return
}

// ExecCommand executes a command.
func ExecCommand(cmd *parse.CommandNode) (pid int, err error) {
	args := evalCommandArgs(cmd)
	if len(args) == 0 {
		return 0, fmt.Errorf("empty command")
	}
	full := search(args[0])
	if len(full) == 0 {
		return 0, fmt.Errorf("command not found: %s", args[0])
	}
	args[0] = full

	files := []uintptr{0, 1, 2}

	for _, r := range cmd.Redirs {
		fd := r.Fd()

		if fd > 2 {
			return 0, fmt.Errorf("redir on fd > 2 not yet supported")
		}

		switch r := r.(type) {
		case *parse.FdRedir:
			oldFd := r.OldFd
			if oldFd > 2 {
				return 0, fmt.Errorf("fd redir from fd > 2 not yet supported")
			}
			files[fd] = files[oldFd]
		case *parse.CloseRedir:
			files[fd] = FILE_CLOSE
		case *parse.FilenameRedir:
			// TODO haz hardcoded permbits now
			fname := evalTerm(r.Filename)
			oldFd, err := syscall.Open(fname, r.Flag, 0644)
			if err != nil {
				return 0, fmt.Errorf("failed to open file %q: %s",
				                     r.Filename, err)
			}
			files[fd] = uintptr(oldFd)
			defer syscall.Close(oldFd)
		default:
			panic("unreachable")
		}
	}

	sys := syscall.SysProcAttr{}
	attr := syscall.ProcAttr{Env: envAsSlice(env), Files: files, Sys: &sys}
	return syscall.ForkExec(full, args, &attr)
}
<|endoftext|>


<commit_before>package engine

//import "log"

type SceneData struct {
	name        string
	gameObjects []*GameObject
	Camera      *Camera
}

type Scene interface {
	New() Scene
	Load()
	SceneBase() *SceneData
}

func NewScene(name string) *SceneData {
	return &SceneData{name: name, gameObjects: make([]*GameObject, 0)}
}

func (s *SceneData) SetCamera(Camera *Camera) {
	s.Camera = Camera
}

func (s *SceneData) Name() string {
	return s.name
}

func (s *SceneData) SceneBase() *SceneData {
	return s
}

func (s *SceneData) addGameObject(gameObject ...*GameObject) {
	for _, obj := range gameObject {
		s.gameObjects = append(s.gameObjects, obj)
		obj.transform.childOfScene = true
		for _, t := range obj.transform.children {
			s.addGameObject(t.gameObject)
		}
	}
}

func (s *SceneData) AddGameObject(gameObject ...*GameObject) {
	if s == GetScene().SceneBase() {
		for _, obj := range gameObject {
			obj.AddToScene()
		}
	} else {
		s.addGameObject(gameObject...)
	}
}

func (s *SceneData) removeGameObject(g *GameObject) {
	if g == nil {
		return
	}
	g.transform.removeFromParent()
	for i, c := range s.gameObjects {
		if g == c {
			s.gameObjects[i].transform.childOfScene = false
			for _, t := range g.transform.children {
				s.removeGameObject(t.gameObject)
			}
			s.gameObjects[i] = nil
			break
		}
	}
}

func (s *SceneData) cleanNil() {
	for i := 0; i < len(s.gameObjects); i++ {
		if s.gameObjects[i] == nil {
			s.gameObjects[i], s.gameObjects = s.gameObjects[len(s.gameObjects)-1], s.gameObjects[:len(s.gameObjects)-1]
			i--
		}
	}
}

func (s *SceneData) RemoveGameObject(g *GameObject) {
	if g == nil {
		return
	}
	if s == GetScene().SceneBase() {
		g.RemoveFromScene()
	} else {
		s.removeGameObject(g)
	}
}
<commit_msg>Fixed removeGameObject function.<commit_after>package engine

//import "log"

type SceneData struct {
	name        string
	gameObjects []*GameObject
	Camera      *Camera
}

type Scene interface {
	New() Scene
	Load()
	SceneBase() *SceneData
}

func NewScene(name string) *SceneData {
	return &SceneData{name: name, gameObjects: make([]*GameObject, 0)}
}

func (s *SceneData) SetCamera(Camera *Camera) {
	s.Camera = Camera
}

func (s *SceneData) Name() string {
	return s.name
}

func (s *SceneData) SceneBase() *SceneData {
	return s
}

func (s *SceneData) addGameObject(gameObject ...*GameObject) {
	for _, obj := range gameObject {
		s.gameObjects = append(s.gameObjects, obj)
		obj.transform.childOfScene = true
		for _, t := range obj.transform.children {
			s.addGameObject(t.gameObject)
		}
	}
}

func (s *SceneData) AddGameObject(gameObject ...*GameObject) {
	if s == GetScene().SceneBase() {
		for _, obj := range gameObject {
			obj.AddToScene()
		}
	} else {
		s.addGameObject(gameObject...)
	}
}

func (s *SceneData) removeGameObject(g *GameObject) {
	if g == nil {
		return
	}
	for i, c := range s.gameObjects {
		if g == c {
			s.gameObjects[i].transform.childOfScene = false
			for _, t := range g.transform.children {
				s.removeGameObject(t.gameObject)
			}
			s.gameObjects[i] = nil
			break
		}
	}
}

func (s *SceneData) cleanNil() {
	for i := 0; i < len(s.gameObjects); i++ {
		if s.gameObjects[i] == nil {
			s.gameObjects[i], s.gameObjects = s.gameObjects[len(s.gameObjects)-1], s.gameObjects[:len(s.gameObjects)-1]
			i--
		}
	}
}

func (s *SceneData) RemoveGameObject(g *GameObject) {
	if g == nil {
		return
	}
	if s == GetScene().SceneBase() {
		g.RemoveFromScene()
	} else {
		g.transform.removeFromParent()
		s.removeGameObject(g)
	}
}
<|endoftext|>