<commit_before>package config

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"

	"github.com/docker/docker/pkg/urlutil"
	"github.com/docker/libcompose/utils"
	composeYaml "github.com/docker/libcompose/yaml"
	"github.com/rancher/rancher-compose/template"
	"gopkg.in/yaml.v2"
)

var (
	noMerge = []string{
		"links",
		"volumes_from",
	}
	defaultParseOptions = ParseOptions{
		Interpolate: true,
		Validate:    true,
	}
)

// CreateConfig unmarshals contents to config and creates config based on version
func CreateConfig(contents []byte) (*Config, error) {
	var config Config
	if err := yaml.Unmarshal(contents, &config); err != nil {
		return nil, err
	}

	if config.Version != "2" {
		var baseRawServices RawServiceMap
		if err := yaml.Unmarshal(contents, &baseRawServices); err != nil {
			return nil, err
		}
		config.Services = baseRawServices
	}

	if config.Volumes == nil {
		config.Volumes = make(map[string]interface{})
	}
	if config.Networks == nil {
		config.Networks = make(map[string]interface{})
	}

	return &config, nil
}

// Merge merges a compose file into an existing set of service configs
func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, contents []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
	if options == nil {
		options = &defaultParseOptions
	}

	var err error
	contents, err = template.Apply(contents, environmentLookup.Variables())
	if err != nil {
		return "", nil, nil, nil, err
	}

	config, err := CreateConfig(contents)
	if err != nil {
		return "", nil, nil, nil, err
	}
	baseRawServices := config.Services

	if options.Interpolate {
		if err := InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil {
			return "", nil, nil, nil, err
		}

		for k, v := range config.Volumes {
			if err := Interpolate(k, &v, environmentLookup); err != nil {
				return "", nil, nil, nil, err
			}
			config.Volumes[k] = v
		}

		for k, v := range config.Networks {
			if err := Interpolate(k, &v, environmentLookup); err != nil {
				return "", nil, nil, nil, err
			}
			config.Networks[k] = v
		}
	}

	if options.Preprocess != nil {
		var err error
		baseRawServices, err = options.Preprocess(baseRawServices)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	var serviceConfigs map[string]*ServiceConfig
	if config.Version == "2" {
		var err error
		serviceConfigs, err = MergeServicesV2(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options)
		if err != nil {
			return "", nil, nil, nil, err
		}
	} else {
		serviceConfigsV1, err := MergeServicesV1(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options)
		if err != nil {
			return "", nil, nil, nil, err
		}
		serviceConfigs, err = ConvertServices(serviceConfigsV1)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	adjustValues(serviceConfigs)

	if options.Postprocess != nil {
		var err error
		serviceConfigs, err = options.Postprocess(serviceConfigs)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	var volumes map[string]*VolumeConfig
	var networks map[string]*NetworkConfig
	if err := utils.Convert(config.Volumes, &volumes); err != nil {
		return "", nil, nil, nil, err
	}
	if err := utils.Convert(config.Networks, &networks); err != nil {
		return "", nil, nil, nil, err
	}

	return config.Version, serviceConfigs, volumes, networks, nil
}

func InterpolateRawServiceMap(baseRawServices *RawServiceMap, environmentLookup EnvironmentLookup) error {
	for k, v := range *baseRawServices {
		for k2, v2 := range v {
			if err := Interpolate(k2, &v2, environmentLookup); err != nil {
				return err
			}
			(*baseRawServices)[k][k2] = v2
		}
	}
	return nil
}

func adjustValues(configs map[string]*ServiceConfig) {
	// yaml parser turns "no" into "false" but that is not valid for a restart policy
	for _, v := range configs {
		if v.Restart == "false" {
			v.Restart = "no"
		}
	}
}

func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawService) (RawService, error) {
	if _, ok := serviceData["env_file"]; !ok {
		return serviceData, nil
	}

	var envFiles composeYaml.Stringorslice

	if err := utils.Convert(serviceData["env_file"], &envFiles); err != nil {
		return nil, err
	}

	if len(envFiles) == 0 {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
	}

	var vars composeYaml.MaporEqualSlice

	if _, ok := serviceData["environment"]; ok {
		if err := utils.Convert(serviceData["environment"], &vars); err != nil {
			return nil, err
		}
	}

	for i := len(envFiles) - 1; i >= 0; i-- {
		envFile := envFiles[i]
		content, _, err := resourceLookup.Lookup(envFile, inFile)
		if err != nil {
			return nil, err
		}

		if err != nil {
			return nil, err
		}

		scanner := bufio.NewScanner(bytes.NewBuffer(content))
		for scanner.Scan() {
			line := strings.TrimSpace(scanner.Text())

			if len(line) > 0 && !strings.HasPrefix(line, "#") {
				key := strings.SplitAfter(line, "=")[0]

				found := false
				for _, v := range vars {
					if strings.HasPrefix(v, key) {
						found = true
						break
					}
				}

				if !found {
					vars = append(vars, line)
				}
			}
		}

		if scanner.Err() != nil {
			return nil, scanner.Err()
		}
	}

	serviceData["environment"] = vars

	delete(serviceData, "env_file")

	return serviceData, nil
}

func mergeConfig(baseService, serviceData RawService) RawService {
	for k, v := range serviceData {
		// Image and build are mutually exclusive in merge
		if k == "image" {
			delete(baseService, "build")
		} else if k == "build" {
			delete(baseService, "image")
		}
		existing, ok := baseService[k]
		if ok {
			baseService[k] = merge(existing, v)
		} else {
			baseService[k] = v
		}
	}

	return baseService
}

// IsValidRemote checks if the specified string is a valid remote (for builds)
func IsValidRemote(remote string) bool {
	return urlutil.IsGitURL(remote) || urlutil.IsURL(remote)
}
<commit_msg>Check for nil VolumeConfig<commit_after>package config

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"

	"github.com/docker/docker/pkg/urlutil"
	"github.com/docker/libcompose/utils"
	composeYaml "github.com/docker/libcompose/yaml"
	"github.com/rancher/rancher-compose/template"
	"gopkg.in/yaml.v2"
)

var (
	noMerge = []string{
		"links",
		"volumes_from",
	}
	defaultParseOptions = ParseOptions{
		Interpolate: true,
		Validate:    true,
	}
)

// CreateConfig unmarshals contents to config and creates config based on version
func CreateConfig(contents []byte) (*Config, error) {
	var config Config
	if err := yaml.Unmarshal(contents, &config); err != nil {
		return nil, err
	}

	if config.Version != "2" {
		var baseRawServices RawServiceMap
		if err := yaml.Unmarshal(contents, &baseRawServices); err != nil {
			return nil, err
		}
		config.Services = baseRawServices
	}

	if config.Volumes == nil {
		config.Volumes = make(map[string]interface{})
	}
	if config.Networks == nil {
		config.Networks = make(map[string]interface{})
	}

	return &config, nil
}

// Merge merges a compose file into an existing set of service configs
func Merge(existingServices *ServiceConfigs, environmentLookup EnvironmentLookup, resourceLookup ResourceLookup, file string, contents []byte, options *ParseOptions) (string, map[string]*ServiceConfig, map[string]*VolumeConfig, map[string]*NetworkConfig, error) {
	if options == nil {
		options = &defaultParseOptions
	}

	var err error
	contents, err = template.Apply(contents, environmentLookup.Variables())
	if err != nil {
		return "", nil, nil, nil, err
	}

	config, err := CreateConfig(contents)
	if err != nil {
		return "", nil, nil, nil, err
	}
	baseRawServices := config.Services

	if options.Interpolate {
		if err := InterpolateRawServiceMap(&baseRawServices, environmentLookup); err != nil {
			return "", nil, nil, nil, err
		}

		for k, v := range config.Volumes {
			if err := Interpolate(k, &v, environmentLookup); err != nil {
				return "", nil, nil, nil, err
			}
			config.Volumes[k] = v
		}

		for k, v := range config.Networks {
			if err := Interpolate(k, &v, environmentLookup); err != nil {
				return "", nil, nil, nil, err
			}
			config.Networks[k] = v
		}
	}

	if options.Preprocess != nil {
		var err error
		baseRawServices, err = options.Preprocess(baseRawServices)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	var serviceConfigs map[string]*ServiceConfig
	if config.Version == "2" {
		var err error
		serviceConfigs, err = MergeServicesV2(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options)
		if err != nil {
			return "", nil, nil, nil, err
		}
	} else {
		serviceConfigsV1, err := MergeServicesV1(existingServices, environmentLookup, resourceLookup, file, baseRawServices, options)
		if err != nil {
			return "", nil, nil, nil, err
		}
		serviceConfigs, err = ConvertServices(serviceConfigsV1)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	adjustValues(serviceConfigs)

	if options.Postprocess != nil {
		var err error
		serviceConfigs, err = options.Postprocess(serviceConfigs)
		if err != nil {
			return "", nil, nil, nil, err
		}
	}

	var volumes map[string]*VolumeConfig
	var networks map[string]*NetworkConfig
	if err := utils.Convert(config.Volumes, &volumes); err != nil {
		return "", nil, nil, nil, err
	}
	for i, volume := range volumes {
		if volume == nil {
			volumes[i] = &VolumeConfig{}
		}
	}
	if err := utils.Convert(config.Networks, &networks); err != nil {
		return "", nil, nil, nil, err
	}

	return config.Version, serviceConfigs, volumes, networks, nil
}

func InterpolateRawServiceMap(baseRawServices *RawServiceMap, environmentLookup EnvironmentLookup) error {
	for k, v := range *baseRawServices {
		for k2, v2 := range v {
			if err := Interpolate(k2, &v2, environmentLookup); err != nil {
				return err
			}
			(*baseRawServices)[k][k2] = v2
		}
	}
	return nil
}

func adjustValues(configs map[string]*ServiceConfig) {
	// yaml parser turns "no" into "false" but that is not valid for a restart policy
	for _, v := range configs {
		if v.Restart == "false" {
			v.Restart = "no"
		}
	}
}

func readEnvFile(resourceLookup ResourceLookup, inFile string, serviceData RawService) (RawService, error) {
	if _, ok := serviceData["env_file"]; !ok {
		return serviceData, nil
	}

	var envFiles composeYaml.Stringorslice

	if err := utils.Convert(serviceData["env_file"], &envFiles); err != nil {
		return nil, err
	}

	if len(envFiles) == 0 {
		return serviceData, nil
	}

	if resourceLookup == nil {
		return nil, fmt.Errorf("Can not use env_file in file %s no mechanism provided to load files", inFile)
	}

	var vars composeYaml.MaporEqualSlice

	if _, ok := serviceData["environment"]; ok {
		if err := utils.Convert(serviceData["environment"], &vars); err != nil {
			return nil, err
		}
	}

	for i := len(envFiles) - 1; i >= 0; i-- {
		envFile := envFiles[i]
		content, _, err := resourceLookup.Lookup(envFile, inFile)
		if err != nil {
			return nil, err
		}

		if err != nil {
			return nil, err
		}

		scanner := bufio.NewScanner(bytes.NewBuffer(content))
		for scanner.Scan() {
			line := strings.TrimSpace(scanner.Text())

			if len(line) > 0 && !strings.HasPrefix(line, "#") {
				key := strings.SplitAfter(line, "=")[0]

				found := false
				for _, v := range vars {
					if strings.HasPrefix(v, key) {
						found = true
						break
					}
				}

				if !found {
					vars = append(vars, line)
				}
			}
		}

		if scanner.Err() != nil {
			return nil, scanner.Err()
		}
	}

	serviceData["environment"] = vars

	delete(serviceData, "env_file")

	return serviceData, nil
}

func mergeConfig(baseService, serviceData RawService) RawService {
	for k, v := range serviceData {
		// Image and build are mutually exclusive in merge
		if k == "image" {
			delete(baseService, "build")
		} else if k == "build" {
			delete(baseService, "image")
		}
		existing, ok := baseService[k]
		if ok {
			baseService[k] = merge(existing, v)
		} else {
			baseService[k] = v
		}
	}

	return baseService
}

// IsValidRemote checks if the specified string is a valid remote (for builds)
func IsValidRemote(remote string) bool {
	return urlutil.IsGitURL(remote) || urlutil.IsURL(remote)
}
<|endoftext|>


<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)
	}
}

