<commit_before>package plugin

/*

Here are a bunch of frameworky-helper functions for use when creating a new backup/restore plugin. Important things to remember:

Use plugin.Run()  for starting your plugin execution.

Use plugin.PluginInfo to fill out the info for your plugin.
Make your plugin conform to the Plugin interface, by implementing Backup(), Restore(), Retrieve(), and Store(). If they don't make sense, just return plugin.UNSUPPORTED_ACTION, and a helpful errorm essage

plugin.Exec() can be used to easily run external commands sending their stdin/stdout to that of the plugin command. Keep in mind the commands don't get run in a shell, so things like '>', '<', '|' won't work the way you want them to, but you can just run /bin/bash -c <command> to solve that, right?

*/

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"

	"github.com/jhunt/go-cli"
	env "github.com/jhunt/go-envirotron"
	"github.com/pborman/uuid"
)

type Opt struct {
	HelpShort bool   `cli:"-h"`
	HelpFull  bool   `cli:"--help"`
	Debug     bool   `cli:"-D, --debug"     env:"DEBUG"`
	Version   bool   `cli:"-v, --version"`
	Endpoint  string `cli:"-e,--endpoint"`
	Key       string `cli:"-k, --key"`
	Text      bool   `cli:"--text"`

	Info     struct{} `cli:"info"`
	Example  struct{} `cli:"example"`
	Validate struct{} `cli:"validate"`
	Backup   struct{} `cli:"backup"`
	Restore  struct{} `cli:"restore"`
	Store    struct{} `cli:"store"`
	Retrieve struct{} `cli:"retrieve"`
	Purge    struct{} `cli:"purge"`
}

type Plugin interface {
	Validate(ShieldEndpoint) error
	Backup(ShieldEndpoint) error
	Restore(ShieldEndpoint) error
	Store(ShieldEndpoint) (string, int64, error)
	Retrieve(ShieldEndpoint, string) error
	Purge(ShieldEndpoint, string) error
	Meta() PluginInfo
}

type Field struct {
	Mode     string   `json:"mode"`
	Name     string   `json:"name"`
	Type     string   `json:"type"`
	Title    string   `json:"title,omitempty"`
	Help     string   `json:"help,omitempty"`
	Example  string   `json:"example,omitempty"`
	Default  string   `json:"default,omitempty"`
	Enum     []string `json:"enum,omitempty"`
	Required bool     `json:"required,omitempty"`
}

type PluginInfo struct {
	Name     string         `json:"name"`
	Author   string         `json:"author"`
	Version  string         `json:"version"`
	Features PluginFeatures `json:"features"`

	Example  string `json:"-"`
	Defaults string `json:"-"`

	Fields []Field `json:"fields"`
}

type PluginFeatures struct {
	Target string `json:"target"`
	Store  string `json:"store"`
}

var debug bool

func DEBUG(format string, args ...interface{}) {
	if debug {
		for _, line := range strings.Split(fmt.Sprintf(format, args...), "\n") {
			fmt.Fprintf(os.Stderr, "DEBUG> %s\n", line)
		}
	}
}

func Debugf(f string, args ...interface{}) {
	if debug {
		for _, line := range strings.Split(fmt.Sprintf(f, args...), "\n") {
			fmt.Fprintf(os.Stderr, "DEBUG> %s\n", line)
		}
	}
}
func Infof(f string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, f+"\n", args...)
}

func Run(p Plugin) {
	var opt Opt
	info := p.Meta()
	env.Override(&opt)
	command, args, err := cli.Parse(&opt)
	if err != nil {
		fmt.Fprintf(os.Stderr, "!!! %s\n", err)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Try %s --help for more information.\n", os.Args[0])
		os.Exit(USAGE)
	}
	if opt.Debug {
		debug = true
	}

	if opt.HelpShort {
		fmt.Fprintf(os.Stderr, "%s v%s - %s\n", info.Name, info.Version, info.Author)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, `OPTIONS
  -h, --help      Get some help. (--help provides more detail; -h, less)
  -D, --debug     Enable debugging.
  -v, --version   Print the version of this plugin and exit.

COMMANDS
  info                         Print plugin information (name / version / author)
  validate -e JSON             Validate endpoint JSON/configuration
  backup   -e JSON             Backup a target
  restore  -e JSON             Replay a backup archive to a target
  store    -e JSON [--text]    Store a backup archive
  retrieve -e JSON -k KEY      Stream a backup archive from storage
  purge    -e JSON -k KEY      Delete a backup archive from storage
`)
		if info.Example != "" {
			fmt.Fprintf(os.Stderr, "\nEXAMPLE ENDPOINT CONFIGURATION\n%s\n", info.Example)
		}
		if info.Defaults != "" {
			fmt.Fprintf(os.Stderr, "\nDEFAULT ENDPOINT\n%s\n", info.Defaults)
		}
		os.Exit(0)
	}

	if opt.HelpFull {
		fmt.Fprintf(os.Stderr, "%s v%s - %s\n", info.Name, info.Version, info.Author)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, `OPTIONS
  -h, --help      Get some help. (--help provides more detail; -h, less)
  -D, --debug     Enable debugging.
  -v, --version   Print the version of this plugin and exit.

  -e, --endpoint  JSON string representing what to backup / where to back it up.

GENERAL COMMANDS

  info

    Print information about this plugin, in JSON format, to standard output.

  validate --endpoint ENDPOINT-JSON

    Validates the given ENDPOINT-JSON to ensure that it is (a) well-formed
    JSON data, and (b) is semantically valid for this plugin.  Checks that
    required configuration is set, and verifies the format and suitability
    of the given configuration.

BACKUP COMMANDS

  backup --endpoint TARGET-ENDPOINT-JSON

    Perform a backup of the indicated target endpoint.  The raw (uncompressed)
    backup archive will be written to standard output.

  restore --endpoint TARGET-ENDPOINT-JSON

    Reads a raw (uncompressed) backup archive on standard input and attempts to
    replay it to the given target.

STORAGE COMMANDS

  store --endpoint STORE-ENDPOINT-JSON [--text]

    Reads a compressed backup archive on standard input and attempts to
    persist it to the backing storage system indicated by --endpoint.
    Upon success, writes the STORAGE-HANDLE to standard output.

    If --text is given, the STORAGE-HANDLE is printed on a single line,
    without any additional whitespace or formatting.  By default, it will
    be printed inside of a JSON structure.

  retrieve --key STORAGE-HANDLE --endpoint STORE-ENDPOINT-JSON

    Retrieves a compressed backup archive from the backing storage,
    using the STORAGE-HANDLE given by a previous 'store' command, and
    writes it to standard output.

  purge --key STORAGE-HANDLE --endpoint STORE-ENDPOINT-JSON

    Removes a backup archive from the backing storage, using the
    STORAGE-HANDLE given by a previous 'store' command.
`)
		os.Exit(0)
	}

	if len(args) != 0 {
		fmt.Fprintf(os.Stderr, "extra arguments found, starting at %v\n", args[0])
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", info.Name)
		os.Exit(USAGE)
	}

	if opt.Version {
		fmt.Printf("%s v%s - %s\n", info.Name, info.Version, info.Author)
		os.Exit(0)
	}

	switch command {
	case "info":
		if os.Getenv("SHIELD_PEDANTIC_INFO") != "" {
			/* validate the plugin info with great pedantry */
			ok := true
			for i, f := range info.Fields {
				name := f.Name
				if f.Name == "" {
					fmt.Fprintf(os.Stderr, "!! %s: field #%d has no name\n", info.Name, i+1)
					name = fmt.Sprintf("field #%d", i+1)
					ok = false
				}

				if f.Type == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no type\n", info.Name, name)
					ok = false
				}

				if f.Title == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no title\n", info.Name, name)
					ok = false
				}

				if f.Help == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no help\n", info.Name, name)
					ok = false
				} else if !strings.HasSuffix(f.Help, ".") {
					fmt.Fprintf(os.Stderr, "!! %s: %s help field does not end in a period.\n", info.Name, name)
					ok = false
				}

				if f.Type == "enum" {
					if len(f.Enum) == 0 {
						fmt.Fprintf(os.Stderr, "!! %s: %s is defined as an enum, but specifies no allowed values.\n", info.Name, name)
						ok = false
					}
				} else {
					if len(f.Enum) != 0 {
						fmt.Fprintf(os.Stderr, "!! %s: %s is not defined as an enum, but has the following allowed values: [%s]\n", info.Name, name, f.Enum)
						ok = false
					}
				}
			}

			if !ok {
				os.Exit(1)
			}
		}
		json, err := json.MarshalIndent(info, "", "    ")
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(JSON_FAILURE)
		}
		fmt.Printf("%s\n", json)
		os.Exit(0)

	default:
		err = dispatch(p, command, opt)
		if err != nil {
			DEBUG("'%s' action returned error: %s", command, err)
			switch err.(type) {
			case UnsupportedActionError:
				if err.(UnsupportedActionError).Action == "" {
					e := err.(UnsupportedActionError)
					e.Action = command
					err = e
				}
			}
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(codeForError(err))
		}
	}
	os.Exit(0)
}

func dispatch(p Plugin, mode string, opt Opt) error {
	var (
		err      error
		key      string
		size     int64
		endpoint ShieldEndpoint
	)

	if debug {
		DEBUG("'%s' action requested with the following options:", mode)
		if opt.HelpShort {
			DEBUG("  -h (shorter --help)")
		}
		if opt.HelpFull {
			DEBUG("  --help")
		}
		if opt.Version {
			DEBUG("  --version")
		}
		if opt.Endpoint != "" {
			DEBUG("  --endpoint '%s'", opt.Endpoint)
		}
		if opt.Key != "" {
			DEBUG("  --key '%s'", opt.Key)
		}
		if opt.Text {
			DEBUG("  --text")
		}
	}

	switch mode {
	case "validate":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Validate(endpoint)

	case "backup":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Backup(endpoint)

	case "restore":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Restore(endpoint)

	case "store":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}

		key, size, err = p.Store(endpoint)
		if opt.Text {
			fmt.Printf("%s\n", key)

		} else {
			output, err := json.MarshalIndent(struct {
				Key  string `json:"key"`
				Size int64  `json:"archive_size"`
			}{
				Key:  key,
				Size: size,
			}, "", "    ")

			if err != nil {
				return JSONError{Err: fmt.Sprintf("Could not JSON encode blob key: %s", err)}
			}

			fmt.Printf("%s\n", string(output))
		}

	case "retrieve":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		if opt.Key == "" {
			return MissingRestoreKeyError{}
		}
		err = p.Retrieve(endpoint, opt.Key)

	case "purge":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		if opt.Key == "" {
			return MissingRestoreKeyError{}
		}
		err = p.Purge(endpoint, opt.Key)

	default:
		return UnsupportedActionError{Action: mode}
	}

	return err
}

func GenUUID() string {
	return uuid.New()
}

func Redact(raw string) string {
	return fmt.Sprintf("<redacted>%s</redacted>", raw)
}

