<commit_before>package configfile

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/docker/cli/cli/config/credentials"
	"github.com/docker/cli/cli/config/types"
	"github.com/pkg/errors"
)

const (
	// This constant is only used for really old config files when the
	// URL wasn't saved as part of the config file and it was just
	// assumed to be this value.
	defaultIndexServer = "https://index.docker.io/v1/"
)

// ConfigFile ~/.docker/config.json file info
type ConfigFile struct {
	AuthConfigs          map[string]types.AuthConfig  `json:"auths"`
	HTTPHeaders          map[string]string            `json:"HttpHeaders,omitempty"`
	PsFormat             string                       `json:"psFormat,omitempty"`
	ImagesFormat         string                       `json:"imagesFormat,omitempty"`
	NetworksFormat       string                       `json:"networksFormat,omitempty"`
	PluginsFormat        string                       `json:"pluginsFormat,omitempty"`
	VolumesFormat        string                       `json:"volumesFormat,omitempty"`
	StatsFormat          string                       `json:"statsFormat,omitempty"`
	DetachKeys           string                       `json:"detachKeys,omitempty"`
	CredentialsStore     string                       `json:"credsStore,omitempty"`
	CredentialHelpers    map[string]string            `json:"credHelpers,omitempty"`
	Filename             string                       `json:"-"` // Note: for internal use only
	ServiceInspectFormat string                       `json:"serviceInspectFormat,omitempty"`
	ServicesFormat       string                       `json:"servicesFormat,omitempty"`
	TasksFormat          string                       `json:"tasksFormat,omitempty"`
	SecretFormat         string                       `json:"secretFormat,omitempty"`
	ConfigFormat         string                       `json:"configFormat,omitempty"`
	NodesFormat          string                       `json:"nodesFormat,omitempty"`
	PruneFilters         []string                     `json:"pruneFilters,omitempty"`
	Proxies              map[string]ProxyConfig       `json:"proxies,omitempty"`
	Experimental         string                       `json:"experimental,omitempty"`
	StackOrchestrator    string                       `json:"stackOrchestrator,omitempty"`
	Kubernetes           *KubernetesConfig            `json:"kubernetes,omitempty"`
	CurrentContext       string                       `json:"currentContext,omitempty"`
	CLIPluginsExtraDirs  []string                     `json:"cliPluginsExtraDirs,omitempty"`
	Plugins              map[string]map[string]string `json:"plugins,omitempty"`
	Aliases              map[string]string            `json:"aliases,omitempty"`
}

// ProxyConfig contains proxy configuration settings
type ProxyConfig struct {
	HTTPProxy  string `json:"httpProxy,omitempty"`
	HTTPSProxy string `json:"httpsProxy,omitempty"`
	NoProxy    string `json:"noProxy,omitempty"`
	FTPProxy   string `json:"ftpProxy,omitempty"`
}

// KubernetesConfig contains Kubernetes orchestrator settings
type KubernetesConfig struct {
	AllNamespaces string `json:"allNamespaces,omitempty"`
}

// New initializes an empty configuration file for the given filename 'fn'
func New(fn string) *ConfigFile {
	return &ConfigFile{
		AuthConfigs: make(map[string]types.AuthConfig),
		HTTPHeaders: make(map[string]string),
		Filename:    fn,
		Plugins:     make(map[string]map[string]string),
		Aliases:     make(map[string]string),
	}
}

// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
// auth config information with given directory and populates the receiver object
func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
	b, err := ioutil.ReadAll(configData)
	if err != nil {
		return err
	}

	if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
		arr := strings.Split(string(b), "\n")
		if len(arr) < 2 {
			return errors.Errorf("The Auth config file is empty")
		}
		authConfig := types.AuthConfig{}
		origAuth := strings.Split(arr[0], " = ")
		if len(origAuth) != 2 {
			return errors.Errorf("Invalid Auth config file")
		}
		authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
		if err != nil {
			return err
		}
		authConfig.ServerAddress = defaultIndexServer
		configFile.AuthConfigs[defaultIndexServer] = authConfig
	} else {
		for k, authConfig := range configFile.AuthConfigs {
			authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
			if err != nil {
				return err
			}
			authConfig.Auth = ""
			authConfig.ServerAddress = k
			configFile.AuthConfigs[k] = authConfig
		}
	}
	return nil
}

// LoadFromReader reads the configuration data given and sets up the auth config
// information with given directory and populates the receiver object
func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
	if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
		return err
	}
	var err error
	for addr, ac := range configFile.AuthConfigs {
		if ac.Auth != "" {
			ac.Username, ac.Password, err = decodeAuth(ac.Auth)
			if err != nil {
				return err
			}
		}
		ac.Auth = ""
		ac.ServerAddress = addr
		configFile.AuthConfigs[addr] = ac
	}
	return checkKubernetesConfiguration(configFile.Kubernetes)
}

// ContainsAuth returns whether there is authentication configured
// in this file or not.
func (configFile *ConfigFile) ContainsAuth() bool {
	return configFile.CredentialsStore != "" ||
		len(configFile.CredentialHelpers) > 0 ||
		len(configFile.AuthConfigs) > 0
}

// GetAuthConfigs returns the mapping of repo to auth configuration
func (configFile *ConfigFile) GetAuthConfigs() map[string]types.AuthConfig {
	return configFile.AuthConfigs
}

// SaveToWriter encodes and writes out all the authorization information to
// the given writer
func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
	// Encode sensitive data into a new/temp struct
	tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs))
	for k, authConfig := range configFile.AuthConfigs {
		authCopy := authConfig
		// encode and save the authstring, while blanking out the original fields
		authCopy.Auth = encodeAuth(&authCopy)
		authCopy.Username = ""
		authCopy.Password = ""
		authCopy.ServerAddress = ""
		tmpAuthConfigs[k] = authCopy
	}

	saveAuthConfigs := configFile.AuthConfigs
	configFile.AuthConfigs = tmpAuthConfigs
	defer func() { configFile.AuthConfigs = saveAuthConfigs }()

	data, err := json.MarshalIndent(configFile, "", "\t")
	if err != nil {
		return err
	}
	_, err = writer.Write(data)
	return err
}

// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() error {
	if configFile.Filename == "" {
		return errors.Errorf("Can't save config with empty filename")
	}

	dir := filepath.Dir(configFile.Filename)
	if err := os.MkdirAll(dir, 0700); err != nil {
		return err
	}
	temp, err := ioutil.TempFile(dir, filepath.Base(configFile.Filename))
	if err != nil {
		return err
	}
	err = configFile.SaveToWriter(temp)
	temp.Close()
	if err != nil {
		os.Remove(temp.Name())
		return err
	}
	// Try copying the current config file (if any) ownership and permissions
	copyFilePermissions(configFile.Filename, temp.Name())

	return os.Rename(temp.Name(), configFile.Filename)
}

// ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and
// then checking this against any environment variables provided to the container
func (configFile *ConfigFile) ParseProxyConfig(host string, runOpts map[string]*string) map[string]*string {
	var cfgKey string

	if _, ok := configFile.Proxies[host]; !ok {
		cfgKey = "default"
	} else {
		cfgKey = host
	}

	config := configFile.Proxies[cfgKey]
	permitted := map[string]*string{
		"HTTP_PROXY":  &config.HTTPProxy,
		"HTTPS_PROXY": &config.HTTPSProxy,
		"NO_PROXY":    &config.NoProxy,
		"FTP_PROXY":   &config.FTPProxy,
	}
	m := runOpts
	if m == nil {
		m = make(map[string]*string)
	}
	for k := range permitted {
		if *permitted[k] == "" {
			continue
		}
		if _, ok := m[k]; !ok {
			m[k] = permitted[k]
		}
		if _, ok := m[strings.ToLower(k)]; !ok {
			m[strings.ToLower(k)] = permitted[k]
		}
	}
	return m
}

// encodeAuth creates a base64 encoded string to containing authorization information
func encodeAuth(authConfig *types.AuthConfig) string {
	if authConfig.Username == "" && authConfig.Password == "" {
		return ""
	}

	authStr := authConfig.Username + ":" + authConfig.Password
	msg := []byte(authStr)
	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
	base64.StdEncoding.Encode(encoded, msg)
	return string(encoded)
}

// decodeAuth decodes a base64 encoded string and returns username and password
func decodeAuth(authStr string) (string, string, error) {
	if authStr == "" {
		return "", "", nil
	}

	decLen := base64.StdEncoding.DecodedLen(len(authStr))
	decoded := make([]byte, decLen)
	authByte := []byte(authStr)
	n, err := base64.StdEncoding.Decode(decoded, authByte)
	if err != nil {
		return "", "", err
	}
	if n > decLen {
		return "", "", errors.Errorf("Something went wrong decoding auth config")
	}
	arr := strings.SplitN(string(decoded), ":", 2)
	if len(arr) != 2 {
		return "", "", errors.Errorf("Invalid auth configuration file")
	}
	password := strings.Trim(arr[1], "\x00")
	return arr[0], password, nil
}

// GetCredentialsStore returns a new credentials store from the settings in the
// configuration file
func (configFile *ConfigFile) GetCredentialsStore(registryHostname string) credentials.Store {
	if helper := getConfiguredCredentialStore(configFile, registryHostname); helper != "" {
		return newNativeStore(configFile, helper)
	}
	return credentials.NewFileStore(configFile)
}

// var for unit testing.
var newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
	return credentials.NewNativeStore(configFile, helperSuffix)
}

// GetAuthConfig for a repository from the credential store
func (configFile *ConfigFile) GetAuthConfig(registryHostname string) (types.AuthConfig, error) {
	return configFile.GetCredentialsStore(registryHostname).Get(registryHostname)
}

// getConfiguredCredentialStore returns the credential helper configured for the
// given registry, the default credsStore, or the empty string if neither are
// configured.
func getConfiguredCredentialStore(c *ConfigFile, registryHostname string) string {
	if c.CredentialHelpers != nil && registryHostname != "" {
		if helper, exists := c.CredentialHelpers[registryHostname]; exists {
			return helper
		}
	}
	return c.CredentialsStore
}

// GetAllCredentials returns all of the credentials stored in all of the
// configured credential stores.
func (configFile *ConfigFile) GetAllCredentials() (map[string]types.AuthConfig, error) {
	auths := make(map[string]types.AuthConfig)
	addAll := func(from map[string]types.AuthConfig) {
		for reg, ac := range from {
			auths[reg] = ac
		}
	}

	defaultStore := configFile.GetCredentialsStore("")
	newAuths, err := defaultStore.GetAll()
	if err != nil {
		return nil, err
	}
	addAll(newAuths)

	// Auth configs from a registry-specific helper should override those from the default store.
	for registryHostname := range configFile.CredentialHelpers {
		newAuth, err := configFile.GetAuthConfig(registryHostname)
		if err != nil {
			return nil, err
		}
		auths[registryHostname] = newAuth
	}
	return auths, nil
}

// GetFilename returns the file name that this config file is based on.
func (configFile *ConfigFile) GetFilename() string {
	return configFile.Filename
}

// PluginConfig retrieves the requested option for the given plugin.
func (configFile *ConfigFile) PluginConfig(pluginname, option string) (string, bool) {
	if configFile.Plugins == nil {
		return "", false
	}
	pluginConfig, ok := configFile.Plugins[pluginname]
	if !ok {
		return "", false
	}
	value, ok := pluginConfig[option]
	return value, ok
}

// SetPluginConfig sets the option to the given value for the given
// plugin. Passing a value of "" will remove the option. If removing
// the final config item for a given plugin then also cleans up the
// overall plugin entry.
func (configFile *ConfigFile) SetPluginConfig(pluginname, option, value string) {
	if configFile.Plugins == nil {
		configFile.Plugins = make(map[string]map[string]string)
	}
	pluginConfig, ok := configFile.Plugins[pluginname]
	if !ok {
		pluginConfig = make(map[string]string)
		configFile.Plugins[pluginname] = pluginConfig
	}
	if value != "" {
		pluginConfig[option] = value
	} else {
		delete(pluginConfig, option)
	}
	if len(pluginConfig) == 0 {
		delete(configFile.Plugins, pluginname)
	}
}

func checkKubernetesConfiguration(kubeConfig *KubernetesConfig) error {
	if kubeConfig == nil {
		return nil
	}
	switch kubeConfig.AllNamespaces {
	case "":
	case "enabled":
	case "disabled":
	default:
		return fmt.Errorf("invalid 'kubernetes.allNamespaces' value, should be 'enabled' or 'disabled': %s", kubeConfig.AllNamespaces)
	}
	return nil
}
<commit_msg>Handle errors on close in config file write.<commit_after>package configfile

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/docker/cli/cli/config/credentials"
	"github.com/docker/cli/cli/config/types"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

const (
	// This constant is only used for really old config files when the
	// URL wasn't saved as part of the config file and it was just
	// assumed to be this value.
	defaultIndexServer = "https://index.docker.io/v1/"
)

