<commit_before>// Copyright 2018 NetApp, Inc. All Rights Reserved.

package logging

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"

	"github.com/netapp/trident/config"
	"github.com/netapp/trident/utils"
)

const (
	TextFormat             = "text"
	JSONFormat             = "json"
	defaultTimestampFormat = time.RFC3339
)

// InitLoggingForDocker configures logging for nDVP.  Logs are written both to a log file as well as stdout/stderr.
// Since logrus doesn't support multiple writers, each log stream is implemented as a hook.
func InitLoggingForDocker(logName, logFormat string) error {

	// No output except for the hooks
	log.SetOutput(ioutil.Discard)

	// Write to the log file
	logFileHook, err := NewFileHook(logName, logFormat)
	if err != nil {
		return fmt.Errorf("could not initialize logging to file: %v", err)
	}
	log.AddHook(logFileHook)

	// Write to stdout/stderr
	logConsoleHook, err := NewConsoleHook(logFormat)
	if err != nil {
		return fmt.Errorf("could not initialize logging to console: %v", err)
	}
	log.AddHook(logConsoleHook)

	// Remind users where the log file lives
	log.WithFields(log.Fields{
		"logLevel":        log.GetLevel().String(),
		"logFileLocation": logFileHook.GetLocation(),
		"buildTime":       config.BuildTime,
	}).Info("Initialized logging.")

	customInterval := os.Getenv(RandomLogcheckEnvVar)
	if customInterval != "" {
		customIntervalValue, err := strconv.Atoi(customInterval)
		if err == nil {
			randomLogcheckInterval = customIntervalValue
		}
	}

	return nil
}

// InitLogLevel configures the logging level.  The debug flag takes precedence if set,
// otherwise the logLevel flag (debug, info, warn, error, fatal) is used.
func InitLogLevel(debug bool, logLevel string) error {
	if debug {
		log.SetLevel(log.DebugLevel)
	} else {
		level, err := log.ParseLevel(logLevel)
		if err != nil {
			return err
		}
		log.SetLevel(level)
	}
	return nil
}

// InitLogFormat configures the log format, allowing a choice of text or JSON.
func InitLogFormat(logFormat string) error {
	switch logFormat {
	case TextFormat:
		log.SetFormatter(&log.TextFormatter{})
	case JSONFormat:
		log.SetFormatter(&JSONFormatter{})
	default:
		return fmt.Errorf("unknown log format: %s", logFormat)
	}
	return nil
}

// ConsoleHook sends log entries to stdout.
type ConsoleHook struct {
	formatter log.Formatter
}

// NewConsoleHook creates a new log hook for writing to stdout/stderr.
func NewConsoleHook(logFormat string) (*ConsoleHook, error) {

	var formatter log.Formatter

	switch logFormat {
	case TextFormat:
		formatter = &log.TextFormatter{FullTimestamp: true}
	case JSONFormat:
		formatter = &JSONFormatter{}
	default:
		return nil, fmt.Errorf("unknown log format: %s", logFormat)
	}

	return &ConsoleHook{formatter}, nil
}

func (hook *ConsoleHook) Levels() []log.Level {
	return log.AllLevels
}

func (hook *ConsoleHook) checkIfTerminal(w io.Writer) bool {
	switch v := w.(type) {
	case *os.File:
		return terminal.IsTerminal(int(v.Fd()))
	default:
		return false
	}
}

func (hook *ConsoleHook) Fire(entry *log.Entry) error {

	// Determine output stream
	var logWriter io.Writer
	switch entry.Level {
	case log.DebugLevel, log.InfoLevel, log.WarnLevel:
		logWriter = os.Stdout
	case log.ErrorLevel, log.FatalLevel, log.PanicLevel:
		logWriter = os.Stderr
	default:
		return fmt.Errorf("unknown log level: %v", entry.Level)
	}

	// Write log entry to output stream
	if textFormatter, ok := hook.formatter.(*log.TextFormatter); ok {
		textFormatter.ForceColors = hook.checkIfTerminal(logWriter)
	}

	lineBytes, err := hook.formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
		return err
	}
	if len(lineBytes) > MaxLogEntryLength {
		if _, err := logWriter.Write(lineBytes[:MaxLogEntryLength]); err != nil {
			return err
		}
		if _, err = logWriter.Write([]byte("<truncated>\n")); err != nil {
			return err
		}
	} else {
		if _, err := logWriter.Write(lineBytes); err != nil {
			return err
		}
	}

	return nil
}

// FileHook sends log entries to a file.
type FileHook struct {
	logFileLocation string
	formatter       log.Formatter
	mutex           *sync.Mutex
}

// NewFileHook creates a new log hook for writing to a file.
func NewFileHook(logName, logFormat string) (*FileHook, error) {

	var formatter log.Formatter

	switch logFormat {
	case TextFormat:
		formatter = &PlainTextFormatter{}
	case JSONFormat:
		formatter = &JSONFormatter{}
	default:
		return nil, fmt.Errorf("unknown log format: %s", logFormat)
	}

	// If config.LogRoot doesn't exist, make it
	dir, err := os.Lstat(LogRoot)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(LogRoot, 0755); err != nil {
			return nil, fmt.Errorf("could not create log directory %v. %v", LogRoot, err)
		}
	}
	// If config.LogRoot isn't a directory, return an error
	if dir != nil && !dir.IsDir() {
		return nil, fmt.Errorf("log path %v exists and is not a directory, please remove it", LogRoot)
	}

	// Build log file path
	logFileLocation := ""
	switch runtime.GOOS {
	case utils.Linux:
		logFileLocation = LogRoot + "/" + logName + ".log"
	case utils.Darwin:
		logFileLocation = LogRoot + "/" + logName + ".log"
	case utils.Windows:
		logFileLocation = logName + ".log"
	}

	return &FileHook{logFileLocation, formatter, &sync.Mutex{}}, nil
}

func (hook *FileHook) Levels() []log.Level {
	return log.AllLevels
}

func (hook *FileHook) Fire(entry *log.Entry) error {

	// Get formatted entry
	lineBytes, err := hook.formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not read log entry. %v", err)
		return err
	}

	// Write log entry to file
	logFile, err := hook.openFile()
	defer logFile.Close() //nolint
	if err != nil {
		return err
	}
	if _, err = logFile.WriteString(string(lineBytes)); err != nil {
		return err
	}

	// Rotate the file as needed
	if err = hook.maybeDoLogfileRotation(); err != nil {
		return err
	}

	return nil
}

func (hook *FileHook) GetLocation() string {
	return hook.logFileLocation
}

func (hook *FileHook) openFile() (*os.File, error) {

	logFile, err := os.OpenFile(hook.logFileLocation, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not open log file %v. %v", hook.logFileLocation, err)
		return nil, err
	}
	return logFile, nil
}

// logfileNeedsRotation checks to see if a file has grown too large
func (hook *FileHook) logfileNeedsRotation() bool {
	logFile, err := hook.openFile()
	if err != nil {
		return false
	}

	fileInfo, err := logFile.Stat()
	if err != nil {
		logFile.Close()
		return false
	}

	size := fileInfo.Size()
	logFile.Close()

	return size >= LogRotationThreshold
}

// maybeDoLogfileRotation prevents descending into doLogfileRotation on every call as the inner
// func is somewhat expensive and doesn't really need to happen every log entry.
func (hook *FileHook) maybeDoLogfileRotation() error {
	// Could use a counter or some other heuristic to decide when to do this, but it's
	// more a less a wash to let rand() do it every 1/n times.
	if rand.Intn(randomLogcheckInterval) == 0 {
		return hook.doLogfileRotation()
	}
	return nil
}

func (hook *FileHook) doLogfileRotation() error {
	// We use a mutex to protect rotation from concurrent loggers, but in order to avoid
	// contention over this resource with high logging levels, check the file before taking
	// the lock.  Only if the file needs rotating do we then acquire the lock and recheck
	// the size under it.  The winner of the lock race will rotate the file.
	if hook.logfileNeedsRotation() {
		hook.mutex.Lock()
		defer hook.mutex.Unlock()

		if hook.logfileNeedsRotation() {
			// Do the rotation.  The Rename call will overwrite any previous .old file.
			oldLogFileLocation := hook.logFileLocation + ".old"
			if err := os.Rename(hook.logFileLocation, oldLogFileLocation); err != nil {
				return err
			}
		}
	}

	return nil
}

// PlainTextFormatter is a formatter than does no coloring *and* does not insist on writing logs as key/value pairs.
type PlainTextFormatter struct {

	// TimestampFormat to use for display when a full timestamp is printed
	TimestampFormat string

	// The fields are sorted by default for a consistent output. For applications
	// that log extremely frequently and don't use the JSON formatter this may not
	// be desired.
	DisableSorting bool
}

func (f *PlainTextFormatter) Format(entry *log.Entry) ([]byte, error) {

	var b *bytes.Buffer
	var keys = make([]string, 0, len(entry.Data))
	for k := range entry.Data {
		keys = append(keys, k)
	}

	if !f.DisableSorting {
		sort.Strings(keys)
	}
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	f.prefixFieldClashes(entry.Data)

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = time.RFC3339
	}
	f.printUncolored(b, entry, keys, timestampFormat)
	b.WriteByte('\n')

	return b.Bytes(), nil
}

func (f *PlainTextFormatter) prefixFieldClashes(data log.Fields) {
	if t, ok := data["time"]; ok {
		data["fields.time"] = t
	}

	if m, ok := data["msg"]; ok {
		data["fields.msg"] = m
	}

	if l, ok := data["level"]; ok {
		data["fields.level"] = l
	}
}

func (f *PlainTextFormatter) printUncolored(b *bytes.Buffer, entry *log.Entry, keys []string, timestampFormat string) {

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	fmt.Fprintf(b, "%s[%s] %-44s ", levelText, entry.Time.Format(timestampFormat), entry.Message)
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " %s=", k)
		f.appendValue(b, v)
	}
}

func (f *PlainTextFormatter) needsQuoting(text string) bool {
	for _, ch := range text {
		if !((ch >= 'a' && ch <= 'z') ||
			(ch >= 'A' && ch <= 'Z') ||
			(ch >= '0' && ch <= '9') ||
			ch == '-' || ch == '.') {
			return true
		}
	}
	return false
}

func (f *PlainTextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
	switch value := value.(type) {
	case string:
		if !f.needsQuoting(value) {
			b.WriteString(value)
		} else {
			fmt.Fprintf(b, "%q", value)
		}
	case error:
		errmsg := value.Error()
		if !f.needsQuoting(errmsg) {
			b.WriteString(errmsg)
		} else {
			fmt.Fprintf(b, "%q", errmsg)
		}
	default:
		fmt.Fprint(b, value)
	}
}

type JSONFormatter struct {
	// TimestampFormat sets the format used for marshaling timestamps.
	TimestampFormat string
	// DisableTimestamp allows disabling automatic timestamps in output
	DisableTimestamp bool
	// PrettyPrint will indent all json logs
	PrettyPrint bool
}

func (f *JSONFormatter) Format(entry *log.Entry) ([]byte, error) {

	data := make(map[string]string, len(entry.Data)+4)
	for k, v := range entry.Data {
		switch v := v.(type) {
		case error:
			// Otherwise errors are ignored by `encoding/json`
			// https://github.com/sirupsen/logrus/issues/137
			data[k] = v.Error()
		default:
			data[k] = fmt.Sprintf("%+v", v)
		}
	}

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = defaultTimestampFormat
	}

	if !f.DisableTimestamp {
		data["@timestamp"] = entry.Time.Format(timestampFormat)
	}
	data["message"] = entry.Message
	data["level"] = entry.Level.String()

	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	encoder := json.NewEncoder(b)
	if f.PrettyPrint {
		encoder.SetIndent("", "  ")
	}
	if err := encoder.Encode(data); err != nil {
		return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
	}

	return b.Bytes(), nil
}
<commit_msg>tridentctl to output timestamps when debug is true<commit_after>// Copyright 2018 NetApp, Inc. All Rights Reserved.

package logging

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"

	"github.com/netapp/trident/config"
	"github.com/netapp/trident/utils"
)

const (
	TextFormat             = "text"
	JSONFormat             = "json"
	defaultTimestampFormat = time.RFC3339
)