func codeForError(e error) int {
	var code int
	if e != nil {
		switch e.(type) {
		case UnsupportedActionError:
			code = UNSUPPORTED_ACTION
		case EndpointMissingRequiredDataError:
			code = ENDPOINT_MISSING_KEY
		case EndpointDataTypeMismatchError:
			code = ENDPOINT_BAD_DATA
		case ExecFailure:
			code = EXEC_FAILURE
		case JSONError:
			code = JSON_FAILURE
		case MissingRestoreKeyError:
			code = RESTORE_KEY_REQUIRED
		default:
			code = PLUGIN_FAILURE
		}
	} else {
		code = SUCCESS
	}

	return code
}
<commit_msg>Remove dead "example" command from plugin framework<commit_after>package plugin

/*

Here are a bunch of frameworky-helper functions for use when creating a new backup/restore plugin. Important things to remember:

Use plugin.Run()  for starting your plugin execution.

Use plugin.PluginInfo to fill out the info for your plugin.
Make your plugin conform to the Plugin interface, by implementing Backup(), Restore(), Retrieve(), and Store(). If they don't make sense, just return plugin.UNSUPPORTED_ACTION, and a helpful errorm essage

plugin.Exec() can be used to easily run external commands sending their stdin/stdout to that of the plugin command. Keep in mind the commands don't get run in a shell, so things like '>', '<', '|' won't work the way you want them to, but you can just run /bin/bash -c <command> to solve that, right?

*/

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"

	"github.com/jhunt/go-cli"
	env "github.com/jhunt/go-envirotron"
	"github.com/pborman/uuid"
)

type Opt struct {
	HelpShort bool   `cli:"-h"`
	HelpFull  bool   `cli:"--help"`
	Debug     bool   `cli:"-D, --debug"     env:"DEBUG"`
	Version   bool   `cli:"-v, --version"`
	Endpoint  string `cli:"-e,--endpoint"`
	Key       string `cli:"-k, --key"`
	Text      bool   `cli:"--text"`

	Info     struct{} `cli:"info"`
	Validate struct{} `cli:"validate"`
	Backup   struct{} `cli:"backup"`
	Restore  struct{} `cli:"restore"`
	Store    struct{} `cli:"store"`
	Retrieve struct{} `cli:"retrieve"`
	Purge    struct{} `cli:"purge"`
}

type Plugin interface {
	Validate(ShieldEndpoint) error
	Backup(ShieldEndpoint) error
	Restore(ShieldEndpoint) error
	Store(ShieldEndpoint) (string, int64, error)
	Retrieve(ShieldEndpoint, string) error
	Purge(ShieldEndpoint, string) error
	Meta() PluginInfo
}

type Field struct {
	Mode     string   `json:"mode"`
	Name     string   `json:"name"`
	Type     string   `json:"type"`
	Title    string   `json:"title,omitempty"`
	Help     string   `json:"help,omitempty"`
	Example  string   `json:"example,omitempty"`
	Default  string   `json:"default,omitempty"`
	Enum     []string `json:"enum,omitempty"`
	Required bool     `json:"required,omitempty"`
}

type PluginInfo struct {
	Name     string         `json:"name"`
	Author   string         `json:"author"`
	Version  string         `json:"version"`
	Features PluginFeatures `json:"features"`

	Example  string `json:"-"`
	Defaults string `json:"-"`

	Fields []Field `json:"fields"`
}

type PluginFeatures struct {
	Target string `json:"target"`
	Store  string `json:"store"`
}

var debug bool

func DEBUG(format string, args ...interface{}) {
	if debug {
		for _, line := range strings.Split(fmt.Sprintf(format, args...), "\n") {
			fmt.Fprintf(os.Stderr, "DEBUG> %s\n", line)
		}
	}
}

func Debugf(f string, args ...interface{}) {
	if debug {
		for _, line := range strings.Split(fmt.Sprintf(f, args...), "\n") {
			fmt.Fprintf(os.Stderr, "DEBUG> %s\n", line)
		}
	}
}
func Infof(f string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, f+"\n", args...)
}

func Run(p Plugin) {
	var opt Opt
	info := p.Meta()
	env.Override(&opt)
	command, args, err := cli.Parse(&opt)
	if err != nil {
		fmt.Fprintf(os.Stderr, "!!! %s\n", err)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "Try %s --help for more information.\n", os.Args[0])
		os.Exit(USAGE)
	}
	if opt.Debug {
		debug = true
	}

	if opt.HelpShort {
		fmt.Fprintf(os.Stderr, "%s v%s - %s\n", info.Name, info.Version, info.Author)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, `OPTIONS
  -h, --help      Get some help. (--help provides more detail; -h, less)
  -D, --debug     Enable debugging.
  -v, --version   Print the version of this plugin and exit.

COMMANDS
  info                         Print plugin information (name / version / author)
  validate -e JSON             Validate endpoint JSON/configuration
  backup   -e JSON             Backup a target
  restore  -e JSON             Replay a backup archive to a target
  store    -e JSON [--text]    Store a backup archive
  retrieve -e JSON -k KEY      Stream a backup archive from storage
  purge    -e JSON -k KEY      Delete a backup archive from storage
`)
		if info.Example != "" {
			fmt.Fprintf(os.Stderr, "\nEXAMPLE ENDPOINT CONFIGURATION\n%s\n", info.Example)
		}
		if info.Defaults != "" {
			fmt.Fprintf(os.Stderr, "\nDEFAULT ENDPOINT\n%s\n", info.Defaults)
		}
		os.Exit(0)
	}

	if opt.HelpFull {
		fmt.Fprintf(os.Stderr, "%s v%s - %s\n", info.Name, info.Version, info.Author)
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, `OPTIONS
  -h, --help      Get some help. (--help provides more detail; -h, less)
  -D, --debug     Enable debugging.
  -v, --version   Print the version of this plugin and exit.

  -e, --endpoint  JSON string representing what to backup / where to back it up.

GENERAL COMMANDS

  info

    Print information about this plugin, in JSON format, to standard output.

  validate --endpoint ENDPOINT-JSON

    Validates the given ENDPOINT-JSON to ensure that it is (a) well-formed
    JSON data, and (b) is semantically valid for this plugin.  Checks that
    required configuration is set, and verifies the format and suitability
    of the given configuration.

BACKUP COMMANDS

  backup --endpoint TARGET-ENDPOINT-JSON

    Perform a backup of the indicated target endpoint.  The raw (uncompressed)
    backup archive will be written to standard output.

  restore --endpoint TARGET-ENDPOINT-JSON

    Reads a raw (uncompressed) backup archive on standard input and attempts to
    replay it to the given target.

STORAGE COMMANDS

  store --endpoint STORE-ENDPOINT-JSON [--text]

    Reads a compressed backup archive on standard input and attempts to
    persist it to the backing storage system indicated by --endpoint.
    Upon success, writes the STORAGE-HANDLE to standard output.

    If --text is given, the STORAGE-HANDLE is printed on a single line,
    without any additional whitespace or formatting.  By default, it will
    be printed inside of a JSON structure.

  retrieve --key STORAGE-HANDLE --endpoint STORE-ENDPOINT-JSON

    Retrieves a compressed backup archive from the backing storage,
    using the STORAGE-HANDLE given by a previous 'store' command, and
    writes it to standard output.

  purge --key STORAGE-HANDLE --endpoint STORE-ENDPOINT-JSON

    Removes a backup archive from the backing storage, using the
    STORAGE-HANDLE given by a previous 'store' command.
`)
		os.Exit(0)
	}

	if len(args) != 0 {
		fmt.Fprintf(os.Stderr, "extra arguments found, starting at %v\n", args[0])
		fmt.Fprintf(os.Stderr, "USAGE: %s [OPTIONS...] COMMAND [OPTIONS...]\n\n", info.Name)
		os.Exit(USAGE)
	}

	if opt.Version {
		fmt.Printf("%s v%s - %s\n", info.Name, info.Version, info.Author)
		os.Exit(0)
	}

	switch command {
	case "info":
		if os.Getenv("SHIELD_PEDANTIC_INFO") != "" {
			/* validate the plugin info with great pedantry */
			ok := true
			for i, f := range info.Fields {
				name := f.Name
				if f.Name == "" {
					fmt.Fprintf(os.Stderr, "!! %s: field #%d has no name\n", info.Name, i+1)
					name = fmt.Sprintf("field #%d", i+1)
					ok = false
				}

				if f.Type == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no type\n", info.Name, name)
					ok = false
				}

				if f.Title == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no title\n", info.Name, name)
					ok = false
				}

				if f.Help == "" {
					fmt.Fprintf(os.Stderr, "!! %s: %s has no help\n", info.Name, name)
					ok = false
				} else if !strings.HasSuffix(f.Help, ".") {
					fmt.Fprintf(os.Stderr, "!! %s: %s help field does not end in a period.\n", info.Name, name)
					ok = false
				}

				if f.Type == "enum" {
					if len(f.Enum) == 0 {
						fmt.Fprintf(os.Stderr, "!! %s: %s is defined as an enum, but specifies no allowed values.\n", info.Name, name)
						ok = false
					}
				} else {
					if len(f.Enum) != 0 {
						fmt.Fprintf(os.Stderr, "!! %s: %s is not defined as an enum, but has the following allowed values: [%s]\n", info.Name, name, f.Enum)
						ok = false
					}
				}
			}

			if !ok {
				os.Exit(1)
			}
		}
		json, err := json.MarshalIndent(info, "", "    ")
		if err != nil {
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(JSON_FAILURE)
		}
		fmt.Printf("%s\n", json)
		os.Exit(0)

	default:
		err = dispatch(p, command, opt)
		if err != nil {
			DEBUG("'%s' action returned error: %s", command, err)
			switch err.(type) {
			case UnsupportedActionError:
				if err.(UnsupportedActionError).Action == "" {
					e := err.(UnsupportedActionError)
					e.Action = command
					err = e
				}
			}
			fmt.Fprintf(os.Stderr, "%s\n", err)
			os.Exit(codeForError(err))
		}
	}
	os.Exit(0)
}

func dispatch(p Plugin, mode string, opt Opt) error {
	var (
		err      error
		key      string
		size     int64
		endpoint ShieldEndpoint
	)

	if debug {
		DEBUG("'%s' action requested with the following options:", mode)
		if opt.HelpShort {
			DEBUG("  -h (shorter --help)")
		}
		if opt.HelpFull {
			DEBUG("  --help")
		}
		if opt.Version {
			DEBUG("  --version")
		}
		if opt.Endpoint != "" {
			DEBUG("  --endpoint '%s'", opt.Endpoint)
		}
		if opt.Key != "" {
			DEBUG("  --key '%s'", opt.Key)
		}
		if opt.Text {
			DEBUG("  --text")
		}
	}

	switch mode {
	case "validate":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Validate(endpoint)

	case "backup":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Backup(endpoint)

	case "restore":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		err = p.Restore(endpoint)

	case "store":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}

		key, size, err = p.Store(endpoint)
		if opt.Text {
			fmt.Printf("%s\n", key)

		} else {
			output, err := json.MarshalIndent(struct {
				Key  string `json:"key"`
				Size int64  `json:"archive_size"`
			}{
				Key:  key,
				Size: size,
			}, "", "    ")

			if err != nil {
				return JSONError{Err: fmt.Sprintf("Could not JSON encode blob key: %s", err)}
			}

			fmt.Printf("%s\n", string(output))
		}

	case "retrieve":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		if opt.Key == "" {
			return MissingRestoreKeyError{}
		}
		err = p.Retrieve(endpoint, opt.Key)

	case "purge":
		endpoint, err = getEndpoint(opt.Endpoint)
		if err != nil {
			return err
		}
		if opt.Key == "" {
			return MissingRestoreKeyError{}
		}
		err = p.Purge(endpoint, opt.Key)

	default:
		return UnsupportedActionError{Action: mode}
	}

	return err
}