func createViper(name string, configPath string) (*viper.Viper, error) {
	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)) {
	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 locks for reload<commit_after>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
}
<|endoftext|>


<commit_before>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package url

import (
	"bytes"
	"github.com/jteeuwen/ircb/plugin"
	"github.com/jteeuwen/ircb/proto"
	"html"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
)

func init() { plugin.Register(New) }

type Plugin struct {
	*plugin.Base

	// Each entry holds a regex pattern which should be excluded
	// from the url-title-lookup.
	exclude []*regexp.Regexp

	// Pattern which recognizes urls.
	url *regexp.Regexp
}

func New(profile string) plugin.Plugin {
	p := new(Plugin)
	p.Base = plugin.New(profile, "url")
	p.url = regexp.MustCompile(`\bhttps?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]+(\:[0-9]+)?(/\S*)?\b`)
	return p
}

// Init initializes the plugin. it loads configuration data and binds
// commands and protocol handlers.
func (p *Plugin) Load(c *proto.Client) (err error) {
	err = p.Base.Load(c)
	if err != nil {
		return
	}

	c.Bind(proto.CmdPrivMsg, func(c *proto.Client, m *proto.Message) {
		p.parseURL(c, m)
	})

	ini := p.LoadConfig()
	if ini != nil {
		s := ini.Section("exclude")
		list := s.List("url")
		p.exclude = make([]*regexp.Regexp, len(list))

		for i := range list {
			p.exclude[i], err = regexp.Compile(list[i])

			if err != nil {
				return
			}
		}
	}

	return
}

// parseURL looks for URL's embedded in incoming messages.
// If they are valid http[s] url's and not in the exclude list,
// we use them to fetch page titles from the internet.
func (p *Plugin) parseURL(c *proto.Client, m *proto.Message) {
	list := p.url.FindAllString(m.Data, -1)
	if len(list) == 0 {
		return
	}

	for _, url := range list {
		if !p.excluded(url) {
			go fetchTitle(c, m, url)
		}
	}
}

// excluded returns true if the given url is part of the exclusion list.
func (p *Plugin) excluded(url string) bool {
	for _, excl := range p.exclude {
		if excl.MatchString(url) {
			return true
		}
	}

	return false
}

// fetchTitle attempts to retrieve the title element for a given url.
func fetchTitle(c *proto.Client, m *proto.Message, url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Printf("[url] Failed to fetch %s", url)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		log.Printf("[url] Failed to read %s", url)
		return
	}

	body = bytes.ToLower(body)
	s := bytes.Index(body, []byte("<title>"))
	if s == -1 {
		return
	}

	body = body[s+7:]

	e := bytes.Index(body, []byte("</title>"))
	if e == -1 {
		e = len(body) - 1
	}

	body = bytes.TrimSpace(body[:e])

	c.PrivMsg(m.Receiver, "%s's link shows: %s",
		m.SenderName, html.UnescapeString(string(body)))
}
<commit_msg>Minor cleanup in url plugin.<commit_after>// This file is subject to a 1-clause BSD license.
// Its contents can be found in the enclosed LICENSE file.

package url

import (
	"bytes"
	"github.com/jteeuwen/ircb/plugin"
	"github.com/jteeuwen/ircb/proto"
	"html"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"
)

func init() { plugin.Register(New) }

type Plugin struct {
	*plugin.Base

	// Each entry holds a regex pattern which should be excluded
	// from the url-title-lookup.
	exclude []*regexp.Regexp

	// Pattern which recognizes urls.
	url *regexp.Regexp
}

func New(profile string) plugin.Plugin {
	p := new(Plugin)
	p.Base = plugin.New(profile, "url")
	p.url = regexp.MustCompile(`\bhttps?\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]+(\:[0-9]+)?(/\S*)?\b`)
	return p
}

// Init initializes the plugin. it loads configuration data and binds
// commands and protocol handlers.
func (p *Plugin) Load(c *proto.Client) (err error) {
	err = p.Base.Load(c)
	if err != nil {
		return
	}

	c.Bind(proto.CmdPrivMsg, func(c *proto.Client, m *proto.Message) {
		p.parseURL(c, m)
	})

	ini := p.LoadConfig()
	if ini == nil {
		return
	}

	s := ini.Section("exclude")
	list := s.List("url")
	p.exclude = make([]*regexp.Regexp, len(list))

	for i := range list {
		p.exclude[i], err = regexp.Compile(list[i])

		if err != nil {
			return
		}
	}

	return
}

// parseURL looks for URL's embedded in incoming messages.
// If they are valid http[s] url's and not in the exclude list,
// we use them to fetch page titles from the internet.
func (p *Plugin) parseURL(c *proto.Client, m *proto.Message) {
	list := p.url.FindAllString(m.Data, -1)
	if len(list) == 0 {
		return
	}

	for _, url := range list {
		if !p.excluded(url) {
			go fetchTitle(c, m, url)
		}
	}
}

// excluded returns true if the given url is part of the exclusion list.
func (p *Plugin) excluded(url string) bool {
	for _, excl := range p.exclude {
		if excl.MatchString(url) {
			return true
		}
	}

	return false
}

// fetchTitle attempts to retrieve the title element for a given url.
func fetchTitle(c *proto.Client, m *proto.Message, url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Printf("[url] Failed to fetch %s", url)
		return
	}

	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()

	if err != nil {
		log.Printf("[url] Failed to read %s", url)
		return
	}

	body = bytes.ToLower(body)
	s := bytes.Index(body, []byte("<title>"))
	if s == -1 {
		return
	}

	body = body[s+7:]

	e := bytes.Index(body, []byte("</title>"))
	if e == -1 {
		e = len(body) - 1
	}

	body = bytes.TrimSpace(body[:e])

	c.PrivMsg(m.Receiver, "%s's link shows: %s",
		m.SenderName, html.UnescapeString(string(body)))
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import (
	"fmt"

	"github.com/jacobsa/comeback/crypto"
)

// Return a blob store that wraps the supplied one, encrypting and decrypting
// data as it passes through. The supplied crypter should have deterministic
// output.
func NewEncryptingStore(crypter crypto.Crypter, wrapped Store) Store {
	return &encryptingStore{crypter, wrapped}
}

type encryptingStore struct {
	crypter crypto.Crypter
	wrapped Store
}

func (s *encryptingStore) Store(blob []byte) (Score, error) {
	// Encrypt the plaintext blob.
	ciphertext, err := s.crypter.Encrypt(blob)
	if err != nil {
		return Score{}, fmt.Errorf("Encrypt: %v", err)
	}

	// Pass on the encrypted blob.
	return s.wrapped.Store(ciphertext)
}

func (s *encryptingStore) Load(score Score) ([]byte, error) {
	// Load the encrypted blob.
	ciphertext, err := s.wrapped.Load(score)
	if err != nil {
		return nil, err
	}

	// Decrypt the ciphertext.
	plaintext, err := s.crypter.Decrypt(ciphertext)
	if err != nil {
		return nil, fmt.Errorf("Decrypt: %v", err)
	}

	return plaintext, nil
}