// InitLoggingForDocker configures logging for nDVP.  Logs are written both to a log file as well as stdout/stderr.
// Since logrus doesn't support multiple writers, each log stream is implemented as a hook.
func InitLoggingForDocker(logName, logFormat string) error {

	// No output except for the hooks
	log.SetOutput(ioutil.Discard)

	// Write to the log file
	logFileHook, err := NewFileHook(logName, logFormat)
	if err != nil {
		return fmt.Errorf("could not initialize logging to file: %v", err)
	}
	log.AddHook(logFileHook)

	// Write to stdout/stderr
	logConsoleHook, err := NewConsoleHook(logFormat)
	if err != nil {
		return fmt.Errorf("could not initialize logging to console: %v", err)
	}
	log.AddHook(logConsoleHook)

	// Remind users where the log file lives
	log.WithFields(log.Fields{
		"logLevel":        log.GetLevel().String(),
		"logFileLocation": logFileHook.GetLocation(),
		"buildTime":       config.BuildTime,
	}).Info("Initialized logging.")

	customInterval := os.Getenv(RandomLogcheckEnvVar)
	if customInterval != "" {
		customIntervalValue, err := strconv.Atoi(customInterval)
		if err == nil {
			randomLogcheckInterval = customIntervalValue
		}
	}

	return nil
}

// InitLogLevel configures the logging level.  The debug flag takes precedence if set,
// otherwise the logLevel flag (debug, info, warn, error, fatal) is used.
func InitLogLevel(debug bool, logLevel string) error {
	if debug {
		log.SetLevel(log.DebugLevel)
		log.SetFormatter(&log.TextFormatter{FullTimestamp: true})
	} else {
		level, err := log.ParseLevel(logLevel)
		if err != nil {
			return err
		}
		log.SetLevel(level)
	}
	return nil
}

// InitLogFormat configures the log format, allowing a choice of text or JSON.
func InitLogFormat(logFormat string) error {
	switch logFormat {
	case TextFormat:
		log.SetFormatter(&log.TextFormatter{})
	case JSONFormat:
		log.SetFormatter(&JSONFormatter{})
	default:
		return fmt.Errorf("unknown log format: %s", logFormat)
	}
	return nil
}

// ConsoleHook sends log entries to stdout.
type ConsoleHook struct {
	formatter log.Formatter
}

// NewConsoleHook creates a new log hook for writing to stdout/stderr.
func NewConsoleHook(logFormat string) (*ConsoleHook, error) {

	var formatter log.Formatter

	switch logFormat {
	case TextFormat:
		formatter = &log.TextFormatter{FullTimestamp: true}
	case JSONFormat:
		formatter = &JSONFormatter{}
	default:
		return nil, fmt.Errorf("unknown log format: %s", logFormat)
	}

	return &ConsoleHook{formatter}, nil
}

func (hook *ConsoleHook) Levels() []log.Level {
	return log.AllLevels
}

func (hook *ConsoleHook) checkIfTerminal(w io.Writer) bool {
	switch v := w.(type) {
	case *os.File:
		return terminal.IsTerminal(int(v.Fd()))
	default:
		return false
	}
}

func (hook *ConsoleHook) Fire(entry *log.Entry) error {

	// Determine output stream
	var logWriter io.Writer
	switch entry.Level {
	case log.DebugLevel, log.InfoLevel, log.WarnLevel:
		logWriter = os.Stdout
	case log.ErrorLevel, log.FatalLevel, log.PanicLevel:
		logWriter = os.Stderr
	default:
		return fmt.Errorf("unknown log level: %v", entry.Level)
	}

	// Write log entry to output stream
	if textFormatter, ok := hook.formatter.(*log.TextFormatter); ok {
		textFormatter.ForceColors = hook.checkIfTerminal(logWriter)
	}

	lineBytes, err := hook.formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err)
		return err
	}
	if len(lineBytes) > MaxLogEntryLength {
		if _, err := logWriter.Write(lineBytes[:MaxLogEntryLength]); err != nil {
			return err
		}
		if _, err = logWriter.Write([]byte("<truncated>\n")); err != nil {
			return err
		}
	} else {
		if _, err := logWriter.Write(lineBytes); err != nil {
			return err
		}
	}

	return nil
}

// FileHook sends log entries to a file.
type FileHook struct {
	logFileLocation string
	formatter       log.Formatter
	mutex           *sync.Mutex
}

// NewFileHook creates a new log hook for writing to a file.
func NewFileHook(logName, logFormat string) (*FileHook, error) {

	var formatter log.Formatter

	switch logFormat {
	case TextFormat:
		formatter = &PlainTextFormatter{}
	case JSONFormat:
		formatter = &JSONFormatter{}
	default:
		return nil, fmt.Errorf("unknown log format: %s", logFormat)
	}

	// If config.LogRoot doesn't exist, make it
	dir, err := os.Lstat(LogRoot)
	if os.IsNotExist(err) {
		if err := os.MkdirAll(LogRoot, 0755); err != nil {
			return nil, fmt.Errorf("could not create log directory %v. %v", LogRoot, err)
		}
	}
	// If config.LogRoot isn't a directory, return an error
	if dir != nil && !dir.IsDir() {
		return nil, fmt.Errorf("log path %v exists and is not a directory, please remove it", LogRoot)
	}

	// Build log file path
	logFileLocation := ""
	switch runtime.GOOS {
	case utils.Linux:
		logFileLocation = LogRoot + "/" + logName + ".log"
	case utils.Darwin:
		logFileLocation = LogRoot + "/" + logName + ".log"
	case utils.Windows:
		logFileLocation = logName + ".log"
	}

	return &FileHook{logFileLocation, formatter, &sync.Mutex{}}, nil
}

func (hook *FileHook) Levels() []log.Level {
	return log.AllLevels
}

func (hook *FileHook) Fire(entry *log.Entry) error {

	// Get formatted entry
	lineBytes, err := hook.formatter.Format(entry)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not read log entry. %v", err)
		return err
	}

	// Write log entry to file
	logFile, err := hook.openFile()
	defer logFile.Close() //nolint
	if err != nil {
		return err
	}
	if _, err = logFile.WriteString(string(lineBytes)); err != nil {
		return err
	}

	// Rotate the file as needed
	if err = hook.maybeDoLogfileRotation(); err != nil {
		return err
	}

	return nil
}

func (hook *FileHook) GetLocation() string {
	return hook.logFileLocation
}

func (hook *FileHook) openFile() (*os.File, error) {

	logFile, err := os.OpenFile(hook.logFileLocation, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Could not open log file %v. %v", hook.logFileLocation, err)
		return nil, err
	}
	return logFile, nil
}

// logfileNeedsRotation checks to see if a file has grown too large
func (hook *FileHook) logfileNeedsRotation() bool {
	logFile, err := hook.openFile()
	if err != nil {
		return false
	}

	fileInfo, err := logFile.Stat()
	if err != nil {
		logFile.Close()
		return false
	}

	size := fileInfo.Size()
	logFile.Close()

	return size >= LogRotationThreshold
}

// maybeDoLogfileRotation prevents descending into doLogfileRotation on every call as the inner
// func is somewhat expensive and doesn't really need to happen every log entry.
func (hook *FileHook) maybeDoLogfileRotation() error {
	// Could use a counter or some other heuristic to decide when to do this, but it's
	// more a less a wash to let rand() do it every 1/n times.
	if rand.Intn(randomLogcheckInterval) == 0 {
		return hook.doLogfileRotation()
	}
	return nil
}

func (hook *FileHook) doLogfileRotation() error {
	// We use a mutex to protect rotation from concurrent loggers, but in order to avoid
	// contention over this resource with high logging levels, check the file before taking
	// the lock.  Only if the file needs rotating do we then acquire the lock and recheck
	// the size under it.  The winner of the lock race will rotate the file.
	if hook.logfileNeedsRotation() {
		hook.mutex.Lock()
		defer hook.mutex.Unlock()

		if hook.logfileNeedsRotation() {
			// Do the rotation.  The Rename call will overwrite any previous .old file.
			oldLogFileLocation := hook.logFileLocation + ".old"
			if err := os.Rename(hook.logFileLocation, oldLogFileLocation); err != nil {
				return err
			}
		}
	}

	return nil
}

// PlainTextFormatter is a formatter than does no coloring *and* does not insist on writing logs as key/value pairs.
type PlainTextFormatter struct {

	// TimestampFormat to use for display when a full timestamp is printed
	TimestampFormat string

	// The fields are sorted by default for a consistent output. For applications
	// that log extremely frequently and don't use the JSON formatter this may not
	// be desired.
	DisableSorting bool
}

func (f *PlainTextFormatter) Format(entry *log.Entry) ([]byte, error) {

	var b *bytes.Buffer
	var keys = make([]string, 0, len(entry.Data))
	for k := range entry.Data {
		keys = append(keys, k)
	}

	if !f.DisableSorting {
		sort.Strings(keys)
	}
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	f.prefixFieldClashes(entry.Data)

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = time.RFC3339
	}
	f.printUncolored(b, entry, keys, timestampFormat)
	b.WriteByte('\n')

	return b.Bytes(), nil
}

func (f *PlainTextFormatter) prefixFieldClashes(data log.Fields) {
	if t, ok := data["time"]; ok {
		data["fields.time"] = t
	}

	if m, ok := data["msg"]; ok {
		data["fields.msg"] = m
	}

	if l, ok := data["level"]; ok {
		data["fields.level"] = l
	}
}

func (f *PlainTextFormatter) printUncolored(b *bytes.Buffer, entry *log.Entry, keys []string, timestampFormat string) {

	levelText := strings.ToUpper(entry.Level.String())[0:4]

	fmt.Fprintf(b, "%s[%s] %-44s ", levelText, entry.Time.Format(timestampFormat), entry.Message)
	for _, k := range keys {
		v := entry.Data[k]
		fmt.Fprintf(b, " %s=", k)
		f.appendValue(b, v)
	}
}

func (f *PlainTextFormatter) needsQuoting(text string) bool {
	for _, ch := range text {
		if !((ch >= 'a' && ch <= 'z') ||
			(ch >= 'A' && ch <= 'Z') ||
			(ch >= '0' && ch <= '9') ||
			ch == '-' || ch == '.') {
			return true
		}
	}
	return false
}

func (f *PlainTextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
	switch value := value.(type) {
	case string:
		if !f.needsQuoting(value) {
			b.WriteString(value)
		} else {
			fmt.Fprintf(b, "%q", value)
		}
	case error:
		errmsg := value.Error()
		if !f.needsQuoting(errmsg) {
			b.WriteString(errmsg)
		} else {
			fmt.Fprintf(b, "%q", errmsg)
		}
	default:
		fmt.Fprint(b, value)
	}
}

type JSONFormatter struct {
	// TimestampFormat sets the format used for marshaling timestamps.
	TimestampFormat string
	// DisableTimestamp allows disabling automatic timestamps in output
	DisableTimestamp bool
	// PrettyPrint will indent all json logs
	PrettyPrint bool
}

func (f *JSONFormatter) Format(entry *log.Entry) ([]byte, error) {

	data := make(map[string]string, len(entry.Data)+4)
	for k, v := range entry.Data {
		switch v := v.(type) {
		case error:
			// Otherwise errors are ignored by `encoding/json`
			// https://github.com/sirupsen/logrus/issues/137
			data[k] = v.Error()
		default:
			data[k] = fmt.Sprintf("%+v", v)
		}
	}

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = defaultTimestampFormat
	}

	if !f.DisableTimestamp {
		data["@timestamp"] = entry.Time.Format(timestampFormat)
	}
	data["message"] = entry.Message
	data["level"] = entry.Level.String()

	var b *bytes.Buffer
	if entry.Buffer != nil {
		b = entry.Buffer
	} else {
		b = &bytes.Buffer{}
	}

	encoder := json.NewEncoder(b)
	if f.PrettyPrint {
		encoder.SetIndent("", "  ")
	}
	if err := encoder.Encode(data); err != nil {
		return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)
	}

	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package apigee

import (
	"fmt"
	"github.com/gofrs/uuid"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/zambien/go-apigee-edge"
	"log"
	"strings"
)