func GenUUID() string {
	return uuid.New()
}

func Redact(raw string) string {
	return fmt.Sprintf("<redacted>%s</redacted>", raw)
}

func codeForError(e error) int {
	var code int
	if e != nil {
		switch e.(type) {
		case UnsupportedActionError:
			code = UNSUPPORTED_ACTION
		case EndpointMissingRequiredDataError:
			code = ENDPOINT_MISSING_KEY
		case EndpointDataTypeMismatchError:
			code = ENDPOINT_BAD_DATA
		case ExecFailure:
			code = EXEC_FAILURE
		case JSONError:
			code = JSON_FAILURE
		case MissingRestoreKeyError:
			code = RESTORE_KEY_REQUIRED
		default:
			code = PLUGIN_FAILURE
		}
	} else {
		code = SUCCESS
	}

	return code
}
<|endoftext|>


<commit_before>/*
 *  Goji Framework
 *  Copyright (C) Roland Singer
 */

package plugin

import (
	htemplate "html/template"

	"bytes"
	"code.desertbit.com/bulldozer/bulldozer/log"
	"code.desertbit.com/bulldozer/bulldozer/template"
	"fmt"
	"strings"
)

type Args map[string]string

//######################//
//### Plugin options ###//
//######################//

type Opts struct {
	Type       string // The plugin type.
	HasSection bool   // If the plugin requires a template section.
	RequireID  bool   // If the plugin requires a unique ID as argument.
}

//########################//
//### Plugin Interface ###//
//########################//

type Plugin interface {
	Initialize() *template.Template                  // Called only once during plugin initialization.
	Prepare(d *Data)                                 // Prepare is called for each plugin context. Settings should be parsed...
	Render(c *template.Context, d *Data) interface{} // Render is called during each plugin template rendering request. Template render data can be returned.
}

//##########################//
//### Plugin data struct ###//
//##########################//

type Data struct {
	// Private
	id                     string
	additionalStyleClasses []string

	// Public
	Value   interface{}
	Section string
	Args    Args
}

//##############################//
//### Template plugin struct ###//
//##############################//

type templatePlugin struct {
	plugin Plugin
	opts   *Opts
	t      *template.Template
}

func (tp *templatePlugin) Prepare(d *template.PluginData) (err error) {
	// Recover panics and return the error
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("plugin '%s': prepare panic: %v", tp.opts.Type, e)
		}
	}()

	// Create the plugin data value.
	data := &Data{
		Args:    Args(d.Args),
		Section: d.Section,
	}

	// Obtain the plugin ID from the arguments.
	id, ok := data.Args["id"]
	if ok {
		if len(id) == 0 {
			return fmt.Errorf("the passed ID is emtpy!")
		}

		// Remove it from the arguments map.
		delete(data.Args, "id")
	} else {
		// Return an error if the ID is required
		if tp.opts.RequireID {
			return fmt.Errorf("an unique ID is required!")
		}

		// Fallback to the plugin type string as ID.
		id = tp.opts.Type
	}

	// Set the ID.
	data.id = id

	// Parse for core plugin arguments.
	// Check if the class argument is set.
	if classes, ok := data.Args["class"]; ok {
		// Add the style classes to the data value.
		data.additionalStyleClasses = strings.Fields(classes)

		// Remove the class argument from the argument map
		delete(data.Args, "class")
	}

	// Save the plugin data.
	d.Value = data

	// Call the plugin interface prepare method.
	tp.plugin.Prepare(data)

	return nil
}

func (tp *templatePlugin) Render(c *template.Context, d *template.PluginData) (r interface{}, err error) {
	// Recover panics and return the error
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("render panic: %v", e)
		}
	}()

	// Cast to plugin data pointer
	data := d.Value.(*Data)

	// Create the unique plugin template ID.
	id := c.ID() + "~" + data.id

	// Create the plugin template context.
	pContext := template.NewContext(c.Session(), tp.t, id, c.ParentID(), data.additionalStyleClasses)

	// Get the render data for the template.
	renderData := tp.plugin.Render(pContext, data)

	// Execute the plugin template.
	var b bytes.Buffer
	err = template.ExecuteContext(pContext, &b, renderData)
	if err != nil {
		return "", fmt.Errorf("failed to execute template: %v", err)
	}

	// Return the final html text.
	// By casting to a html template, we effectively unescape this portion.
	return htemplate.HTML(b.String()), nil
}

//##############//
//### Public ###//
//##############//

// Must will on error panic.
func Must(err error) {
	if err != nil {
		panic(err)
	}
}

// Must will log the error and exit the application.
func MustFatal(err error) {
	if err != nil {
		log.L.Fatal(err.Error())
	}
}

// Register registers a new plugin.
func Register(p Plugin, o *Opts) (err error) {
	if len(o.Type) == 0 {
		return fmt.Errorf("bulldozer plugin: failed to register new plugin: type string is empty!")
	}

	// Recover panics and return the error.
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("failed to register plugin '%s': %v", o.Type, e)
		}
	}()

	// Call the interface initialize method to obtain the template.
	t := p.Initialize()
	if t == nil {
		return fmt.Errorf("failed to register plugin '%s': the plugin's Initialize method returned nil!", o.Type)
	}

	// Register the plugin events to the template.
	t.RegisterEvents(p)

	// Create a new template plugin value.
	tp := &templatePlugin{
		plugin: p,
		opts:   o,
		t:      t,
	}

	// Conversion.
	templateOpts := template.PluginOpts(*o)

	// Register the plugin to the template plugins.
	return template.RegisterPlugin(tp, &templateOpts)
}
<commit_msg>small fix<commit_after>/*
 *  Goji Framework
 *  Copyright (C) Roland Singer
 */

package plugin

import (
	htemplate "html/template"

	"bytes"
	"code.desertbit.com/bulldozer/bulldozer/log"
	"code.desertbit.com/bulldozer/bulldozer/template"
	"fmt"
	"strings"
)

type Args map[string]string

//######################//
//### Plugin options ###//
//######################//

type Opts struct {
	Type       string // The plugin type.
	HasSection bool   // If the plugin requires a template section.
	RequireID  bool   // If the plugin requires a unique ID as argument.
}

//########################//
//### Plugin Interface ###//
//########################//

type Plugin interface {
	Initialize() *template.Template                  // Called only once during plugin initialization.
	Prepare(d *Data)                                 // Prepare is called for each plugin context. Settings should be parsed...
	Render(c *template.Context, d *Data) interface{} // Render is called during each plugin template rendering request. Template render data can be returned.
}

//##########################//
//### Plugin data struct ###//
//##########################//

type Data struct {
	// Private
	id                     string
	additionalStyleClasses []string

	// Public
	Value   interface{}
	Section string
	Args    Args
}

//##############################//
//### Template plugin struct ###//
//##############################//

type templatePlugin struct {
	plugin Plugin
	opts   *Opts
	t      *template.Template
}

func (tp *templatePlugin) Prepare(d *template.PluginData) (err error) {
	// Recover panics and return the error
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("plugin '%s': prepare panic: %v", tp.opts.Type, e)
		}
	}()

	// Create the plugin data value.
	data := &Data{
		Args:    Args(d.Args),
		Section: d.Section,
	}

	// Obtain the plugin ID from the arguments.
	id, ok := data.Args["id"]
	if ok {
		if len(id) == 0 {
			return fmt.Errorf("the passed ID is emtpy!")
		}

		// Remove it from the arguments map.
		delete(data.Args, "id")
	} else if tp.opts.RequireID {
		// Return an error if the ID is required
		return fmt.Errorf("an unique ID is required!")
	}

	if len(id) > 0 {
		id = tp.opts.Type + "@" + id
	} else {
		id = tp.opts.Type
	}

	// Set the ID.
	data.id = id

	// Parse for core plugin arguments.
	// Check if the class argument is set.
	if classes, ok := data.Args["class"]; ok {
		// Add the style classes to the data value.
		data.additionalStyleClasses = strings.Fields(classes)

		// Remove the class argument from the argument map
		delete(data.Args, "class")
	}

	// Save the plugin data.
	d.Value = data

	// Call the plugin interface prepare method.
	tp.plugin.Prepare(data)

	return nil
}

func (tp *templatePlugin) Render(c *template.Context, d *template.PluginData) (r interface{}, err error) {
	// Recover panics and return the error
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("render panic: %v", e)
		}
	}()

	// Cast to plugin data pointer
	data := d.Value.(*Data)

	// Create the unique plugin template ID.
	id := c.ID() + "~" + data.id

	// Create the plugin template context.
	pContext := template.NewContext(c.Session(), tp.t, id, c.ParentID(), data.additionalStyleClasses)

	// Get the render data for the template.
	renderData := tp.plugin.Render(pContext, data)

	// Execute the plugin template.
	var b bytes.Buffer
	err = template.ExecuteContext(pContext, &b, renderData)
	if err != nil {
		return "", fmt.Errorf("failed to execute template: %v", err)
	}

	// Return the final html text.
	// By casting to a html template, we effectively unescape this portion.
	return htemplate.HTML(b.String()), nil
}

//##############//
//### Public ###//
//##############//

// Must will on error panic.
func Must(err error) {
	if err != nil {
		panic(err)
	}
}

// Must will log the error and exit the application.
func MustFatal(err error) {
	if err != nil {
		log.L.Fatal(err.Error())
	}
}

// Register registers a new plugin.
func Register(p Plugin, o *Opts) (err error) {
	if len(o.Type) == 0 {
		return fmt.Errorf("bulldozer plugin: failed to register new plugin: type string is empty!")
	}

	// Recover panics and return the error.
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("failed to register plugin '%s': %v", o.Type, e)
		}
	}()

	// Call the interface initialize method to obtain the template.
	t := p.Initialize()
	if t == nil {
		return fmt.Errorf("failed to register plugin '%s': the plugin's Initialize method returned nil!", o.Type)
	}

	// Register the plugin events to the template.
	t.RegisterEvents(p)

	// Create a new template plugin value.
	tp := &templatePlugin{
		plugin: p,
		opts:   o,
		t:      t,
	}

	// Conversion.
	templateOpts := template.PluginOpts(*o)

	// Register the plugin to the template plugins.
	return template.RegisterPlugin(tp, &templateOpts)
}
<|endoftext|>


<commit_before>// Copyright 2013 Travis Keep. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or
// at http://opensource.org/licenses/BSD-3-Clause.

package gohue_test

import (
  "errors"
  "github.com/keep94/gohue"
  "github.com/keep94/maybe"
  "github.com/keep94/tasks"
  "reflect"
  "testing"
  "time"
)

var (
  kNow = time.Date(2013, 9, 15, 14, 0, 0, 0, time.Local)
  kSomeError = errors.New("gohue: someError.")
)