// ConfigFile ~/.docker/config.json file info
type ConfigFile struct {
	AuthConfigs          map[string]types.AuthConfig  `json:"auths"`
	HTTPHeaders          map[string]string            `json:"HttpHeaders,omitempty"`
	PsFormat             string                       `json:"psFormat,omitempty"`
	ImagesFormat         string                       `json:"imagesFormat,omitempty"`
	NetworksFormat       string                       `json:"networksFormat,omitempty"`
	PluginsFormat        string                       `json:"pluginsFormat,omitempty"`
	VolumesFormat        string                       `json:"volumesFormat,omitempty"`
	StatsFormat          string                       `json:"statsFormat,omitempty"`
	DetachKeys           string                       `json:"detachKeys,omitempty"`
	CredentialsStore     string                       `json:"credsStore,omitempty"`
	CredentialHelpers    map[string]string            `json:"credHelpers,omitempty"`
	Filename             string                       `json:"-"` // Note: for internal use only
	ServiceInspectFormat string                       `json:"serviceInspectFormat,omitempty"`
	ServicesFormat       string                       `json:"servicesFormat,omitempty"`
	TasksFormat          string                       `json:"tasksFormat,omitempty"`
	SecretFormat         string                       `json:"secretFormat,omitempty"`
	ConfigFormat         string                       `json:"configFormat,omitempty"`
	NodesFormat          string                       `json:"nodesFormat,omitempty"`
	PruneFilters         []string                     `json:"pruneFilters,omitempty"`
	Proxies              map[string]ProxyConfig       `json:"proxies,omitempty"`
	Experimental         string                       `json:"experimental,omitempty"`
	StackOrchestrator    string                       `json:"stackOrchestrator,omitempty"`
	Kubernetes           *KubernetesConfig            `json:"kubernetes,omitempty"`
	CurrentContext       string                       `json:"currentContext,omitempty"`
	CLIPluginsExtraDirs  []string                     `json:"cliPluginsExtraDirs,omitempty"`
	Plugins              map[string]map[string]string `json:"plugins,omitempty"`
	Aliases              map[string]string            `json:"aliases,omitempty"`
}

// ProxyConfig contains proxy configuration settings
type ProxyConfig struct {
	HTTPProxy  string `json:"httpProxy,omitempty"`
	HTTPSProxy string `json:"httpsProxy,omitempty"`
	NoProxy    string `json:"noProxy,omitempty"`
	FTPProxy   string `json:"ftpProxy,omitempty"`
}

// KubernetesConfig contains Kubernetes orchestrator settings
type KubernetesConfig struct {
	AllNamespaces string `json:"allNamespaces,omitempty"`
}

// New initializes an empty configuration file for the given filename 'fn'
func New(fn string) *ConfigFile {
	return &ConfigFile{
		AuthConfigs: make(map[string]types.AuthConfig),
		HTTPHeaders: make(map[string]string),
		Filename:    fn,
		Plugins:     make(map[string]map[string]string),
		Aliases:     make(map[string]string),
	}
}

// LegacyLoadFromReader reads the non-nested configuration data given and sets up the
// auth config information with given directory and populates the receiver object
func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
	b, err := ioutil.ReadAll(configData)
	if err != nil {
		return err
	}

	if err := json.Unmarshal(b, &configFile.AuthConfigs); err != nil {
		arr := strings.Split(string(b), "\n")
		if len(arr) < 2 {
			return errors.Errorf("The Auth config file is empty")
		}
		authConfig := types.AuthConfig{}
		origAuth := strings.Split(arr[0], " = ")
		if len(origAuth) != 2 {
			return errors.Errorf("Invalid Auth config file")
		}
		authConfig.Username, authConfig.Password, err = decodeAuth(origAuth[1])
		if err != nil {
			return err
		}
		authConfig.ServerAddress = defaultIndexServer
		configFile.AuthConfigs[defaultIndexServer] = authConfig
	} else {
		for k, authConfig := range configFile.AuthConfigs {
			authConfig.Username, authConfig.Password, err = decodeAuth(authConfig.Auth)
			if err != nil {
				return err
			}
			authConfig.Auth = ""
			authConfig.ServerAddress = k
			configFile.AuthConfigs[k] = authConfig
		}
	}
	return nil
}

// LoadFromReader reads the configuration data given and sets up the auth config
// information with given directory and populates the receiver object
func (configFile *ConfigFile) LoadFromReader(configData io.Reader) error {
	if err := json.NewDecoder(configData).Decode(&configFile); err != nil {
		return err
	}
	var err error
	for addr, ac := range configFile.AuthConfigs {
		if ac.Auth != "" {
			ac.Username, ac.Password, err = decodeAuth(ac.Auth)
			if err != nil {
				return err
			}
		}
		ac.Auth = ""
		ac.ServerAddress = addr
		configFile.AuthConfigs[addr] = ac
	}
	return checkKubernetesConfiguration(configFile.Kubernetes)
}

// ContainsAuth returns whether there is authentication configured
// in this file or not.
func (configFile *ConfigFile) ContainsAuth() bool {
	return configFile.CredentialsStore != "" ||
		len(configFile.CredentialHelpers) > 0 ||
		len(configFile.AuthConfigs) > 0
}

// GetAuthConfigs returns the mapping of repo to auth configuration
func (configFile *ConfigFile) GetAuthConfigs() map[string]types.AuthConfig {
	return configFile.AuthConfigs
}

// SaveToWriter encodes and writes out all the authorization information to
// the given writer
func (configFile *ConfigFile) SaveToWriter(writer io.Writer) error {
	// Encode sensitive data into a new/temp struct
	tmpAuthConfigs := make(map[string]types.AuthConfig, len(configFile.AuthConfigs))
	for k, authConfig := range configFile.AuthConfigs {
		authCopy := authConfig
		// encode and save the authstring, while blanking out the original fields
		authCopy.Auth = encodeAuth(&authCopy)
		authCopy.Username = ""
		authCopy.Password = ""
		authCopy.ServerAddress = ""
		tmpAuthConfigs[k] = authCopy
	}

	saveAuthConfigs := configFile.AuthConfigs
	configFile.AuthConfigs = tmpAuthConfigs
	defer func() { configFile.AuthConfigs = saveAuthConfigs }()

	data, err := json.MarshalIndent(configFile, "", "\t")
	if err != nil {
		return err
	}
	_, err = writer.Write(data)
	return err
}

// Save encodes and writes out all the authorization information
func (configFile *ConfigFile) Save() (retErr error) {
	if configFile.Filename == "" {
		return errors.Errorf("Can't save config with empty filename")
	}

	dir := filepath.Dir(configFile.Filename)
	if err := os.MkdirAll(dir, 0700); err != nil {
		return err
	}
	temp, err := ioutil.TempFile(dir, filepath.Base(configFile.Filename))
	if err != nil {
		return err
	}
	defer func() {
		temp.Close()
		if retErr != nil {
			if err := os.Remove(temp.Name()); err != nil {
				logrus.WithError(err).WithField("file", temp.Name()).Debug("Error cleaning up temp file")
			}
		}
	}()

	err = configFile.SaveToWriter(temp)
	if err != nil {
		return err
	}

	if err := temp.Close(); err != nil {
		return errors.Wrap(err, "error closing temp file")
	}

	// Try copying the current config file (if any) ownership and permissions
	copyFilePermissions(configFile.Filename, temp.Name())
	return os.Rename(temp.Name(), configFile.Filename)
}

// ParseProxyConfig computes proxy configuration by retrieving the config for the provided host and
// then checking this against any environment variables provided to the container
func (configFile *ConfigFile) ParseProxyConfig(host string, runOpts map[string]*string) map[string]*string {
	var cfgKey string

	if _, ok := configFile.Proxies[host]; !ok {
		cfgKey = "default"
	} else {
		cfgKey = host
	}

	config := configFile.Proxies[cfgKey]
	permitted := map[string]*string{
		"HTTP_PROXY":  &config.HTTPProxy,
		"HTTPS_PROXY": &config.HTTPSProxy,
		"NO_PROXY":    &config.NoProxy,
		"FTP_PROXY":   &config.FTPProxy,
	}
	m := runOpts
	if m == nil {
		m = make(map[string]*string)
	}
	for k := range permitted {
		if *permitted[k] == "" {
			continue
		}
		if _, ok := m[k]; !ok {
			m[k] = permitted[k]
		}
		if _, ok := m[strings.ToLower(k)]; !ok {
			m[strings.ToLower(k)] = permitted[k]
		}
	}
	return m
}

// encodeAuth creates a base64 encoded string to containing authorization information
func encodeAuth(authConfig *types.AuthConfig) string {
	if authConfig.Username == "" && authConfig.Password == "" {
		return ""
	}

	authStr := authConfig.Username + ":" + authConfig.Password
	msg := []byte(authStr)
	encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
	base64.StdEncoding.Encode(encoded, msg)
	return string(encoded)
}

// decodeAuth decodes a base64 encoded string and returns username and password
func decodeAuth(authStr string) (string, string, error) {
	if authStr == "" {
		return "", "", nil
	}

	decLen := base64.StdEncoding.DecodedLen(len(authStr))
	decoded := make([]byte, decLen)
	authByte := []byte(authStr)
	n, err := base64.StdEncoding.Decode(decoded, authByte)
	if err != nil {
		return "", "", err
	}
	if n > decLen {
		return "", "", errors.Errorf("Something went wrong decoding auth config")
	}
	arr := strings.SplitN(string(decoded), ":", 2)
	if len(arr) != 2 {
		return "", "", errors.Errorf("Invalid auth configuration file")
	}
	password := strings.Trim(arr[1], "\x00")
	return arr[0], password, nil
}

// GetCredentialsStore returns a new credentials store from the settings in the
// configuration file
func (configFile *ConfigFile) GetCredentialsStore(registryHostname string) credentials.Store {
	if helper := getConfiguredCredentialStore(configFile, registryHostname); helper != "" {
		return newNativeStore(configFile, helper)
	}
	return credentials.NewFileStore(configFile)
}

// var for unit testing.
var newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
	return credentials.NewNativeStore(configFile, helperSuffix)
}

// GetAuthConfig for a repository from the credential store
func (configFile *ConfigFile) GetAuthConfig(registryHostname string) (types.AuthConfig, error) {
	return configFile.GetCredentialsStore(registryHostname).Get(registryHostname)
}

// getConfiguredCredentialStore returns the credential helper configured for the
// given registry, the default credsStore, or the empty string if neither are
// configured.
func getConfiguredCredentialStore(c *ConfigFile, registryHostname string) string {
	if c.CredentialHelpers != nil && registryHostname != "" {
		if helper, exists := c.CredentialHelpers[registryHostname]; exists {
			return helper
		}
	}
	return c.CredentialsStore
}

// GetAllCredentials returns all of the credentials stored in all of the
// configured credential stores.
func (configFile *ConfigFile) GetAllCredentials() (map[string]types.AuthConfig, error) {
	auths := make(map[string]types.AuthConfig)
	addAll := func(from map[string]types.AuthConfig) {
		for reg, ac := range from {
			auths[reg] = ac
		}
	}

	defaultStore := configFile.GetCredentialsStore("")
	newAuths, err := defaultStore.GetAll()
	if err != nil {
		return nil, err
	}
	addAll(newAuths)

	// Auth configs from a registry-specific helper should override those from the default store.
	for registryHostname := range configFile.CredentialHelpers {
		newAuth, err := configFile.GetAuthConfig(registryHostname)
		if err != nil {
			return nil, err
		}
		auths[registryHostname] = newAuth
	}
	return auths, nil
}

// GetFilename returns the file name that this config file is based on.
func (configFile *ConfigFile) GetFilename() string {
	return configFile.Filename
}

// PluginConfig retrieves the requested option for the given plugin.
func (configFile *ConfigFile) PluginConfig(pluginname, option string) (string, bool) {
	if configFile.Plugins == nil {
		return "", false
	}
	pluginConfig, ok := configFile.Plugins[pluginname]
	if !ok {
		return "", false
	}
	value, ok := pluginConfig[option]
	return value, ok
}

// SetPluginConfig sets the option to the given value for the given
// plugin. Passing a value of "" will remove the option. If removing
// the final config item for a given plugin then also cleans up the
// overall plugin entry.
func (configFile *ConfigFile) SetPluginConfig(pluginname, option, value string) {
	if configFile.Plugins == nil {
		configFile.Plugins = make(map[string]map[string]string)
	}
	pluginConfig, ok := configFile.Plugins[pluginname]
	if !ok {
		pluginConfig = make(map[string]string)
		configFile.Plugins[pluginname] = pluginConfig
	}
	if value != "" {
		pluginConfig[option] = value
	} else {
		delete(pluginConfig, option)
	}
	if len(pluginConfig) == 0 {
		delete(configFile.Plugins, pluginname)
	}
}