func resourceCompanyApp() *schema.Resource {
	return &schema.Resource{
		Create: resourceCompanyAppCreate,
		Read:   resourceCompanyAppRead,
		Update: resourceCompanyAppUpdate,
		Delete: resourceCompanyAppDelete,

		Schema: map[string]*schema.Schema{
			"company_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"api_products": {
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"attributes": {
				Type:     schema.TypeMap,
				Optional: true,
			},
			"credentials": {
				Type:     schema.TypeList,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeMap},
			},
			"scopes": {
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"callback_url": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"app_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceCompanyAppCreate(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppCreate START")

	client := meta.(*apigee.EdgeClient)

	u1, _ := uuid.NewV4()
	d.SetId(u1.String())

	CompanyAppData, err := setCompanyAppData(d)
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppCreate error in setCompanyAppData: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppCreate error in setCompanyAppData: %s", err.Error())
	}

	log.Printf("[DEBUG] resourceCompanyAppCreate sending object: %+v\n", CompanyAppData)

	_, _, e := client.CompanyApps.Create(d.Get("company_name").(string), CompanyAppData)
	if e != nil {
		log.Printf("[ERROR] resourceCompanyAppCreate error in company app creation: %s", e.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppCreate error in company app creation: %s", e.Error())
	}

	return resourceCompanyAppRead(d, meta)
}

func resourceCompanyAppRead(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppRead START")
	client := meta.(*apigee.EdgeClient)

	CompanyAppData, _, err := client.CompanyApps.Get(d.Get("company_name").(string), d.Get("name").(string))
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppRead error getting company apps: %s", err.Error())
		if strings.Contains(err.Error(), "404 ") {
			log.Printf("[DEBUG] resourceCompanyAppRead 404 encountered.  Removing state for company app: %#v", d.Get("name").(string))
			d.SetId("")
			return nil
		} else {
			log.Printf("[ERROR] resourceCompanyAppRead error error getting company apps: %s", err.Error())
			return fmt.Errorf("[ERROR] resourceCompanyAppRead error getting company apps: %s", err.Error())
		}
	}

	log.Printf("[DEBUG] resourceCompanyAppRead CompanyAppData: %+v\n", CompanyAppData)

	//Scopes and apiProducts are tricky.  These actually result in an array which will always have
	//one element unless an outside API is called.  Since using terraform we assume you do everything there
	//you might only ever have one credential... we'll see.
	scopes := flattenStringList(CompanyAppData.Credentials[0].Scopes)

	credentials := mapFromCredentials(CompanyAppData.Credentials)

	//Apigee does not return products in the order you send them
	oldApiProducts := getStringList("api_products", d)
	newApiProducts := apiProductsListFromCredentials(CompanyAppData.Credentials[0].ApiProducts)

	if !arraySortedEqual(oldApiProducts, newApiProducts) {
		d.Set("api_products", newApiProducts)
	} else {
		d.Set("api_products", oldApiProducts)
	}

	d.Set("name", CompanyAppData.Name)
	d.Set("attributes", CompanyAppData.Attributes)
	d.Set("credentials", credentials)
	d.Set("scopes", scopes)
	d.Set("callback_url", CompanyAppData.CallbackUrl)
	d.Set("app_id", CompanyAppData.AppId)
	d.Set("company_name", CompanyAppData.CompanyName)
	d.Set("status", CompanyAppData.Status)

	return nil
}

func resourceCompanyAppUpdate(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppUpdate START")

	client := meta.(*apigee.EdgeClient)

	CompanyAppData, err := setCompanyAppData(d)
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppUpdate error in setCompanyAppData: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppUpdate error in setCompanyAppData: %s", err.Error())
	}

	_, _, e := client.CompanyApps.Update(d.Get("company_name").(string), CompanyAppData)
	if e != nil {
		log.Printf("[ERROR] resourceCompanyAppUpdate error in company app update: %s", e.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppUpdate error in company app update: %s", e.Error())
	}

	return resourceCompanyAppRead(d, meta)
}

func resourceCompanyAppDelete(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppDelete START")

	client := meta.(*apigee.EdgeClient)

	_, err := client.CompanyApps.Delete(d.Get("company_name").(string), d.Get("name").(string))
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppDelete error in company app delete: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppDelete error in company app delete: %s", err.Error())
	}

	return nil
}

func setCompanyAppData(d *schema.ResourceData) (apigee.CompanyApp, error) {

	log.Print("[DEBUG] setCompanyAppData START")

	apiProducts := []string{""}
	if d.Get("api_products") != nil {
		apiProducts = getStringList("api_products", d)
	}

	scopes := []string{""}
	if d.Get("scopes") != nil {
		scopes = getStringList("scopes", d)
	}
	log.Printf("[DEBUG] setCompanyAppData scopes: %+v\n", scopes)

	attributes := []apigee.Attribute{}
	if d.Get("attributes") != nil {
		attributes = attributesFromMap(d.Get("attributes").(map[string]interface{}))
	}

	CompanyApp := apigee.CompanyApp{
		Name:        d.Get("name").(string),
		Attributes:  attributes,
		ApiProducts: apiProducts,
		Scopes:      scopes,
		CallbackUrl: d.Get("callback_url").(string),
	}

	return CompanyApp, nil
}
<commit_msg>add in creds map wip code<commit_after>package apigee

import (
	"fmt"
	"github.com/gofrs/uuid"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/zambien/go-apigee-edge"
	"log"
	"strings"
)

func resourceCompanyApp() *schema.Resource {
	return &schema.Resource{
		Create: resourceCompanyAppCreate,
		Read:   resourceCompanyAppRead,
		Update: resourceCompanyAppUpdate,
		Delete: resourceCompanyAppDelete,

		Schema: map[string]*schema.Schema{
			"company_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"api_products": {
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"attributes": {
				Type:     schema.TypeMap,
				Optional: true,
			},
			"test": {
				Type:     schema.TypeString,
				Computed: true,
			},
			/*
			"credentials": {
				Type:     schema.TypeList,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeMap},
			},*/
			"credentials": {
				Type:     schema.TypeList,
				Computed: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"consumer_key": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"consumer_secret": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
			},
			"ssl_info": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"ssl_enabled": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"client_auth_enabled": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"key_store": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
						"trust_store": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
						"key_alias": &schema.Schema{
							Type:     schema.TypeString,
							Optional: true,
						},
						"ciphers": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},
						"protocols": &schema.Schema{
							Type:     schema.TypeList,
							Optional: true,
							Elem:     &schema.Schema{Type: schema.TypeString},
						},
					},
				},
			},
			"scopes": {
				Type:     schema.TypeList,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},
			"callback_url": {
				Type:     schema.TypeString,
				Optional: true,
			},
			"app_id": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"status": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceCompanyAppCreate(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppCreate START")

	client := meta.(*apigee.EdgeClient)

	u1, _ := uuid.NewV4()
	d.SetId(u1.String())

	CompanyAppData, err := setCompanyAppData(d)
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppCreate error in setCompanyAppData: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppCreate error in setCompanyAppData: %s", err.Error())
	}

	log.Printf("[DEBUG] resourceCompanyAppCreate sending object: %+v\n", CompanyAppData)

	_, _, e := client.CompanyApps.Create(d.Get("company_name").(string), CompanyAppData)
	if e != nil {
		log.Printf("[ERROR] resourceCompanyAppCreate error in company app creation: %s", e.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppCreate error in company app creation: %s", e.Error())
	}

	return resourceCompanyAppRead(d, meta)
}

func resourceCompanyAppRead(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppRead START")
	client := meta.(*apigee.EdgeClient)

	CompanyAppData, _, err := client.CompanyApps.Get(d.Get("company_name").(string), d.Get("name").(string))
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppRead error getting company apps: %s", err.Error())
		if strings.Contains(err.Error(), "404 ") {
			log.Printf("[DEBUG] resourceCompanyAppRead 404 encountered.  Removing state for company app: %#v", d.Get("name").(string))
			d.SetId("")
			return nil
		} else {
			log.Printf("[ERROR] resourceCompanyAppRead error error getting company apps: %s", err.Error())
			return fmt.Errorf("[ERROR] resourceCompanyAppRead error getting company apps: %s", err.Error())
		}
	}

	log.Printf("[DEBUG] resourceCompanyAppRead CompanyAppData: %+v\n", CompanyAppData)

	//Scopes and apiProducts are tricky.  These actually result in an array which will always have
	//one element unless an outside API is called.  Since using terraform we assume you do everything there
	//you might only ever have one credential... we'll see.
	scopes := flattenStringList(CompanyAppData.Credentials[0].Scopes)

	credentials := mapFromCredentials(CompanyAppData.Credentials)

	//credentials_again
	if CompanyAppData.Credentials != nil {

		log.Print("[DEBUG] resourceCompanyAppRead credentials ConsumerKey: ", CompanyAppData.Credentials[0].ConsumerKey)
		log.Print("[DEBUG] resourceCompanyAppRead credentials ConsumerSecret: ", CompanyAppData.Credentials[0].ConsumerSecret)

		d.Set("credentials.0.consumer_key", CompanyAppData.Credentials[0].ConsumerKey)
		d.Set("credentials.0.consumer_secret", CompanyAppData.Credentials[0].ConsumerSecret)

		log.Print("[DEBUG] resourceCompanyAppRead credentials: ", d.Get("credentials.0"))
		log.Print("[DEBUG] resourceCompanyAppRead credentials consumer key: ", d.Get("credentials.0.consumer_key"))
	}

	//Apigee does not return products in the order you send them
	oldApiProducts := getStringList("api_products", d)
	newApiProducts := apiProductsListFromCredentials(CompanyAppData.Credentials[0].ApiProducts)

	if !arraySortedEqual(oldApiProducts, newApiProducts) {
		d.Set("api_products", newApiProducts)
	} else {
		d.Set("api_products", oldApiProducts)
	}

	d.Set("test","tester")
	d.Set("name", CompanyAppData.Name)
	d.Set("attributes", CompanyAppData.Attributes)
	d.Set("credentials", CompanyAppData.Credentials)
	d.Set("scopes", scopes)
	d.Set("callback_url", CompanyAppData.CallbackUrl)
	d.Set("app_id", CompanyAppData.AppId)
	d.Set("company_name", CompanyAppData.CompanyName)
	d.Set("status", CompanyAppData.Status)

	log.Print("[DEBUG] resourceCompanyAppRead credentials: ", credentials)

	return nil
}

func resourceCompanyAppUpdate(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppUpdate START")

	client := meta.(*apigee.EdgeClient)

	CompanyAppData, err := setCompanyAppData(d)
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppUpdate error in setCompanyAppData: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppUpdate error in setCompanyAppData: %s", err.Error())
	}

	_, _, e := client.CompanyApps.Update(d.Get("company_name").(string), CompanyAppData)
	if e != nil {
		log.Printf("[ERROR] resourceCompanyAppUpdate error in company app update: %s", e.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppUpdate error in company app update: %s", e.Error())
	}

	return resourceCompanyAppRead(d, meta)
}

func resourceCompanyAppDelete(d *schema.ResourceData, meta interface{}) error {

	log.Print("[DEBUG] resourceCompanyAppDelete START")

	client := meta.(*apigee.EdgeClient)

	_, err := client.CompanyApps.Delete(d.Get("company_name").(string), d.Get("name").(string))
	if err != nil {
		log.Printf("[ERROR] resourceCompanyAppDelete error in company app delete: %s", err.Error())
		return fmt.Errorf("[ERROR] resourceCompanyAppDelete error in company app delete: %s", err.Error())
	}

	return nil
}

func setCompanyAppData(d *schema.ResourceData) (apigee.CompanyApp, error) {

	log.Print("[DEBUG] setCompanyAppData START")

	apiProducts := []string{""}
	if d.Get("api_products") != nil {
		apiProducts = getStringList("api_products", d)
	}

	log.Print("[DEBUG] setCompanyAppData credentials: ", d.Get("credentials"))
	var credentials []apigee.Credential
	if d.Get("credentials") != nil {

		credentialsMap := d.Get("credentials").([]interface{})

		for elem := range credentialsMap {

			log.Printf("[DEBUG] setCompanyAppData credentialsMap element: %v", elem)

			//credentials = append(result, t)
		}
	}

	scopes := []string{""}
	if d.Get("scopes") != nil {
		scopes = getStringList("scopes", d)
	}
	log.Printf("[DEBUG] setCompanyAppData scopes: %+v\n", scopes)

	attributes := []apigee.Attribute{}
	if d.Get("attributes") != nil {
		attributes = attributesFromMap(d.Get("attributes").(map[string]interface{}))
	}

	CompanyApp := apigee.CompanyApp{
		Name:        d.Get("name").(string),
		Attributes:  attributes,
		ApiProducts: apiProducts,
		Scopes:      scopes,
		Credentials: credentials,
		CallbackUrl: d.Get("callback_url").(string),
	}

	return CompanyApp, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/limetext/text"
)

type settingsWatcher struct {
	structPtr       interface{} // pointer to root struct
	settings        *text.Settings
	watchedSettings map[string]watchedSetting
}

func newSettingsWatcher(structPtr interface{}, settings *text.Settings) *settingsWatcher {
	w := &settingsWatcher{
		structPtr:       structPtr,
		settings:        settings,
		watchedSettings: make(map[string]watchedSetting),
	}
	settings.AddOnChange("settingsWatcher", w.onSettingChange)
	return w
}