func TestGradient(t *testing.T) {
  action := gohue.Action{
      Lights: []int{2},
      G: &gohue.Gradient {
          Cds: []gohue.ColorDuration{
              {C: gohue.NewMaybeColor(gohue.NewColor(0.2, 0.1)),
               Bri: maybe.NewUint8(0), D: 0},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.3, 0.3)),
               Bri: maybe.NewUint8(30), D: 1000},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.9, 0.9)),
               Bri: maybe.NewUint8(100), D: 1000},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.8, 0.7)),
              Bri: maybe.NewUint8(100),  D: 1000},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.2, 0.4)),
               Bri: maybe.NewUint8(10), D: 1750},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.29, 0.46)),
               Bri: maybe.NewUint8(22), D: 2500}},
          Refresh: 500},
      On: true}
  expected := []request {
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.2, 0.1)),
       Bri: maybe.NewUint8(0),
       On: maybe.NewBool(true),
       D: 0},
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.25, 0.2)),
       Bri: maybe.NewUint8(15),
       D: 500},
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.8, 0.7)),
       Bri: maybe.NewUint8(100),
       D: 1000},
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.4, 0.5)),
       Bri: maybe.NewUint8(40),
       D: 1500},
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.23, 0.42)),
       Bri: maybe.NewUint8(14),
       D:2000},
      {L: 2,
       C: gohue.NewMaybeColor(gohue.NewColor(0.29, 0.46)),
       Bri: maybe.NewUint8(22),
       D:2500}}
  verifyAction(t, expected, action)
}

func TestGradient2(t *testing.T) {
  action := gohue.Action{
      G: &gohue.Gradient{
          Cds: []gohue.ColorDuration{
              {C: gohue.NewMaybeColor(gohue.NewColor(0.2, 0.1)), D: 0},
              {C: gohue.NewMaybeColor(gohue.NewColor(0.3, 0.3)), D: 1000}},
          Refresh: 600}}
  expected := []request {
      {L: 0, C: gohue.NewMaybeColor(gohue.NewColor(0.2, 0.1)), D: 0},
      {L: 0, C: gohue.NewMaybeColor(gohue.NewColor(0.26, 0.22)), D: 600},
      {L: 0, C: gohue.NewMaybeColor(gohue.NewColor(0.3, 0.3)), D: 1200}}
  verifyAction(t, expected, action)
}

func TestGradient3(t *testing.T) {
  action := gohue.Action{
      G: &gohue.Gradient{
          Cds: []gohue.ColorDuration{
              {Bri: maybe.NewUint8(gohue.Bright), D: 0},
              {Bri: maybe.NewUint8(gohue.Bright),
               C: gohue.NewMaybeColor(gohue.Red),
               D: 1000},
              {C: gohue.NewMaybeColor(gohue.Red), D: 2000},
              {Bri: maybe.NewUint8(gohue.Dim), D: 3000},
              {Bri: maybe.NewUint8(gohue.Dim), D: 4000}},
          Refresh: 500}}
  expected := []request {
      {L: 0, Bri: maybe.NewUint8(gohue.Bright), D: 0},
      {L: 0, Bri: maybe.NewUint8(gohue.Bright), D: 500},
      {L: 0,
       Bri: maybe.NewUint8(gohue.Bright),
       C: gohue.NewMaybeColor(gohue.Red),
       D: 1000},
      {L: 0,
       Bri: maybe.NewUint8(gohue.Bright),
       C: gohue.NewMaybeColor(gohue.Red),
       D: 1500},
      {L: 0, C: gohue.NewMaybeColor(gohue.Red), D: 2000},
      {L: 0, C: gohue.NewMaybeColor(gohue.Red), D: 2500},
      {L: 0, Bri: maybe.NewUint8(gohue.Dim), D: 3000},
      {L: 0, Bri: maybe.NewUint8(gohue.Dim), D: 3500},
      {L: 0, Bri: maybe.NewUint8(gohue.Dim), D: 4000}}
  verifyAction(t, expected, action)
}

func TestOnColor(t *testing.T) {
  action := gohue.Action{
      On: true, C: gohue.NewMaybeColor(gohue.NewColor(0.4, 0.2))}
  expected := []request {
      {L: 0,
       C: gohue.NewMaybeColor(gohue.NewColor(0.4, 0.2)),
       On: maybe.NewBool(true),
       D: 0}}
  verifyAction(t, expected, action)
}

func TestOnBrightness(t *testing.T) {
  action := gohue.Action{
      On: true, Bri: maybe.NewUint8(135)}
  expected := []request {
      {L: 0, Bri: maybe.NewUint8(135), On: maybe.NewBool(true), D: 0}}
  verifyAction(t, expected, action)
}

func TestOn(t *testing.T) {
  action := gohue.Action{On: true}
  expected := []request {{L: 0, On: maybe.NewBool(true), D: 0}}
  verifyAction(t, expected, action)
}

func TestOff(t *testing.T) {
  action := gohue.Action{Off: true}
  expected := []request {{L: 0, On: maybe.NewBool(false), D: 0}}
  verifyAction(t, expected, action)
}

func TestColorOnly(t *testing.T) {
  action := gohue.Action{C: gohue.NewMaybeColor(gohue.Yellow)}
  expected := []request {
      {L: 0,
       C: gohue.NewMaybeColor(gohue.Yellow),
       D: 0}}
  verifyAction(t, expected, action)
}

func TestRepeat(t *testing.T) {
  action := gohue.Action{On: true, Repeat: 3}
  expected := []request {
      {L: 0, On: maybe.NewBool(true), D: 0},
      {L: 0, On: maybe.NewBool(true), D: 0},
      {L: 0, On: maybe.NewBool(true), D: 0}}
  verifyAction(t, expected, action)
}

func TestSeries(t *testing.T) {
  action := gohue.Action{
      Series: []*gohue.Action {
          {Lights: []int{2, 3}, On: true},
          {Sleep: 3000},
          {Off: true}}}
  expected := []request {
      {L: 2, On: maybe.NewBool(true),  D: 0},
      {L: 3, On: maybe.NewBool(true),  D: 0},
      {L: 0, On: maybe.NewBool(false), D: 3000}}
  verifyAction(t, expected, action)
}

func TestSeries2(t *testing.T) {
  action := gohue.Action{
      Lights: []int{1, 4},
      Series: []*gohue.Action {
          {On: true},
          {Sleep: 3000},
          {Off: true}}}
  expected := []request {
      {L: 1, On: maybe.NewBool(true),  D: 0},
      {L: 4, On: maybe.NewBool(true),  D: 0},
      {L: 1, On: maybe.NewBool(false),  D: 3000},
      {L: 4, On: maybe.NewBool(false),  D: 3000}}
  verifyAction(t, expected, action)
}

func TestError(t *testing.T) {
  action := gohue.Action{
      Series: []*gohue.Action {
          {Lights: []int{2, 3}, On: true},
          {Sleep: 3000},
          {Off: true}}}
  expected := []request {
      {L: 2, On: maybe.NewBool(true),  D: 0}}
  clock := &tasks.ClockForTesting{kNow}
  context := &setterForTesting{err: kSomeError, clock: clock, now: kNow}
  if err := tasks.RunForTesting(
      action.AsTask(context, nil), clock); err != kSomeError {
    t.Error("Expected to get kSomeError.")
  }
  if !reflect.DeepEqual(expected, context.requests) {
    t.Errorf("Expected %v, got %v", expected, context.requests)
  }
}

type request struct {
  L int
  C gohue.MaybeColor
  Bri maybe.Uint8
  On maybe.Bool
  D time.Duration
}

type setterForTesting struct {
  err error
  clock *tasks.ClockForTesting
  now time.Time
  requests []request
}

func (s *setterForTesting) Set(lightId int, p *gohue.LightProperties) (result []byte, err error) {
  var r request
  r.L = lightId
  r.C = p.C
  r.Bri = p.Bri
  r.On = p.On
  r.D = s.clock.Current.Sub(s.now)
  s.requests = append(s.requests, r)
  if s.err != nil {
    err = s.err
  }
  return
}

func verifyAction(t *testing.T, expected []request, action gohue.Action) {
  clock := &tasks.ClockForTesting{kNow}
  context := &setterForTesting{clock: clock, now: kNow}
  tasks.RunForTesting(action.AsTask(context, nil), clock)
  if !reflect.DeepEqual(expected, context.requests) {
    t.Errorf("Expected %v, got %v", expected, context.requests)
  }
}
<commit_msg>Remove old test file.<commit_after><|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 main

import (
	"flag"
	"time"

	"github.com/googlecloudplatform/gcsfuse/mount"
)

////////////////////////////////////////////////////////////////////////
// Flags
////////////////////////////////////////////////////////////////////////

type flagStorage struct {
	Help                               bool
	MountOptions                       map[string]string
	Uid                                int64
	Gid                                int64
	FileMode                           uint
	DirMode                            uint
	TempDir                            string
	TempDirLimit                       int64
	GCSChunkSize                       uint64
	ImplicitDirs                       bool
	StatCacheTTL                       time.Duration
	TypeCacheTTL                       time.Duration
	OpRateLimitHz                      float64
	EgressBandwidthLimitBytesPerSecond float64
}

// Add the flags accepted by run to the supplied flag set, returning the
// variables into which the flags will parse.
func populateFlagSet(fs *flag.FlagSet) (flags *flagStorage) {
	flags = new(flagStorage)

	flag.BoolVar(
		&flags.Help,
		"help",
		false,
		"If set, print usage and exit successfully.")

	flag.Var(
		mount.OptionValue(flags.MountOptions),
		"o",
		"Additional system-specific mount options. Be careful!")

	flag.Int64Var(
		&flags.Uid,
		"uid",
		-1,
		"If non-negative, the UID that owns all inodes. The default is the UID of "+
			"the gcsfuse process.")

	flag.Int64Var(
		&flags.Gid,
		"gid",
		-1,
		"If non-negative, the GID that owns all inodes. The default is the GID of "+
			"the gcsfuse process.")

	flag.UintVar(
		&flags.FileMode,
		"file_mode",
		0644,
		"Permissions bits for files. Default is 0644.")

	flag.UintVar(
		&flags.DirMode,
		"dir_mode",
		0755,
		"Permissions bits for directories. Default is 0755.")

	flag.StringVar(
		&flags.TempDir,
		"temp_dir", "",
		"The temporary directory in which to store local copies of GCS objects. "+
			"If empty, the system default (probably /tmp) will be used.")

	flag.Int64Var(
		&flags.TempDirLimit,
		"temp_dir_bytes", 1<<31,
		"A desired limit on the number of bytes used in --temp_dir. May be "+
			"exceeded for dirty files that have not been flushed or closed.")

	flag.Uint64Var(
		&flags.GCSChunkSize,
		"gcs_chunk_size", 1<<24,
		"If set to a non-zero value N, split up GCS objects into multiple "+
			"chunks of size at most N when reading, and do not read or cache "+
			"unnecessary chunks.")

	flag.BoolVar(
		&flags.ImplicitDirs,
		"implicit_dirs",
		false,
		"Implicitly define directories based on their content. See "+
			"docs/semantics.md.")

	flag.DurationVar(
		&flags.StatCacheTTL,
		"stat_cache_ttl",
		time.Minute,
		"How long to cache StatObject results from GCS.")

	flag.DurationVar(
		&flags.TypeCacheTTL,
		"type_cache_ttl",
		time.Minute,
		"How long to cache name -> file/dir type mappings in directory inodes.")

	flag.Float64Var(
		&flags.OpRateLimitHz,
		"op_rate_limit_hz",
		-1,
		"If positive, a limit on the rate at which we send requests to GCS, "+
			"measured over a 30-second window.")

	flag.Float64Var(
		&flags.EgressBandwidthLimitBytesPerSecond,
		"egress_bandwidth_limit_bytes_per_second",
		-1,
		"If positive, a limit on the GCS -> gcsfuse bandwidth for reading "+
			"objects, measured over a 30-second window.")

	return
}
<commit_msg>Removed the redundant banner.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 main