func (s *encryptingStore) Flush() (err error) {
	err = s.wrapped.Flush()
	return
}

func (s *encryptingStore) Contains(score Score) (b bool) {
	b = s.wrapped.Contains(score)
	return
}
<commit_msg>encryptingStore<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/crypto"
)

// Return a blob store that wraps the supplied one, encrypting and decrypting
// data as it passes through. The supplied crypter should have deterministic
// output.
func NewEncryptingStore(crypter crypto.Crypter, wrapped Store) Store {
	return &encryptingStore{crypter, wrapped}
}

type encryptingStore struct {
	crypter crypto.Crypter
	wrapped Store
}

func (s *encryptingStore) Store(
	ctx context.Context,
	blob []byte) (Score, error) {
	// Encrypt the plaintext blob.
	ciphertext, err := s.crypter.Encrypt(blob)
	if err != nil {
		return Score{}, fmt.Errorf("Encrypt: %v", err)
	}

	// Pass on the encrypted blob.
	return s.wrapped.Store(ctx, ciphertext)
}

func (s *encryptingStore) Load(
	ctx context.Context,
	score Score) ([]byte, error) {
	// Load the encrypted blob.
	ciphertext, err := s.wrapped.Load(ctx, score)
	if err != nil {
		return nil, err
	}

	// Decrypt the ciphertext.
	plaintext, err := s.crypter.Decrypt(ciphertext)
	if err != nil {
		return nil, fmt.Errorf("Decrypt: %v", err)
	}

	return plaintext, nil
}

func (s *encryptingStore) Flush(ctx context.Context) (err error) {
	err = s.wrapped.Flush(ctx)
	return
}

func (s *encryptingStore) Contains(ctx context.Context, score Score) (b bool) {
	b = s.wrapped.Contains(ctx, score)
	return
}
<|endoftext|>


<commit_before>package find