func (w *settingsWatcher) onSettingChange(name string) {
	fmt.Printf("SettingChanged: %s %v\n", name, w.settings.Get(name))

	if s, ok := w.watchedSettings[name]; ok {
		s.setFromSettings(w.structPtr, w.settings)
	}
}

type watchedSetting interface {
	setFromSettings(structPtr interface{}, settings *text.Settings)
}

func (w *settingsWatcher) watchInt(name string, fieldPtr *int, defaultValue int, mapFn ...func(int) int) {
	s := &watchedSettingInt{
		name:         name,
		fieldPtr:     fieldPtr,
		defaultValue: defaultValue,
	}
	if len(mapFn) == 1 {
		s.mapFn = mapFn[0]
	}
	w.watchedSettings[name] = s
	s.setFromSettings(w.structPtr, w.settings)
}

type watchedSettingInt struct {
	name         string
	fieldPtr     *int
	defaultValue int
	mapFn        func(int) int
}

func (s *watchedSettingInt) setFromSettings(structPtr interface{}, settings *text.Settings) {
	current := settings.Int(s.name, s.defaultValue)
	if s.mapFn != nil {
		current = s.mapFn(current)
	}
	*s.fieldPtr = current
	fe.qmlChanged(structPtr, s.fieldPtr)
}

func (w *settingsWatcher) watchString(name string, fieldPtr *string, defaultValue string, mapFn ...func(string) string) {
	s := &watchedSettingString{
		name:         name,
		fieldPtr:     fieldPtr,
		defaultValue: defaultValue,
	}
	if len(mapFn) == 1 {
		s.mapFn = mapFn[0]
	}
	w.watchedSettings[name] = s
	s.setFromSettings(w.structPtr, w.settings)
}

type watchedSettingString struct {
	name         string
	fieldPtr     *string
	defaultValue string
	mapFn        func(string) string
}

func (s *watchedSettingString) setFromSettings(structPtr interface{}, settings *text.Settings) {
	current := settings.String(s.name, s.defaultValue)
	if s.mapFn != nil {
		current = s.mapFn(current)
	}
	*s.fieldPtr = current
	fe.qmlChanged(structPtr, s.fieldPtr)
}
<commit_msg>Add license to settings.go<commit_after>// Copyright 2013 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package main

import (
	"fmt"

	"github.com/limetext/text"
)

type settingsWatcher struct {
	structPtr       interface{} // pointer to root struct
	settings        *text.Settings
	watchedSettings map[string]watchedSetting
}

func newSettingsWatcher(structPtr interface{}, settings *text.Settings) *settingsWatcher {
	w := &settingsWatcher{
		structPtr:       structPtr,
		settings:        settings,
		watchedSettings: make(map[string]watchedSetting),
	}
	settings.AddOnChange("settingsWatcher", w.onSettingChange)
	return w
}

func (w *settingsWatcher) onSettingChange(name string) {
	fmt.Printf("SettingChanged: %s %v\n", name, w.settings.Get(name))

	if s, ok := w.watchedSettings[name]; ok {
		s.setFromSettings(w.structPtr, w.settings)
	}
}

type watchedSetting interface {
	setFromSettings(structPtr interface{}, settings *text.Settings)
}

func (w *settingsWatcher) watchInt(name string, fieldPtr *int, defaultValue int, mapFn ...func(int) int) {
	s := &watchedSettingInt{
		name:         name,
		fieldPtr:     fieldPtr,
		defaultValue: defaultValue,
	}
	if len(mapFn) == 1 {
		s.mapFn = mapFn[0]
	}
	w.watchedSettings[name] = s
	s.setFromSettings(w.structPtr, w.settings)
}

type watchedSettingInt struct {
	name         string
	fieldPtr     *int
	defaultValue int
	mapFn        func(int) int
}

func (s *watchedSettingInt) setFromSettings(structPtr interface{}, settings *text.Settings) {
	current := settings.Int(s.name, s.defaultValue)
	if s.mapFn != nil {
		current = s.mapFn(current)
	}
	*s.fieldPtr = current
	fe.qmlChanged(structPtr, s.fieldPtr)
}

func (w *settingsWatcher) watchString(name string, fieldPtr *string, defaultValue string, mapFn ...func(string) string) {
	s := &watchedSettingString{
		name:         name,
		fieldPtr:     fieldPtr,
		defaultValue: defaultValue,
	}
	if len(mapFn) == 1 {
		s.mapFn = mapFn[0]
	}
	w.watchedSettings[name] = s
	s.setFromSettings(w.structPtr, w.settings)
}

type watchedSettingString struct {
	name         string
	fieldPtr     *string
	defaultValue string
	mapFn        func(string) string
}

func (s *watchedSettingString) setFromSettings(structPtr interface{}, settings *text.Settings) {
	current := settings.String(s.name, s.defaultValue)
	if s.mapFn != nil {
		current = s.mapFn(current)
	}
	*s.fieldPtr = current
	fe.qmlChanged(structPtr, s.fieldPtr)
}
<|endoftext|>


<commit_before>package main

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", k, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                _stdscr.MovePrintf(k, 0, "%2d:     [%-96s] %.3f", k, impl.db[j].task, val)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<commit_msg>Display task sample counts<commit_after>package main

func ReportThread(t []target) {
    for {
        k := 0
        for i := range t {
            impl := target.GetImpl(t[i])
            addr := impl.conf.Target.Addr
            if impl.conf.Target.Prot == "EXEC" {
                addr = "127.0.0.1"
            }
            _stdscr.MovePrintf(k, 0, "%2d: Target Name: %s, Addr: %s, Sys: %s\n", i, impl.conf.Target.Name, addr, impl.conf.Target.Sys)
            _stdscr.ClearToEOL()
            k++
            for range impl.task {
                if _, err := target.Report(t[i]); err == nil {
                }
            }
            for j := range impl.db {
                val := 0.
                switch impl.task[j].Exec.Reports[0] {
                    case "RATE":
                        val = impl.db[j].rate
                    case "RAW":
                        val = impl.db[j].dpN.y
                    default:
                        val = -1.
                }
                _stdscr.MovePrintf(k, 0, "    %4d: [%-96s] %.3f", impl.db[j].N, impl.db[j].task, val)
                _stdscr.ClearToEOL()
                k++
            }
            _stdscr.Refresh()
        }
    }
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"testing"

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

func TestRun(t *testing.T) {

	assert := assert.New(t)

	nameVer := ParseName("jq")

	wd, _ := os.Getwd()
	manifestFinder, err := NewManifestFinder(path.Join(wd, "testdata"))
	assert.Nil(err)
	assert.NotNil(manifestFinder)

	logger := &MemLogger{}
	config := &MemConfig{}
	config.Set("strategy.priority", "binary,docker")
	manifestFinder.Logger = logger
	manifestFinder.ConfigGetter = config

	manifest, err := manifestFinder.Find(nameVer)
	assert.Nil(err)

	runner := &MemRunner{}
	downloader := &MemDownloader{}
	system := &MemSystem{runtime.GOOS, runtime.GOARCH, 1000, 1000, make(map[string]bool)}
	manifest.Runner = runner
	manifest.Downloader = downloader
	manifest.System = system

	err = manifest.Run(nameVer, []string{"."})
	assert.Nil(err)

	for _, foo := range logger.Debugs {
		fmt.Println(foo)
	}
	for url, foo := range downloader.Files {
		fmt.Println(url, foo)
	}
	for _, foo := range runner.History {
		fmt.Println(foo)
	}
}
<commit_msg>check for download and run in manifest test<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"runtime"
	"testing"

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

func TestRun(t *testing.T) {

	assert := assert.New(t)

	nameVer := ParseName("jq")

	wd, _ := os.Getwd()
	manifestFinder, err := NewManifestFinder(path.Join(wd, "testdata"))
	assert.Nil(err)
	assert.NotNil(manifestFinder)

	logger := &MemLogger{}
	config := &MemConfig{}
	config.Set("strategy.priority", "binary,docker")
	manifestFinder.Logger = logger
	manifestFinder.ConfigGetter = config

	manifest, err := manifestFinder.Find(nameVer)
	assert.Nil(err)

	runner := &MemRunner{}
	downloader := &MemDownloader{}
	system := &MemSystem{runtime.GOOS, runtime.GOARCH, 1000, 1000, make(map[string]bool)}
	manifest.Runner = runner
	manifest.Downloader = downloader
	manifest.System = system

	err = manifest.Run(nameVer, []string{"."})
	assert.Nil(err)

	localPath := path.Join(os.Getenv("HOME"), ".local/share/holen/bin/jq--1.5")
	remoteUrl := "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64"

	// check download
	assert.Contains(downloader.Files, remoteUrl)
	assert.Equal(downloader.Files[remoteUrl], localPath)

	// check run
	assert.Equal(runner.History[0], fmt.Sprintf("%s .", localPath))
}
<|endoftext|>


<commit_before>package market

import (
	"errors"
	"fmt"
	"log"
	"path/filepath"
	"strings"

	"github.com/nzai/Tast/config"
	"github.com/nzai/stockrecorder/io"
)

//	市场更新
type MarketUpdater interface {
	//	名称
	Name() string
	//	时区
	Timezone() string
	//	获取上市公司列表
	//	Companies() ([]Company, error)
	//	更新上市公司列表
	UpdateCompanies() ([]Company, error)
}

//	市场
type Market struct {
	//	名称
	Name string
	//	时区
	Timezone string
	//	上市公司
	Companies []Company

	//	更新器
	updater MarketUpdater
}

func newMarket(updater MarketUpdater) (*Market, error) {

	m := &Market{
		Name:     updater.Name(),
		Timezone: updater.Timezone(),
		updater:  updater}

	//	尝试更新上市公司列表
	log.Printf("[%s]更新上市公司列表-开始", m.Name)
	companies, err := updater.UpdateCompanies()
	if err != nil {

		//	如果更新失败，则尝试从上次的存档文件中读取上市公司列表
		log.Printf("[%s]更新上市公司列表失败，尝试从存档读取", m.Name)
		companies, err = m.loadCompanies()
		if err != nil {
			log.Printf("[%s]尝试从存档读取上市公司列表-失败", m.Name)
			return nil, err
		}

		m.Companies = companies
		log.Printf("[%s]尝试从存档读取上市公司列表-成功,共%d家上市公司", m.Name, len(m.Companies))

		return m, nil
	}

	//	存档
	m.Companies = companies
	err = m.saveCompanies()
	if err != nil {
		return nil, err
	}
	log.Printf("[%s]更新上市公司列表-成功,共%d家上市公司", m.Name, len(m.Companies))

	return m, nil
}

//	上市公司保存路径
func (m Market) companiesSavePath() string {
	dir, _ := config.GetDataDir()
	return filepath.Join(dir, m.Name, companiesFileName)
}

//	保存上市公司到文件
func (m Market) saveCompanies() error {

	lines := make([]string, 0)
	for _, company := range m.Companies {
		lines = append(lines, fmt.Sprintf("%s\t%s\n", company.Code, company.Name))
	}

	return io.WriteLines(m.companiesSavePath(), lines)
}

// 从文件读取上市公司
func (m Market) loadCompanies() ([]Company, error) {

	lines, err := io.ReadLines(m.companiesSavePath())
	if err != nil {
		return nil, err
	}

	companies := make([]Company, 0)
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) != 2 {
			return nil, errors.New("错误的上市公司列表格式")
		}

		companies = append(companies, Company{Code: parts[0], Name: parts[1]})
	}

	return companies, nil
}

func Start() error {
	_, err := newMarket(America{})

	return err
}
<commit_msg>修正错误的包引用<commit_after>package market

import (
	"errors"
	"fmt"
	"log"
	"path/filepath"
	"strings"

	"github.com/nzai/stockrecorder/config"
	"github.com/nzai/stockrecorder/io"
)

//	市场更新
type MarketUpdater interface {
	//	名称
	Name() string
	//	时区
	Timezone() string
	//	获取上市公司列表
	//	Companies() ([]Company, error)
	//	更新上市公司列表
	UpdateCompanies() ([]Company, error)
}

//	市场
type Market struct {
	//	名称
	Name string
	//	时区
	Timezone string
	//	上市公司
	Companies []Company

	//	更新器
	updater MarketUpdater
}