import (
	"flag"
	"time"

	"github.com/googlecloudplatform/gcsfuse/mount"
)

type flagStorage struct {
	Help                               bool
	MountOptions                       map[string]string
	Uid                                int64
	Gid                                int64
	FileMode                           uint
	DirMode                            uint
	TempDir                            string
	TempDirLimit                       int64
	GCSChunkSize                       uint64
	ImplicitDirs                       bool
	StatCacheTTL                       time.Duration
	TypeCacheTTL                       time.Duration
	OpRateLimitHz                      float64
	EgressBandwidthLimitBytesPerSecond float64
}

// Add the flags accepted by run to the supplied flag set, returning the
// variables into which the flags will parse.
func populateFlagSet(fs *flag.FlagSet) (flags *flagStorage) {
	flags = new(flagStorage)

	flag.BoolVar(
		&flags.Help,
		"help",
		false,
		"If set, print usage and exit successfully.")

	flag.Var(
		mount.OptionValue(flags.MountOptions),
		"o",
		"Additional system-specific mount options. Be careful!")

	flag.Int64Var(
		&flags.Uid,
		"uid",
		-1,
		"If non-negative, the UID that owns all inodes. The default is the UID of "+
			"the gcsfuse process.")

	flag.Int64Var(
		&flags.Gid,
		"gid",
		-1,
		"If non-negative, the GID that owns all inodes. The default is the GID of "+
			"the gcsfuse process.")

	flag.UintVar(
		&flags.FileMode,
		"file_mode",
		0644,
		"Permissions bits for files. Default is 0644.")

	flag.UintVar(
		&flags.DirMode,
		"dir_mode",
		0755,
		"Permissions bits for directories. Default is 0755.")

	flag.StringVar(
		&flags.TempDir,
		"temp_dir", "",
		"The temporary directory in which to store local copies of GCS objects. "+
			"If empty, the system default (probably /tmp) will be used.")

	flag.Int64Var(
		&flags.TempDirLimit,
		"temp_dir_bytes", 1<<31,
		"A desired limit on the number of bytes used in --temp_dir. May be "+
			"exceeded for dirty files that have not been flushed or closed.")

	flag.Uint64Var(
		&flags.GCSChunkSize,
		"gcs_chunk_size", 1<<24,
		"If set to a non-zero value N, split up GCS objects into multiple "+
			"chunks of size at most N when reading, and do not read or cache "+
			"unnecessary chunks.")

	flag.BoolVar(
		&flags.ImplicitDirs,
		"implicit_dirs",
		false,
		"Implicitly define directories based on their content. See "+
			"docs/semantics.md.")

	flag.DurationVar(
		&flags.StatCacheTTL,
		"stat_cache_ttl",
		time.Minute,
		"How long to cache StatObject results from GCS.")

	flag.DurationVar(
		&flags.TypeCacheTTL,
		"type_cache_ttl",
		time.Minute,
		"How long to cache name -> file/dir type mappings in directory inodes.")

	flag.Float64Var(
		&flags.OpRateLimitHz,
		"op_rate_limit_hz",
		-1,
		"If positive, a limit on the rate at which we send requests to GCS, "+
			"measured over a 30-second window.")

	flag.Float64Var(
		&flags.EgressBandwidthLimitBytesPerSecond,
		"egress_bandwidth_limit_bytes_per_second",
		-1,
		"If positive, a limit on the GCS -> gcsfuse bandwidth for reading "+
			"objects, measured over a 30-second window.")

	return
}
<|endoftext|>


<commit_before>package service

import (
	"context"
	"crypto/sha1"
	"fmt"
	"io"
	"net/url"
	"sort"
	"time"

	"github.com/builderscon/octav/octav/cache"
	"github.com/builderscon/octav/octav/db"
	"github.com/builderscon/octav/octav/model"
	"github.com/builderscon/octav/octav/tools"
	pdebug "github.com/lestrrat/go-pdebug"
	urlenc "github.com/lestrrat/go-urlenc"
	"github.com/pkg/errors"
)

func (v *BlogEntrySvc) Init() {}

func (v *BlogEntrySvc) populateRowForCreate(vdb *db.BlogEntry, payload *model.CreateBlogEntryRequest) error {
	vdb.EID = tools.UUID()
	vdb.ConferenceID = payload.ConferenceID
	vdb.Title = payload.Title
	vdb.Status = payload.Status

	// Parse the URL, and do away with the URL fragment, if any
	u, err := url.Parse(payload.URL)
	if err != nil {
		return errors.Wrap(err, "failed to parse URL")
	}
	u.Fragment = ""
	vdb.URL = u.String()

	h := sha1.New()
	io.WriteString(h, payload.URL)
	vdb.URLHash = fmt.Sprintf("%x", (h.Sum(nil)))
	return nil
}

func (v *BlogEntrySvc) populateRowForUpdate(vdb *db.BlogEntry, payload *model.UpdateBlogEntryRequest) error {
	if payload.Title.Valid() {
		vdb.Title = payload.Title.String
	}
	if payload.URL.Valid() {
		vdb.URL = payload.URL.String
	}
	return nil
}

func invalidateBlogEntryLoadByConferenceID(confID string) error {
	c := Cache()

	var r model.ListBlogEntriesRequest
	r.ConferenceID = confID

	var keys []string
	for _, status := range [][]string{{"private"}, {"public"}, {"private", "public"}} {
		for _, trustedCall := range []bool{true, false} {
			for _, lang := range []string{"ja", "en", ""} {
				if lang == "" {
					r.Lang.ValidFlag = false
					r.Lang.String = ""
				} else {
					r.Lang.Set(lang)
				}

				r.Status = status
				r.TrustedCall = trustedCall
				keybytes, err := urlenc.Marshal(r)
				if err != nil {
					return errors.Wrap(err, "failed to marshal payload")
				}

				key := c.Key("BlogEntry", "ListFromPayload", string(keybytes))
				keys = append(keys, key)
			}
		}
	}

	for _, key := range keys {
		c.Delete(key)
	}
	return nil
}

func (v *BlogEntrySvc) PostCreateHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) PostUpdateHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) PostDeleteHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) Decorate(tx *db.Tx, v *model.BlogEntry, trustedCall bool, lang string) (err error) {
	// If this is not a trustedCall, we don't want to send the conference_id, status, or the url_hash
	if !trustedCall {
		v.ConferenceID = ""
		v.Status = ""
		v.URLHash = ""
	}
	return nil
}

func (v *BlogEntrySvc) CreateFromPayload(ctx context.Context, tx *db.Tx, result *model.BlogEntry, payload *model.CreateBlogEntryRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.CreateFromPayload").BindError(&err)
		defer g.End()
	}

	su := User()
	if err := su.IsConferenceAdministrator(tx, payload.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "creating blog entries require conference administrator privileges")
	}

	var vdb db.BlogEntry
	if err := v.Create(tx, &vdb, payload); err != nil {
		return errors.Wrap(err, "failed to insert into database")
	}

	if result != nil {
		var m model.BlogEntry
		if err := m.FromRow(&vdb); err != nil {
			return errors.Wrap(err, "failed to populate model from database")
		}

		*result = m
	}
	return nil
}

func (v *BlogEntrySvc) DeleteFromPayload(ctx context.Context, tx *db.Tx, payload *model.DeleteBlogEntryRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.DeleteFromPayload").BindError(&err)
		defer g.End()
	}

	var m model.BlogEntry
	if err := v.Lookup(tx, &m, payload.ID); err != nil {
		return errors.Wrap(err, "failed to look up blog entry")
	}

	su := User()
	if err := su.IsConferenceAdministrator(tx, m.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "deleting blog entries requires conference administrator privilege")
	}

	if err := v.Delete(tx, payload.ID); err != nil {
		return errors.Wrap(err, "failed to delete session")
	}
	return nil
}

func (v *BlogEntrySvc) ListFromPayload(tx *db.Tx, result *model.BlogEntryList, payload *model.ListBlogEntriesRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.ListFromPayload").BindError(&err)
		defer g.End()
	}

	status := payload.Status
	if len(status) == 0 {
		status = append(status, model.StatusPublic)
	}

	sort.Strings(payload.Status) // normalize
	keybytes, err := urlenc.Marshal(payload)
	if err != nil {
		return errors.Wrap(err, "failed to marshal payload")
	}
	c := Cache()
	key := c.Key("BlogEntry", "ListFromPayload", string(keybytes))
	x, err := c.GetOrSet(key, result, func() (interface{}, error) {
		if pdebug.Enabled {
			pdebug.Printf("CACHE MISS: Re-generating")
		}

		var vdbl db.BlogEntryList
		if err := vdbl.LoadByConference(tx, payload.ConferenceID, status); err != nil {
			return nil, errors.Wrap(err, "failed to load from database")
		}

		l := make(model.BlogEntryList, len(vdbl))
		for i, vdb := range vdbl {
			if err := l[i].FromRow(&vdb); err != nil {
				return nil, errors.Wrap(err, "failed to populate model from database")
			}

			if err := v.Decorate(tx, &l[i], payload.TrustedCall, payload.Lang.String); err != nil {
				return nil, errors.Wrap(err, "failed to decorate session with associated data")
			}
		}

		return &l, nil
	}, cache.WithExpires(10*time.Minute))

	if err != nil {
		return err
	}

	*result = *(x.(*model.BlogEntryList))
	return nil

}
<commit_msg>fix var name<commit_after>package service

import (
	"context"
	"crypto/sha1"
	"fmt"
	"io"
	"net/url"
	"sort"
	"time"

	"github.com/builderscon/octav/octav/cache"
	"github.com/builderscon/octav/octav/db"
	"github.com/builderscon/octav/octav/model"
	"github.com/builderscon/octav/octav/tools"
	pdebug "github.com/lestrrat/go-pdebug"
	urlenc "github.com/lestrrat/go-urlenc"
	"github.com/pkg/errors"
)

func (v *BlogEntrySvc) Init() {}

func (v *BlogEntrySvc) populateRowForCreate(vdb *db.BlogEntry, payload *model.CreateBlogEntryRequest) error {
	vdb.EID = tools.UUID()
	vdb.ConferenceID = payload.ConferenceID
	vdb.Title = payload.Title
	vdb.Status = payload.Status

	// Parse the URL, and do away with the URL fragment, if any
	u, err := url.Parse(payload.URL)
	if err != nil {
		return errors.Wrap(err, "failed to parse URL")
	}
	u.Fragment = ""
	vdb.URL = u.String()

	h := sha1.New()
	io.WriteString(h, payload.URL)
	vdb.URLHash = fmt.Sprintf("%x", (h.Sum(nil)))
	return nil
}

func (v *BlogEntrySvc) populateRowForUpdate(vdb *db.BlogEntry, payload *model.UpdateBlogEntryRequest) error {
	if payload.Title.Valid() {
		vdb.Title = payload.Title.String
	}
	if payload.URL.Valid() {
		vdb.URL = payload.URL.String
	}
	return nil
}