func checkKubernetesConfiguration(kubeConfig *KubernetesConfig) error {
	if kubeConfig == nil {
		return nil
	}
	switch kubeConfig.AllNamespaces {
	case "":
	case "enabled":
	case "disabled":
	default:
		return fmt.Errorf("invalid 'kubernetes.allNamespaces' value, should be 'enabled' or 'disabled': %s", kubeConfig.AllNamespaces)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

const (
	defaultEnv      = "NOTI_DEFAULT"
	pushbulletEnv   = "NOTI_PUSHBULLET_TOK"
	slackChannelEnv = "NOTI_SLACK_DEST"
	slackEnv        = "NOTI_SLACK_TOK"
	soundEnv        = "NOTI_SOUND"
	voiceEnv        = "NOTI_VOICE"

	version = "2.0.0-rc2"
)

var (
	title       = flag.String("t", "noti", "")
	message     = flag.String("m", "Done!", "")
	showVersion = flag.Bool("v", false, "")
	showHelp    = flag.Bool("h", false, "")

	// Notifications
	banner     = flag.Bool("b", false, "")
	pushbullet = flag.Bool("p", false, "")
	speech     = flag.Bool("s", false, "")
	slack      = flag.Bool("k", false, "")
)

func init() {
	flag.StringVar(title, "title", "noti", "")
	flag.StringVar(message, "message", "Done!", "")
	flag.BoolVar(showVersion, "version", false, "")
	flag.BoolVar(showHelp, "help", false, "")

	// Notifications
	flag.BoolVar(banner, "banner", false, "")
	flag.BoolVar(speech, "speech", false, "")
	flag.BoolVar(pushbullet, "pushbullet", false, "")
	flag.BoolVar(slack, "slack", false, "")
}

func main() {
	log.SetFlags(0)
	flag.Parse()

	if *showVersion {
		fmt.Printf("noti version %s\n", version)
		return
	}
	if *showHelp {
		flag.Usage()
		return
	}

	runUtility()

	if defs := strings.TrimSpace(os.Getenv(defaultEnv)); defs != "" {
		*banner = strings.Contains(defs, "banner")
		*speech = strings.Contains(defs, "speech")
		*pushbullet = strings.Contains(defs, "pushbullet")
		*slack = strings.Contains(defs, "slack")
	} else {
		var explicitSet bool
		var val bool

		flag.Visit(func(f *flag.Flag) {
			if f.Name == "b" || f.Name == "banner" {
				explicitSet = true
				// Ignoring error, false on error is fine.
				val, _ = strconv.ParseBool(f.Value.String())
			}
		})

		// If the user explicitly set -banner, then use the value that the user
		// set, but if no banner flag was set, then the default is true.
		if explicitSet {
			*banner = val
		} else {
			*banner = true
		}
	}

	if *banner {
		bannerNotify()
	}
	if *speech {
		speechNotify()
	}
	if *pushbullet {
		pushbulletNotify()
	}
	if *slack {
		slackNotify()
	}
}

func runUtility() {
	var cmd *exec.Cmd

	if args := flag.Args(); len(args) < 1 {
		return
	}

	cmd = exec.Command(args[0], args[1:]...)
	*title = args[0]

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		*title = *title + " failed"
		*message = err.Error()
	}
}
<commit_msg>Fix syntax error<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

const (
	defaultEnv      = "NOTI_DEFAULT"
	pushbulletEnv   = "NOTI_PUSHBULLET_TOK"
	slackChannelEnv = "NOTI_SLACK_DEST"
	slackEnv        = "NOTI_SLACK_TOK"
	soundEnv        = "NOTI_SOUND"
	voiceEnv        = "NOTI_VOICE"

	version = "2.0.0-rc2"
)

var (
	title       = flag.String("t", "noti", "")
	message     = flag.String("m", "Done!", "")
	showVersion = flag.Bool("v", false, "")
	showHelp    = flag.Bool("h", false, "")

	// Notifications
	banner     = flag.Bool("b", false, "")
	pushbullet = flag.Bool("p", false, "")
	speech     = flag.Bool("s", false, "")
	slack      = flag.Bool("k", false, "")
)

func init() {
	flag.StringVar(title, "title", "noti", "")
	flag.StringVar(message, "message", "Done!", "")
	flag.BoolVar(showVersion, "version", false, "")
	flag.BoolVar(showHelp, "help", false, "")

	// Notifications
	flag.BoolVar(banner, "banner", false, "")
	flag.BoolVar(speech, "speech", false, "")
	flag.BoolVar(pushbullet, "pushbullet", false, "")
	flag.BoolVar(slack, "slack", false, "")
}

func main() {
	log.SetFlags(0)
	flag.Parse()

	if *showVersion {
		fmt.Printf("noti version %s\n", version)
		return
	}
	if *showHelp {
		flag.Usage()
		return
	}

	runUtility()

	if defs := strings.TrimSpace(os.Getenv(defaultEnv)); defs != "" {
		*banner = strings.Contains(defs, "banner")
		*speech = strings.Contains(defs, "speech")
		*pushbullet = strings.Contains(defs, "pushbullet")
		*slack = strings.Contains(defs, "slack")
	} else {
		var explicitSet bool
		var val bool

		flag.Visit(func(f *flag.Flag) {
			if f.Name == "b" || f.Name == "banner" {
				explicitSet = true
				// Ignoring error, false on error is fine.
				val, _ = strconv.ParseBool(f.Value.String())
			}
		})

		// If the user explicitly set -banner, then use the value that the user
		// set, but if no banner flag was set, then the default is true.
		if explicitSet {
			*banner = val
		} else {
			*banner = true
		}
	}

	if *banner {
		bannerNotify()
	}
	if *speech {
		speechNotify()
	}
	if *pushbullet {
		pushbulletNotify()
	}
	if *slack {
		slackNotify()
	}
}

func runUtility() {
	var cmd *exec.Cmd

	args := flag.Args()
	if len(args) < 1 {
		return
	}

	cmd = exec.Command(args[0], args[1:]...)
	*title = args[0]

	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		*title = *title + " failed"
		*message = err.Error()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/fatih/structs"
	"github.com/maliceio/go-plugin-utils/database/elasticsearch"
	"github.com/maliceio/go-plugin-utils/utils"
	"github.com/parnurzeal/gorequest"
	"github.com/urfave/cli"
	"github.com/willf/bloom"
)

var (
	// Version stores the plugin's version
	Version string

	// BuildTime stores the plugin's build time
	BuildTime string

	// ErrorRate stores the bloomfilter desired error-rate
	ErrorRate string

	// NSRL fields
	sha1         = 0
	md5          = 1
	crc32        = 2
	fileName     = 3
	fileSize     = 4
	productCode  = 5
	opSystemCode = 6
	specialCode  = 7
)

const (
	name     = "nsrl"
	category = "intel"
)

type pluginResults struct {
	ID   string      `json:"id" gorethink:"id,omitempty"`
	Data ResultsData `json:"nsrl" gorethink:"nsrl"`
}

// Nsrl json object
type Nsrl struct {
	Results ResultsData `json:"nsrl"`
}

// ResultsData json object
type ResultsData struct {
	Found bool `json:"found"`
}

func printMarkDownTable(nsrl Nsrl) {
	fmt.Println("#### NSRL Database")
	if nsrl.Results.Found {
		fmt.Println(" - Found :white_check_mark:")
	} else {
		fmt.Println(" - Not Found :grey_question:")
	}
}

func lineCounter(r io.Reader) (uint64, error) {
	buf := make([]byte, 32*1024)
	var count uint64
	lineSep := []byte{'\n'}

	for {
		c, err := r.Read(buf)
		count += uint64(bytes.Count(buf[:c], lineSep))

		switch {
		case err == io.EOF:
			return count, nil

		case err != nil:
			return count, err
		}
	}
}

// build bloomfilter from NSRL database
func buildFilter() {

	// open NSRL database
	nsrlDB, err := os.Open("NSRLFile.txt")
	utils.Assert(err)
	defer nsrlDB.Close()
	// count lines in NSRL database
	lines, err := lineCounter(nsrlDB)
	log.Debugf("Number of lines in NSRLFile.txt: %d", lines)
	// write line count to file LINECOUNT
	buf := new(bytes.Buffer)
	utils.Assert(binary.Write(buf, binary.LittleEndian, lines))
	utils.Assert(ioutil.WriteFile("LINECOUNT", buf.Bytes(), 0644))

	// Create new bloomfilter with size = number of lines in NSRL database
	erate, err := strconv.ParseFloat(ErrorRate, 64)
	utils.Assert(err)

	filter := bloom.NewWithEstimates(uint(lines), erate)

	// jump back to the begining of the file
	_, err = nsrlDB.Seek(0, io.SeekStart)
	utils.Assert(err)

	log.Debug("Loading NSRL database into bloomfilter")
	reader := csv.NewReader(nsrlDB)
	// strip off csv header
	_, _ = reader.Read()
	for {
		record, err := reader.Read()

		if err == io.EOF {
			break
		}
		utils.Assert(err)

		// Add md5
		filter.Add([]byte(record[md5]))
		// log.Debug(record)
	}

	bloomFile, err := os.Create("nsrl.bloom")
	utils.Assert(err)
	defer bloomFile.Close()

	log.Debug("Writing bloomfilter to disk")
	_, err = filter.WriteTo(bloomFile)
	utils.Assert(err)
}

// lookUp queries the NSRL bloomfilter for a hash
func lookUp(hash string, timeout int) ResultsData {

	var lines uint64
	nsrlResults := ResultsData{}

	// read line count from file LINECOUNT
	lineCount, err := ioutil.ReadFile("LINECOUNT")
	utils.Assert(err)
	buf := bytes.NewReader(lineCount)
	utils.Assert(binary.Read(buf, binary.LittleEndian, &lines))
	log.Debugf("Number of lines in NSRLFile.txt: %d", lines)

	// Create new bloomfilter with size = number of lines in NSRL database
	erate, err := strconv.ParseFloat(ErrorRate, 64)
	filter := bloom.NewWithEstimates(uint(lines), erate)

	// load NSRL bloomfilter from file
	f, err := os.Open("nsrl.bloom")
	utils.Assert(err)
	_, err = filter.ReadFrom(f)
	utils.Assert(err)

	// test of existance of hash in bloomfilter
	nsrlResults.Found = filter.TestString(hash)

	return nsrlResults
}

func printStatus(resp gorequest.Response, body string, errs []error) {
	fmt.Println(body)
}

func main() {

	var elastic string

	cli.AppHelpTemplate = utils.AppHelpTemplate
	app := cli.NewApp()

	app.Name = "nsrl"
	app.Author = "blacktop"
	app.Email = "https://github.com/blacktop"
	app.Version = Version + ", BuildTime: " + BuildTime
	app.Compiled, _ = time.Parse("20060102", BuildTime)
	app.Usage = "Malice NSRL Plugin"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:        "elasitcsearch",
			Value:       "",
			Usage:       "elasitcsearch address for Malice to store results",
			EnvVar:      "MALICE_ELASTICSEARCH",
			Destination: &elastic,
		},
		cli.BoolFlag{
			Name:   "post, p",
			Usage:  "POST results to Malice webhook",
			EnvVar: "MALICE_ENDPOINT",
		},
		cli.BoolFlag{
			Name:   "proxy, x",
			Usage:  "proxy settings for Malice webhook endpoint",
			EnvVar: "MALICE_PROXY",
		},
		cli.BoolFlag{
			Name:  "table, t",
			Usage: "output as Markdown table",
		},
		cli.IntFlag{
			Name:   "timeout",
			Value:  60,
			Usage:  "malice plugin timeout (in seconds)",
			EnvVar: "MALICE_TIMEOUT",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "build",
			Aliases: []string{"b"},
			Usage:   "Build bloomfilter from NSRL database",
			Action: func(c *cli.Context) error {
				if c.GlobalBool("verbose") {
					log.SetLevel(log.DebugLevel)
				}

				// build bloomfilter
				buildFilter()
				return nil
			},
		},
		{
			Name:      "lookup",
			Aliases:   []string{"l"},
			Usage:     "Query NSRL for hash",
			ArgsUsage: "MD5 to query NSRL with",
			Action: func(c *cli.Context) error {
				if c.Args().Present() {
					hash := c.Args().First()

					if c.GlobalBool("verbose") {
						log.SetLevel(log.DebugLevel)
					}

					nsrl := Nsrl{Results: lookUp(hash, c.Int("timeout"))}

					// upsert into Database
					elasticsearch.InitElasticSearch(elastic)
					elasticsearch.WritePluginResultsToDatabase(elasticsearch.PluginResults{
						ID:       utils.Getopt("MALICE_SCANID", hash),
						Name:     name,
						Category: category,
						Data:     structs.Map(nsrl.Results),
					})

					if c.GlobalBool("table") {
						printMarkDownTable(nsrl)
					} else {
						nsrlJSON, err := json.Marshal(nsrl)
						utils.Assert(err)
						if c.GlobalBool("post") {
							request := gorequest.New()
							if c.GlobalBool("proxy") {
								request = gorequest.New().Proxy(os.Getenv("MALICE_PROXY"))
							}
							request.Post(os.Getenv("MALICE_ENDPOINT")).
								Set("X-Malice-ID", utils.Getopt("MALICE_SCANID", hash)).
								Send(string(nsrlJSON)).
								End(printStatus)

							return nil
						}
						fmt.Println(string(nsrlJSON))
					}
				} else {
					log.Fatal(fmt.Errorf("Please supply a MD5 hash to query NSRL with."))
				}
				return nil
			},
		},
	}

	err := app.Run(os.Args)
	utils.Assert(err)
}
<commit_msg>constants are constant<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/fatih/structs"
	"github.com/maliceio/go-plugin-utils/database/elasticsearch"
	"github.com/maliceio/go-plugin-utils/utils"
	"github.com/parnurzeal/gorequest"
	"github.com/urfave/cli"
	"github.com/willf/bloom"
)