func newMarket(updater MarketUpdater) (*Market, error) {

	m := &Market{
		Name:     updater.Name(),
		Timezone: updater.Timezone(),
		updater:  updater}

	//	尝试更新上市公司列表
	log.Printf("[%s]更新上市公司列表-开始", m.Name)
	companies, err := updater.UpdateCompanies()
	if err != nil {

		//	如果更新失败，则尝试从上次的存档文件中读取上市公司列表
		log.Printf("[%s]更新上市公司列表失败，尝试从存档读取", m.Name)
		companies, err = m.loadCompanies()
		if err != nil {
			log.Printf("[%s]尝试从存档读取上市公司列表-失败", m.Name)
			return nil, err
		}

		m.Companies = companies
		log.Printf("[%s]尝试从存档读取上市公司列表-成功,共%d家上市公司", m.Name, len(m.Companies))

		return m, nil
	}

	//	存档
	m.Companies = companies
	err = m.saveCompanies()
	if err != nil {
		return nil, err
	}
	log.Printf("[%s]更新上市公司列表-成功,共%d家上市公司", m.Name, len(m.Companies))

	return m, nil
}

//	上市公司保存路径
func (m Market) companiesSavePath() string {
	return filepath.Join(config.GetDataDir(), m.Name, companiesFileName)
}

//	保存上市公司到文件
func (m Market) saveCompanies() error {

	lines := make([]string, 0)
	for _, company := range m.Companies {
		lines = append(lines, fmt.Sprintf("%s\t%s\n", company.Code, company.Name))
	}

	return io.WriteLines(m.companiesSavePath(), lines)
}

// 从文件读取上市公司
func (m Market) loadCompanies() ([]Company, error) {

	lines, err := io.ReadLines(m.companiesSavePath())
	if err != nil {
		return nil, err
	}

	companies := make([]Company, 0)
	for _, line := range lines {
		parts := strings.Split(line, "\t")
		if len(parts) != 2 {
			return nil, errors.New("错误的上市公司列表格式")
		}

		companies = append(companies, Company{Code: parts[0], Name: parts[1]})
	}

	return companies, nil
}

func Start() error {
	_, err := newMarket(America{})

	return err
}
<|endoftext|>


<commit_before>/*
Package markov is a minor adaptation of https://golang.org/doc/codewalk/markov.go
with the difference being that it attempts to load text from a url linking to
a .txt file and only returns chains that are < textLength characters long.

This is because I wrote it for implementation in an IRCBOT and the IRC protocol
is limited in characters per message
*/
package markov

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"regexp"
	"strings"
	"time"
)

var (
	supportedFile = regexp.MustCompile(`.*\.txt$`)
	textLength    = 400
)

// Prefix is a Markov chain prefix of one or more words.
type Prefix []string

// String returns the Prefix as a string (for use as a map key).
func (p Prefix) String() string {
	return strings.Join(p, " ")
}

// Shift removes the first word from the Prefix and appends the given word.
func (p Prefix) Shift(word string) {
	copy(p, p[1:])
	p[len(p)-1] = word
}

// Chain contains a map ("chain") of prefixes to a list of suffixes.
// A prefix is a string of prefixLen words joined with spaces.
// A suffix is a single word. A prefix can have multiple suffixes.
type Chain struct {
	chain     map[string][]string
	prefixLen int
}

// NewChain returns a new Chain with prefixes of prefixLen words.
func NewChain(prefixLen int) *Chain {
	return &Chain{make(map[string][]string), prefixLen}
}

// Build reads text from the provided Reader and
// parses it into prefixes and suffixes that are stored in Chain.
func (c *Chain) Build(r io.Reader) {
	br := bufio.NewReader(r)
	p := make(Prefix, c.prefixLen)
	for {
		var s string
		if _, err := fmt.Fscan(br, &s); err != nil {
			break
		}
		key := p.String()
		c.chain[key] = append(c.chain[key], s)
		p.Shift(s)
	}
}

// Generate returns a string of at most n words generated from Chain.
func (c *Chain) Generate(n int) string {
	rand.Seed(time.Now().UnixNano())
	p := make(Prefix, c.prefixLen)
	var words []string
	for i := 0; i < n; i++ {
		choices := c.chain[p.String()]
		if len(choices) == 0 {
			break
		}
		next := choices[rand.Intn(len(choices))]
		words = append(words, next)
		p.Shift(next)
	}
	return strings.Join(words, " ")
}

// GoNuts retrieves url (if it is supported) and returns a markov chain
// based on its contents
func GoNuts(url string) (string, error) {
	if !supportedFile.MatchString(url) {
		return "", fmt.Errorf("Unsupported filetype: %v", url)
	}

	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("Could not retrieve file: %v", err)
	}
	defer resp.Body.Close()

	c := NewChain(2)   // Initialize a new Chain.
	c.Build(resp.Body) // Build chains from standard input.

	tLen := textLength / 2
	text := c.Generate(tLen)
	for len(text) > textLength {
		text = c.Generate(tLen) // Generate text.
		tLen--
	}
	return text, nil
}
<commit_msg>removed arbitrary chain limitation<commit_after>/*
Package markov is a minor adaptation of https://golang.org/doc/codewalk/markov.go
with the difference being that it attempts to load text from a url linking to
a .txt file and only returns chains that are < textLength characters long.
*/
package markov

import (
	"bufio"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"regexp"
	"strings"
	"time"
)

var (
	supportedFile = regexp.MustCompile(`.*\.txt$`)
)

// Prefix is a Markov chain prefix of one or more words.
type Prefix []string

// String returns the Prefix as a string (for use as a map key).
func (p Prefix) String() string {
	return strings.Join(p, " ")
}

// Shift removes the first word from the Prefix and appends the given word.
func (p Prefix) Shift(word string) {
	copy(p, p[1:])
	p[len(p)-1] = word
}

// Chain contains a map ("chain") of prefixes to a list of suffixes.
// A prefix is a string of prefixLen words joined with spaces.
// A suffix is a single word. A prefix can have multiple suffixes.
type Chain struct {
	chain     map[string][]string
	prefixLen int
}

// NewChain returns a new Chain with prefixes of prefixLen words.
func NewChain(prefixLen int) *Chain {
	return &Chain{make(map[string][]string), prefixLen}
}

// Build reads text from the provided Reader and
// parses it into prefixes and suffixes that are stored in Chain.
func (c *Chain) Build(r io.Reader) {
	br := bufio.NewReader(r)
	p := make(Prefix, c.prefixLen)
	for {
		var s string
		if _, err := fmt.Fscan(br, &s); err != nil {
			break
		}
		key := p.String()
		c.chain[key] = append(c.chain[key], s)
		p.Shift(s)
	}
}

// Generate returns a string of at most n words generated from Chain.
func (c *Chain) Generate(n int) string {
	rand.Seed(time.Now().UnixNano())
	p := make(Prefix, c.prefixLen)
	var words []string
	for i := 0; i < n; i++ {
		choices := c.chain[p.String()]
		if len(choices) == 0 {
			break
		}
		next := choices[rand.Intn(len(choices))]
		words = append(words, next)
		p.Shift(next)
	}
	return strings.Join(words, " ")
}

// FromURL retrieves url (if it is supported) and returns a markov chain
// based on its contents
func FromURL(url string, textLength int) (string, error) {
	if !supportedFile.MatchString(url) {
		return "", fmt.Errorf("Unsupported filetype: %v", url)
	}

	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("Could not retrieve file: %v", err)
	}
	defer resp.Body.Close()

	c := NewChain(2)   // Initialize a new Chain.
	c.Build(resp.Body) // Build chains from standard input.

	text := c.Generate(textLength)
	return text, nil
}
<|endoftext|>


<commit_before>// Copyright ©2015 The gonum 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 mat64

import "fmt"

// Product calculates the product of the given factors and places the result in
// the receiver. The order of multiplication operations is optimized to minimize
// the number of floating point operations on the basis that all matrix
// multiplications are general.
func (m *Dense) Product(factors ...Matrix) {
	// The operation order optimisation is the naive O(n^3) dynamic
	// programming approach and does not take into consideration
	// finer-grained optimisations that might be available.
	//
	// TODO(kortschak) Consider using the O(nlogn) or O(mlogn)
	// algorithms that are available. e.g.
	//
	// e.g. http://www.jofcis.com/publishedpapers/2014_10_10_4299_4306.pdf
	//
	// In the case that this is replaced, retain this code in
	// tests to compare against.

	r, c := m.Dims()
	switch len(factors) {
	case 0:
		if r != 0 || c != 0 {
			panic(ErrShape)
		}
		return
	case 1:
		m.reuseAs(factors[0].Dims())
		m.Copy(factors[0])
		return
	case 2:
		// Don't do work that we know the answer to.
		m.Mul(factors[0], factors[1])
		return
	}

	p := newMultiplier(m, factors)
	p.optimize()
	p.multiply()

	m.reuseAs(p.stack[0].Dims())
	m.Copy(p.stack[0])
}

// debugProductWalk enables debugging output for Product.
const debugProductWalk = false

// multiplier performs operation order optimisation and tree traversal.
type multiplier struct {
	// factors is the ordered set of
	// factors to multiply.
	factors []Matrix
	// dims is the chain of factor
	// dimensions.
	dims []int

	// table contains the dynamic
	// programming costs and subchain
	// division indices.
	table table

	// stack holds intermediate results
	// in the product tree. onStack
	// indicates whether a matrix to
	// be multiplied is on the stack or
	// in the input factors.
	stack   []*Dense
	onStack []bool
}

func newMultiplier(m *Dense, factors []Matrix) *multiplier {
	// Check size early, but don't yet
	// allocate data for m.
	r, c := m.Dims()
	fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2.
	if !m.isZero() {
		if fr != r {
			panic(ErrShape)
		}
		if _, lc := factors[len(factors)-1].Dims(); lc != c {
			panic(ErrShape)
		}
	}

	dims := make([]int, len(factors)+1)
	dims[0] = r
	dims[len(dims)-1] = c
	pc := fc
	for i, f := range factors[1:] {
		cr, cc := f.Dims()
		dims[i+1] = cr
		if pc != cr {
			panic(ErrShape)
		}
		pc = cc
	}

	return &multiplier{
		factors: factors,
		dims:    dims,
		table:   newTable(len(factors)),
		onStack: make([]bool, len(factors)),
	}
}

// optimize determines an optimal matrix multiply operation order.
func (p *multiplier) optimize() {
	if debugProductWalk {
		fmt.Printf("chain dims: %v\n", p.dims)
	}
	const maxInt = int(^uint(0) >> 1)
	for f := 1; f < len(p.factors); f++ {
		for i := 0; i < len(p.factors)-f; i++ {
			j := i + f
			p.table.set(i, j, entry{cost: maxInt})
			for k := i; k < j; k++ {
				cost := p.table.at(i, k).cost + p.table.at(k+1, j).cost + p.dims[i]*p.dims[k+1]*p.dims[j+1]
				if cost < p.table.at(i, j).cost {
					p.table.set(i, j, entry{cost: cost, k: k})
				}
			}
		}
	}
}

// multiply walks the optimal operation tree found by optimize,
// leaving the final result in the stack.
func (p *multiplier) multiply() {
	p.multiplySubchain(0, len(p.factors)-1)
	if debugProductWalk {
		r, c := p.stack[0].Dims()
		fmt.Printf("\tpop result (%d×%d) cost=%d\n", r, c, p.table.at(0, len(p.factors)-1).cost)
	}
}

func (p *multiplier) multiplySubchain(i, j int) {
	if i == j {
		return
	}

	p.multiplySubchain(i, p.table.at(i, j).k)
	p.multiplySubchain(p.table.at(i, j).k+1, j)

	b := p.factor(j)
	a := p.factor(i)
	_, ac := a.Dims()
	br, _ := b.Dims()
	if ac != br {
		// Panic with a string since this
		// is not a user-facing panic.
		panic(ErrShape.string)
	}

	if debugProductWalk {
		ar, ac := a.Dims()
		br, bc := b.Dims()
		fmt.Printf("\tpush f[%d] (%d×%d)%s * f[%d] (%d×%d)%s\n",
			i, ar, ac, result(p.onStack[i]), j, br, bc, result(p.onStack[j]))
	}

	// TODO(kortschak) Use pool for r. This requires that
	// we know whether a/b came from factors or the stack.
	var r Dense
	r.Mul(a, b)
	p.push(&r, i, j)
}

func (p *multiplier) push(m *Dense, i, j int) {
	p.onStack[i] = true
	p.onStack[j] = true
	p.stack = append(p.stack, m)
}

func (p *multiplier) factor(i int) Matrix {
	if !p.onStack[i] {
		return p.factors[i]
	}
	var m *Dense
	m, p.stack = p.stack[len(p.stack)-1], p.stack[:len(p.stack)-1]
	return m
}

type entry struct {
	k    int // is the chain subdivision index.
	cost int // cost is the cost of the operation.
}