import (
	"github.com/monochromegane/the_platinum_searcher/search/file"
	"github.com/monochromegane/the_platinum_searcher/search/grep"
	"github.com/monochromegane/the_platinum_searcher/search/ignore"
	"github.com/monochromegane/the_platinum_searcher/search/option"
	"github.com/monochromegane/the_platinum_searcher/search/pattern"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

type Finder struct {
	Out    chan *grep.Params
	Option *option.Option
}

func (self *Finder) Find(root string, pattern *pattern.Pattern) {
	if self.Option.SearchStream {
		self.findStream(pattern)
	} else {
		self.findFile(root, pattern)
	}
}

func (self *Finder) findStream(pattern *pattern.Pattern) {
	// TODO: File type is fixed in ASCII because it can not determine the character code.
	self.Out <- &grep.Params{"", file.ASCII, pattern}
	close(self.Out)
}

func (self *Finder) findFile(root string, pattern *pattern.Pattern) {
	if self.Option.NoPtIgnore == false {
		usr, err := user.Current()
		if err != nil {
			return
		}
		self.Option.Ignore = append(self.Option.Ignore, ignore.IgnorePatterns(usr.HomeDir, []string{".ptignore"})...)
	}
	Walk(root, self.Option.Ignore, self.Option.Follow, func(path string, info *FileInfo, depth int, ig ignore.Ignore, err error) (error, ignore.Ignore) {
		if info.IsDir() {
			if depth > self.Option.Depth+1 {
				return filepath.SkipDir, ig
			}
			//Current Directory skipping should be checked first before loading ignores
			//within this directory
			if !isRoot(depth) && isHidden(info.Name()) {
				return filepath.SkipDir, ig
			} else {
				for _, p := range ig.Patterns {
					val, _:= filepath.Match(p, filepath.Base(path) + "/")
					if val {
						return filepath.SkipDir, ig
					}
				}
			}
			ig.Patterns = append(ig.Patterns, ignore.IgnorePatterns(path, self.Option.VcsIgnores())...)
			return nil, ig
		}
		if !info.follow && info.IsSymlink() {
			return nil, ig
		}
		if !isRoot(depth) && isHidden(info.Name()) {
			return nil, ig
		}
		for _, p := range ig.Patterns {
			val, _:= filepath.Match(p, filepath.Base(path))
			if val {
				return nil, ig
			}
		}
		if pattern.FileRegexp != nil && !pattern.FileRegexp.MatchString(path) {
			return nil, ig
		}
		fileType := ""
		if self.Option.FilesWithRegexp == "" {
			fileType = file.IdentifyType(path)
			if fileType == file.ERROR || fileType == file.BINARY {
				return nil, ig
			}
		}
		self.Out <- &grep.Params{path, fileType, pattern}
		return nil, ig
	})
	close(self.Out)
}

type WalkFunc func(path string, info *FileInfo, depth int, ig ignore.Ignore, err error) (error, ignore.Ignore)

func Walk(root string, ignorePatterns []string, follow bool, walkFn WalkFunc) error {
	info, err := os.Lstat(root)
	fileInfo := newFileInfo(root, info, follow)
	if err != nil {
		walkError, _ := walkFn(root, fileInfo, 1, ignore.Ignore{}, err)
		return walkError
	}
	return walk(root, fileInfo, 1, ignore.Ignore{Patterns: ignorePatterns}, walkFn)
}

func walkOnGoRoutine(path string, info *FileInfo, notify chan int, depth int, parentIgnore ignore.Ignore, walkFn WalkFunc) {
	walk(path, info, depth, parentIgnore, walkFn)
	notify <- 0
}

func walk(path string, info *FileInfo, depth int, parentIgnore ignore.Ignore, walkFn WalkFunc) error {
	err, ig := walkFn(path, info, depth, parentIgnore, nil)
	if err != nil {
		if info.IsDir() && err == filepath.SkipDir {
			return nil
		}
		return err
	}

	if !info.IsDir() {
		return nil
	}

	list, err := ioutil.ReadDir(path)
	if err != nil {
		walkError, _ := walkFn(path, info, depth, ig, err)
		return walkError
	}

	depth++
	notify := make(chan int, len(list))
	for _, l := range list {
		fileInfo := newFileInfo(path, l, info.follow)
		if isDirectRoot(depth) {
			go walkOnGoRoutine(filepath.Join(path, fileInfo.Name()), fileInfo, notify, depth, ig, walkFn)

		} else {
			walk(filepath.Join(path, fileInfo.Name()), fileInfo, depth, ig, walkFn)
		}
	}
	if isDirectRoot(depth) {
		for i := 0; i < cap(notify); i++ {
			<-notify
		}
	}
	return nil
}

func isRoot(depth int) bool {
	return depth == 1
}

func isDirectRoot(depth int) bool {
	return depth == 2
}

func isHidden(name string) bool {
	return strings.HasPrefix(name, ".") && len(name) > 1
}

func contains(path string, patterns *[]string) bool {
	for _, p := range *patterns {
		if p == path {
			return true
		}
	}
	return false
}
<commit_msg>Fixed goroutine deadlock when cross compilation without cgo support in darwin, unix. Because user.Current() calls stub in this case.<commit_after>package find

import (
	"github.com/monochromegane/the_platinum_searcher/search/file"
	"github.com/monochromegane/the_platinum_searcher/search/grep"
	"github.com/monochromegane/the_platinum_searcher/search/ignore"
	"github.com/monochromegane/the_platinum_searcher/search/option"
	"github.com/monochromegane/the_platinum_searcher/search/pattern"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"strings"
)

type Finder struct {
	Out    chan *grep.Params
	Option *option.Option
}

func (self *Finder) Find(root string, pattern *pattern.Pattern) {
	if self.Option.SearchStream {
		self.findStream(pattern)
	} else {
		self.findFile(root, pattern)
	}
}

func (self *Finder) findStream(pattern *pattern.Pattern) {
	// TODO: File type is fixed in ASCII because it can not determine the character code.
	self.Out <- &grep.Params{"", file.ASCII, pattern}
	close(self.Out)
}

func (self *Finder) findFile(root string, pattern *pattern.Pattern) {
	if self.Option.NoPtIgnore == false {
		usr, err := user.Current()
		var homeDir string
		if err == nil {
			homeDir = usr.HomeDir
		} else {
			// Maybe it's cross compilation without cgo support. (darwin, unix)
			homeDir = os.Getenv("HOME")
		}
		if homeDir != "" {
			self.Option.Ignore = append(self.Option.Ignore, ignore.IgnorePatterns(homeDir, []string{".ptignore"})...)
		}
	}
	Walk(root, self.Option.Ignore, self.Option.Follow, func(path string, info *FileInfo, depth int, ig ignore.Ignore, err error) (error, ignore.Ignore) {
		if info.IsDir() {
			if depth > self.Option.Depth+1 {
				return filepath.SkipDir, ig
			}
			//Current Directory skipping should be checked first before loading ignores
			//within this directory
			if !isRoot(depth) && isHidden(info.Name()) {
				return filepath.SkipDir, ig
			} else {
				for _, p := range ig.Patterns {
					val, _:= filepath.Match(p, filepath.Base(path) + "/")
					if val {
						return filepath.SkipDir, ig
					}
				}
			}
			ig.Patterns = append(ig.Patterns, ignore.IgnorePatterns(path, self.Option.VcsIgnores())...)
			return nil, ig
		}
		if !info.follow && info.IsSymlink() {
			return nil, ig
		}
		if !isRoot(depth) && isHidden(info.Name()) {
			return nil, ig
		}
		for _, p := range ig.Patterns {
			val, _:= filepath.Match(p, filepath.Base(path))
			if val {
				return nil, ig
			}
		}
		if pattern.FileRegexp != nil && !pattern.FileRegexp.MatchString(path) {
			return nil, ig
		}
		fileType := ""
		if self.Option.FilesWithRegexp == "" {
			fileType = file.IdentifyType(path)
			if fileType == file.ERROR || fileType == file.BINARY {
				return nil, ig
			}
		}
		self.Out <- &grep.Params{path, fileType, pattern}
		return nil, ig
	})
	close(self.Out)
}

type WalkFunc func(path string, info *FileInfo, depth int, ig ignore.Ignore, err error) (error, ignore.Ignore)

func Walk(root string, ignorePatterns []string, follow bool, walkFn WalkFunc) error {
	info, err := os.Lstat(root)
	fileInfo := newFileInfo(root, info, follow)
	if err != nil {
		walkError, _ := walkFn(root, fileInfo, 1, ignore.Ignore{}, err)
		return walkError
	}
	return walk(root, fileInfo, 1, ignore.Ignore{Patterns: ignorePatterns}, walkFn)
}

func walkOnGoRoutine(path string, info *FileInfo, notify chan int, depth int, parentIgnore ignore.Ignore, walkFn WalkFunc) {
	walk(path, info, depth, parentIgnore, walkFn)
	notify <- 0
}

func walk(path string, info *FileInfo, depth int, parentIgnore ignore.Ignore, walkFn WalkFunc) error {
	err, ig := walkFn(path, info, depth, parentIgnore, nil)
	if err != nil {
		if info.IsDir() && err == filepath.SkipDir {
			return nil
		}
		return err
	}

	if !info.IsDir() {
		return nil
	}

	list, err := ioutil.ReadDir(path)
	if err != nil {
		walkError, _ := walkFn(path, info, depth, ig, err)
		return walkError
	}

	depth++
	notify := make(chan int, len(list))
	for _, l := range list {
		fileInfo := newFileInfo(path, l, info.follow)
		if isDirectRoot(depth) {
			go walkOnGoRoutine(filepath.Join(path, fileInfo.Name()), fileInfo, notify, depth, ig, walkFn)

		} else {
			walk(filepath.Join(path, fileInfo.Name()), fileInfo, depth, ig, walkFn)
		}
	}
	if isDirectRoot(depth) {
		for i := 0; i < cap(notify); i++ {
			<-notify
		}
	}
	return nil
}

func isRoot(depth int) bool {
	return depth == 1
}

func isDirectRoot(depth int) bool {
	return depth == 2
}

func isHidden(name string) bool {
	return strings.HasPrefix(name, ".") && len(name) > 1
}

func contains(path string, patterns *[]string) bool {
	for _, p := range *patterns {
		if p == path {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package selector

import (
	"sync"
	"time"

	"github.com/micro/go-log"
	"github.com/micro/go-micro/registry"
)

type registrySelector struct {
	so  Options
	ttl time.Duration

	// registry cache
	sync.RWMutex
	cache map[string][]*registry.Service
	ttls  map[string]time.Time

	watched map[string]bool

	// used to close or reload watcher
	reload chan bool
	exit   chan bool
}

var (
	DefaultTTL = time.Minute
)

// isValid checks if the service is valid
func (c *registrySelector) isValid(services []*registry.Service, ttl time.Time) bool {
	// no services exist
	if len(services) == 0 {
		return false
	}

	// ttl is invalid
	if ttl.IsZero() {
		return false
	}

	// time since ttl is longer than timeout
	if time.Since(ttl) > c.ttl {
		return false
	}

	// ok
	return true
}

func (c *registrySelector) quit() bool {
	select {
	case <-c.exit:
		return true
	default:
		return false
	}
}

// cp copies a service. Because we're caching handing back pointers would
// create a race condition, so we do this instead
// its fast enough
func (c *registrySelector) cp(current []*registry.Service) []*registry.Service {
	var services []*registry.Service

	for _, service := range current {
		// copy service
		s := new(registry.Service)
		*s = *service

		// copy nodes
		var nodes []*registry.Node
		for _, node := range service.Nodes {
			n := new(registry.Node)
			*n = *node
			nodes = append(nodes, n)
		}
		s.Nodes = nodes

		// copy endpoints
		var eps []*registry.Endpoint
		for _, ep := range service.Endpoints {
			e := new(registry.Endpoint)
			*e = *ep
			eps = append(eps, e)
		}
		s.Endpoints = eps

		// append service
		services = append(services, s)
	}

	return services
}

func (c *registrySelector) del(service string) {
	delete(c.cache, service)
	delete(c.ttls, service)
}

func (c *registrySelector) get(service string) ([]*registry.Service, error) {
	// read lock
	c.RLock()

	// check the cache first
	services := c.cache[service]
	// get cache ttl
	ttl := c.ttls[service]

	// got services && within ttl so return cache
	if c.isValid(services, ttl) {
		// make a copy
		cp := c.cp(services)
		// unlock the read
		c.RUnlock()
		// return servics
		return cp, nil
	}

	// get does the actual request for a service and cache it
	get := func(service string) ([]*registry.Service, error) {
		// ask the registry
		services, err := c.so.Registry.GetService(service)
		if err != nil {
			return nil, err
		}

		// cache results
		c.Lock()
		c.set(service, c.cp(services))
		c.Unlock()

		return services, nil
	}

	// watch service if not watched
	if _, ok := c.watched[service]; !ok {
		go c.run(service)
	}

	// unlock the read lock
	c.RUnlock()

	// get and return services
	return get(service)
}

func (c *registrySelector) set(service string, services []*registry.Service) {
	c.cache[service] = services
	c.ttls[service] = time.Now().Add(c.ttl)
}

func (c *registrySelector) update(res *registry.Result) {
	if res == nil || res.Service == nil {
		return
	}

	c.Lock()
	defer c.Unlock()

	services, ok := c.cache[res.Service.Name]
	if !ok {
		// we're not going to cache anything
		// unless there was already a lookup
		return
	}

	if len(res.Service.Nodes) == 0 {
		switch res.Action {
		case "delete":
			c.del(res.Service.Name)
		}
		return
	}

	// existing service found
	var service *registry.Service
	var index int
	for i, s := range services {
		if s.Version == res.Service.Version {
			service = s
			index = i
		}
	}

	switch res.Action {
	case "create", "update":
		if service == nil {
			c.set(res.Service.Name, append(services, res.Service))
			return
		}

		// append old nodes to new service
		for _, cur := range service.Nodes {
			var seen bool
			for _, node := range res.Service.Nodes {
				if cur.Id == node.Id {
					seen = true
					break
				}
			}
			if !seen {
				res.Service.Nodes = append(res.Service.Nodes, cur)
			}
		}

		services[index] = res.Service
		c.set(res.Service.Name, services)
	case "delete":
		if service == nil {
			return
		}

		var nodes []*registry.Node

		// filter cur nodes to remove the dead one
		for _, cur := range service.Nodes {
			var seen bool
			for _, del := range res.Service.Nodes {
				if del.Id == cur.Id {
					seen = true
					break
				}
			}
			if !seen {
				nodes = append(nodes, cur)
			}
		}

		// still got nodes, save and return
		if len(nodes) > 0 {
			service.Nodes = nodes
			services[index] = service
			c.set(service.Name, services)
			return
		}

		// zero nodes left

		// only have one thing to delete
		// nuke the thing
		if len(services) == 1 {
			c.del(service.Name)
			return
		}

		// still have more than 1 service
		// check the version and keep what we know
		var srvs []*registry.Service
		for _, s := range services {
			if s.Version != service.Version {
				srvs = append(srvs, s)
			}
		}

		// save
		c.set(service.Name, srvs)
	}
}

// run starts the cache watcher loop
// it creates a new watcher if there's a problem
// reloads the watcher if Init is called
// and returns when Close is called
func (c *registrySelector) run(name string) {
	// set watcher
	c.Lock()
	c.watched[name] = true
	c.Unlock()

	// delete watcher on exit
	defer func() {
		c.Lock()
		delete(c.watched, name)
		c.Unlock()
	}()

	// error counter
	var cerr int

	for {
		// exit early if already dead
		if c.quit() {
			return
		}

		// create new watcher
		w, err := c.so.Registry.Watch(
			registry.WatchService(name),
		)

		if err != nil {
			if c.quit() {
				return
			}
			cerr++
			if cerr > 3 {
				log.Log(err)
				cerr = 0
			}
			time.Sleep(time.Second)
			continue
		}

		// watch for events
		if err := c.watch(w); err != nil {
			if c.quit() {
				return
			}
			cerr++
			if cerr > 3 {
				cerr = 0
				log.Log(err)
			}
			continue
		}

		// reset err counter
		cerr = 0
	}
}

// watch loops the next event and calls update
// it returns if there's an error
func (c *registrySelector) watch(w registry.Watcher) error {
	defer w.Stop()

	// reload chan
	reload := make(chan bool, 1)

	// manage this loop
	go func() {
		// wait for exit or reload signal
		select {
		case <-c.exit:
		case <-c.reload:
			reload <- true
		}

		// stop the watcher
		w.Stop()
	}()

	for {
		res, err := w.Next()
		if err != nil {
			select {
			case <-reload:
				return nil
			default:
				return err
			}
		}
		c.update(res)
	}
}

func (c *registrySelector) Init(opts ...Option) error {
	for _, o := range opts {
		o(&c.so)
	}

	// reload the watcher
	go func() {
		select {
		case <-c.exit:
			return
		default:
			c.reload <- true
		}
	}()

	return nil
}

func (c *registrySelector) Options() Options {
	return c.so
}

func (c *registrySelector) Select(service string, opts ...SelectOption) (Next, error) {
	sopts := SelectOptions{
		Strategy: c.so.Strategy,
	}

	for _, opt := range opts {
		opt(&sopts)
	}

	// get the service
	// try the cache first
	// if that fails go directly to the registry
	services, err := c.get(service)
	if err != nil {
		return nil, err
	}

	// apply the filters
	for _, filter := range sopts.Filters {
		services = filter(services)
	}

	// if there's nothing left, return
	if len(services) == 0 {
		return nil, ErrNoneAvailable
	}

	return sopts.Strategy(services), nil
}

func (c *registrySelector) Mark(service string, node *registry.Node, err error) {
}

func (c *registrySelector) Reset(service string) {
}

// Close stops the watcher and destroys the cache
func (c *registrySelector) Close() error {
	c.Lock()
	c.cache = make(map[string][]*registry.Service)
	c.watched = make(map[string]bool)
	c.Unlock()

	select {
	case <-c.exit:
		return nil
	default:
		close(c.exit)
	}
	return nil
}

func (c *registrySelector) String() string {
	return "registry"
}

func NewSelector(opts ...Option) Selector {
	sopts := Options{
		Strategy: Random,
	}

	for _, opt := range opts {
		opt(&sopts)
	}

	if sopts.Registry == nil {
		sopts.Registry = registry.DefaultRegistry
	}

	ttl := DefaultTTL

	if sopts.Context != nil {
		if t, ok := sopts.Context.Value("selector_ttl").(time.Duration); ok {
			ttl = t
		}
	}

	return &registrySelector{
		so:      sopts,
		ttl:     ttl,
		watched: make(map[string]bool),
		cache:   make(map[string][]*registry.Service),
		ttls:    make(map[string]time.Time),
		reload:  make(chan bool, 1),
		exit:    make(chan bool),
	}
}
<commit_msg>reuse rcache<commit_after>package selector

import (
	"time"

	"github.com/micro/go-micro/registry"
	"github.com/micro/go-rcache"
)

type registrySelector struct {
	so Options
	rc rcache.Cache
}

func (c *registrySelector) newRCache() rcache.Cache {
	ropts := []rcache.Option{}
	if c.so.Context != nil {
		if t, ok := c.so.Context.Value("selector_ttl").(time.Duration); ok {
			ropts = append(ropts, rcache.WithTTL(t))
		}
	}
	return rcache.New(c.so.Registry, ropts...)
}

func (c *registrySelector) Init(opts ...Option) error {
	for _, o := range opts {
		o(&c.so)
	}

	c.rc.Stop()
	c.rc = c.newRCache()

	return nil
}

func (c *registrySelector) Options() Options {
	return c.so
}

func (c *registrySelector) Select(service string, opts ...SelectOption) (Next, error) {
	sopts := SelectOptions{
		Strategy: c.so.Strategy,
	}

	for _, opt := range opts {
		opt(&sopts)
	}

	// get the service
	// try the cache first
	// if that fails go directly to the registry
	services, err := c.rc.GetService(service)
	if err != nil {
		return nil, err
	}

	// apply the filters
	for _, filter := range sopts.Filters {
		services = filter(services)
	}

	// if there's nothing left, return
	if len(services) == 0 {
		return nil, ErrNoneAvailable
	}

	return sopts.Strategy(services), nil
}

func (c *registrySelector) Mark(service string, node *registry.Node, err error) {
}

func (c *registrySelector) Reset(service string) {
}

// Close stops the watcher and destroys the cache
func (c *registrySelector) Close() error {
	c.rc.Stop()

	return nil
}

func (c *registrySelector) String() string {
	return "registry"
}

func NewSelector(opts ...Option) Selector {
	sopts := Options{
		Strategy: Random,
	}

	for _, opt := range opts {
		opt(&sopts)
	}

	if sopts.Registry == nil {
		sopts.Registry = registry.DefaultRegistry
	}

	s := &registrySelector{
		so: sopts,
	}
	s.rc = s.newRCache()

	return s
}
<|endoftext|>


<commit_before>package batch

import (
	"testing"

	"go.polydawn.net/go-timeless-api"
	. "go.polydawn.net/repeatr/testutil"
)

func TestNilRelationLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {},
		"stepB": {},
		"stepA": {},
		"stepC": {},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}

func TestFanoutLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepB": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepA": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepC": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"step0": {},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"step0",
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}

func TestFanInLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {},
		"stepB": {},
		"stepA": {},
		"stepC": {},
		"step9": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/":  {"wire", "stepA", "/out"},
			"/1": {"wire", "stepB", "/out"},
			"/2": {"wire", "stepC", "/out"},
			"/3": {"wire", "stepD", "/out"},
		}},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
		"step9",
	})
}

func TestSimpleLinearOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepA": {},
		"stepB": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepA", "/out"},
		}},
		"stepC": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepB", "/out"},
		}},
		"stepD": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepC", "/out"},
		}},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}
<commit_msg>Additional graph tests.<commit_after>package batch

import (
	"testing"

	"go.polydawn.net/go-timeless-api"
	. "go.polydawn.net/repeatr/testutil"
)

func TestNilRelationLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {},
		"stepB": {},
		"stepA": {},
		"stepC": {},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}

func TestFanoutLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepB": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepA": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"stepC": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "step0", "/out"},
		}},
		"step0": {},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"step0",
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}

func TestFanInLexicalOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepD": {},
		"stepB": {},
		"stepA": {},
		"stepC": {},
		"step9": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/":  {"wire", "stepA", "/out"},
			"/1": {"wire", "stepB", "/out"},
			"/2": {"wire", "stepC", "/out"},
			"/3": {"wire", "stepD", "/out"},
		}},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
		"step9",
	})
}

func TestSimpleLinearOrdering(t *testing.T) {
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepA": {},
		"stepB": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepA", "/out"},
		}},
		"stepC": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepB", "/out"},
		}},
		"stepD": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepC", "/out"},
		}},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA",
		"stepB",
		"stepC",
		"stepD",
	})
}

func TestComplexOrdering(t *testing.T) {
	/*
		             /------------> K --\
		             |                   \
		A --> B -----E ------> H --------> L
		            /                     /
		  C --> D -----F --> G ----------/
		               |
		               \------> I----------> M
		               |                    /
		               \--------> J -------/
	*/
	basting := api.Basting{Steps: map[string]api.BastingStep{
		"stepA": {},
		"stepB": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepA", "/out"},
		}},
		"stepC": {},
		"stepD": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepC", "/out"},
		}},
		"stepE": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/":  {"wire", "stepB", "/out"},
			"/1": {"wire", "stepD", "/out"},
		}},
		"stepF": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepD", "/out"},
		}},
		"stepG": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepF", "/out"},
		}},
		"stepH": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepE", "/out"},
		}},
		"stepI": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepF", "/out"},
		}},
		"stepJ": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepF", "/out"},
		}},
		"stepK": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/": {"wire", "stepE", "/out"},
		}},
		"stepL": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/":  {"wire", "stepG", "/out"},
			"/1": {"wire", "stepK", "/out"},
			"/2": {"wire", "stepH", "/out"},
		}},
		"stepM": {Imports: map[api.AbsPath]api.ReleaseItemID{
			"/":  {"wire", "stepI", "/out"},
			"/1": {"wire", "stepJ", "/out"},
		}},
	}}
	order, err := orderSteps(basting)
	WantEqual(t, err, nil)
	WantEqual(t, order, []string{
		"stepA", "stepB", "stepC", "stepD", "stepE",
		"stepF", "stepG", "stepH", "stepI", "stepJ",
		"stepK", "stepL", "stepM",
	})
}
<|endoftext|>


<commit_before>package plus

import (
	"log"
	"testing"

	"github.com/stretchr/testify/assert"
)

func init() {
	log.Print(`hate this`)
}

func constructMockPayloads(num uint64) keys {
	keys := make(keys, 0, num)
	for i := uint64(0); i < num; i++ {
		keys = append(keys, newPayload(newMockKey(i, i)))
	}

	return keys
}

func constructMockKeys(num uint64) keys {
	keys := make(keys, 0, num)

	for i := uint64(0); i < num; i++ {
		keys = append(keys, newMockKey(i, i))
	}

	return keys
}

func constructMockNodes(num uint64) nodes {
	nodes := make(nodes, 0, num)
	for i := uint64(0); i < num; i++ {
		keys := make(keys, 0, num)
		for j := uint64(0); j < num; j++ {
			keys = append(keys, newPayload(newMockKey(j*i+j, j*i+j)))
		}

		node := &lnode{
			keys: keys,
		}
		nodes = append(nodes, node)
		if i > 0 {
			nodes[i-1].(*lnode).pointer = node
		}
	}

	return nodes
}

func constructMockInternalNode(nodes nodes) *inode {
	if len(nodes) < 2 {
		return nil
	}

	keys := make(keys, 0, len(nodes)-1)
	for i := 1; i < len(nodes); i++ {
		keys = append(keys, nodes[i].(*lnode).keys[0].(*payload).key())
	}

	in := &inode{
		keys:  keys,
		nodes: nodes,
	}
	return in
}

func TestLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)
	key := newMockKey(3, 3)

	n.insert(tree, key)

	assert.Len(t, n.keys, 1)
	assert.Nil(t, n.pointer)
	assert.Equal(t, n.keys[0].(*payload).keys[0], key)
	assert.Equal(t, 0, n.keys[0].Compare(key))
}

func TestDuplicateLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)
	k1 := newMockKey(3, 3)
	k2 := newMockKey(3, 4)

	assert.True(t, n.insert(tree, k1))
	assert.True(t, n.insert(tree, k2))
	assert.False(t, n.insert(tree, k1))

	assert.Len(t, n.keys, 1)
	assert.Nil(t, n.pointer)
	if !assert.Len(t, n.keys[0].(*payload).keys, 2) {
		return
	}
	assert.Equal(t, n.keys[0].(*payload).keys[0], k1)
	assert.Equal(t, n.keys[0].(*payload).keys[1], k2)
	assert.Equal(t, 0, n.keys[0].Compare(k1))
	assert.Equal(t, 0, n.keys[0].Compare(k2))
}

func TestMultipleLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)

	k1 := newMockKey(3, 3)
	k2 := newMockKey(4, 4)

	assert.True(t, n.insert(tree, k1))
	n.insert(tree, k2)

	if !assert.Len(t, n.keys, 2) {
		return
	}
	assert.Nil(t, n.pointer)
	assert.Equal(t, k1, n.keys[0].(*payload).keys[0])
	assert.Equal(t, k2, n.keys[1].(*payload).keys[0])
}

func TestLeafNodeSplitEvenNumber(t *testing.T) {
	keys := constructMockPayloads(4)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[2].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:2])
	assert.Equal(t, right.(*lnode).keys, keys[2:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestLeafNodeSplitOddNumber(t *testing.T) {
	keys := constructMockPayloads(3)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[1].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:1])
	assert.Equal(t, right.(*lnode).keys, keys[1:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestTwoKeysLeafNodeSplit(t *testing.T) {
	keys := constructMockPayloads(2)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[1].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:1])
	assert.Equal(t, right.(*lnode).keys, keys[1:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestLessThanTwoKeysSplit(t *testing.T) {
	keys := constructMockPayloads(1)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Nil(t, key)
	assert.Nil(t, left)
	assert.Nil(t, right)
}

func TestInternalNodeSplit2_3_4(t *testing.T) {
	nodes := constructMockNodes(4)
	in := constructMockInternalNode(nodes)

	key, left, right := in.split()
	assert.Equal(t, nodes[3].(*lnode).keys[0].(*payload).key(), key)
	assert.Len(t, left.(*inode).keys, 1)
	assert.Len(t, right.(*inode).keys, 1)
	assert.Equal(t, nodes[:2], left.(*inode).nodes)
	assert.Equal(t, nodes[2:], right.(*inode).nodes)
}

func TestInternalNodeSplit3_4_5(t *testing.T) {
	nodes := constructMockNodes(5)
	in := constructMockInternalNode(nodes)

	key, left, right := in.split()
	assert.Equal(t, nodes[4].(*lnode).keys[0].(*payload).key(), key)
	assert.Len(t, left.(*inode).keys, 2)
	assert.Len(t, right.(*inode).keys, 1)
	assert.Equal(t, nodes[:3], left.(*inode).nodes)
	assert.Equal(t, nodes[3:], right.(*inode).nodes)
}
<commit_msg>Added additional unit test.<commit_after>package plus

import (
	"log"
	"testing"

	"github.com/stretchr/testify/assert"
)

func init() {
	log.Print(`hate this`)
}

func constructMockPayloads(num uint64) keys {
	keys := make(keys, 0, num)
	for i := uint64(0); i < num; i++ {
		keys = append(keys, newPayload(newMockKey(i, i)))
	}

	return keys
}

func constructMockKeys(num uint64) keys {
	keys := make(keys, 0, num)

	for i := uint64(0); i < num; i++ {
		keys = append(keys, newMockKey(i, i))
	}

	return keys
}

func constructMockNodes(num uint64) nodes {
	nodes := make(nodes, 0, num)
	for i := uint64(0); i < num; i++ {
		keys := make(keys, 0, num)
		for j := uint64(0); j < num; j++ {
			keys = append(keys, newPayload(newMockKey(j*i+j, j*i+j)))
		}

		node := &lnode{
			keys: keys,
		}
		nodes = append(nodes, node)
		if i > 0 {
			nodes[i-1].(*lnode).pointer = node
		}
	}

	return nodes
}

func constructMockInternalNode(nodes nodes) *inode {
	if len(nodes) < 2 {
		return nil
	}

	keys := make(keys, 0, len(nodes)-1)
	for i := 1; i < len(nodes); i++ {
		keys = append(keys, nodes[i].(*lnode).keys[0].(*payload).key())
	}

	in := &inode{
		keys:  keys,
		nodes: nodes,
	}
	return in
}

func TestLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)
	key := newMockKey(3, 3)

	n.insert(tree, key)

	assert.Len(t, n.keys, 1)
	assert.Nil(t, n.pointer)
	assert.Equal(t, n.keys[0].(*payload).keys[0], key)
	assert.Equal(t, 0, n.keys[0].Compare(key))
}

func TestDuplicateLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)
	k1 := newMockKey(3, 3)
	k2 := newMockKey(3, 4)

	assert.True(t, n.insert(tree, k1))
	assert.True(t, n.insert(tree, k2))
	assert.False(t, n.insert(tree, k1))

	assert.Len(t, n.keys, 1)
	assert.Nil(t, n.pointer)
	if !assert.Len(t, n.keys[0].(*payload).keys, 2) {
		return
	}
	assert.Equal(t, n.keys[0].(*payload).keys[0], k1)
	assert.Equal(t, n.keys[0].(*payload).keys[1], k2)
	assert.Equal(t, 0, n.keys[0].Compare(k1))
	assert.Equal(t, 0, n.keys[0].Compare(k2))
}

func TestMultipleLeafNodeInsert(t *testing.T) {
	tree := newBTree(3)
	n := newLeafNode(3)

	k1 := newMockKey(3, 3)
	k2 := newMockKey(4, 4)

	assert.True(t, n.insert(tree, k1))
	n.insert(tree, k2)

	if !assert.Len(t, n.keys, 2) {
		return
	}
	assert.Nil(t, n.pointer)
	assert.Equal(t, k1, n.keys[0].(*payload).keys[0])
	assert.Equal(t, k2, n.keys[1].(*payload).keys[0])
}