func invalidateBlogEntryLoadByConferenceID(confID string) error {
	c := Cache()

	var r model.ListBlogEntriesRequest
	r.ConferenceID = confID

	var keys []string
	for _, status := range [][]string{{"private"}, {"public"}, {"private", "public"}} {
		for _, trustedCall := range []bool{true, false} {
			for _, lang := range []string{"ja", "en", ""} {
				if lang == "" {
					r.Lang.ValidFlag = false
					r.Lang.String = ""
				} else {
					r.Lang.Set(lang)
				}

				r.Status = status
				r.TrustedCall = trustedCall
				keybytes, err := urlenc.Marshal(r)
				if err != nil {
					return errors.Wrap(err, "failed to marshal payload")
				}

				key := c.Key("BlogEntry", "ListFromPayload", string(keybytes))
				keys = append(keys, key)
			}
		}
	}

	for _, key := range keys {
		c.Delete(key)
	}
	return nil
}

func (v *BlogEntrySvc) PostCreateHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) PostUpdateHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) PostDeleteHook(_ *db.Tx, vdb *db.BlogEntry) error {
	return invalidateBlogEntryLoadByConferenceID(vdb.ConferenceID)
}

func (v *BlogEntrySvc) Decorate(tx *db.Tx, m *model.BlogEntry, trustedCall bool, lang string) (err error) {
	// If this is not a trustedCall, we don't want to send the conference_id, status, or the url_hash
	if !trustedCall {
		m.ConferenceID = ""
		m.Status = ""
		m.URLHash = ""
	}
	return nil
}

func (v *BlogEntrySvc) CreateFromPayload(ctx context.Context, tx *db.Tx, result *model.BlogEntry, payload *model.CreateBlogEntryRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.CreateFromPayload").BindError(&err)
		defer g.End()
	}

	su := User()
	if err := su.IsConferenceAdministrator(tx, payload.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "creating blog entries require conference administrator privileges")
	}

	var vdb db.BlogEntry
	if err := v.Create(tx, &vdb, payload); err != nil {
		return errors.Wrap(err, "failed to insert into database")
	}

	if result != nil {
		var m model.BlogEntry
		if err := m.FromRow(&vdb); err != nil {
			return errors.Wrap(err, "failed to populate model from database")
		}

		*result = m
	}
	return nil
}

func (v *BlogEntrySvc) DeleteFromPayload(ctx context.Context, tx *db.Tx, payload *model.DeleteBlogEntryRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.DeleteFromPayload").BindError(&err)
		defer g.End()
	}

	var m model.BlogEntry
	if err := v.Lookup(tx, &m, payload.ID); err != nil {
		return errors.Wrap(err, "failed to look up blog entry")
	}

	su := User()
	if err := su.IsConferenceAdministrator(tx, m.ConferenceID, payload.UserID); err != nil {
		return errors.Wrap(err, "deleting blog entries requires conference administrator privilege")
	}

	if err := v.Delete(tx, payload.ID); err != nil {
		return errors.Wrap(err, "failed to delete session")
	}
	return nil
}

func (v *BlogEntrySvc) ListFromPayload(tx *db.Tx, result *model.BlogEntryList, payload *model.ListBlogEntriesRequest) (err error) {
	if pdebug.Enabled {
		g := pdebug.Marker("BlogEntrySvc.ListFromPayload").BindError(&err)
		defer g.End()
	}

	status := payload.Status
	if len(status) == 0 {
		status = append(status, model.StatusPublic)
	}

	sort.Strings(payload.Status) // normalize
	keybytes, err := urlenc.Marshal(payload)
	if err != nil {
		return errors.Wrap(err, "failed to marshal payload")
	}
	c := Cache()
	key := c.Key("BlogEntry", "ListFromPayload", string(keybytes))
	x, err := c.GetOrSet(key, result, func() (interface{}, error) {
		if pdebug.Enabled {
			pdebug.Printf("CACHE MISS: Re-generating")
		}

		var vdbl db.BlogEntryList
		if err := vdbl.LoadByConference(tx, payload.ConferenceID, status); err != nil {
			return nil, errors.Wrap(err, "failed to load from database")
		}

		l := make(model.BlogEntryList, len(vdbl))
		for i, vdb := range vdbl {
			if err := l[i].FromRow(&vdb); err != nil {
				return nil, errors.Wrap(err, "failed to populate model from database")
			}

			if err := v.Decorate(tx, &l[i], payload.TrustedCall, payload.Lang.String); err != nil {
				return nil, errors.Wrap(err, "failed to decorate session with associated data")
			}
		}

		return &l, nil
	}, cache.WithExpires(10*time.Minute))

	if err != nil {
		return err
	}

	*result = *(x.(*model.BlogEntryList))
	return nil

}
<|endoftext|>


<commit_before>package modelmapper_test

import (
	"encoding/json"
	"testing"

	"github.com/herb-go/herb/model/sql/db"
	"github.com/herb-go/herb/model/sql/querybuilder/modelmapper"
)

func TestAlias(t *testing.T) {
	var DB = db.New()
	var config = db.NewConfig()
	var err error
	err = json.Unmarshal([]byte(MysqlConfigJSON), config)
	if err != nil {
		t.Fatal(err)
	}
	err = DB.Init(config)
	if err != nil {
		t.Fatal(err)
	}
	table1 := modelmapper.New(DB.Table("testtable1"))
	table1.SetAlias("")
	field := table1.FieldAlias("id")
	if field != "id" {
		t.Fatal(field)
	}
	table1.SetAlias("test")
	field = table1.FieldAlias("id")
	if field != "test.id" {
		t.Fatal(field)
	}
}
<commit_msg>update<commit_after>package modelmapper_test

import (
	"encoding/json"
	"testing"

	"github.com/herb-go/herb/model/sql/db"
	"github.com/herb-go/herb/model/sql/querybuilder/modelmapper"
	_ "github.com/mattn/go-sqlite3"
)

var SqliteConfigJSON = `
{
	"Driver": "sqlite3",
	"DataSource": "_test/sqlite.db",
	"Prefix": "",
	"MaxIdleConns":10,
	"ConnMaxLifetimeInSecond":3600,
	"MaxOpenConns":10
}
`

func TestAlias(t *testing.T) {
	var DB = db.New()
	var config = db.NewConfig()
	var err error
	err = json.Unmarshal([]byte(SqliteConfigJSON), config)
	if err != nil {
		t.Fatal(err)
	}
	err = DB.Init(config)
	if err != nil {
		t.Fatal(err)
	}
	table1 := modelmapper.New(DB.Table("testtable1"))
	table1.SetAlias("")
	field := table1.FieldAlias("id")
	if field != "id" {
		t.Fatal(field)
	}
	table1.SetAlias("test")
	field = table1.FieldAlias("id")
	if field != "test.id" {
		t.Fatal(field)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"image"
	"image/color"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"log"
	"math"
	"os"

	"github.com/nfnt/resize"
)

const ANSIClear = "\033[0m"

func init() {
	log.SetFlags(0)
}

func main() {
	width := flag.Int("width", 0, "desired width in terminal columns")
	pad := flag.Bool("pad", false, "pad output on the left with whitespace")
	paletteName := flag.String("color", "256", "color palette (8, 256, gray, ...)")
	fontAspect := flag.Float64("fontaspect", 0.5, "aspect ratio (width/height)")
	flag.Parse()

	palette := ansiPalettes[*paletteName]
	if palette == nil {
		log.Fatalf("color palette not one of %q", ANSIPalettes())
	}

	if flag.NArg() < 1 {
		log.Fatal("missing filename")
	}
	if flag.NArg() > 1 {
		log.Fatal("unexpected arguments")
	}
	filename := flag.Arg(0)

	img, _, err := readImage(filename)
	if err != nil {
		log.Fatalf("image: %v", err)
	}

	// resize img to the proper width and aspect ratio
	size := img.Bounds().Size()
	if *width > 0 {
		size = sizeWidth(size, *width, *fontAspect)
	} else {
		size = sizeNormal(size, *fontAspect)
	}
	img = resize.Resize(uint(size.X), uint(size.Y), img, 0)

	err = writePixelsANSI(os.Stdout, img, palette, *pad)
	if err != nil {
		log.Fatalf("write: %v", err)
	}
}

func writePixelsANSI(w io.Writer, img image.Image, p ANSIPalette, pad bool) error {
	wbuf := bufio.NewWriter(w)
	rect := img.Bounds()
	size := rect.Size()
	for y := 0; y < size.Y; y++ {
		if pad {
			fmt.Fprint(wbuf, "  ")
		}
		for x := 0; x < size.X; x++ {
			color := img.At(rect.Min.X+x, rect.Min.Y+y)
			fmt.Fprint(wbuf, p.ANSI(color)+" ")
		}
		fmt.Fprintln(wbuf, ANSIClear)
	}
	return wbuf.Flush()
}

// readImage reads an image.Image from a specified file.
func readImage(filename string) (image.Image, string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, "", err
	}
	defer f.Close()

	img, format, err := image.Decode(f)
	if err != nil {
		return nil, "", err
	}
	return img, format, nil
}

// sizeWidth returns a point with X equal to width and the same normalized
// aspect ratio as size.
func sizeWidth(size image.Point, width int, fontAspect float64) image.Point {
	size = sizeNormal(size, fontAspect)
	aspect := float64(size.X) / float64(size.Y)
	size.X = width
	size.Y = int(round(float64(width) / aspect))
	return size
}

// sizeNormal scales size according to aspect ratio fontAspect and returns the
// new size.
func sizeNormal(size image.Point, fontAspect float64) image.Point {
	aspect := float64(size.X) / float64(size.Y)
	norm := size
	norm.Y = size.Y
	w := float64(norm.Y) * aspect / fontAspect
	norm.X = int(round(w))
	return norm
}

// round x to the nearest integer biased toward +Inf.
func round(x float64) float64 {
	return math.Ceil(x - 0.5)
}

type ANSIPalette interface {
	ANSI(color.Color) string
}

var ansiPalettes = map[string]ANSIPalette{
	"256":       new(Palette256),
	"256-color": new(Palette256),
	"8":         DefaultPalette8,
	"8-color":   DefaultPalette8,
	"gray":      new(PaletteGray),
	"grayscale": new(PaletteGray),
	"grey":      new(PaletteGray),
	"greyscale": new(PaletteGray),
}

func ANSIPalettes() []string {
	var names []string
	for name := range ansiPalettes {
		names = append(names, name)
	}
	return names
}

// PaletteGray is an ANSIPalette that maps color.Color values to one of twenty
// four grayscale values.
type PaletteGray struct {
}

func (p *PaletteGray) ANSI(c color.Color) string {
	const begin = 0xe8
	const ratio = 24.0 / 255.0
	_, _, _, a := c.RGBA()
	if a == 0 {
		return ANSIClear
	}
	gray := color.GrayModel.Convert(c).(color.Gray).Y
	scaled := int(round(ratio * float64(gray)))
	return fmt.Sprintf("\033[48;5;%dm", scaled+begin)
}

// Palette8 is an ANSIPalette that maps color.Color values to one of 8 color
// indexes by minimizing euclidean RGB distance.
type Palette8 [8][3]uint8