var (
	// Version stores the plugin's version
	Version string

	// BuildTime stores the plugin's build time
	BuildTime string

	// ErrorRate stores the bloomfilter desired error-rate
	ErrorRate string
)

const (
	// NSRL fields
	sha1         = 0
	md5          = 1
	crc32        = 2
	fileName     = 3
	fileSize     = 4
	productCode  = 5
	opSystemCode = 6
	specialCode  = 7
)

const (
	name     = "nsrl"
	category = "intel"
)

type pluginResults struct {
	ID   string      `json:"id" gorethink:"id,omitempty"`
	Data ResultsData `json:"nsrl" gorethink:"nsrl"`
}

// Nsrl json object
type Nsrl struct {
	Results ResultsData `json:"nsrl"`
}

// ResultsData json object
type ResultsData struct {
	Found bool `json:"found"`
}

func printMarkDownTable(nsrl Nsrl) {
	fmt.Println("#### NSRL Database")
	if nsrl.Results.Found {
		fmt.Println(" - Found :white_check_mark:")
	} else {
		fmt.Println(" - Not Found :grey_question:")
	}
}

func lineCounter(r io.Reader) (uint64, error) {
	buf := make([]byte, 32*1024)
	var count uint64
	lineSep := []byte{'\n'}

	for {
		c, err := r.Read(buf)
		count += uint64(bytes.Count(buf[:c], lineSep))

		switch {
		case err == io.EOF:
			return count, nil

		case err != nil:
			return count, err
		}
	}
}

// build bloomfilter from NSRL database
func buildFilter() {

	// open NSRL database
	nsrlDB, err := os.Open("NSRLFile.txt")
	utils.Assert(err)
	defer nsrlDB.Close()
	// count lines in NSRL database
	lines, err := lineCounter(nsrlDB)
	log.Debugf("Number of lines in NSRLFile.txt: %d", lines)
	// write line count to file LINECOUNT
	buf := new(bytes.Buffer)
	utils.Assert(binary.Write(buf, binary.LittleEndian, lines))
	utils.Assert(ioutil.WriteFile("LINECOUNT", buf.Bytes(), 0644))

	// Create new bloomfilter with size = number of lines in NSRL database
	erate, err := strconv.ParseFloat(ErrorRate, 64)
	utils.Assert(err)

	filter := bloom.NewWithEstimates(uint(lines), erate)

	// jump back to the begining of the file
	_, err = nsrlDB.Seek(0, io.SeekStart)
	utils.Assert(err)

	log.Debug("Loading NSRL database into bloomfilter")
	reader := csv.NewReader(nsrlDB)
	// strip off csv header
	_, _ = reader.Read()
	for {
		record, err := reader.Read()

		if err == io.EOF {
			break
		}
		utils.Assert(err)

		// Add md5
		filter.Add([]byte(record[md5]))
		// log.Debug(record)
	}

	bloomFile, err := os.Create("nsrl.bloom")
	utils.Assert(err)
	defer bloomFile.Close()

	log.Debug("Writing bloomfilter to disk")
	_, err = filter.WriteTo(bloomFile)
	utils.Assert(err)
}

// lookUp queries the NSRL bloomfilter for a hash
func lookUp(hash string, timeout int) ResultsData {

	var lines uint64
	nsrlResults := ResultsData{}

	// read line count from file LINECOUNT
	lineCount, err := ioutil.ReadFile("LINECOUNT")
	utils.Assert(err)
	buf := bytes.NewReader(lineCount)
	utils.Assert(binary.Read(buf, binary.LittleEndian, &lines))
	log.Debugf("Number of lines in NSRLFile.txt: %d", lines)

	// Create new bloomfilter with size = number of lines in NSRL database
	erate, err := strconv.ParseFloat(ErrorRate, 64)
	filter := bloom.NewWithEstimates(uint(lines), erate)

	// load NSRL bloomfilter from file
	f, err := os.Open("nsrl.bloom")
	utils.Assert(err)
	_, err = filter.ReadFrom(f)
	utils.Assert(err)

	// test of existance of hash in bloomfilter
	nsrlResults.Found = filter.TestString(hash)

	return nsrlResults
}

func printStatus(resp gorequest.Response, body string, errs []error) {
	fmt.Println(body)
}

func main() {

	var elastic string

	cli.AppHelpTemplate = utils.AppHelpTemplate
	app := cli.NewApp()

	app.Name = "nsrl"
	app.Author = "blacktop"
	app.Email = "https://github.com/blacktop"
	app.Version = Version + ", BuildTime: " + BuildTime
	app.Compiled, _ = time.Parse("20060102", BuildTime)
	app.Usage = "Malice NSRL Plugin"
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, V",
			Usage: "verbose output",
		},
		cli.StringFlag{
			Name:        "elasitcsearch",
			Value:       "",
			Usage:       "elasitcsearch address for Malice to store results",
			EnvVar:      "MALICE_ELASTICSEARCH",
			Destination: &elastic,
		},
		cli.BoolFlag{
			Name:   "post, p",
			Usage:  "POST results to Malice webhook",
			EnvVar: "MALICE_ENDPOINT",
		},
		cli.BoolFlag{
			Name:   "proxy, x",
			Usage:  "proxy settings for Malice webhook endpoint",
			EnvVar: "MALICE_PROXY",
		},
		cli.BoolFlag{
			Name:  "table, t",
			Usage: "output as Markdown table",
		},
		cli.IntFlag{
			Name:   "timeout",
			Value:  60,
			Usage:  "malice plugin timeout (in seconds)",
			EnvVar: "MALICE_TIMEOUT",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:    "build",
			Aliases: []string{"b"},
			Usage:   "Build bloomfilter from NSRL database",
			Action: func(c *cli.Context) error {
				if c.GlobalBool("verbose") {
					log.SetLevel(log.DebugLevel)
				}

				// build bloomfilter
				buildFilter()
				return nil
			},
		},
		{
			Name:      "lookup",
			Aliases:   []string{"l"},
			Usage:     "Query NSRL for hash",
			ArgsUsage: "MD5 to query NSRL with",
			Action: func(c *cli.Context) error {
				if c.Args().Present() {
					hash := c.Args().First()

					if c.GlobalBool("verbose") {
						log.SetLevel(log.DebugLevel)
					}

					nsrl := Nsrl{Results: lookUp(hash, c.Int("timeout"))}

					// upsert into Database
					elasticsearch.InitElasticSearch(elastic)
					elasticsearch.WritePluginResultsToDatabase(elasticsearch.PluginResults{
						ID:       utils.Getopt("MALICE_SCANID", hash),
						Name:     name,
						Category: category,
						Data:     structs.Map(nsrl.Results),
					})

					if c.GlobalBool("table") {
						printMarkDownTable(nsrl)
					} else {
						nsrlJSON, err := json.Marshal(nsrl)
						utils.Assert(err)
						if c.GlobalBool("post") {
							request := gorequest.New()
							if c.GlobalBool("proxy") {
								request = gorequest.New().Proxy(os.Getenv("MALICE_PROXY"))
							}
							request.Post(os.Getenv("MALICE_ENDPOINT")).
								Set("X-Malice-ID", utils.Getopt("MALICE_SCANID", hash)).
								Send(string(nsrlJSON)).
								End(printStatus)

							return nil
						}
						fmt.Println(string(nsrlJSON))
					}
				} else {
					log.Fatal(fmt.Errorf("Please supply a MD5 hash to query NSRL with."))
				}
				return nil
			},
		},
	}

	err := app.Run(os.Args)
	utils.Assert(err)
}
<|endoftext|>


<commit_before>package kumo

import (
	"fmt"
	"log"
	"sync"

	"github.com/sww/kumo/nntp"
)

type Connection struct {
	group  string
	client *nntp.NNTP
}

type ConnectionPool struct {
	size        int
	connections chan Connection
}

func InitConnectionPool(server, username, password string, port, connections int, ssl bool) (*ConnectionPool, error) {
	pool := new(ConnectionPool)
	pool.connections = make(chan Connection, connections)
	pool.size = connections

	wait := new(sync.WaitGroup)
	wait.Add(connections)

	var errors []error

	for i := 0; i < connections; i++ {
		go func() {
			defer wait.Done()

			connection := new(Connection)
			client, err := nntp.New("tcp", fmt.Sprintf("%v:%v", server, port), ssl)
			if err != nil {
				log.Printf("Error Connecting to \"%v\"", server)
				errors = append(errors, err)
			}

			msg, err := client.Auth(username, password)
			if err != nil {
				log.Printf("Problem authenticating, got msg: %v", msg)
				errors = append(errors, err)
			}

			connection.group = ""
			connection.client = client

			pool.connections <- *connection
		}()
	}

	wait.Wait()

	if len(errors) > 0 {
		// Return an error if any connection failed for now.
		return nil, errors[0]
	} else {
		return pool, nil
	}
}
<commit_msg>Return an error only if all connections fail.<commit_after>package kumo

import (
	"errors"
	"fmt"
	"log"
	"sync"

	"github.com/sww/kumo/nntp"
)

type Connection struct {
	group  string
	client *nntp.NNTP
}

type ConnectionPool struct {
	size        int
	connections chan Connection
}

func InitConnectionPool(server, username, password string, port, connections int, ssl bool) (*ConnectionPool, error) {
	pool := &ConnectionPool{
		connections: make(chan Connection, connections),
		size:        connections,
	}

	wait := new(sync.WaitGroup)
	wait.Add(connections)

	for i := 0; i < connections; i++ {
		go func() {
			defer wait.Done()

			connection := new(Connection)
			client, err := nntp.New("tcp", fmt.Sprintf("%v:%v", server, port), ssl)
			if err != nil {
				log.Printf("Error Connecting to \"%v\"", server)
				return
			}

			msg, err := client.Auth(username, password)
			if err != nil {
				log.Printf("Problem authenticating, got msg: %v", msg)
				return
			}

			connection.group = ""
			connection.client = client

			pool.connections <- *connection
		}()
	}

	wait.Wait()

	if len(pool.connections) < 1 {
		return nil, errors.New("no connections available")
	}

	return pool, nil
}
<|endoftext|>


<commit_before>// This source file is part of the Packet Guardian project.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"net/http"
	"strconv"
	"time"

	"github.com/onesimus-systems/packet-guardian/src/common"
	"github.com/onesimus-systems/packet-guardian/src/models"
)

type User struct {
	e *common.Environment
}

func NewUserController(e *common.Environment) *User {
	return &User{e: e}
}

func (u *User) UserHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		u.saveUserHandler(w, r)
	} else if r.Method == "DELETE" {
		u.deleteUserHandler(w, r)
	}
}