// table is a row major n×n dynamic programming table.
type table struct {
	n       int
	entries []entry
}

func newTable(n int) table {
	return table{n: n, entries: make([]entry, n*n)}
}

func (t table) at(i, j int) entry     { return t.entries[i*t.n+j] }
func (t table) set(i, j int, e entry) { t.entries[i*t.n+j] = e }

type result bool

func (r result) String() string {
	if r {
		return " (popped result)"
	}
	return ""
}
<commit_msg>mat64: use pools for intermediate product results<commit_after>// Copyright ©2015 The gonum 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 mat64

import "fmt"

// Product calculates the product of the given factors and places the result in
// the receiver. The order of multiplication operations is optimized to minimize
// the number of floating point operations on the basis that all matrix
// multiplications are general.
func (m *Dense) Product(factors ...Matrix) {
	// The operation order optimisation is the naive O(n^3) dynamic
	// programming approach and does not take into consideration
	// finer-grained optimisations that might be available.
	//
	// TODO(kortschak) Consider using the O(nlogn) or O(mlogn)
	// algorithms that are available. e.g.
	//
	// e.g. http://www.jofcis.com/publishedpapers/2014_10_10_4299_4306.pdf
	//
	// In the case that this is replaced, retain this code in
	// tests to compare against.

	r, c := m.Dims()
	switch len(factors) {
	case 0:
		if r != 0 || c != 0 {
			panic(ErrShape)
		}
		return
	case 1:
		m.reuseAs(factors[0].Dims())
		m.Copy(factors[0])
		return
	case 2:
		// Don't do work that we know the answer to.
		m.Mul(factors[0], factors[1])
		return
	}

	p := newMultiplier(m, factors)
	p.optimize()
	p.multiply()

	m.reuseAs(p.stack[0].Dims())
	m.Copy(p.stack[0])
	putWorkspace(p.stack[0])
}

// debugProductWalk enables debugging output for Product.
const debugProductWalk = false

// multiplier performs operation order optimisation and tree traversal.
type multiplier struct {
	// factors is the ordered set of
	// factors to multiply.
	factors []Matrix
	// dims is the chain of factor
	// dimensions.
	dims []int

	// table contains the dynamic
	// programming costs and subchain
	// division indices.
	table table

	// stack holds intermediate results
	// in the product tree. onStack
	// indicates whether a matrix to
	// be multiplied is on the stack or
	// in the input factors.
	stack   []*Dense
	onStack []bool
}

func newMultiplier(m *Dense, factors []Matrix) *multiplier {
	// Check size early, but don't yet
	// allocate data for m.
	r, c := m.Dims()
	fr, fc := factors[0].Dims() // newMultiplier is only called with len(factors) > 2.
	if !m.isZero() {
		if fr != r {
			panic(ErrShape)
		}
		if _, lc := factors[len(factors)-1].Dims(); lc != c {
			panic(ErrShape)
		}
	}

	dims := make([]int, len(factors)+1)
	dims[0] = r
	dims[len(dims)-1] = c
	pc := fc
	for i, f := range factors[1:] {
		cr, cc := f.Dims()
		dims[i+1] = cr
		if pc != cr {
			panic(ErrShape)
		}
		pc = cc
	}

	return &multiplier{
		factors: factors,
		dims:    dims,
		table:   newTable(len(factors)),
		onStack: make([]bool, len(factors)),
	}
}

// optimize determines an optimal matrix multiply operation order.
func (p *multiplier) optimize() {
	if debugProductWalk {
		fmt.Printf("chain dims: %v\n", p.dims)
	}
	const maxInt = int(^uint(0) >> 1)
	for f := 1; f < len(p.factors); f++ {
		for i := 0; i < len(p.factors)-f; i++ {
			j := i + f
			p.table.set(i, j, entry{cost: maxInt})
			for k := i; k < j; k++ {
				cost := p.table.at(i, k).cost + p.table.at(k+1, j).cost + p.dims[i]*p.dims[k+1]*p.dims[j+1]
				if cost < p.table.at(i, j).cost {
					p.table.set(i, j, entry{cost: cost, k: k})
				}
			}
		}
	}
}

// multiply walks the optimal operation tree found by optimize,
// leaving the final result in the stack.
func (p *multiplier) multiply() {
	p.multiplySubchain(0, len(p.factors)-1)
	if debugProductWalk {
		r, c := p.stack[0].Dims()
		fmt.Printf("\tpop result (%d×%d) cost=%d\n", r, c, p.table.at(0, len(p.factors)-1).cost)
	}
}

func (p *multiplier) multiplySubchain(i, j int) {
	if i == j {
		return
	}

	p.multiplySubchain(i, p.table.at(i, j).k)
	p.multiplySubchain(p.table.at(i, j).k+1, j)

	b := p.factor(j)
	a := p.factor(i)
	ar, ac := a.Dims()
	br, bc := b.Dims()
	if ac != br {
		// Panic with a string since this
		// is not a user-facing panic.
		panic(ErrShape.string)
	}

	if debugProductWalk {
		ar, ac := a.Dims()
		br, bc := b.Dims()
		fmt.Printf("\tpush f[%d] (%d×%d)%s * f[%d] (%d×%d)%s\n",
			i, ar, ac, result(p.onStack[i]), j, br, bc, result(p.onStack[j]))
	}

	r := getWorkspace(ar, bc, false)
	r.Mul(a, b)
	if p.onStack[i] {
		putWorkspace(a.(*Dense))
	}
	if p.onStack[j] {
		putWorkspace(b.(*Dense))
	}
	p.push(r, i, j)
}

func (p *multiplier) push(m *Dense, i, j int) {
	p.onStack[i] = true
	p.onStack[j] = true
	p.stack = append(p.stack, m)
}

func (p *multiplier) factor(i int) Matrix {
	if !p.onStack[i] {
		return p.factors[i]
	}
	var m *Dense
	m, p.stack = p.stack[len(p.stack)-1], p.stack[:len(p.stack)-1]
	return m
}

type entry struct {
	k    int // is the chain subdivision index.
	cost int // cost is the cost of the operation.
}

// table is a row major n×n dynamic programming table.
type table struct {
	n       int
	entries []entry
}

func newTable(n int) table {
	return table{n: n, entries: make([]entry, n*n)}
}

func (t table) at(i, j int) entry     { return t.entries[i*t.n+j] }
func (t table) set(i, j int, e entry) { t.entries[i*t.n+j] = e }

type result bool

func (r result) String() string {
	if r {
		return " (popped result)"
	}
	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"github.com/hanwen/go-fuse/termite"
	"io/ioutil"
	"strings"
)

func main() {
	cachedir := flag.String("cachedir", "/tmp/fsserver-cache", "content cache")
	workers := flag.String("workers", "localhost:1235", "comma separated list of worker addresses")
	socket := flag.String("socket", ".termite-socket", "socket to listen for commands")
	exclude := flag.String("exclude", "/sys,/proc,/dev,/selinux", "prefixes to not export.")
	secretFile := flag.String("secret", "/tmp/secret.txt", "file containing password.")
	jobs := flag.Int("jobs", 1, "number of jobs to run")

	flag.Parse()
	secret, err := ioutil.ReadFile(*secretFile)
	if err != nil {
		log.Fatal("ReadFile", err)
	}

	workerList := strings.Split(*workers, ",", -1)
	excludeList := strings.Split(*exclude, ",", -1)
	c := termite.NewDiskFileCache(*cachedir)
	master := termite.NewMaster(
		c, workerList, secret, excludeList, *jobs)
	master.Start(*socket)
}
<commit_msg>Add /cgroup exclude.<commit_after>package main

import (
	"flag"
	"log"
	"github.com/hanwen/go-fuse/termite"
	"io/ioutil"
	"strings"
)

func main() {
	cachedir := flag.String("cachedir", "/tmp/fsserver-cache", "content cache")
	workers := flag.String("workers", "localhost:1235", "comma separated list of worker addresses")
	socket := flag.String("socket", ".termite-socket", "socket to listen for commands")
	exclude := flag.String("exclude", "/sys,/proc,/dev,/selinux,/cgroup", "prefixes to not export.")
	secretFile := flag.String("secret", "/tmp/secret.txt", "file containing password.")
	jobs := flag.Int("jobs", 1, "number of jobs to run")

	flag.Parse()
	secret, err := ioutil.ReadFile(*secretFile)
	if err != nil {
		log.Fatal("ReadFile", err)
	}

	workerList := strings.Split(*workers, ",", -1)
	excludeList := strings.Split(*exclude, ",", -1)
	c := termite.NewDiskFileCache(*cachedir)
	master := termite.NewMaster(
		c, workerList, secret, excludeList, *jobs)
	master.Start(*socket)
}
<|endoftext|>


<commit_before>// Copyright 2014 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 main

import (
	"bufio"
	"bytes"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func loadSyms(t *testing.T) map[string]string {
	cmd := exec.Command("go", "tool", "nm", os.Args[0])
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
	}
	syms := make(map[string]string)
	scanner := bufio.NewScanner(bytes.NewReader(out))
	for scanner.Scan() {
		f := strings.Fields(scanner.Text())
		if len(f) < 3 {
			continue
		}
		syms[f[2]] = f[0]
	}
	if err := scanner.Err(); err != nil {
		t.Fatalf("error reading symbols: %v", err)
	}
	return syms
}

func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno string) {
	cmd := exec.Command(exepath, os.Args[0])
	cmd.Stdin = strings.NewReader(addr)
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out))
	}
	f := strings.Split(string(out), "\n")
	if len(f) < 3 && f[2] == "" {
		t.Fatal("addr2line output must have 2 lines")
	}
	funcname = f[0]
	pathAndLineNo := f[1]
	f = strings.Split(pathAndLineNo, ":")
	if runtime.GOOS == "windows" {
		switch len(f) {
		case 2:
			return funcname, f[0], f[1]
		case 3:
			return funcname, f[0] + ":" + f[1], f[2]
		default:
			t.Fatalf("no line number found in %q", pathAndLineNo)
		}
	}
	if len(f) != 2 {
		t.Fatalf("no line number found in %q", pathAndLineNo)
	}
	return funcname, f[0], f[1]
}

const symName = "cmd/addr2line.TestAddr2Line"

func testAddr2Line(t *testing.T, exepath, addr string) {
	funcName, srcPath, srcLineNo := runAddr2Line(t, exepath, addr)
	if symName != funcName {
		t.Fatalf("expected function name %v; got %v", symName, funcName)
	}
	fi1, err := os.Stat("addr2line_test.go")
	if err != nil {
		t.Fatalf("Stat failed: %v", err)
	}
	fi2, err := os.Stat(srcPath)
	if err != nil {
		t.Fatalf("Stat failed: %v", err)
	}
	if !os.SameFile(fi1, fi2) {
		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
	}
	if srcLineNo != "95" {
		t.Fatalf("line number = %v; want 95", srcLineNo)
	}
}

// This is line 94. The test depends on that.
func TestAddr2Line(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	syms := loadSyms(t)

	tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
	if err != nil {
		t.Fatal("TempDir failed: ", err)
	}
	defer os.RemoveAll(tmpDir)

	exepath := filepath.Join(tmpDir, "testaddr2line.exe")
	out, err := exec.Command("go", "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
	if err != nil {
		t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
	}

	testAddr2Line(t, exepath, syms[symName])
	testAddr2Line(t, exepath, "0x"+syms[symName])
}
<commit_msg>cmd/addr2line: simplify windows test<commit_after>// Copyright 2014 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 main

import (
	"bufio"
	"bytes"
	"internal/testenv"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
)

func loadSyms(t *testing.T) map[string]string {
	cmd := exec.Command("go", "tool", "nm", os.Args[0])
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
	}
	syms := make(map[string]string)
	scanner := bufio.NewScanner(bytes.NewReader(out))
	for scanner.Scan() {
		f := strings.Fields(scanner.Text())
		if len(f) < 3 {
			continue
		}
		syms[f[2]] = f[0]
	}
	if err := scanner.Err(); err != nil {
		t.Fatalf("error reading symbols: %v", err)
	}
	return syms
}

func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno string) {
	cmd := exec.Command(exepath, os.Args[0])
	cmd.Stdin = strings.NewReader(addr)
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out))
	}
	f := strings.Split(string(out), "\n")
	if len(f) < 3 && f[2] == "" {
		t.Fatal("addr2line output must have 2 lines")
	}
	funcname = f[0]
	pathAndLineNo := f[1]
	f = strings.Split(pathAndLineNo, ":")
	if runtime.GOOS == "windows" && len(f) == 3 {
		// Reattach drive letter.
		f = []string{f[0] + ":" + f[1], f[2]}
	}
	if len(f) != 2 {
		t.Fatalf("no line number found in %q", pathAndLineNo)
	}
	return funcname, f[0], f[1]
}