var DefaultPalette8 = &Palette8{
	{0, 0, 0},       // black
	{191, 25, 25},   // red
	{25, 184, 25},   // green
	{188, 110, 25},  // orange/brown/yellow
	{25, 25, 184},   // blue
	{186, 25, 186},  // magenta
	{25, 187, 187},  // cyan
	{178, 178, 178}, // gray
}

func (p *Palette8) ANSI(c color.Color) string {
	_, _, _, a := c.RGBA()
	if a == 0 {
		return ANSIClear
	}
	min := math.Inf(1) // minimum distance from c
	var imin int       // minimizing index
	for i, rgb := range *p {
		other := color.RGBA{rgb[0], rgb[1], rgb[2], 0}
		dist := Distance(other, c)
		if dist < min {
			min = dist
			imin = i
		}
	}
	return fmt.Sprintf("\033[4%dm", imin)
}

// Palette256 is an ANSIPalette that maps color.Color to one of 256 RGB colors.
type Palette256 struct {
}

func (p *Palette256) ANSI(c color.Color) string {
	const begin = 16
	const ratio = 5.0 / (1<<16 - 1)
	rf, gf, bf, af := c.RGBA()
	if af == 0 {
		return ANSIClear
	}
	r := int(round(ratio * float64(rf)))
	g := int(round(ratio * float64(gf)))
	b := int(round(ratio * float64(bf)))
	return fmt.Sprintf("\033[48;5;%dm", r*6*6+g*6+b+begin)
}

// Distance computes euclidean distance between the RGB values of c1 and c2.
func Distance(c1, c2 color.Color) float64 {
	r1, g1, b1, _ := c1.RGBA()
	r2, g2, b2, _ := c2.RGBA()
	rdiff := float64(int(r1) - int(r2))
	gdiff := float64(int(g1) - int(g2))
	bdiff := float64(int(b1) - int(b2))
	return math.Sqrt(rdiff*rdiff + gdiff*gdiff + bdiff*bdiff)
}
<commit_msg>profiling + optimizations<commit_after>package main

import (
	"bufio"
	"flag"
	"image"
	"image/color"
	_ "image/gif"
	_ "image/jpeg"
	_ "image/png"
	"io"
	"log"
	"math"
	"os"
	"runtime/pprof"
	"strconv"

	"github.com/nfnt/resize"
)

const ANSIClear = "\033[0m"

func init() {
	log.SetFlags(0)
}

func main() {
	cpuprofile := flag.String("cpuprofile", "", "path of pprof CPU profile output")
	width := flag.Int("width", 0, "desired width in terminal columns")
	pad := flag.Bool("pad", false, "pad output on the left with whitespace")
	paletteName := flag.String("color", "256", "color palette (8, 256, gray, ...)")
	fontAspect := flag.Float64("fontaspect", 0.5, "aspect ratio (width/height)")
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	palette := ansiPalettes[*paletteName]
	if palette == nil {
		log.Fatalf("color palette not one of %q", ANSIPalettes())
	}

	if flag.NArg() < 1 {
		log.Fatal("missing filename")
	}
	if flag.NArg() > 1 {
		log.Fatal("unexpected arguments")
	}
	filename := flag.Arg(0)

	img, _, err := readImage(filename)
	if err != nil {
		log.Fatalf("image: %v", err)
	}

	// resize img to the proper width and aspect ratio
	size := img.Bounds().Size()
	if *width > 0 {
		size = sizeWidth(size, *width, *fontAspect)
	} else {
		size = sizeNormal(size, *fontAspect)
	}
	img = resize.Resize(uint(size.X), uint(size.Y), img, 0)

	err = writePixelsANSI(os.Stdout, img, palette, *pad)
	if err != nil {
		log.Fatalf("write: %v", err)
	}
}

var lineBytes = []byte{'\n'}
var spaceBytes = []byte{' '}

func writePixelsANSI(w io.Writer, img image.Image, p ANSIPalette, pad bool) error {
	wbuf := bufio.NewWriter(w)
	rect := img.Bounds()
	size := rect.Size()
	for y := 0; y < size.Y; y++ {
		if pad {
			wbuf.Write(spaceBytes)
			wbuf.Write(spaceBytes)
		}
		for x := 0; x < size.X; x++ {
			color := img.At(rect.Min.X+x, rect.Min.Y+y)
			io.WriteString(wbuf, p.ANSI(color))
			wbuf.Write(spaceBytes)

		}
		io.WriteString(wbuf, ANSIClear)
		wbuf.Write(lineBytes)
	}
	return wbuf.Flush()
}

// readImage reads an image.Image from a specified file.
func readImage(filename string) (image.Image, string, error) {
	f, err := os.Open(filename)
	if err != nil {
		return nil, "", err
	}
	defer f.Close()

	img, format, err := image.Decode(f)
	if err != nil {
		return nil, "", err
	}
	return img, format, nil
}

// sizeWidth returns a point with X equal to width and the same normalized
// aspect ratio as size.
func sizeWidth(size image.Point, width int, fontAspect float64) image.Point {
	size = sizeNormal(size, fontAspect)
	aspect := float64(size.X) / float64(size.Y)
	size.X = width
	size.Y = int(round(float64(width) / aspect))
	return size
}

// sizeNormal scales size according to aspect ratio fontAspect and returns the
// new size.
func sizeNormal(size image.Point, fontAspect float64) image.Point {
	aspect := float64(size.X) / float64(size.Y)
	norm := size
	norm.Y = size.Y
	w := float64(norm.Y) * aspect / fontAspect
	norm.X = int(round(w))
	return norm
}

// round x to the nearest integer biased toward +Inf.
func round(x float64) float64 {
	return math.Ceil(x - 0.5)
}

type ANSIPalette interface {
	ANSI(color.Color) string
}

var ansiPalettes = map[string]ANSIPalette{
	"256":       new(Palette256),
	"256-color": new(Palette256),
	"8":         DefaultPalette8,
	"8-color":   DefaultPalette8,
	"gray":      new(PaletteGray),
	"grayscale": new(PaletteGray),
	"grey":      new(PaletteGray),
	"greyscale": new(PaletteGray),
}

func ANSIPalettes() []string {
	var names []string
	for name := range ansiPalettes {
		names = append(names, name)
	}
	return names
}

// PaletteGray is an ANSIPalette that maps color.Color values to one of twenty
// four grayscale values.
type PaletteGray struct {
}

func (p *PaletteGray) ANSI(c color.Color) string {
	const begin = 0xe8
	const ratio = 24.0 / 255.0
	_, _, _, a := c.RGBA()
	if a == 0 {
		return ANSIClear
	}
	gray := color.GrayModel.Convert(c).(color.Gray).Y
	scaled := int(round(ratio * float64(gray)))
	value := scaled + begin
	return "\033[48;5;" + strconv.Itoa(value) + "m"
}

// Palette8 is an ANSIPalette that maps color.Color values to one of 8 color
// indexes by minimizing euclidean RGB distance.
type Palette8 [8][3]uint8

var DefaultPalette8 = &Palette8{
	{0, 0, 0},       // black
	{191, 25, 25},   // red
	{25, 184, 25},   // green
	{188, 110, 25},  // orange/brown/yellow
	{25, 25, 184},   // blue
	{186, 25, 186},  // magenta
	{25, 187, 187},  // cyan
	{178, 178, 178}, // gray
}

func (p *Palette8) ANSI(c color.Color) string {
	_, _, _, a := c.RGBA()
	if a == 0 {
		return ANSIClear
	}
	min := math.Inf(1) // minimum distance from c
	var imin int       // minimizing index
	for i, rgb := range *p {
		other := color.RGBA{rgb[0], rgb[1], rgb[2], 0}
		dist := Distance(other, c)
		if dist < min {
			min = dist
			imin = i
		}
	}
	return "\033[4" + strconv.Itoa(imin) + "m"
}

// Palette256 is an ANSIPalette that maps color.Color to one of 256 RGB colors.
type Palette256 struct {
}

func (p *Palette256) ANSI(c color.Color) string {
	const begin = 16
	const ratio = 5.0 / (1<<16 - 1)
	rf, gf, bf, af := c.RGBA()
	if af == 0 {
		return ANSIClear
	}
	r := int(round(ratio * float64(rf)))
	g := int(round(ratio * float64(gf)))
	b := int(round(ratio * float64(bf)))
	val := r*6*6 + g*6 + b + begin
	return "\033[48;5;" + strconv.Itoa(val) + "m"
}

// Distance computes euclidean distance between the RGB values of c1 and c2.
func Distance(c1, c2 color.Color) float64 {
	r1, g1, b1, _ := c1.RGBA()
	r2, g2, b2, _ := c2.RGBA()
	rdiff := float64(int(r1) - int(r2))
	gdiff := float64(int(g1) - int(g2))
	bdiff := float64(int(b1) - int(b2))
	return math.Sqrt(rdiff*rdiff + gdiff*gdiff + bdiff*bdiff)
}
<|endoftext|>


<commit_before>package aranGO

import (
	"errors"
	"strings"
)

type Document struct {
	Id  string `json:"_id,omitempty"  `
	Rev string `json:"_rev,omitempty" `
	Key string `json:"_key,omitempty" `

	Error   bool   `json:"error,omitempty"`
  /*
	Message string `json:"errorMessage,omitempty"`
	Code    int    `json:"code,omitempty"`
	Num     int    `json:"errorNum,omitempty"`
  */
}

func NewDocument(id string) (*Document, error) {
	// some basic validation
	sid := strings.Split(id, "/")
	if len(sid) != 2 {
		return nil, errors.New("Invalid id")
	}
	if id == "" {
		return nil, errors.New("Invalid empty id")
	}
	var d Document
	d.Id = id
	d.Key = sid[1]
	return &d, nil
}

func (d *Document) SetKey(key string) error {
	//valitated key
	d.Key = key
	return nil
}

func (d *Document) SetRev(rev string) error {
	d.Rev = rev
	return nil
}

// Check if a document was updated
func (d *Document) Updated(db *Database) (bool,error){
	if db == nil {
		return false, errors.New("Invalid db")
	}
  // check document id and rev
  if d.Id == "" || d.Rev == "" {
    return false, errors.New("Document must exist or have valid _rev and _id")
  }
  // add revision id
  res, err := db.get("document",d.Id + "?rev="+d.Rev,"GET",nil,nil,nil)

  if err != nil{
    return false,err
  }

  switch res.Status(){
    case 404:
       return true,nil
    case 412:
       return true,nil
    default:
       return false,nil
  }
}

// Check if document exist
func (d *Document) Exist(db *Database) (bool, error) {

	if db == nil {
		return false, errors.New("Invalid db")
	}
  // check document id and rev
  if d.Id == "" {
    return false, errors.New("Document must exist or have valid _rev and _id")
  }
  // add revision id
  res, err := db.get("document",d.Id,"GET",nil,nil,nil)

  if err != nil{
    return false,err
  }

  switch res.Status(){
    case 404:
       return false,nil
    default:
       return true,nil
  }
}

<commit_msg>messages in error<commit_after>package aranGO

import (
	"errors"
	"strings"
)