func TestLeafNodeSplitEvenNumber(t *testing.T) {
	keys := constructMockPayloads(4)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[2].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:2])
	assert.Equal(t, right.(*lnode).keys, keys[2:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestLeafNodeSplitOddNumber(t *testing.T) {
	keys := constructMockPayloads(3)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[1].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:1])
	assert.Equal(t, right.(*lnode).keys, keys[1:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestTwoKeysLeafNodeSplit(t *testing.T) {
	keys := constructMockPayloads(2)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Equal(t, keys[1].(*payload).key(), key)
	assert.Equal(t, left.(*lnode).keys, keys[:1])
	assert.Equal(t, right.(*lnode).keys, keys[1:])
	assert.Equal(t, left.(*lnode).pointer, right)
}

func TestLessThanTwoKeysSplit(t *testing.T) {
	keys := constructMockPayloads(1)

	node := &lnode{
		keys: keys,
	}

	key, left, right := node.split()
	assert.Nil(t, key)
	assert.Nil(t, left)
	assert.Nil(t, right)
}

func TestInternalNodeSplit2_3_4(t *testing.T) {
	nodes := constructMockNodes(4)
	in := constructMockInternalNode(nodes)

	key, left, right := in.split()
	assert.Equal(t, nodes[3].(*lnode).keys[0].(*payload).key(), key)
	assert.Len(t, left.(*inode).keys, 1)
	assert.Len(t, right.(*inode).keys, 1)
	assert.Equal(t, nodes[:2], left.(*inode).nodes)
	assert.Equal(t, nodes[2:], right.(*inode).nodes)
}

func TestInternalNodeSplit3_4_5(t *testing.T) {
	nodes := constructMockNodes(5)
	in := constructMockInternalNode(nodes)

	key, left, right := in.split()
	assert.Equal(t, nodes[4].(*lnode).keys[0].(*payload).key(), key)
	assert.Len(t, left.(*inode).keys, 2)
	assert.Len(t, right.(*inode).keys, 1)
	assert.Equal(t, nodes[:3], left.(*inode).nodes)
	assert.Equal(t, nodes[3:], right.(*inode).nodes)
}

func TestInternalNodeLessThan3Keys(t *testing.T) {
	nodes := constructMockNodes(2)
	in := constructMockInternalNode(nodes)

	key, left, right := in.split()
	assert.Nil(t, key)
	assert.Nil(t, left)
	assert.Nil(t, right)
}
<|endoftext|>


<commit_before>package version

// Version tells us the app version string
const Version = "2.8.1"
<commit_msg>Bump to v2.9.0<commit_after>package version

// Version tells us the app version string
const Version = "2.9.0"
<|endoftext|>


<commit_before>// Library for all global variables used by the Yieldbot
// Infrastructure teams in sensu
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package sensuutil

// MonitoringErrorCodes provides a standard set of error codes to use.
// Please use the below codes instead of random non-zero so that monitoring can
// utilize existing maps for alerting and help avoid unnecessary noise.
var MonitoringErrorCodes = map[string]int{
	"GENERALGOLANGERROR": 129, // internal script error
	"CONFIGERROR":        127, // unix config error, not enough parms, etc
	"PERMISSIONERROR":    126, // not executable, etc
	"RUNTIMEERROR":       42,  // self explantory
        "DEBUG":              37,  // You had the Alliance on you, criminals and savages… half the people on this
                                   // ship have been shot or wounded, including yourself, and you’re harboring known fugitives.
	"OK":                 0,   // “We’re still flying”
	"WARNING":            1,   // this kinda sucks but don't get out of bed to deal with it
	"CRITICAL":           2,   // “The ships hung in the sky in much the same way that bricks don't.”
	"UNKNOWN":            3,   // Would it save you a lot of time if I just gave up and went mad now?
}
<commit_msg>Update common.go<commit_after>// Library for all global variables used by the Yieldbot
// Infrastructure teams in sensu
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package sensuutil

// MonitoringErrorCodes provides a standard set of error codes to use.
// Please use the below codes instead of random non-zero so that monitoring can
// utilize existing maps for alerting and help avoid unnecessary noise.
var MonitoringErrorCodes = map[string]int{
	"GENERALGOLANGERROR": 129, // internal script error
	"CONFIGERROR":        127, // unix config error, not enough parms, etc
	"PERMISSIONERROR":    126, // not executable, etc
	"RUNTIMEERROR":       42,  // self explantory
        "DEBUG":              37,  // You had the Alliance on you, criminals and savages… half the people on this
                                   // ship have been shot or wounded, including yourself, and you’re harboring known fugitives.
	"UNKNOWN":            3,   // Would it save you a lot of time if I just gave up and went mad now?
	"CRITICAL":           2,   // “The ships hung in the sky in much the same way that bricks don't.”
	"WARNING":            1,   // this kinda sucks but don't get out of bed to deal with it
	"OK":                 0,   // “We’re still flying”

}
<|endoftext|>


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

package docker

import (
	"github.com/globocom/tsuru/heal"
	"launchpad.net/gocheck"
	"sync/atomic"
)

type HealerSuite struct {
	healer  *ContainerHealer
	calls   int64
	cleanup func()
}

var _ = gocheck.Suite(&HealerSuite{})

func (s *HealerSuite) SetUpSuite(c *gocheck.C) {
	s.healer = &ContainerHealer{}
	createFakeContainers([]string{"8dfafdbc3a40", "dca19cd9bb9e", "3fd99cd9bb84"}, c)
	s.cleanup, _ = startDockerTestServer("4567", &s.calls)
}

func (s *HealerSuite) TearDownTest(c *gocheck.C) {
	atomic.StoreInt64(&s.calls, 0)
}

func (s *HealerSuite) TearDownSuite(c *gocheck.C) {
	defer s.cleanup()
	clearSchedStorage(c)
}

func (s *HealerSuite) TestContainerHealerShouldBeRegistered(c *gocheck.C) {
	h, err := heal.Get("docker", "container")
	c.Assert(err, gocheck.IsNil)
	c.Assert(h, gocheck.FitsTypeOf, ContainerHealer{})
}

func (s *HealerSuite) TestContainerHealerImplementsHealInterface(c *gocheck.C) {
	var h interface{}
	h = &ContainerHealer{}
	_, ok := h.(heal.Healer)
	c.Assert(ok, gocheck.Equals, true)
}

func (s *HealerSuite) TestContainerHealPerformListContainersKillAndStartOnUnhealthyContainers(c *gocheck.C) {
	err := s.healer.Heal()
	c.Assert(err, gocheck.IsNil)
	c.Assert(atomic.LoadInt64(&s.calls), gocheck.Equals, int64(3))
}

func (s *HealerSuite) TestCollectContainersCallsDockerApi(c *gocheck.C) {
	_, err := s.healer.collectContainers()
	c.Assert(err, gocheck.IsNil)
	c.Assert(atomic.LoadInt64(&s.calls), gocheck.Equals, int64(1))
}

func (s *HealerSuite) TestCollectContainerReturnsCollectedContainers(c *gocheck.C) {
	containers, err := s.healer.collectContainers()
	c.Assert(err, gocheck.IsNil)
	c.Assert(len(containers), gocheck.Equals, 3)
	expected := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
		{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"},
	}
	c.Assert(containers, gocheck.DeepEquals, expected)
}

func (s *HealerSuite) TestIsHealthyReturnsTrueWhenContainerIsUp(c *gocheck.C) {
	container := container{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, true)
}

func (s *HealerSuite) TestIsHealthyReturnsFalseWhenContainerIsGhost(c *gocheck.C) {
	container := container{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsHealthyReturnsFalseWhenContainerHasExitedWithStatusNotZero(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 127"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsHealthyReturnsTrueWhenContainerHasExitedWithStatusZero(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, true)
}

func (s *HealerSuite) TestIsRunningReturnsFalseForExitedContainers(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"}
	running := s.healer.isRunning(&container)
	c.Assert(running, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsRunningReturnsTrueForGhostContainers(c *gocheck.C) {
	container := container{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"}
	running := s.healer.isRunning(&container)
	c.Assert(running, gocheck.Equals, true)
}

func (s *HealerSuite) TestUnhealthyRunningContainers(c *gocheck.C) {
	containers := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
		{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Exit 127"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"},
	}
	expected := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
	}
	unhealthy := s.healer.unhealthyRunningContainers(containers)
	c.Assert(unhealthy, gocheck.DeepEquals, expected)
}
<commit_msg>provision/docker: fix HealerSuite<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"github.com/globocom/docker-cluster/cluster"
	"github.com/globocom/tsuru/heal"
	"launchpad.net/gocheck"
	"net/http/httptest"
	"sync/atomic"
)

type HealerSuite struct {
	healer  *ContainerHealer
	calls   int64
	cleanup func()
}

var _ = gocheck.Suite(&HealerSuite{})

func (s *HealerSuite) SetUpSuite(c *gocheck.C) {
	var err error
	var server *httptest.Server
	s.healer = &ContainerHealer{}
	s.cleanup, server = startDockerTestServer("4567", &s.calls)
	storage := mapStorage{}
	storage.StoreContainer("8dfafdbc3a40", "server")
	storage.StoreContainer("dca19cd9bb9e", "server")
	storage.StoreContainer("3fd99cd9bb84", "server")
	cmutex.Lock()
	defer cmutex.Unlock()
	dCluster, err = cluster.New(nil, &storage,
		cluster.Node{ID: "server", Address: server.URL},
	)
	c.Assert(err, gocheck.IsNil)
}

func (s *HealerSuite) TearDownTest(c *gocheck.C) {
	atomic.StoreInt64(&s.calls, 0)
}

func (s *HealerSuite) TearDownSuite(c *gocheck.C) {
	s.cleanup()
}

func (s *HealerSuite) TestContainerHealerShouldBeRegistered(c *gocheck.C) {
	h, err := heal.Get("docker", "container")
	c.Assert(err, gocheck.IsNil)
	c.Assert(h, gocheck.FitsTypeOf, ContainerHealer{})
}

func (s *HealerSuite) TestContainerHealerImplementsHealInterface(c *gocheck.C) {
	var h interface{}
	h = &ContainerHealer{}
	_, ok := h.(heal.Healer)
	c.Assert(ok, gocheck.Equals, true)
}

func (s *HealerSuite) TestContainerHealPerformListContainersKillAndStartOnUnhealthyContainers(c *gocheck.C) {
	err := s.healer.Heal()
	c.Assert(err, gocheck.IsNil)
	c.Assert(atomic.LoadInt64(&s.calls), gocheck.Equals, int64(3))
}

func (s *HealerSuite) TestCollectContainersCallsDockerApi(c *gocheck.C) {
	_, err := s.healer.collectContainers()
	c.Assert(err, gocheck.IsNil)
	c.Assert(atomic.LoadInt64(&s.calls), gocheck.Equals, int64(1))
}

func (s *HealerSuite) TestCollectContainerReturnsCollectedContainers(c *gocheck.C) {
	containers, err := s.healer.collectContainers()
	c.Assert(err, gocheck.IsNil)
	c.Assert(len(containers), gocheck.Equals, 3)
	expected := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
		{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"},
	}
	c.Assert(containers, gocheck.DeepEquals, expected)
}

func (s *HealerSuite) TestIsHealthyReturnsTrueWhenContainerIsUp(c *gocheck.C) {
	container := container{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, true)
}

func (s *HealerSuite) TestIsHealthyReturnsFalseWhenContainerIsGhost(c *gocheck.C) {
	container := container{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsHealthyReturnsFalseWhenContainerHasExitedWithStatusNotZero(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 127"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsHealthyReturnsTrueWhenContainerHasExitedWithStatusZero(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"}
	isHealthy := s.healer.isHealthy(&container)
	c.Assert(isHealthy, gocheck.Equals, true)
}

func (s *HealerSuite) TestIsRunningReturnsFalseForExitedContainers(c *gocheck.C) {
	container := container{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"}
	running := s.healer.isRunning(&container)
	c.Assert(running, gocheck.Equals, false)
}

func (s *HealerSuite) TestIsRunningReturnsTrueForGhostContainers(c *gocheck.C) {
	container := container{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"}
	running := s.healer.isRunning(&container)
	c.Assert(running, gocheck.Equals, true)
}

func (s *HealerSuite) TestUnhealthyRunningContainers(c *gocheck.C) {
	containers := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
		{ID: "dca19cd9bb9e", Image: "tsuru/python:latest", Status: "Exit 0"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Exit 127"},
		{ID: "3fd99cd9bb84", Image: "tsuru/python:latest", Status: "Up 7 seconds"},
	}
	expected := []container{
		{ID: "8dfafdbc3a40", Image: "base:latest", Status: "Ghost"},
	}
	unhealthy := s.healer.unhealthyRunningContainers(containers)
	c.Assert(unhealthy, gocheck.DeepEquals, expected)
}
<|endoftext|>


<commit_before>package container

import (
	"encoding/base64"
	"strings"
)

type V1 struct {
	Version    string
	KeyName    string
	ContentKey []byte
	Content    []byte
}

func ParseV1(str string) (*V1, error) {
	basic, err := ParseBasic(str)
	if err != nil {
		return nil, err
	}

	if basic.Version != "1" {
		return nil, ErrDifferentVersion
	}

	parts := strings.SplitN(basic.Content, ":", 3) // key name, format, content

	if len(parts) < 3 {
		return nil, ErrParse
	}

	keyName := parts[0]
	format := parts[1]
	contentPart := parts[2]

	var contentKey []byte
	var content []byte
	if format == "long" {
		contentKeyAndContent := strings.SplitN(contentPart, ",", 2)
		if len(parts) < 2 {
			return nil, ErrParse
		}

		var err error

		contentKey, err = base64.StdEncoding.DecodeString(contentKeyAndContent[0])
		if err != nil {
			return nil, err
		}

		content, err = base64.StdEncoding.DecodeString(contentKeyAndContent[1])
		if err != nil {
			return nil, err
		}
	} else {
		content, err = base64.StdEncoding.DecodeString(contentPart)
		if err != nil {
			return nil, err
		}
	}

	return &V1{
		Version:    basic.Version,
		KeyName:    keyName,
		ContentKey: contentKey,
		Content:    content,
	}, nil
}
<commit_msg>dupe definition<commit_after>package container

import (
	"encoding/base64"
	"strings"
)

type V1 struct {
	Version    string
	KeyName    string
	ContentKey []byte
	Content    []byte
}

func ParseV1(str string) (*V1, error) {
	basic, err := ParseBasic(str)
	if err != nil {
		return nil, err
	}

	if basic.Version != "1" {
		return nil, ErrDifferentVersion
	}

	parts := strings.SplitN(basic.Content, ":", 3) // key name, format, content

	if len(parts) < 3 {
		return nil, ErrParse
	}

	keyName := parts[0]
	format := parts[1]
	contentPart := parts[2]

	var contentKey []byte
	var content []byte
	if format == "long" {
		contentKeyAndContent := strings.SplitN(contentPart, ",", 2)
		if len(parts) < 2 {
			return nil, ErrParse
		}

		contentKey, err = base64.StdEncoding.DecodeString(contentKeyAndContent[0])
		if err != nil {
			return nil, err
		}

		content, err = base64.StdEncoding.DecodeString(contentKeyAndContent[1])
		if err != nil {
			return nil, err
		}
	} else {
		content, err = base64.StdEncoding.DecodeString(contentPart)
		if err != nil {
			return nil, err
		}
	}

	return &V1{
		Version:    basic.Version,
		KeyName:    keyName,
		ContentKey: contentKey,
		Content:    content,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/platforms/intel-iot/edison"
	"github.com/wfernandes/homesec/broker"
	"github.com/wfernandes/homesec/sensor_processor/config"
	"github.com/wfernandes/homesec/sensor_processor/sensors"
)

var configFilePath = flag.String("config", "config/sensor.json", "Path to the Sensor Processor json config file")

func main() {
	flag.Parse()
	config, err := config.Configuration(*configFilePath)
	if err != nil {
		panic(err)
	}

	gbot := gobot.NewGobot()
	broker := broker.NewMQTTBroker("edison processor", config.BrokerUrl)
	adapter := edison.NewEdisonAdaptor("edison")
	//	adapter := testutils.NewMockAdapter("mockAdapter")
	service := sensors.Initialize(gbot, adapter, broker)

	for pin, stype := range config.Sensors {
		switch stype {
		case "touch":
			service.NewTouchSensor(pin)
		}
	}

	gbot.Start()
}
<commit_msg>Actually connects the broker on edison processor start up<commit_after>package main

import (
	"flag"

	"github.com/hybridgroup/gobot"
	"github.com/hybridgroup/gobot/platforms/intel-iot/edison"
	"github.com/wfernandes/homesec/broker"
	"github.com/wfernandes/homesec/sensor_processor/config"
	"github.com/wfernandes/homesec/sensor_processor/sensors"
)

var configFilePath = flag.String("config", "config/sensor.json", "Path to the Sensor Processor json config file")

func main() {
	flag.Parse()
	config, err := config.Configuration(*configFilePath)
	if err != nil {
		panic(err)
	}

	gbot := gobot.NewGobot()
	broker := broker.NewMQTTBroker("edison processor", config.BrokerUrl)
	err = broker.Connect()
	if err != nil {
		panic(err)
	}
	adapter := edison.NewEdisonAdaptor("edison")
	//	adapter := testutils.NewMockAdapter("mockAdapter")
	service := sensors.Initialize(gbot, adapter, broker)

	for pin, stype := range config.Sensors {
		switch stype {
		case "touch":
			service.NewTouchSensor(pin)
		}
	}

	gbot.Start()
}
<|endoftext|>


<commit_before>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api

import (
	"fmt"
	"net/url"

	"github.com/google/go-querystring/query"
)

// AuthServer holds an authentication server
type AuthServer struct {
	ID              int    `json:"id,omitempty" url:"id,omitempty"`
	Address         string `json:"address" url:"address"`
	Protocol        int    `json:"protocol" url:"protocol"`
	Enabled         bool   `json:"enabled" url:"enabled"`
	SplitAddress    bool   `json:"split_address" url:"split_address"`
	UserMapTemplate string `json:"user_map_template" url:"user_map_template"`
}

// AuthServerList holds authentication servers
type AuthServerList struct {
	Items []AuthServer `json:"items"`
	Links Links        `json:"links"`
	Meta  Meta         `json:"meta"`
}

// GetAuthServers returns a AuthServerList object
// This contains a paginated list of authentication servers and links
// to the neighbouring pages.
// https://www.baruwa.com/docs/api/#listing-authentication-settings
func (c *Client) GetAuthServers(domainID int, opts *ListOptions) (l *AuthServerList, err error) {
	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	l = &AuthServerList{}

	err = c.get(fmt.Sprintf("authservers/%d", domainID), opts, l)

	return
}

// GetAuthServer returns an authentication server
// https://www.baruwa.com/docs/api/#retrieve-authentication-settings
func (c *Client) GetAuthServer(domainID, serverID int) (server *AuthServer, err error) {
	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if serverID <= 0 {
		err = fmt.Errorf(serverIDError)
		return
	}

	server = &AuthServer{}

	err = c.get(fmt.Sprintf("authservers/%d/%d", domainID, serverID), nil, server)

	return
}

// CreateAuthServer creates an authentication server
// https://www.baruwa.com/docs/api/#create-authentication-settings
func (c *Client) CreateAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.post(fmt.Sprintf("authservers/%d", domainID), v, server)

	return
}

// UpdateAuthServer updates an authentication server
// https://www.baruwa.com/docs/api/#update-authentication-settings
func (c *Client) UpdateAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.put(fmt.Sprintf("authservers/%d/%d", domainID, server.ID), v, nil)

	return
}

// DeleteAuthServer deletes an authentication server
// https://www.baruwa.com/docs/api/#delete-authentication-settings
func (c *Client) DeleteAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.delete(fmt.Sprintf("authservers/%d/%d", domainID, server.ID), v)

	return
}
<commit_msg>FIX: Add missing port param<commit_after>// BaruwaAPI Golang bindings for Baruwa REST API
// Copyright (C) 2019 Andrew Colin Kissa <andrew@topdog.za.net>

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package api

import (
	"fmt"
	"net/url"

	"github.com/google/go-querystring/query"
)

// AuthServer holds an authentication server
type AuthServer struct {
	ID              int    `json:"id,omitempty" url:"id,omitempty"`
	Address         string `json:"address" url:"address"`
	Port            int    `json:"port" url:"port"`
	Protocol        int    `json:"protocol" url:"protocol"`
	Enabled         bool   `json:"enabled" url:"enabled"`
	SplitAddress    bool   `json:"split_address" url:"split_address"`
	UserMapTemplate string `json:"user_map_template" url:"user_map_template"`
}

// AuthServerList holds authentication servers
type AuthServerList struct {
	Items []AuthServer `json:"items"`
	Links Links        `json:"links"`
	Meta  Meta         `json:"meta"`
}

// GetAuthServers returns a AuthServerList object
// This contains a paginated list of authentication servers and links
// to the neighbouring pages.
// https://www.baruwa.com/docs/api/#listing-authentication-settings
func (c *Client) GetAuthServers(domainID int, opts *ListOptions) (l *AuthServerList, err error) {
	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	l = &AuthServerList{}

	err = c.get(fmt.Sprintf("authservers/%d", domainID), opts, l)

	return
}

// GetAuthServer returns an authentication server
// https://www.baruwa.com/docs/api/#retrieve-authentication-settings
func (c *Client) GetAuthServer(domainID, serverID int) (server *AuthServer, err error) {
	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if serverID <= 0 {
		err = fmt.Errorf(serverIDError)
		return
	}

	server = &AuthServer{}

	err = c.get(fmt.Sprintf("authservers/%d/%d", domainID, serverID), nil, server)

	return
}

// CreateAuthServer creates an authentication server
// https://www.baruwa.com/docs/api/#create-authentication-settings
func (c *Client) CreateAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.post(fmt.Sprintf("authservers/%d", domainID), v, server)

	return
}

// UpdateAuthServer updates an authentication server
// https://www.baruwa.com/docs/api/#update-authentication-settings
func (c *Client) UpdateAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.put(fmt.Sprintf("authservers/%d/%d", domainID, server.ID), v, nil)

	return
}

// DeleteAuthServer deletes an authentication server
// https://www.baruwa.com/docs/api/#delete-authentication-settings
func (c *Client) DeleteAuthServer(domainID int, server *AuthServer) (err error) {
	var v url.Values

	if domainID <= 0 {
		err = fmt.Errorf(domainIDError)
		return
	}

	if server == nil {
		err = fmt.Errorf(serverParamError)
		return
	}

	if server.ID <= 0 {
		err = fmt.Errorf(serverSIDError)
		return
	}

	if v, err = query.Values(server); err != nil {
		return
	}

	err = c.delete(fmt.Sprintf("authservers/%d/%d", domainID, server.ID), v)

	return
}
<|endoftext|>