const symName = "cmd/addr2line.TestAddr2Line"

func testAddr2Line(t *testing.T, exepath, addr string) {
	funcName, srcPath, srcLineNo := runAddr2Line(t, exepath, addr)
	if symName != funcName {
		t.Fatalf("expected function name %v; got %v", symName, funcName)
	}
	fi1, err := os.Stat("addr2line_test.go")
	if err != nil {
		t.Fatalf("Stat failed: %v", err)
	}
	fi2, err := os.Stat(srcPath)
	if err != nil {
		t.Fatalf("Stat failed: %v", err)
	}
	if !os.SameFile(fi1, fi2) {
		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
	}
	if srcLineNo != "89" {
		t.Fatalf("line number = %v; want 89", srcLineNo)
	}
}

// This is line 88. The test depends on that.
func TestAddr2Line(t *testing.T) {
	testenv.MustHaveGoBuild(t)

	syms := loadSyms(t)

	tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
	if err != nil {
		t.Fatal("TempDir failed: ", err)
	}
	defer os.RemoveAll(tmpDir)

	exepath := filepath.Join(tmpDir, "testaddr2line.exe")
	out, err := exec.Command("go", "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
	if err != nil {
		t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
	}

	testAddr2Line(t, exepath, syms[symName])
	testAddr2Line(t, exepath, "0x"+syms[symName])
}
<|endoftext|>


<commit_before>package hypervisor

import (
	"net"
	"time"

	"github.com/Symantec/Dominator/lib/tags"
)

const (
	StateStarting      = 0
	StateRunning       = 1
	StateFailedToStart = 2
	StateStopping      = 3
	StateStopped       = 4
	StateDestroying    = 5

	VolumeFormatRaw   = 0
	VolumeFormatQCOW2 = 1
)

type AcknowledgeVmRequest struct {
	IpAddress net.IP
}

type AcknowledgeVmResponse struct {
	Error string
}

type Address struct {
	IpAddress  net.IP `json:",omitempty"`
	MacAddress string
}

type BecomePrimaryVmOwnerRequest struct {
	IpAddress net.IP
}

type BecomePrimaryVmOwnerResponse struct {
	Error string
}

type ChangeAddressPoolRequest struct {
	AddressesToAdd       []Address
	MaximumFreeAddresses map[string]uint // Key: subnet ID.
}

type ChangeAddressPoolResponse struct {
	Error string
}

type ChangeVmOwnerUsersRequest struct {
	IpAddress  net.IP
	OwnerUsers []string
}

type ChangeVmOwnerUsersResponse struct {
	Error string
}

type ChangeVmTagsRequest struct {
	IpAddress net.IP
	Tags      tags.Tags
}

type ChangeVmTagsResponse struct {
	Error string
}

type CommitImportedVmRequest struct {
	IpAddress net.IP
}

type CommitImportedVmResponse struct {
	Error string
}

type CreateVmRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageTimeout     time.Duration
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SecondaryVolumes []Volume
	UserDataSize     uint64
	VmInfo
} // RAW image data (length=ImageDataSize) and user data (length=UserDataSize)
// are streamed afterwards.

type CreateVmResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	IpAddress       net.IP
	ProgressMessage string
	Error           string
}

type DestroyVmRequest struct {
	IpAddress net.IP
}

type DestroyVmResponse struct {
	Error string
}

type DiscardVmOldImageRequest struct {
	IpAddress net.IP
}

type DiscardVmOldImageResponse struct {
	Error string
}

type DiscardVmOldUserDataRequest struct {
	IpAddress net.IP
}

type DiscardVmOldUserDataResponse struct {
	Error string
}

type DiscardVmSnapshotRequest struct {
	IpAddress net.IP
}

type DiscardVmSnapshotResponse struct {
	Error string
}

// The GetUpdates() RPC is fully streamed.
// The client sends no information to the server.
// The server sends a stream of Update messages.

type Update struct {
	HaveAddressPool  bool               `json:",omitempty"`
	AddressPool      []Address          `json:",omitempty"` // Used & free.
	NumFreeAddresses map[string]uint    `json:",omitempty"` // Key: subnet ID.
	HaveSubnets      bool               `json:",omitempty"`
	Subnets          []Subnet           `json:",omitempty"`
	HaveVMs          bool               `json:",omitempty"`
	VMs              map[string]*VmInfo `json:",omitempty"` // Key: IP address.
}

type GetVmInfoRequest struct {
	IpAddress net.IP
}

type GetVmInfoResponse struct {
	VmInfo VmInfo
	Error  string
}

type ImportLocalVmRequest struct {
	VerificationCookie []byte
	VmInfo
	VolumeFilenames []string
}

type ImportLocalVmResponse struct {
	Error string
}

type ListVMsRequest struct {
	Sort bool
}

type ListVMsResponse struct {
	IpAddresses []net.IP
}

type ListVolumeDirectoriesRequest struct{}

type ListVolumeDirectoriesResponse struct {
	Directories []string
	Error       string
}

type NetbootMachineRequest struct {
	Address                      Address
	Files                        map[string][]byte
	FilesExpiration              time.Duration
	Hostname                     string
	NumAcknowledgementsToWaitFor uint
	OfferExpiration              time.Duration
	Subnet                       *Subnet
	WaitTimeout                  time.Duration
}

type NetbootMachineResponse struct {
	Error string
}

type ProbeVmPortRequest struct {
	IpAddress  net.IP
	PortNumber uint
	Timeout    time.Duration
}

type ProbeVmPortResponse struct {
	PortIsOpen bool
	Error      string
}

type ReplaceVmImageRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageName        string `json:",omitempty"`
	ImageTimeout     time.Duration
	ImageURL         string `json:",omitempty"`
	IpAddress        net.IP
	MinimumFreeBytes uint64
	RoundupPower     uint64
} // RAW image data (length=ImageDataSize) is streamed afterwards.

type ReplaceVmImageResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	ProgressMessage string
	Error           string
}

type ReplaceVmUserDataRequest struct {
	IpAddress net.IP
	Size      uint64
} // User data (length=Size) are streamed afterwards.

type ReplaceVmUserDataResponse struct {
	Error string
}

type RestoreVmFromSnapshotRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
}

type RestoreVmFromSnapshotResponse struct {
	Error string
}

type RestoreVmImageRequest struct {
	IpAddress net.IP
}

type RestoreVmImageResponse struct {
	Error string
}

type RestoreVmUserDataRequest struct {
	IpAddress net.IP
}

type RestoreVmUserDataResponse struct {
	Error string
}

type SnapshotVmRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
	RootOnly          bool
}

type SnapshotVmResponse struct {
	Error string
}

type StartVmRequest struct {
	DhcpTimeout time.Duration
	IpAddress   net.IP
}

type StartVmResponse struct {
	DhcpTimedOut bool
	Error        string
}

type StopVmRequest struct {
	IpAddress net.IP
}

type StopVmResponse struct {
	Error string
}

type State uint

type Subnet struct {
	Id                string
	IpGateway         net.IP
	IpMask            net.IP // net.IPMask can't be JSON {en,de}coded.
	DomainName        string `json:",omitempty"`
	DomainNameServers []net.IP
	Manage            bool     `json:",omitempty"`
	VlanId            uint     `json:",omitempty"`
	AllowedGroups     []string `json:",omitempty"`
	AllowedUsers      []string `json:",omitempty"`
}

type TraceVmMetadataRequest struct {
	IpAddress net.IP
}

type TraceVmMetadataResponse struct {
	Error string
} // A stream of strings (trace paths) follow.

type UpdateSubnetsRequest struct {
	Add    []Subnet
	Change []Subnet
	Delete []string
}

type UpdateSubnetsResponse struct {
	Error string
}

type VmInfo struct {
	Address       Address
	Hostname      string `json:",omitempty"`
	ImageName     string `json:",omitempty"`
	ImageURL      string `json:",omitempty"`
	MemoryInMiB   uint64
	MilliCPUs     uint
	OwnerGroups   []string `json:",omitempty"`
	OwnerUsers    []string `json:",omitempty"`
	SpreadVolumes bool     `json:",omitempty"`
	State         State
	Tags          tags.Tags `json:",omitempty"`
	SubnetId      string    `json:",omitempty"`
	Uncommitted   bool      `json:",omitempty"`
	Volumes       []Volume  `json:",omitempty"`
}

type Volume struct {
	Size   uint64
	Format VolumeFormat
}

type VolumeFormat uint
<commit_msg>Do not show empty proto/hypervisor.ImportLocalVmRequest.VerificationCookie.<commit_after>package hypervisor

import (
	"net"
	"time"

	"github.com/Symantec/Dominator/lib/tags"
)

const (
	StateStarting      = 0
	StateRunning       = 1
	StateFailedToStart = 2
	StateStopping      = 3
	StateStopped       = 4
	StateDestroying    = 5

	VolumeFormatRaw   = 0
	VolumeFormatQCOW2 = 1
)

type AcknowledgeVmRequest struct {
	IpAddress net.IP
}

type AcknowledgeVmResponse struct {
	Error string
}

type Address struct {
	IpAddress  net.IP `json:",omitempty"`
	MacAddress string
}

type BecomePrimaryVmOwnerRequest struct {
	IpAddress net.IP
}

type BecomePrimaryVmOwnerResponse struct {
	Error string
}

type ChangeAddressPoolRequest struct {
	AddressesToAdd       []Address
	MaximumFreeAddresses map[string]uint // Key: subnet ID.
}

type ChangeAddressPoolResponse struct {
	Error string
}

type ChangeVmOwnerUsersRequest struct {
	IpAddress  net.IP
	OwnerUsers []string
}

type ChangeVmOwnerUsersResponse struct {
	Error string
}

type ChangeVmTagsRequest struct {
	IpAddress net.IP
	Tags      tags.Tags
}

type ChangeVmTagsResponse struct {
	Error string
}

type CommitImportedVmRequest struct {
	IpAddress net.IP
}

type CommitImportedVmResponse struct {
	Error string
}

type CreateVmRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageTimeout     time.Duration
	MinimumFreeBytes uint64
	RoundupPower     uint64
	SecondaryVolumes []Volume
	UserDataSize     uint64
	VmInfo
} // RAW image data (length=ImageDataSize) and user data (length=UserDataSize)
// are streamed afterwards.

type CreateVmResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	IpAddress       net.IP
	ProgressMessage string
	Error           string
}

type DestroyVmRequest struct {
	IpAddress net.IP
}

type DestroyVmResponse struct {
	Error string
}

type DiscardVmOldImageRequest struct {
	IpAddress net.IP
}

type DiscardVmOldImageResponse struct {
	Error string
}

type DiscardVmOldUserDataRequest struct {
	IpAddress net.IP
}

type DiscardVmOldUserDataResponse struct {
	Error string
}

type DiscardVmSnapshotRequest struct {
	IpAddress net.IP
}

type DiscardVmSnapshotResponse struct {
	Error string
}

// The GetUpdates() RPC is fully streamed.
// The client sends no information to the server.
// The server sends a stream of Update messages.

type Update struct {
	HaveAddressPool  bool               `json:",omitempty"`
	AddressPool      []Address          `json:",omitempty"` // Used & free.
	NumFreeAddresses map[string]uint    `json:",omitempty"` // Key: subnet ID.
	HaveSubnets      bool               `json:",omitempty"`
	Subnets          []Subnet           `json:",omitempty"`
	HaveVMs          bool               `json:",omitempty"`
	VMs              map[string]*VmInfo `json:",omitempty"` // Key: IP address.
}

type GetVmInfoRequest struct {
	IpAddress net.IP
}

type GetVmInfoResponse struct {
	VmInfo VmInfo
	Error  string
}

type ImportLocalVmRequest struct {
	VerificationCookie []byte `json:",omitempty"`
	VmInfo
	VolumeFilenames []string
}

type ImportLocalVmResponse struct {
	Error string
}

type ListVMsRequest struct {
	Sort bool
}

type ListVMsResponse struct {
	IpAddresses []net.IP
}

type ListVolumeDirectoriesRequest struct{}

type ListVolumeDirectoriesResponse struct {
	Directories []string
	Error       string
}

type NetbootMachineRequest struct {
	Address                      Address
	Files                        map[string][]byte
	FilesExpiration              time.Duration
	Hostname                     string
	NumAcknowledgementsToWaitFor uint
	OfferExpiration              time.Duration
	Subnet                       *Subnet
	WaitTimeout                  time.Duration
}