type Document struct {
	Id  string `json:"_id,omitempty"  `
	Rev string `json:"_rev,omitempty" `
	Key string `json:"_key,omitempty" `

	Error   bool   `json:"error,omitempty"`
	Message string `json:"errorMessage,omitempty"`
  /*
	Code    int    `json:"code,omitempty"`
	Num     int    `json:"errorNum,omitempty"`
  */
}

func NewDocument(id string) (*Document, error) {
	// some basic validation
	sid := strings.Split(id, "/")
	if len(sid) != 2 {
		return nil, errors.New("Invalid id")
	}
	if id == "" {
		return nil, errors.New("Invalid empty id")
	}
	var d Document
	d.Id = id
	d.Key = sid[1]
	return &d, nil
}

func (d *Document) SetKey(key string) error {
	//valitated key
	d.Key = key
	return nil
}

func (d *Document) SetRev(rev string) error {
	d.Rev = rev
	return nil
}

// Check if a document was updated
func (d *Document) Updated(db *Database) (bool,error){
	if db == nil {
		return false, errors.New("Invalid db")
	}
  // check document id and rev
  if d.Id == "" || d.Rev == "" {
    return false, errors.New("Document must exist or have valid _rev and _id")
  }
  // add revision id
  res, err := db.get("document",d.Id + "?rev="+d.Rev,"GET",nil,nil,nil)

  if err != nil{
    return false,err
  }

  switch res.Status(){
    case 404:
       return true,nil
    case 412:
       return true,nil
    default:
       return false,nil
  }
}

// Check if document exist
func (d *Document) Exist(db *Database) (bool, error) {

	if db == nil {
		return false, errors.New("Invalid db")
	}
  // check document id and rev
  if d.Id == "" {
    return false, errors.New("Document must exist or have valid _rev and _id")
  }
  // add revision id
  res, err := db.get("document",d.Id,"GET",nil,nil,nil)

  if err != nil{
    return false,err
  }

  switch res.Status(){
    case 404:
       return false,nil
    default:
       return true,nil
  }
}

<|endoftext|>


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

package policy

import "errors"

// Type denotes the monitoring policy type.
//
// e.g. "tcp"
type Type string

// Policy is the map containing the rules of a particular monitoring policy.
//
// e.g. "tcp" PolicyType requires 2 policy keys "port" and "frequency"
type Policy struct {
	Name     string            `json:"name"`
	AgentUID string            `json:"agent_uid"`
	Type     Type              `json:"policy_type"`
	M        map[string]string `json:"m"`
}

// Config is the format used to encode/decode the monitoring policy
// received from the message queue or to store in the config file
type Config []Policy

// PolicyFuncMap maps a PolicyType to a handler function
var PolicyFuncMap = map[Type]func(Policy) error{
	"tcp": tcpPolicyHandler,
}

func (p Policy) Execute() error {
	if err := p.Valid(); err != nil {
		return err
	}
	return PolicyFuncMap[p.Type](p)
}

// Valid checks whether the policy is valid.
func (p Policy) Valid() error {
	if p.Name == "" {
		return errors.New("policy name can't be empty")
	}
	// TODO: also check if the name conflicts with already
	// existing ones
	if _, ok := PolicyFuncMap[p.Type]; !ok {
		return errors.New("policy type unknown")
	}
	return nil
}
<commit_msg>remove json tags for Policy<commit_after>// Copyright 2015 CodeIgnition. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package policy

import "errors"

// Type denotes the monitoring policy type.
//
// e.g. "tcp"
type Type string

// Policy is the map containing the rules of a particular monitoring policy.
//
// e.g. "tcp" PolicyType requires 2 policy keys "port" and "frequency"
type Policy struct {
	Name     string
	AgentUID string
	Type     Type
	M        map[string]string
}

// Config is the format used to encode/decode the monitoring policy
// received from the message queue or to store in the config file
type Config []Policy

// PolicyFuncMap maps a PolicyType to a handler function
var PolicyFuncMap = map[Type]func(Policy) error{
	"tcp": tcpPolicyHandler,
}

func (p Policy) Execute() error {
	if err := p.Valid(); err != nil {
		return err
	}
	return PolicyFuncMap[p.Type](p)
}

// Valid checks whether the policy is valid.
func (p Policy) Valid() error {
	if p.Name == "" {
		return errors.New("policy name can't be empty")
	}
	// TODO: also check if the name conflicts with already
	// existing ones
	if _, ok := PolicyFuncMap[p.Type]; !ok {
		return errors.New("policy type unknown")
	}
	return nil
}
<|endoftext|>


<commit_before>// +build darwin,amd64 darwin,arm64 freebsd dragonfly netbsd openbsd

package poll

import (
	"context"
	"golang.org/x/sys/unix"
	"time"
)

type Poller struct {
	kqfd  int
	event unix.Kevent_t
}

func New(fd int) (p *Poller, err error) {
	p = &Poller{}

	p.kqfd, err = unix.Kqueue()
	if p.kqfd == -1 || err != nil {
		return nil, err
	}

	p.event = unix.Kevent_t{
		Ident:  uint64(fd),
		Filter: unix.EVFILT_WRITE,
		Flags:  unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT,
		Fflags: 0,
		Data:   0,
		Udata:  nil,
	}
	return p, nil
}

func (p *Poller) Close() error {
	return unix.Close(p.kqfd)
}

func (p *Poller) WaitWriteCtx(ctx context.Context) error {
	deadline, _ := ctx.Deadline()

	// setup timeout
	var timeout *unix.Timespec
	if !deadline.IsZero() {
		d := deadline.Sub(time.Now())
		t := unix.NsecToTimespec(d.Nanoseconds())
		timeout = &t
	}

	// wait on kevent
	events := make([]unix.Kevent_t, 1)
	n, err := unix.Kevent(p.kqfd, []unix.Kevent_t{p.event}, events, timeout)
	if err != nil {
		return err
	}

	if n < 1 {
		return errTimeout
	}
	return nil
}
<commit_msg>make reuseport compile on netbsd<commit_after>// +build darwin,amd64 darwin,arm64 freebsd dragonfly netbsd openbsd

package poll

import (
	"context"
	"golang.org/x/sys/unix"
	"time"
)

type Poller struct {
	kqfd  int
	event unix.Kevent_t
}

func New(fd int) (p *Poller, err error) {
	p = &Poller{}

	p.kqfd, err = unix.Kqueue()
	if p.kqfd == -1 || err != nil {
		return nil, err
	}

	p.event = unix.Kevent_t{
		Ident:  uint64(fd),
		Filter: unix.EVFILT_WRITE,
		Flags:  unix.EV_ADD | unix.EV_ENABLE | unix.EV_ONESHOT,
	}
	return p, nil
}

func (p *Poller) Close() error {
	return unix.Close(p.kqfd)
}

func (p *Poller) WaitWriteCtx(ctx context.Context) error {
	deadline, _ := ctx.Deadline()

	// setup timeout
	var timeout *unix.Timespec
	if !deadline.IsZero() {
		d := deadline.Sub(time.Now())
		t := unix.NsecToTimespec(d.Nanoseconds())
		timeout = &t
	}

	// wait on kevent
	events := make([]unix.Kevent_t, 1)
	n, err := unix.Kevent(p.kqfd, []unix.Kevent_t{p.event}, events, timeout)
	if err != nil {
		return err
	}

	if n < 1 {
		return errTimeout
	}
	return nil
}
<|endoftext|>


<commit_before>package controller

import (
	"fmt"
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres" // postgres driver
	_ "github.com/jinzhu/gorm/dialects/sqlite"   // sqlite driver
)

// Load environment
const env string = os.Getenv("API_RATINGS_ENV")

// Load database settings
const readDBName string = os.Getenv("API_RATINGS_READDB_NAME")
const readDBHost string = os.Getenv("API_RATINGS_READDB_HOST")
const readDBUser string = os.Getenv("API_RATINGS_READDB_USER")
const readDBPassword string = os.Getenv("API_RATINGS_READDB_PASSWORD")

const writeDBName string = os.Getenv("API_RATINGS_WRITEDB_NAME")
const writeDBHost string = os.Getenv("API_RATINGS_WRITEDB_HOST")
const writeDBUser string = os.Getenv("API_RATINGS_WRITEDB_USER")
const writeDBPassword string = os.Getenv("API_RATINGS_WRITEDB_PASSWORD")

func connectDB(driver string, credentials string) *gorm.DB {
	db, err := gorm.Open(driver, credentials)
	if err != nil {
		panic("Failed to connect to " + driver + " database")
	}
	defer db.Close()

	return db
}

// GetReadDB connects to the read database and return a pointer to the connection
func GetReadDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("sqlite3", readDBHost+'/'+readDBName)
	}

	credentials := fmt.Sprintf(
		"host=%s user=%s dbname=%s sslmode=disable password=%s",
		readDBHost,
		readDBUser,
		readDBName,
		readDBPassword
		)

	return connectDB("postgres", credentials)
}

// GetWriteDB connects to the write database and return a pointer to the connection
func GetWriteDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("sqlite3", writeDBHost+'/'+writeDBName)
	}

	credentials := fmt.Sprintf(
		"host=%s user=%s dbname=%s sslmode=disable password=%s",
		writeDBHost,
		writeDBUser,
		writeDBName,
		writeDBPassword
		)

	return connectDB("postgres", credentials)
}
<commit_msg>Added comment<commit_after>package controller

import (
	"fmt"
	"os"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres" // postgres driver
	_ "github.com/jinzhu/gorm/dialects/sqlite"   // sqlite driver
)

// Load environment
const env string = os.Getenv("API_RATINGS_ENV")

// Load read database settings
const readDBName string = os.Getenv("API_RATINGS_READDB_NAME")
const readDBHost string = os.Getenv("API_RATINGS_READDB_HOST")
const readDBUser string = os.Getenv("API_RATINGS_READDB_USER")
const readDBPassword string = os.Getenv("API_RATINGS_READDB_PASSWORD")

// Load write database settings
const writeDBName string = os.Getenv("API_RATINGS_WRITEDB_NAME")
const writeDBHost string = os.Getenv("API_RATINGS_WRITEDB_HOST")
const writeDBUser string = os.Getenv("API_RATINGS_WRITEDB_USER")
const writeDBPassword string = os.Getenv("API_RATINGS_WRITEDB_PASSWORD")

func connectDB(driver string, credentials string) *gorm.DB {
	db, err := gorm.Open(driver, credentials)
	if err != nil {
		panic("Failed to connect to " + driver + " database")
	}
	defer db.Close()

	return db
}

// GetReadDB connects to the read database and return a pointer to the connection
func GetReadDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("sqlite3", readDBHost+'/'+readDBName)
	}

	credentials := fmt.Sprintf(
		"host=%s user=%s dbname=%s sslmode=disable password=%s", // TODO: Handle sslmode
		readDBHost,
		readDBUser,
		readDBName,
		readDBPassword
		)

	return connectDB("postgres", credentials)
}

// GetWriteDB connects to the write database and return a pointer to the connection
func GetWriteDB() *gorm.DB {
	if env != "PRODUCTION" {
		return connectDB("sqlite3", writeDBHost+'/'+writeDBName)
	}

	credentials := fmt.Sprintf(
		"host=%s user=%s dbname=%s sslmode=disable password=%s", // TODO: Handle sslmode
		writeDBHost,
		writeDBUser,
		writeDBName,
		writeDBPassword
		)

	return connectDB("postgres", credentials)
}
<|endoftext|>