func (u *User) saveUserHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(u.e, username)
	if err != nil {
		u.e.Log.Errorf("Error saving user: %s", err.Error())
		common.NewAPIResponse("Error saving user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	// Password
	password := r.FormValue("password")
	if password != "" {
		if password == "-1" {
			user.RemovePassword()
		} else {
			user.NewPassword(password)
		}
	}

	// Device limit
	limitStr := r.FormValue("device_limit")
	if limitStr != "" {
		limit, err := strconv.Atoi(limitStr)
		if err != nil {
			u.e.Log.Errorf("Error saving user: %s", err.Error())
			common.NewAPIResponse("device_limit must be a number", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		user.DeviceLimit = models.UserDeviceLimit(limit)
	}

	// Default device expiration
	expTypeStr := r.FormValue("expiration_type")
	devExpiration := r.FormValue("device_expiration")
	if expTypeStr != "" || devExpiration != "" {
		if expTypeStr == "" && devExpiration != "" {
			common.NewAPIResponse("Error saving user: Expiration type not given", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}

		expType, err := strconv.Atoi(expTypeStr)
		if err != nil {
			u.e.Log.Errorf("Error saving user: %s", err.Error())
			common.NewAPIResponse("Expiration type must be an integer", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		user.DeviceExpiration.Mode = models.UserExpiration(expType)
		if user.DeviceExpiration.Mode == models.UserDeviceExpirationGlobal ||
			user.DeviceExpiration.Mode == models.UserDeviceExpirationNever ||
			user.DeviceExpiration.Mode == models.UserDeviceExpirationRolling {
			user.DeviceExpiration.Value = 0
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationSpecific {
			t, err := time.Parse(common.TimeFormat, devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid time format", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.DeviceExpiration.Value = t.Unix()
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationDaily {
			secs, err := common.ParseTime(devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid time format", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.DeviceExpiration.Value = secs
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationDuration {
			d, err := time.ParseDuration(devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid duration", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			// time.Duration's Second() returns a float that contains the nanoseconds as well
			// For sanity we don't care and don't want the nanoseconds
			user.DeviceExpiration.Value = int64(d / time.Second)
		} else {
			common.NewAPIResponse("Invalid device expiration type", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	}

	// Valid dates
	validStart := r.FormValue("valid_start")
	validEnd := r.FormValue("valid_end")
	if validStart == "0" && validEnd == "0" {
		user.ValidForever = true
		user.ValidStart = time.Unix(0, 0)
		user.ValidEnd = user.ValidStart
	} else {
		user.ValidForever = false
		if validStart != "" {
			t, err := time.Parse(common.TimeFormat, validStart)
			if err != nil {
				common.NewAPIResponse("Invalid time format: valid_start", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.ValidStart = t
		}
		if validEnd != "" {
			t, err := time.Parse(common.TimeFormat, validEnd)
			if err != nil {
				common.NewAPIResponse("Invalid time format: valid_end", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.ValidEnd = t
		}
		if user.ValidEnd.Before(user.ValidStart) {
			common.NewAPIResponse("valid_start must be before valid_end", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	}

	canManage := r.FormValue("can_manage")
	if canManage != "" {
		user.CanManage = (canManage == "1")
	}

	if err := user.Save(); err != nil {
		u.e.Log.Errorf("Error saving user: %s", err.Error())
		common.NewAPIResponse("Error saving user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	if user.ID == 0 {
		u.e.Log.Infof("Admin %s created user %s", models.GetUserFromContext(r).Username, user.Username)
		common.NewAPIResponse("User created successfully", nil).WriteResponse(w, http.StatusNoContent)
		return
	}
	u.e.Log.Infof("Admin %s edited user %s", models.GetUserFromContext(r).Username, user.Username)
	common.NewAPIResponse("User saved successfully", nil).WriteResponse(w, http.StatusNoContent)
}

func (u *User) deleteUserHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(u.e, username)
	if err != nil {
		u.e.Log.Errorf("Error getting user for deletion: %s", err.Error())
		common.NewAPIResponse("Error deleting user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	if err := user.Delete(); err != nil {
		u.e.Log.Errorf("Error deleting user: %s", err.Error())
		common.NewAPIResponse("Error deleting user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	u.e.Log.Infof("Admin %s deleted user %s", models.GetUserFromContext(r).Username, user.Username)
	common.NewAPIResponse("User deleted", nil).WriteResponse(w, http.StatusNoContent)
}
<commit_msg>Fixed bug where created user message would never show<commit_after>// This source file is part of the Packet Guardian project.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"net/http"
	"strconv"
	"time"

	"github.com/onesimus-systems/packet-guardian/src/common"
	"github.com/onesimus-systems/packet-guardian/src/models"
)

type User struct {
	e *common.Environment
}

func NewUserController(e *common.Environment) *User {
	return &User{e: e}
}

func (u *User) UserHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		u.saveUserHandler(w, r)
	} else if r.Method == "DELETE" {
		u.deleteUserHandler(w, r)
	}
}

func (u *User) saveUserHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(u.e, username)
	if err != nil {
		u.e.Log.Errorf("Error saving user: %s", err.Error())
		common.NewAPIResponse("Error saving user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	// Password
	password := r.FormValue("password")
	if password != "" {
		if password == "-1" {
			user.RemovePassword()
		} else {
			user.NewPassword(password)
		}
	}

	// Device limit
	limitStr := r.FormValue("device_limit")
	if limitStr != "" {
		limit, err := strconv.Atoi(limitStr)
		if err != nil {
			u.e.Log.Errorf("Error saving user: %s", err.Error())
			common.NewAPIResponse("device_limit must be a number", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		user.DeviceLimit = models.UserDeviceLimit(limit)
	}

	// Default device expiration
	expTypeStr := r.FormValue("expiration_type")
	devExpiration := r.FormValue("device_expiration")
	if expTypeStr != "" || devExpiration != "" {
		if expTypeStr == "" && devExpiration != "" {
			common.NewAPIResponse("Error saving user: Expiration type not given", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}

		expType, err := strconv.Atoi(expTypeStr)
		if err != nil {
			u.e.Log.Errorf("Error saving user: %s", err.Error())
			common.NewAPIResponse("Expiration type must be an integer", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
		user.DeviceExpiration.Mode = models.UserExpiration(expType)
		if user.DeviceExpiration.Mode == models.UserDeviceExpirationGlobal ||
			user.DeviceExpiration.Mode == models.UserDeviceExpirationNever ||
			user.DeviceExpiration.Mode == models.UserDeviceExpirationRolling {
			user.DeviceExpiration.Value = 0
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationSpecific {
			t, err := time.Parse(common.TimeFormat, devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid time format", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.DeviceExpiration.Value = t.Unix()
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationDaily {
			secs, err := common.ParseTime(devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid time format", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.DeviceExpiration.Value = secs
		} else if user.DeviceExpiration.Mode == models.UserDeviceExpirationDuration {
			d, err := time.ParseDuration(devExpiration)
			if err != nil {
				common.NewAPIResponse("Invalid duration", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			// time.Duration's Second() returns a float that contains the nanoseconds as well
			// For sanity we don't care and don't want the nanoseconds
			user.DeviceExpiration.Value = int64(d / time.Second)
		} else {
			common.NewAPIResponse("Invalid device expiration type", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	}

	// Valid dates
	validStart := r.FormValue("valid_start")
	validEnd := r.FormValue("valid_end")
	if validStart == "0" && validEnd == "0" {
		user.ValidForever = true
		user.ValidStart = time.Unix(0, 0)
		user.ValidEnd = user.ValidStart
	} else {
		user.ValidForever = false
		if validStart != "" {
			t, err := time.Parse(common.TimeFormat, validStart)
			if err != nil {
				common.NewAPIResponse("Invalid time format: valid_start", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.ValidStart = t
		}
		if validEnd != "" {
			t, err := time.Parse(common.TimeFormat, validEnd)
			if err != nil {
				common.NewAPIResponse("Invalid time format: valid_end", nil).WriteResponse(w, http.StatusBadRequest)
				return
			}
			user.ValidEnd = t
		}
		if user.ValidEnd.Before(user.ValidStart) {
			common.NewAPIResponse("valid_start must be before valid_end", nil).WriteResponse(w, http.StatusBadRequest)
			return
		}
	}

	canManage := r.FormValue("can_manage")
	if canManage != "" {
		user.CanManage = (canManage == "1")
	}

	newUser := (user.ID == 0) // A user get's an ID when it's saved

	if err := user.Save(); err != nil {
		u.e.Log.Errorf("Error saving user: %s", err.Error())
		common.NewAPIResponse("Error saving user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	if newUser {
		u.e.Log.Infof("Admin %s created user %s", models.GetUserFromContext(r).Username, user.Username)
		common.NewAPIResponse("User created successfully", nil).WriteResponse(w, http.StatusNoContent)
		return
	}
	u.e.Log.Infof("Admin %s edited user %s", models.GetUserFromContext(r).Username, user.Username)
	common.NewAPIResponse("User saved successfully", nil).WriteResponse(w, http.StatusNoContent)
}

func (u *User) deleteUserHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("username")
	if username == "" {
		common.NewAPIResponse("Username required", nil).WriteResponse(w, http.StatusBadRequest)
		return
	}

	user, err := models.GetUserByUsername(u.e, username)
	if err != nil {
		u.e.Log.Errorf("Error getting user for deletion: %s", err.Error())
		common.NewAPIResponse("Error deleting user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}

	if err := user.Delete(); err != nil {
		u.e.Log.Errorf("Error deleting user: %s", err.Error())
		common.NewAPIResponse("Error deleting user", nil).WriteResponse(w, http.StatusInternalServerError)
		return
	}
	u.e.Log.Infof("Admin %s deleted user %s", models.GetUserFromContext(r).Username, user.Username)
	common.NewAPIResponse("User deleted", nil).WriteResponse(w, http.StatusNoContent)
}
<|endoftext|>


<commit_before>// cmd_measurements.go

package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"strconv"
)

// init injects our measurement-related commands
func init() {
	cliCommands = append(cliCommands, cli.Command{
		Name: "measurements",
		Aliases: []string{
			"measures",
			"m",
		},
		Usage:       "measurements-related keywords",
		Description: "All the commands for measurements",
		Subcommands: []cli.Command{
			{
				Name:        "list",
				Aliases:     []string{"ls"},
				Usage:       "lists all measurements",
				Description: "displays all measurements",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:        "country, c",
						Usage:       "filter on country",
						Destination: &fCountry,
					},
					cli.StringFlag{
						Name:        "asn",
						Usage:       "filter on asn",
						Value:       "",
						Destination: &fAsn,
					},
					cli.BoolFlag{
						Name:        "A, all",
						Usage:       "all measurements even inactive ones",
						Destination: &fAllMeasurements,
					},
					cli.BoolFlag{
						Name:        "is-anchor",
						Usage:       "select anchor measurements",
						Destination: &fIsAnchor,
					},
					cli.StringFlag{
						Name:        "t, type",
						Usage:       "filter on measurement type",
						Value:       "",
						Destination: &fMeasureType,
					},
				},
				Action: measurementsList,
			},
			{
				Name:        "info",
				Usage:       "info for one measurement",
				Description: "gives info for one measurement",
				Action:      measurementInfo,
			},
			{
				Name:        "results",
				Aliases:     []string{"r", "res"},
				Usage:       "results for one measurement",
				Description: "returns results for one measurement",
				Action:      measurementResults,
			},
			{
				Name:        "delete",
				Aliases:     []string{"rm", "del", "destroy", "stop"},
				Usage:       "info for one measurement",
				Description: "stops one measurement (or all)",
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:        "A",
						Usage:       "select all measurements",
						Destination: &fAllMeasurements,
					},
				},
				Action: measurementDelete,
			},
		},
	})
}

// displayMeasurement returns a string with one measurement
func displayMeasurement(m *atlas.Measurement, verbose bool) (res string) {
	if verbose {
		res = fmt.Sprintf("%v\n", m)
	} else {
		res = fmt.Sprintf("ID: %d type: %s description: %s Target: %s\n", m.ID, m.Type, m.Description, m.Target)
	}
	return
}

// displayAllMeasurements returns a string with all measurements
func displayAllMeasurements(ml *[]atlas.Measurement, verbose bool) (res string) {
	res = ""
	for _, m := range *ml {
		res += displayMeasurement(&m, verbose)
	}
	return
}

// measurementsList returns a list of measurements according to parameters
func measurementsList(c *cli.Context) error {
	opts := make(map[string]string)

	opts = mergeOptions(opts, commonFlags)

	// Check global parameters
	opts = checkGlobalFlags(opts)

	if fVerbose {
		displayOptions(opts)
	}

	q, err := client.GetMeasurements(opts)
	if err != nil {
		log.Fatalf("GetMeasurements err: %v - q:%v", err, q)
	}
	fmt.Printf("Got %d measurements with %v\n", len(q), opts)
	fmt.Print(displayAllMeasurements(&q, fVerbose))

	return nil
}

// measurementInfo is for one measurement only
func measurementInfo(c *cli.Context) error {
	args := c.Args()
	if len(args) == 0 {
		log.Fatal("Error: you must specify a measurement ID!")
	}

	id, _ := strconv.Atoi(args[0])

	p, err := client.GetMeasurement(id)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	fmt.Print(displayMeasurement(p, fVerbose))

	return nil
}

// measurementResults returns the result part of the measurement
func measurementResults(c *cli.Context) error {
	args := c.Args()
	if len(args) == 0 {
		log.Fatal("Error: you must specify a measurement ID!")
	}

	id, _ := strconv.Atoi(args[0])

	m, err := client.GetMeasurement(id)
	if err != nil {
		fmt.Printf("err: %v", err)
		os.Exit(1)
	}

	// m.Result is an URI pointing to results, fetch it
	if m.Result == "" {
		fmt.Println("Empty result")
	}

	resp, err := client.FetchResult(m.Result)
	if err != nil {
		return fmt.Errorf("bad net/http answer for %s: %v", m.Result, err)
	}

	fmt.Print(resp)
	return nil
}

func measurementDelete(c *cli.Context) (err error) {

	if fAllMeasurements {
		opts := make(map[string]string)

		// Check global parameters
		opts = checkGlobalFlags(opts)

		if fVerbose {
			displayOptions(opts)
		}

		list, err := client.GetMeasurements(opts)
		if err != nil {
			err = fmt.Errorf("Delete all failed: %v", err)
		} else {
			for _, m := range list {
				err = client.DeleteMeasurement(m.ID)
				if err != nil {
					err = fmt.Errorf("Error: can not delete measurement %d", m.ID)
				}
			}
			fmt.Println("All measurements stopped.")
		}
	} else {
		args := c.Args()
		if args[0] == "" {
			log.Fatal("Error: you must specify a measurement ID!")
		}

		id, _ := strconv.Atoi(args[0])
		err = client.DeleteMeasurement(id)
	}

	return
}
<commit_msg>Need to see the url in debug.<commit_after>// cmd_measurements.go

package main

import (
	"fmt"
	"github.com/keltia/ripe-atlas"
	"github.com/urfave/cli"
	"log"
	"os"
	"strconv"
)

// init injects our measurement-related commands
func init() {
	cliCommands = append(cliCommands, cli.Command{
		Name: "measurements",
		Aliases: []string{
			"measures",
			"m",
		},
		Usage:       "measurements-related keywords",
		Description: "All the commands for measurements",
		Subcommands: []cli.Command{
			{
				Name:        "list",
				Aliases:     []string{"ls"},
				Usage:       "lists all measurements",
				Description: "displays all measurements",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:        "country, c",
						Usage:       "filter on country",
						Destination: &fCountry,
					},
					cli.StringFlag{
						Name:        "asn",
						Usage:       "filter on asn",
						Value:       "",
						Destination: &fAsn,
					},
					cli.BoolFlag{
						Name:        "A, all",
						Usage:       "all measurements even inactive ones",
						Destination: &fAllMeasurements,
					},
					cli.BoolFlag{
						Name:        "is-anchor",
						Usage:       "select anchor measurements",
						Destination: &fIsAnchor,
					},
					cli.StringFlag{
						Name:        "t, type",
						Usage:       "filter on measurement type",
						Value:       "",
						Destination: &fMeasureType,
					},
				},
				Action: measurementsList,
			},
			{
				Name:        "info",
				Usage:       "info for one measurement",
				Description: "gives info for one measurement",
				Action:      measurementInfo,
			},
			{
				Name:        "results",
				Aliases:     []string{"r", "res"},
				Usage:       "results for one measurement",
				Description: "returns results for one measurement",
				Action:      measurementResults,
			},
			{
				Name:        "delete",
				Aliases:     []string{"rm", "del", "destroy", "stop"},
				Usage:       "info for one measurement",
				Description: "stops one measurement (or all)",
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:        "A",
						Usage:       "select all measurements",
						Destination: &fAllMeasurements,
					},
				},
				Action: measurementDelete,
			},
		},
	})
}

// displayMeasurement returns a string with one measurement
func displayMeasurement(m *atlas.Measurement, verbose bool) (res string) {
	if verbose {
		res = fmt.Sprintf("%v\n", m)
	} else {
		res = fmt.Sprintf("ID: %d type: %s description: %s Target: %s\n", m.ID, m.Type, m.Description, m.Target)
	}
	return
}

// displayAllMeasurements returns a string with all measurements
func displayAllMeasurements(ml *[]atlas.Measurement, verbose bool) (res string) {
	res = ""
	for _, m := range *ml {
		res += displayMeasurement(&m, verbose)
	}
	return
}

// measurementsList returns a list of measurements according to parameters
func measurementsList(c *cli.Context) error {
	opts := make(map[string]string)

	opts = mergeOptions(opts, commonFlags)

	// Check global parameters
	opts = checkGlobalFlags(opts)

	if fVerbose {
		displayOptions(opts)
	}

	q, err := client.GetMeasurements(opts)
	if err != nil {
		log.Fatalf("GetMeasurements err: %v - q:%v", err, q)
	}
	fmt.Printf("Got %d measurements with %v\n", len(q), opts)
	fmt.Print(displayAllMeasurements(&q, fVerbose))

	return nil
}

// measurementInfo is for one measurement only
func measurementInfo(c *cli.Context) error {
	args := c.Args()
	if len(args) == 0 {
		log.Fatal("Error: you must specify a measurement ID!")
	}

	id, _ := strconv.Atoi(args[0])

	p, err := client.GetMeasurement(id)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	fmt.Print(displayMeasurement(p, fVerbose))

	return nil
}

// measurementResults returns the result part of the measurement
func measurementResults(c *cli.Context) error {
	args := c.Args()
	if len(args) == 0 {
		log.Fatal("Error: you must specify a measurement ID!")
	}

	id, _ := strconv.Atoi(args[0])

	m, err := client.GetMeasurement(id)
	if err != nil {
		fmt.Printf("err: %v", err)
		os.Exit(1)
	}

	debug("m=%d url=%s", id, m.Result)

	// m.Result is an URI pointing to results, fetch it
	if m.Result == "" {
		fmt.Println("Empty result")
	}

	resp, err := client.FetchResult(m.Result)
	if err != nil {
		return fmt.Errorf("bad net/http answer for %s: %v", m.Result, err)
	}

	fmt.Print(resp)
	return nil
}

func measurementDelete(c *cli.Context) (err error) {

	if fAllMeasurements {
		opts := make(map[string]string)

		// Check global parameters
		opts = checkGlobalFlags(opts)

		if fVerbose {
			displayOptions(opts)
		}

		list, err := client.GetMeasurements(opts)
		if err != nil {
			err = fmt.Errorf("Delete all failed: %v", err)
		} else {
			for _, m := range list {
				err = client.DeleteMeasurement(m.ID)
				if err != nil {
					err = fmt.Errorf("Error: can not delete measurement %d", m.ID)
				}
			}
			fmt.Println("All measurements stopped.")
		}
	} else {
		args := c.Args()
		if args[0] == "" {
			log.Fatal("Error: you must specify a measurement ID!")
		}

		id, _ := strconv.Atoi(args[0])
		err = client.DeleteMeasurement(id)
	}

	return
}
<|endoftext|>


<commit_before>package gce

import (
	"fmt"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/coreos/coreos-cloudinit/datasource"
	"github.com/coreos/coreos-cloudinit/datasource/metadata"
)

const (
	apiVersion   = "computeMetadata/v1/"
	metadataPath = apiVersion
	userdataPath = apiVersion + "instance/attributes/user-data"
)

type metadataService struct {
	metadata.MetadataService
}

func NewDatasource(root string) *metadataService {
	return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})}
}

func (ms metadataService) FetchMetadata() (datasource.Metadata, error) {
	public, err := ms.fetchIP("instance/network-interfaces/0/access-configs/0/external-ip")
	if err != nil {
		return datasource.Metadata{}, err
	}
	local, err := ms.fetchIP("instance/network-interfaces/0/ip")
	if err != nil {
		return datasource.Metadata{}, err
	}
	hostname, err := ms.fetchString("instance/hostname")
	if err != nil {
		return datasource.Metadata{}, err
	}

	projectSshKeys, err := ms.fetchString("project/attributes/sshKeys")
	if err != nil {
		return datasource.Metadata{}, err
	}
	instanceSshKeys, err := ms.fetchString("instance/attributes/sshKeys")
	if err != nil {
		return datasource.Metadata{}, err
	}

	keyStrings := strings.Split(projectSshKeys+"\n"+instanceSshKeys, "\n")

	sshPublicKeys := map[string]string{}
	i := 0
	for _, keyString := range keyStrings {
		keySlice := strings.SplitN(keyString, ":", 2)
		if len(keySlice) == 2 {
			key := strings.TrimSpace(keySlice[1])
			if key != "" {
				sshPublicKeys[strconv.Itoa(i)] = strings.TrimSpace(keySlice[1])
				i++
			}
		}
	}

	return datasource.Metadata{
		PublicIPv4:    public,
		PrivateIPv4:   local,
		Hostname:      hostname,
		SSHPublicKeys: sshPublicKeys,
	}, nil
}

func (ms metadataService) Type() string {
	return "gce-metadata-service"
}

func (ms metadataService) fetchString(key string) (string, error) {
	data, err := ms.FetchData(ms.MetadataUrl() + key)
	if err != nil {
		return "", err
	}

	return string(data), nil
}

func (ms metadataService) fetchIP(key string) (net.IP, error) {
	str, err := ms.fetchString(key)
	if err != nil {
		return nil, err
	}

	if str == "" {
		return nil, nil
	}

	if ip := net.ParseIP(str); ip != nil {
		return ip, nil
	} else {
		return nil, fmt.Errorf("couldn't parse %q as IP address", str)
	}
}

func (ms metadataService) FetchUserdata() ([]byte, error) {
	data, err := ms.FetchData(ms.UserdataUrl())
	if err != nil {
		return nil, err
	}
	if len(data) == 0 {
		data, err = ms.FetchData(ms.MetadataUrl() + "instance/attributes/startup-script")
		if err != nil {
			return nil, err
		}
	}
	return data, nil
}
<commit_msg>Copyright comment cleanup<commit_after>// Copyright 2016 CoreOS, Inc.
//
// 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 gce

import (
	"fmt"
	"net"
	"net/http"
	"strconv"
	"strings"

	"github.com/coreos/coreos-cloudinit/datasource"
	"github.com/coreos/coreos-cloudinit/datasource/metadata"
)

const (
	apiVersion   = "computeMetadata/v1/"
	metadataPath = apiVersion
	userdataPath = apiVersion + "instance/attributes/user-data"
)

type metadataService struct {
	metadata.MetadataService
}

func NewDatasource(root string) *metadataService {
	return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath, http.Header{"Metadata-Flavor": {"Google"}})}
}

func (ms metadataService) FetchMetadata() (datasource.Metadata, error) {
	public, err := ms.fetchIP("instance/network-interfaces/0/access-configs/0/external-ip")
	if err != nil {
		return datasource.Metadata{}, err
	}
	local, err := ms.fetchIP("instance/network-interfaces/0/ip")
	if err != nil {
		return datasource.Metadata{}, err
	}
	hostname, err := ms.fetchString("instance/hostname")
	if err != nil {
		return datasource.Metadata{}, err
	}

	projectSshKeys, err := ms.fetchString("project/attributes/sshKeys")
	if err != nil {
		return datasource.Metadata{}, err
	}
	instanceSshKeys, err := ms.fetchString("instance/attributes/sshKeys")
	if err != nil {
		return datasource.Metadata{}, err
	}

	keyStrings := strings.Split(projectSshKeys+"\n"+instanceSshKeys, "\n")

	sshPublicKeys := map[string]string{}
	i := 0
	for _, keyString := range keyStrings {
		keySlice := strings.SplitN(keyString, ":", 2)
		if len(keySlice) == 2 {
			key := strings.TrimSpace(keySlice[1])
			if key != "" {
				sshPublicKeys[strconv.Itoa(i)] = strings.TrimSpace(keySlice[1])
				i++
			}
		}
	}

	return datasource.Metadata{
		PublicIPv4:    public,
		PrivateIPv4:   local,
		Hostname:      hostname,
		SSHPublicKeys: sshPublicKeys,
	}, nil
}

func (ms metadataService) Type() string {
	return "gce-metadata-service"
}

func (ms metadataService) fetchString(key string) (string, error) {
	data, err := ms.FetchData(ms.MetadataUrl() + key)
	if err != nil {
		return "", err
	}

	return string(data), nil
}

func (ms metadataService) fetchIP(key string) (net.IP, error) {
	str, err := ms.fetchString(key)
	if err != nil {
		return nil, err
	}

	if str == "" {
		return nil, nil
	}

	if ip := net.ParseIP(str); ip != nil {
		return ip, nil
	} else {
		return nil, fmt.Errorf("couldn't parse %q as IP address", str)
	}
}

func (ms metadataService) FetchUserdata() ([]byte, error) {
	data, err := ms.FetchData(ms.UserdataUrl())
	if err != nil {
		return nil, err
	}
	if len(data) == 0 {
		data, err = ms.FetchData(ms.MetadataUrl() + "instance/attributes/startup-script")
		if err != nil {
			return nil, err
		}
	}
	return data, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	tc "github.com/thijzert/go-termcolours"
	"github.com/thijzert/speeldoos"
	"github.com/thijzert/speeldoos/lib/hivemind"
	"github.com/thijzert/speeldoos/lib/wavreader"
	"github.com/thijzert/speeldoos/lib/zipmap"
	"io"
	"log"
	"os"
	"path"
	"strings"
	"time"
)

type condenseJob struct {
	Carrier   *speeldoos.Carrier
	OutputDir string
}

func (job condenseJob) Run(h hivemind.JC) error {
	zm := zipmap.New()
	defer zm.Close()

	h.SetTitle(job.Carrier.ID)
	var err error

	done := false
	for _, pf := range job.Carrier.Performances {
		for _, sf := range pf.SourceFiles {
			dn := path.Join(Config.LibraryDir, path.Dir(sf.Filename), "folder.jpg")
			if zm.Exists(dn) {
				if err = zm.CopyTo(dn, path.Join(job.OutputDir, "folder.jpg")); err != nil {
					done = true
					break
				}
			}
		}
		if done {
			break
		}
	}

	for _, pf := range job.Carrier.Performances {
		title := "(no title)"
		if len(pf.Work.Title) > 0 {
			title = pf.Work.Title[0].Title
		}

		h.Printf("%s: now processing: %s - %s", tc.Green(job.Carrier.ID), pf.Work.Composer.Name, title)

		if len(pf.SourceFiles) == 0 {
			h.Printf("%s - %s has no source files!\n", pf.Work.Composer.Name, title)
			continue
		}
		outp := fmt.Sprintf("%s - %s.mp3", pf.Work.Composer.Name, title)
		outp = path.Join(job.OutputDir, outp)

		// set up mp3writer
		out, err := os.Create(outp)
		if err != nil {
			return err
		}
		defer out.Close()

		var wout io.WriteCloser = nil

		for _, fn := range pf.SourceFiles {
			f, err := zm.Get(path.Join(Config.LibraryDir, fn.Filename))

			wav, err := wavreader.FromFLAC(f)
			if err != nil {
				h.Println(err.Error())
				continue
			}
			wav.Init()
			defer wav.Close()

			if wout == nil {
				wout, err = wavreader.ToMP3(out, wav.Channels, wav.SampleRate, wav.BitsPerSample)
				if err != nil {
					h.Println(err.Error())
					continue
				}
			}

			_, err = io.Copy(wout, wav)
			if err != nil {
				return err
			}
		}

		if wout == nil {
			break
		}
		wout.Close()

		tags := &mFile{
			Artist:     pf.Work.Composer.Name, // MP3 players are dumb
			Soloist:    pf.Work.Composer.Name, // very dumb
			Album:      job.Carrier.Name,
			Composer:   pf.Work.Composer.Name,
			Performers: make([]string, 0, 2),
			Year:       pf.Work.Year, // Furthermore, the `id3v2` program is also extremely dumb, as it seems to ignore pre-1900 dates
		}
		for _, tit := range pf.Work.Title {
			tags.Title = tit.Title
			break
		}
		for _, p := range pf.Performers {
			tags.Performers = append(tags.Performers, p.Name)

			if p.Role == "soloist" || p.Role == "performer" || p.Role == "" || p.Role == "orchestra" || p.Role == "ensemble" {
				if tags.Orchestra == "" {
					tags.Orchestra = p.Name
				} else {
					tags.Orchestra = tags.Orchestra + "/" + p.Name
				}
			} else if p.Role == "conductor" {
				if tags.Conductor == "" {
					tags.Conductor = p.Name
				} else {
					tags.Conductor = tags.Conductor + "/" + p.Name
				}
			}
		}

		cmd := id3tags(tags, outp)
		if err := cmd.Run(); err != nil {
			return err
		}
	}

	if err := os.Chtimes(job.OutputDir, time.Now(), time.Now()); err != nil {
		return err
	}
	return nil
}

func condense_main(args []string) {
	d, err := os.Open(Config.LibraryDir)
	croak(err)

	files, err := d.Readdir(0)
	croak(err)

	croak(os.MkdirAll(Config.Condense.OutputDir, 0755))

	hive := hivemind.New(Config.ConcurrentJobs)

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		xml := path.Join(Config.LibraryDir, file.Name())
		if len(xml) < 5 || xml[len(xml)-4:] != ".xml" {
			continue
		}

		foo, err := speeldoos.ImportCarrier(xml)
		if err != nil {
			log.Print(err)
			continue
		}

		if foo.ID == "" {
			log.Printf("Carrier in file '%s' has an empty ID. Skipping.", file.Name())
			continue
		}

		outdir := foo.ID
		outdir = strings.Replace(outdir, "/", "-", -1)
		outdir = strings.Replace(outdir, "\n", " ", -1)
		outdir = path.Join(Config.Condense.OutputDir, outdir)
		iout, err := os.Stat(outdir)
		if err == nil {
			if iout.ModTime().Before(file.ModTime()) {
				log.Printf("removing %s", outdir)
				os.RemoveAll(outdir)
			} else {
				log.Printf("skipping '%s' - up to date", foo.ID)
				continue
			}
		}
		croak(os.Mkdir(outdir, 0755))
		tim := file.ModTime().Add(-24 * time.Hour)
		croak(os.Chtimes(outdir, tim, tim))

		hive.AddJob(condenseJob{foo, outdir})
	}

	hive.Wait()
}
<commit_msg>Respect lame encoding configuration<commit_after>package main

import (
	"fmt"
	tc "github.com/thijzert/go-termcolours"
	"github.com/thijzert/speeldoos"
	"github.com/thijzert/speeldoos/lib/hivemind"
	"github.com/thijzert/speeldoos/lib/wavreader"
	"github.com/thijzert/speeldoos/lib/zipmap"
	"io"
	"log"
	"os"
	"path"
	"strings"
	"time"
)

type condenseJob struct {
	Wavconf   wavreader.Config
	Carrier   *speeldoos.Carrier
	OutputDir string
}

func (job condenseJob) Run(h hivemind.JC) error {
	zm := zipmap.New()
	defer zm.Close()

	h.SetTitle(job.Carrier.ID)
	var err error

	done := false
	for _, pf := range job.Carrier.Performances {
		for _, sf := range pf.SourceFiles {
			dn := path.Join(Config.LibraryDir, path.Dir(sf.Filename), "folder.jpg")
			if zm.Exists(dn) {
				if err = zm.CopyTo(dn, path.Join(job.OutputDir, "folder.jpg")); err != nil {
					done = true
					break
				}
			}
		}
		if done {
			break
		}
	}

	for _, pf := range job.Carrier.Performances {
		title := "(no title)"
		if len(pf.Work.Title) > 0 {
			title = pf.Work.Title[0].Title
		}

		h.Printf("%s: now processing: %s - %s", tc.Green(job.Carrier.ID), pf.Work.Composer.Name, title)

		if len(pf.SourceFiles) == 0 {
			h.Printf("%s - %s has no source files!\n", pf.Work.Composer.Name, title)
			continue
		}
		outp := fmt.Sprintf("%s - %s.mp3", pf.Work.Composer.Name, title)
		outp = path.Join(job.OutputDir, outp)

		// set up mp3writer
		out, err := os.Create(outp)
		if err != nil {
			return err
		}
		defer out.Close()

		var wout io.WriteCloser = nil

		for _, fn := range pf.SourceFiles {
			f, err := zm.Get(path.Join(Config.LibraryDir, fn.Filename))

			wav, err := job.Wavconf.FromFLAC(f)
			if err != nil {
				h.Println(err.Error())
				continue
			}
			wav.Init()
			defer wav.Close()

			if wout == nil {
				wout, err = job.Wavconf.ToMP3(out, wav.Channels, wav.SampleRate, wav.BitsPerSample)
				if err != nil {
					h.Println(err.Error())
					continue
				}
			}

			_, err = io.Copy(wout, wav)
			if err != nil {
				return err
			}
		}

		if wout == nil {
			break
		}
		wout.Close()

		tags := &mFile{
			Artist:     pf.Work.Composer.Name, // MP3 players are dumb
			Soloist:    pf.Work.Composer.Name, // very dumb
			Album:      job.Carrier.Name,
			Composer:   pf.Work.Composer.Name,
			Performers: make([]string, 0, 2),
			Year:       pf.Work.Year, // Furthermore, the `id3v2` program is also extremely dumb, as it seems to ignore pre-1900 dates
		}
		for _, tit := range pf.Work.Title {
			tags.Title = tit.Title
			break
		}
		for _, p := range pf.Performers {
			tags.Performers = append(tags.Performers, p.Name)

			if p.Role == "soloist" || p.Role == "performer" || p.Role == "" || p.Role == "orchestra" || p.Role == "ensemble" {
				if tags.Orchestra == "" {
					tags.Orchestra = p.Name
				} else {
					tags.Orchestra = tags.Orchestra + "/" + p.Name
				}
			} else if p.Role == "conductor" {
				if tags.Conductor == "" {
					tags.Conductor = p.Name
				} else {
					tags.Conductor = tags.Conductor + "/" + p.Name
				}
			}
		}

		cmd := id3tags(tags, outp)
		if err := cmd.Run(); err != nil {
			return err
		}
	}

	if err := os.Chtimes(job.OutputDir, time.Now(), time.Now()); err != nil {
		return err
	}
	return nil
}

func condense_main(args []string) {
	wavconf := wavreader.Config{
		LamePath:   Config.Tools.Lame,
		FlacPath:   Config.Tools.Flac,
		VBRQuality: Config.Condense.Quality,
	}

	d, err := os.Open(Config.LibraryDir)
	croak(err)

	files, err := d.Readdir(0)
	croak(err)

	croak(os.MkdirAll(Config.Condense.OutputDir, 0755))

	hive := hivemind.New(Config.ConcurrentJobs)

	for _, file := range files {
		if file.IsDir() {
			continue
		}
		xml := path.Join(Config.LibraryDir, file.Name())
		if len(xml) < 5 || xml[len(xml)-4:] != ".xml" {
			continue
		}

		foo, err := speeldoos.ImportCarrier(xml)
		if err != nil {
			log.Print(err)
			continue
		}

		if foo.ID == "" {
			log.Printf("Carrier in file '%s' has an empty ID. Skipping.", file.Name())
			continue
		}

		outdir := foo.ID
		outdir = strings.Replace(outdir, "/", "-", -1)
		outdir = strings.Replace(outdir, "\n", " ", -1)
		outdir = path.Join(Config.Condense.OutputDir, outdir)
		iout, err := os.Stat(outdir)
		if err == nil {
			if iout.ModTime().Before(file.ModTime()) {
				log.Printf("removing %s", outdir)
				os.RemoveAll(outdir)
			} else {
				log.Printf("skipping '%s' - up to date", foo.ID)
				continue
			}
		}
		croak(os.Mkdir(outdir, 0755))
		tim := file.ModTime().Add(-24 * time.Hour)
		croak(os.Chtimes(outdir, tim, tim))

		hive.AddJob(condenseJob{wavconf, foo, outdir})
	}

	hive.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"time"
	"b00lduck/datalogger/display/framebuffer"
	"b00lduck/datalogger/display/touchscreen"
	"image"
	"image/jpeg"
	"strings"
	"image/png"
	"image/gif"
	"b00lduck/datalogger/display/gui"
	"b00lduck/datalogger/display/tools"
	"fmt"
	"b00lduck/datalogger/display/i2c/hm5883l"
)

func main() {

	var mm hmc5883l.HMC5883L

	mm, err := hmc5883l.CreateHMC5883LI2c(1)
	if (err != nil) {
		mm = hmc5883l.CreateHMC5883LMock()
		fmt.Println("WARNING: HMC5883L magnetometer init failed, using mock instead. No real data will be available!")

	}

	fb := framebuffer.Framebuffer{}
	fb.Open(os.Args[1])
	defer fb.Close()
	//data := fb.Data()

	ts := touchscreen.Touchscreen{}
	ts.Open(os.Args[2])
	defer ts.Close()
	go ts.Run()

	background := loadImage("bg.png")
	arrowUp := loadImage("arrow_up.gif")
	arrowDown := loadImage("arrow_down.gif")

	gui := gui.NewGui()

	gui.SetBackground(background)
	for i := 0; i < 8; i ++ {
		gui.AddButton(arrowUp, 20 + i * 35, 60 )
		gui.AddButton(arrowDown, 20 + i * 35, 140 )
	}

	go gui.Run(fb, &ts.Event)

	for {
		time.Sleep(100 * time.Millisecond)
		vector, err := mm.ReadVector()
		tools.ErrorCheck(err)
		fmt.Printf("X:%d Y:%d Z:%d\n", vector.X, vector.Y, vector.Z)
	}

}

func loadImage(filename string) image.Image {

	f, err := os.Open("images/" + filename)
	tools.ErrorCheck(err)

	var img image.Image = nil

	lowerFilename := strings.ToLower(filename)
	switch {
		case strings.HasSuffix(lowerFilename, ".jpg"):
			img, err = jpeg.Decode(f)
		case strings.HasSuffix(lowerFilename, ".png"):
			img, err = png.Decode(f)
		case strings.HasSuffix(lowerFilename, ".gif"):
			img, err = gif.Decode(f)
	}

	tools.ErrorCheck(err)

	return img
}
<commit_msg>DISPLAY: removed buttons<commit_after>package main

import (
	"os"
	"time"
	"b00lduck/datalogger/display/framebuffer"
	"b00lduck/datalogger/display/touchscreen"
	"image"
	"image/jpeg"
	"strings"
	"image/png"
	"image/gif"
	"b00lduck/datalogger/display/gui"
	"b00lduck/datalogger/display/tools"
	"fmt"
	"b00lduck/datalogger/display/i2c/hm5883l"
)

func main() {

	var mm hmc5883l.HMC5883L

	mm, err := hmc5883l.CreateHMC5883LI2c(1)
	if (err != nil) {
		mm = hmc5883l.CreateHMC5883LMock()
		fmt.Println("WARNING: HMC5883L magnetometer init failed, using mock instead. No real data will be available!")

	}

	fb := framebuffer.Framebuffer{}
	fb.Open(os.Args[1])
	defer fb.Close()
	//data := fb.Data()

	ts := touchscreen.Touchscreen{}
	ts.Open(os.Args[2])
	defer ts.Close()
	go ts.Run()

	background := loadImage("bg.png")
	//arrowUp := loadImage("arrow_up.gif")
	//arrowDown := loadImage("arrow_down.gif")

	gui := gui.NewGui()

	gui.SetBackground(background)
	/*
	for i := 0; i < 8; i ++ {
		gui.AddButton(arrowUp, 20 + i * 35, 60 )
		gui.AddButton(arrowDown, 20 + i * 35, 140 )
	}
	*/

	go gui.Run(fb, &ts.Event)

	for {
		time.Sleep(100 * time.Millisecond)
		vector, err := mm.ReadVector()
		tools.ErrorCheck(err)
		fmt.Printf("X:%d Y:%d Z:%d\n", vector.X, vector.Y, vector.Z)
	}

}

func loadImage(filename string) image.Image {

	f, err := os.Open("images/" + filename)
	tools.ErrorCheck(err)

	var img image.Image = nil

	lowerFilename := strings.ToLower(filename)
	switch {
		case strings.HasSuffix(lowerFilename, ".jpg"):
			img, err = jpeg.Decode(f)
		case strings.HasSuffix(lowerFilename, ".png"):
			img, err = png.Decode(f)
		case strings.HasSuffix(lowerFilename, ".gif"):
			img, err = gif.Decode(f)
	}

	tools.ErrorCheck(err)

	return img
}
<|endoftext|>


<commit_before>package main

/* memorydiskserver: a testing utility.

the archetypal (worst-case) stateful application. a web server, which:
* loads an integer from a file on disk into memory, if it is present, when
  it starts up
* has an endpoint to set the integer, but only sets it in memory
* writes the integer from memory to disk when asked nicely to shut down (SIGTERM)
* has an endpoint to read the integer from memory

this allows us to test the following cases:
* that docker containers stopped and started cleanly around a commit operation
* that switching branches results in container being stopped and started
  with new on-disk state
* that resetting results in container being stopped and started with new
  on-disk state

this application can be built and copied into a docker image "FROM scratch"
(which involves no network operation)

*/

/*

$ curl -sSL http://localhost/set?value=10
$ curl -sSL http://localhost/get
10
$ dvol commit -m "value=10"
$ curl -sSL http://localhost/set?value=20
$ curl -sSL http://localhost/get
20
$ dvol reset --hard HEAD
$ curl -sSL http://localhost/get
10

*/

import (
	"net/http"
	"fmt"
	"io/ioutil"
	"os"
)

const STORE = "/data/memorydiskserver.dat"

var theValue string

func getHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Value: %s", theValue)
}

func setHandler(w http.ResponseWriter, r *http.Request) {
	theValue = r.URL.Query()["value"][0]
	err := writeValueToDisk()
	if err != nil {
		http.Error(w, fmt.Sprintln(err), 500)
	}
}

func writeValueToDisk() error {
	return ioutil.WriteFile(STORE, []byte(theValue), 0600)
}

//func setHandler(w http.ResponseWriter, r *http.Request) {
//    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
//}

//func signalHandler(chan c) {
//    // block until we receive a SIGTERM
//    s := <-c
//    writeValueToDisk()
//    os.Exit(0)
//}

func main() {
	// Read the starting value
	dat, err := ioutil.ReadFile(STORE)
	if err != nil {
		f, _ := os.Create(STORE)
		f.Close()
		dat, _ = ioutil.ReadFile(STORE)
	}
	theValue = string(dat)

	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/set", setHandler)

	//    c := make(chan os.Signal, 1)
	//    signal.Notify(c, os.Interrupt)
	//    go signalHandler(c)

	http.ListenAndServe(":80", nil)
}
<commit_msg>Go fmt.<commit_after>package main

/* memorydiskserver: a testing utility.

the archetypal (worst-case) stateful application. a web server, which:
* loads an integer from a file on disk into memory, if it is present, when
  it starts up
* has an endpoint to set the integer, but only sets it in memory
* writes the integer from memory to disk when asked nicely to shut down (SIGTERM)
* has an endpoint to read the integer from memory

this allows us to test the following cases:
* that docker containers stopped and started cleanly around a commit operation
* that switching branches results in container being stopped and started
  with new on-disk state
* that resetting results in container being stopped and started with new
  on-disk state

this application can be built and copied into a docker image "FROM scratch"
(which involves no network operation)

*/

/*

$ curl -sSL http://localhost/set?value=10
$ curl -sSL http://localhost/get
10
$ dvol commit -m "value=10"
$ curl -sSL http://localhost/set?value=20
$ curl -sSL http://localhost/get
20
$ dvol reset --hard HEAD
$ curl -sSL http://localhost/get
10

*/

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

const STORE = "/data/memorydiskserver.dat"

var theValue string

func getHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Value: %s", theValue)
}

func setHandler(w http.ResponseWriter, r *http.Request) {
	theValue = r.URL.Query()["value"][0]
	err := writeValueToDisk()
	if err != nil {
		http.Error(w, fmt.Sprintln(err), 500)
	}
}

func writeValueToDisk() error {
	return ioutil.WriteFile(STORE, []byte(theValue), 0600)
}

//func setHandler(w http.ResponseWriter, r *http.Request) {
//    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
//}

//func signalHandler(chan c) {
//    // block until we receive a SIGTERM
//    s := <-c
//    writeValueToDisk()
//    os.Exit(0)
//}

func main() {
	// Read the starting value
	dat, err := ioutil.ReadFile(STORE)
	if err != nil {
		f, _ := os.Create(STORE)
		f.Close()
		dat, _ = ioutil.ReadFile(STORE)
	}
	theValue = string(dat)

	http.HandleFunc("/get", getHandler)
	http.HandleFunc("/set", setHandler)

	//    c := make(chan os.Signal, 1)
	//    signal.Notify(c, os.Interrupt)
	//    go signalHandler(c)

	http.ListenAndServe(":80", nil)
}
<|endoftext|>


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

// Package pprof writes runtime profiling data in the format expected
// by the pprof visualization tool.
// For more information about pprof, see
// http://code.google.com/p/google-perftools/.
package pprof

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"runtime"
)

// WriteHeapProfile writes a pprof-formatted heap profile to w.
// If a write to w returns an error, WriteHeapProfile returns that error.
// Otherwise, WriteHeapProfile returns nil.
func WriteHeapProfile(w io.Writer) os.Error {
	// Find out how many records there are (MemProfile(nil, false)),
	// allocate that many records, and get the data.
	// There's a race—more records might be added between
	// the two calls—so allocate a few extra records for safety
	// and also try again if we're very unlucky.
	// The loop should only execute one iteration in the common case.
	var p []runtime.MemProfileRecord
	n, ok := runtime.MemProfile(nil, false)
	for {
		// Allocate room for a slightly bigger profile,
		// in case a few more entries have been added
		// since the call to MemProfile.
		p = make([]runtime.MemProfileRecord, n+50)
		n, ok = runtime.MemProfile(p, false)
		if ok {
			p = p[0:n]
			break
		}
		// Profile grew; try again.
	}

	var total runtime.MemProfileRecord
	for i := range p {
		r := &p[i]
		total.AllocBytes += r.AllocBytes
		total.AllocObjects += r.AllocObjects
		total.FreeBytes += r.FreeBytes
		total.FreeObjects += r.FreeObjects
	}

	// Technically the rate is MemProfileRate not 2*MemProfileRate,
	// but early versions of the C++ heap profiler reported 2*MemProfileRate,
	// so that's what pprof has come to expect.
	b := bufio.NewWriter(w)
	fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
		total.InUseObjects(), total.InUseBytes(),
		total.AllocObjects, total.AllocBytes,
		2*runtime.MemProfileRate)

	for i := range p {
		r := &p[i]
		fmt.Fprintf(b, "%d: %d [%d: %d] @",
			r.InUseObjects(), r.InUseBytes(),
			r.AllocObjects, r.AllocBytes)
		for _, pc := range r.Stack() {
			fmt.Fprintf(b, " %#x", pc)
		}
		fmt.Fprintf(b, "\n")
	}
	return b.Flush()
}
<commit_msg>pprof: dump extra heap information at end of heap profile<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pprof writes runtime profiling data in the format expected
// by the pprof visualization tool.
// For more information about pprof, see
// http://code.google.com/p/google-perftools/.
package pprof

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"runtime"
)

// WriteHeapProfile writes a pprof-formatted heap profile to w.
// If a write to w returns an error, WriteHeapProfile returns that error.
// Otherwise, WriteHeapProfile returns nil.
func WriteHeapProfile(w io.Writer) os.Error {
	// Find out how many records there are (MemProfile(nil, false)),
	// allocate that many records, and get the data.
	// There's a race—more records might be added between
	// the two calls—so allocate a few extra records for safety
	// and also try again if we're very unlucky.
	// The loop should only execute one iteration in the common case.
	var p []runtime.MemProfileRecord
	n, ok := runtime.MemProfile(nil, false)
	for {
		// Allocate room for a slightly bigger profile,
		// in case a few more entries have been added
		// since the call to MemProfile.
		p = make([]runtime.MemProfileRecord, n+50)
		n, ok = runtime.MemProfile(p, false)
		if ok {
			p = p[0:n]
			break
		}
		// Profile grew; try again.
	}

	var total runtime.MemProfileRecord
	for i := range p {
		r := &p[i]
		total.AllocBytes += r.AllocBytes
		total.AllocObjects += r.AllocObjects
		total.FreeBytes += r.FreeBytes
		total.FreeObjects += r.FreeObjects
	}

	// Technically the rate is MemProfileRate not 2*MemProfileRate,
	// but early versions of the C++ heap profiler reported 2*MemProfileRate,
	// so that's what pprof has come to expect.
	b := bufio.NewWriter(w)
	fmt.Fprintf(b, "heap profile: %d: %d [%d: %d] @ heap/%d\n",
		total.InUseObjects(), total.InUseBytes(),
		total.AllocObjects, total.AllocBytes,
		2*runtime.MemProfileRate)

	for i := range p {
		r := &p[i]
		fmt.Fprintf(b, "%d: %d [%d: %d] @",
			r.InUseObjects(), r.InUseBytes(),
			r.AllocObjects, r.AllocBytes)
		for _, pc := range r.Stack() {
			fmt.Fprintf(b, " %#x", pc)
		}
		fmt.Fprintf(b, "\n")
	}

	// Print memstats information too.
	// Pprof will ignore, but useful for people.
	s := &runtime.MemStats
	fmt.Fprintf(b, "\n# runtime.MemStats\n")
	fmt.Fprintf(b, "# Alloc = %d\n", s.Alloc)
	fmt.Fprintf(b, "# TotalAlloc = %d\n", s.TotalAlloc)
	fmt.Fprintf(b, "# Sys = %d\n", s.Sys)
	fmt.Fprintf(b, "# Stacks = %d\n", s.Stacks)
	fmt.Fprintf(b, "# InusePages = %d\n", s.InusePages)
	fmt.Fprintf(b, "# NextGC = %d\n", s.NextGC)
	fmt.Fprintf(b, "# HeapAlloc = %d\n", s.HeapAlloc)
	fmt.Fprintf(b, "# Lookups = %d\n", s.Lookups)
	fmt.Fprintf(b, "# Mallocs = %d\n", s.Mallocs)
	fmt.Fprintf(b, "# PauseNs = %d\n", s.PauseNs)
	fmt.Fprintf(b, "# NumGC = %d\n", s.NumGC)
	fmt.Fprintf(b, "# EnableGC = %v\n", s.EnableGC)
	fmt.Fprintf(b, "# DebugGC = %v\n", s.DebugGC)
	fmt.Fprintf(b, "# BySize = Size * (Active = Mallocs - Frees)\n")
	for _, t := range s.BySize {
		if t.Mallocs > 0 {
			fmt.Fprintf(b, "#   %d * (%d = %d - %d)\n", t.Size, t.Mallocs-t.Frees, t.Mallocs, t.Frees)
		}
	}
	return b.Flush()
}
<|endoftext|>