type NetbootMachineResponse struct {
	Error string
}

type ProbeVmPortRequest struct {
	IpAddress  net.IP
	PortNumber uint
	Timeout    time.Duration
}

type ProbeVmPortResponse struct {
	PortIsOpen bool
	Error      string
}

type ReplaceVmImageRequest struct {
	DhcpTimeout      time.Duration
	ImageDataSize    uint64
	ImageName        string `json:",omitempty"`
	ImageTimeout     time.Duration
	ImageURL         string `json:",omitempty"`
	IpAddress        net.IP
	MinimumFreeBytes uint64
	RoundupPower     uint64
} // RAW image data (length=ImageDataSize) is streamed afterwards.

type ReplaceVmImageResponse struct { // Multiple responses are sent.
	DhcpTimedOut    bool
	Final           bool // If true, this is the final response.
	ProgressMessage string
	Error           string
}

type ReplaceVmUserDataRequest struct {
	IpAddress net.IP
	Size      uint64
} // User data (length=Size) are streamed afterwards.

type ReplaceVmUserDataResponse struct {
	Error string
}

type RestoreVmFromSnapshotRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
}

type RestoreVmFromSnapshotResponse struct {
	Error string
}

type RestoreVmImageRequest struct {
	IpAddress net.IP
}

type RestoreVmImageResponse struct {
	Error string
}

type RestoreVmUserDataRequest struct {
	IpAddress net.IP
}

type RestoreVmUserDataResponse struct {
	Error string
}

type SnapshotVmRequest struct {
	IpAddress         net.IP
	ForceIfNotStopped bool
	RootOnly          bool
}

type SnapshotVmResponse struct {
	Error string
}

type StartVmRequest struct {
	DhcpTimeout time.Duration
	IpAddress   net.IP
}

type StartVmResponse struct {
	DhcpTimedOut bool
	Error        string
}

type StopVmRequest struct {
	IpAddress net.IP
}

type StopVmResponse struct {
	Error string
}

type State uint

type Subnet struct {
	Id                string
	IpGateway         net.IP
	IpMask            net.IP // net.IPMask can't be JSON {en,de}coded.
	DomainName        string `json:",omitempty"`
	DomainNameServers []net.IP
	Manage            bool     `json:",omitempty"`
	VlanId            uint     `json:",omitempty"`
	AllowedGroups     []string `json:",omitempty"`
	AllowedUsers      []string `json:",omitempty"`
}

type TraceVmMetadataRequest struct {
	IpAddress net.IP
}

type TraceVmMetadataResponse struct {
	Error string
} // A stream of strings (trace paths) follow.

type UpdateSubnetsRequest struct {
	Add    []Subnet
	Change []Subnet
	Delete []string
}

type UpdateSubnetsResponse struct {
	Error string
}

type VmInfo struct {
	Address       Address
	Hostname      string `json:",omitempty"`
	ImageName     string `json:",omitempty"`
	ImageURL      string `json:",omitempty"`
	MemoryInMiB   uint64
	MilliCPUs     uint
	OwnerGroups   []string `json:",omitempty"`
	OwnerUsers    []string `json:",omitempty"`
	SpreadVolumes bool     `json:",omitempty"`
	State         State
	Tags          tags.Tags `json:",omitempty"`
	SubnetId      string    `json:",omitempty"`
	Uncommitted   bool      `json:",omitempty"`
	Volumes       []Volume  `json:",omitempty"`
}

type Volume struct {
	Size   uint64
	Format VolumeFormat
}

type VolumeFormat uint
<|endoftext|>


<commit_before>package falcore

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

// Generate an http.Response using the basic fields
func SimpleResponse(req *http.Request, status int, headers http.Header, contentLength int64, body io.Reader) *http.Response {
	res := new(http.Response)
	res.StatusCode = status
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.ContentLength = contentLength
	res.Request = req
	res.Header = make(map[string][]string)
	if body_rdr, ok := body.(io.ReadCloser); ok {
		res.Body = body_rdr
	} else {
		res.Body = ioutil.NopCloser(body)
	}
	if headers != nil {
		res.Header = headers
	}
	return res
}

// Like SimpleResponse but uses a []byte for the body.
func ByteResponse(req *http.Request, status int, headers http.Header, body []byte) *http.Response {
	return SimpleResponse(req, status, headers, int64(len(body)), bytes.NewBuffer(body))
}

// Like StringResponse but uses a string for the body.
func StringResponse(req *http.Request, status int, headers http.Header, body string) *http.Response {
	return SimpleResponse(req, status, headers, int64(len(body)), strings.NewReader(body))
}

// A 302 redirect response
func RedirectResponse(req *http.Request, url string) *http.Response {
	h := make(http.Header)
	h.Set("Location", url)
	return SimpleResponse(req, 302, h, 0, nil)
}

// Generate an http.Response by json encoding body using
// the standard library's json.Encoder.  error will be nil
// unless json encoding fails.
func JSONResponse(req *http.Request, status int, headers http.Header, body interface{}) (*http.Response, error) {
	buf := new(bytes.Buffer)
	if err := json.NewEncoder(buf).Encode(body); err != nil {
		return nil, err
	}

	if headers == nil {
		headers = make(http.Header)
	}
	if headers.Get("Content-Type") == "" {
		headers.Set("Content-Type", "application/json")
	}

	return SimpleResponse(req, status, headers, int64(buf.Len()), buf), nil
}
<commit_msg>added StreamingJSONResponse for when you don't want to pre-buffer the JSON<commit_after>package falcore

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

// Generate an http.Response using the basic fields
func SimpleResponse(req *http.Request, status int, headers http.Header, contentLength int64, body io.Reader) *http.Response {
	res := new(http.Response)
	res.StatusCode = status
	res.ProtoMajor = 1
	res.ProtoMinor = 1
	res.ContentLength = contentLength
	res.Request = req
	res.Header = make(map[string][]string)
	if body_rdr, ok := body.(io.ReadCloser); ok {
		res.Body = body_rdr
	} else {
		res.Body = ioutil.NopCloser(body)
	}
	if headers != nil {
		res.Header = headers
	}
	return res
}

// Like SimpleResponse but uses a []byte for the body.
func ByteResponse(req *http.Request, status int, headers http.Header, body []byte) *http.Response {
	return SimpleResponse(req, status, headers, int64(len(body)), bytes.NewBuffer(body))
}

// Like StringResponse but uses a string for the body.
func StringResponse(req *http.Request, status int, headers http.Header, body string) *http.Response {
	return SimpleResponse(req, status, headers, int64(len(body)), strings.NewReader(body))
}

// A 302 redirect response
func RedirectResponse(req *http.Request, url string) *http.Response {
	h := make(http.Header)
	h.Set("Location", url)
	return SimpleResponse(req, 302, h, 0, nil)
}

// Generate an http.Response by json encoding body using
// the standard library's json.Encoder.  error will be nil
// unless json encoding fails.
func JSONResponse(req *http.Request, status int, headers http.Header, body interface{}) (*http.Response, error) {
	buf := new(bytes.Buffer)
	if err := json.NewEncoder(buf).Encode(body); err != nil {
		return nil, err
	}

	if headers == nil {
		headers = make(http.Header)
	}
	if headers.Get("Content-Type") == "" {
		headers.Set("Content-Type", "application/json")
	}

	return SimpleResponse(req, status, headers, int64(buf.Len()), buf), nil
}

// Streaming version of JSONResponse.  JSON encoding is unbuffered and transfer-encoding will be chunked.
// Errors encountered during encoding will be logged, but are not returned
func StreamingJSONResponse(req *http.Request, status int, headers http.Header, body interface{}) *http.Response {
	pR, pW := io.Pipe()
	go func() {
		if err := json.NewEncoder(pW).Encode(body); err != nil {
			Error("Error encoding JSON: %v", err)
		}
		pW.Close()
	}()

	if headers == nil {
		headers = make(http.Header)
	}
	if headers.Get("Content-Type") == "" {
		headers.Set("Content-Type", "application/json")
	}

	return SimpleResponse(req, status, headers, -1, pR)
}
<|endoftext|>


<commit_before>package rest

import (
	"compress/gzip"
	"encoding/json"
	"net/http"
)

// Inherit from an object implementing the http.ResponseWriter interface,
// and provide additional methods.
type ResponseWriter struct {
	http.ResponseWriter
	is_gzipped   bool
	is_indented  bool
	status_code  int
	wrote_header bool
}

// Overloading of the http.ResponseWriter method.
// Just record the status code for logging.
func (self *ResponseWriter) WriteHeader(code int) {
	self.ResponseWriter.WriteHeader(code)
	self.status_code = code
	self.wrote_header = true
}

// Overloading of the http.ResponseWriter method.
// Provide additional capabilities, like transparent gzip encoding.
func (self *ResponseWriter) Write(b []byte) (int, error) {

	if !self.wrote_header {
		self.WriteHeader(http.StatusOK)
	}

	if self.is_gzipped {
		self.Header().Set("Content-Encoding", "gzip")
		gzip_writer := gzip.NewWriter(self.ResponseWriter)
		defer gzip_writer.Close()
		return gzip_writer.Write(b)
	}

	return self.ResponseWriter.Write(b)
}

// Encode the object in JSON, set the content-type header,
// and call Write.
func (self *ResponseWriter) WriteJson(v interface{}) error {
	self.Header().Set("content-type", "application/json")
	var b []byte
	var err error
	if self.is_indented {
		b, err = json.MarshalIndent(v, "", "  ")
	} else {
		b, err = json.Marshal(v)
	}
	if err != nil {
		return err
	}
	self.Write(b)
	return nil
}

// Produce an error response in JSON with the following structure, '{"error":"error message"}'
// The standard plain text net/http Error helper can still be called like this:
// http.Error(w, "error message", code)
func Error(w *ResponseWriter, error string, code int) {
	w.Header().Set("content-type", "application/json")
	w.WriteHeader(code)
	err := w.WriteJson(map[string]string{"error": error})
	if err != nil {
		panic(err)
	}
}

// Produce a 404 response with the following JSON, '{"error":"Resource not found"}'
// The standard plain text net/http NotFound helper can still be called like this:
// http.NotFound(w, r.Request)
func NotFound(w *ResponseWriter, r *Request) {
	Error(w, "Resource not found", http.StatusNotFound)
}
<commit_msg>Capitable E, for Error.<commit_after>package rest

import (
	"compress/gzip"
	"encoding/json"
	"net/http"
)

// Inherit from an object implementing the http.ResponseWriter interface,
// and provide additional methods.
type ResponseWriter struct {
	http.ResponseWriter
	is_gzipped   bool
	is_indented  bool
	status_code  int
	wrote_header bool
}

// Overloading of the http.ResponseWriter method.
// Just record the status code for logging.
func (self *ResponseWriter) WriteHeader(code int) {
	self.ResponseWriter.WriteHeader(code)
	self.status_code = code
	self.wrote_header = true
}

// Overloading of the http.ResponseWriter method.
// Provide additional capabilities, like transparent gzip encoding.
func (self *ResponseWriter) Write(b []byte) (int, error) {

	if !self.wrote_header {
		self.WriteHeader(http.StatusOK)
	}

	if self.is_gzipped {
		self.Header().Set("Content-Encoding", "gzip")
		gzip_writer := gzip.NewWriter(self.ResponseWriter)
		defer gzip_writer.Close()
		return gzip_writer.Write(b)
	}

	return self.ResponseWriter.Write(b)
}

// Encode the object in JSON, set the content-type header,
// and call Write.
func (self *ResponseWriter) WriteJson(v interface{}) error {
	self.Header().Set("content-type", "application/json")
	var b []byte
	var err error
	if self.is_indented {
		b, err = json.MarshalIndent(v, "", "  ")
	} else {
		b, err = json.Marshal(v)
	}
	if err != nil {
		return err
	}
	self.Write(b)
	return nil
}

// Produce an error response in JSON with the following structure, '{"Error":"My error message"}'
// The standard plain text net/http Error helper can still be called like this:
// http.Error(w, "error message", code)
func Error(w *ResponseWriter, error string, code int) {
	w.Header().Set("content-type", "application/json")
	w.WriteHeader(code)
	err := w.WriteJson(map[string]string{"Error": error})
	if err != nil {
		panic(err)
	}
}

// Produce a 404 response with the following JSON, '{"Error":"Resource not found"}'
// The standard plain text net/http NotFound helper can still be called like this:
// http.NotFound(w, r.Request)
func NotFound(w *ResponseWriter, r *Request) {
	Error(w, "Resource not found", http.StatusNotFound)
}
<|endoftext|>