<commit_before>package todolist

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

type App struct {
	TodoStore Store
	TodoList  *TodoList
}

func NewApp() *App {
	app := &App{TodoList: &TodoList{}, TodoStore: NewFileStore()}
	return app
}

func (a *App) InitializeRepo() {
	a.TodoStore.Initialize()
}

func (a *App) AddTodo(input string) {
	a.Load()
	parser := &Parser{}
	todo := parser.ParseNewTodo(input)
	if todo == nil {
		fmt.Println("I need more information. Try something like 'todo a chat with @bob due tom'")
		return
	}

	id := a.TodoList.NextId()
	a.TodoList.Add(todo)
	a.Save()
	fmt.Printf("Todo %d added.\n", id)
}

func (a *App) DeleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Delete(id)
	a.Save()
	fmt.Println("Todo deleted.")
}

func (a *App) CompleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Complete(id)
	a.Save()
	fmt.Println("Todo completed.")
}

func (a *App) UncompleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Uncomplete(id)
	a.Save()
	fmt.Println("Todo uncompleted.")
}

func (a *App) ArchiveTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Archive(id)
	a.Save()
	fmt.Println("Todo archived.")
}

func (a *App) UnarchiveTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Unarchive(id)
	a.Save()
	fmt.Println("Todo unarchived.")
}

func (a *App) EditTodo(input string) {
	a.Load()
	id, todo := a.getId(input)
	if id == -1 {
		return
	}
	parser := &Parser{}

	if parser.ParseEditTodo(todo, input) {
		a.Save()
		fmt.Println("Todo updated.")
	}
}

func (a *App) ExpandTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	parser := &Parser{}
	if id == -1 {
		return
	}

	commonProject := parser.ExpandProject(input)
	todos := strings.LastIndex(input, ":")
	if commonProject == "" || len(input) <= todos+1 || todos == -1 {
		fmt.Println("I'm expecting a format like \"todolist ex <project>: <todo1>, <todo2>, ...\"")
		return
	}

	newTodos := strings.Split(input[todos+1:], ",")

	for _, todo := range newTodos {
		args := []string{"add ", commonProject, " ", todo}
		a.AddTodo(strings.Join(args, ""))
	}

	a.TodoList.Delete(id)
	a.Save()
	fmt.Println("Todo expanded.")
}

func (a *App) ArchiveCompleted() {
	a.Load()
	for _, todo := range a.TodoList.Todos() {
		if todo.Completed {
			todo.Archived = true
		}
	}
	a.Save()
	fmt.Println("All completed todos have been archived.")
}

func (a *App) ListTodos(input string) {
	a.Load()
	filtered := NewFilter(a.TodoList.Todos()).Filter(input)
	grouped := a.getGroups(input, filtered)

	formatter := NewFormatter(grouped)
	formatter.Print()
}

func (a *App) PrioritizeTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Prioritize(id)
	a.Save()
	fmt.Println("Todo prioritized.")
}

func (a *App) UnprioritizeTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Unprioritize(id)
	a.Save()
	fmt.Println("Todo un-prioritized.")
}

func (a *App) getId(input string) (int, *Todo) {
	re, _ := regexp.Compile("\\d+")
	if re.MatchString(input) {
		id, _ := strconv.Atoi(re.FindString(input))
		todo := a.TodoList.FindById(id)
		if todo == nil {
			fmt.Println("No such id.")
			return -1, nil

		}
		return id, todo

	} else {
		fmt.Println("Invalid id.")
		return -1, nil

	}
}

func (a *App) getGroups(input string, todos []*Todo) *GroupedTodos {
	grouper := &Grouper{}
	contextRegex, _ := regexp.Compile(`by c.*$`)
	projectRegex, _ := regexp.Compile(`by p.*$`)

	var grouped *GroupedTodos

	if contextRegex.MatchString(input) {
		grouped = grouper.GroupByContext(todos)
	} else if projectRegex.MatchString(input) {
		grouped = grouper.GroupByProject(todos)
	} else {
		grouped = grouper.GroupByNothing(todos)
	}
	return grouped
}

func (a *App) GarbageCollect() {
	a.Load()
	a.TodoList.GarbageCollect()
	a.Save()
	fmt.Println("Garbage collection complete.")
}

func (a *App) Load() error {
	todos, err := a.TodoStore.Load()
	if err != nil {
		return err
	}
	a.TodoList.Load(todos)
	return nil
}

func (a *App) Save() {
	a.TodoStore.Save(a.TodoList.Data)
}
<commit_msg>Fix a missed 't.Archive=true' to Archived()<commit_after>package todolist

import (
	"fmt"
	"regexp"
	"strconv"
	"strings"
)

type App struct {
	TodoStore Store
	TodoList  *TodoList
}

func NewApp() *App {
	app := &App{TodoList: &TodoList{}, TodoStore: NewFileStore()}
	return app
}

func (a *App) InitializeRepo() {
	a.TodoStore.Initialize()
}

func (a *App) AddTodo(input string) {
	a.Load()
	parser := &Parser{}
	todo := parser.ParseNewTodo(input)
	if todo == nil {
		fmt.Println("I need more information. Try something like 'todo a chat with @bob due tom'")
		return
	}

	id := a.TodoList.NextId()
	a.TodoList.Add(todo)
	a.Save()
	fmt.Printf("Todo %d added.\n", id)
}

func (a *App) DeleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Delete(id)
	a.Save()
	fmt.Println("Todo deleted.")
}

func (a *App) CompleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Complete(id)
	a.Save()
	fmt.Println("Todo completed.")
}

func (a *App) UncompleteTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Uncomplete(id)
	a.Save()
	fmt.Println("Todo uncompleted.")
}

func (a *App) ArchiveTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Archive(id)
	a.Save()
	fmt.Println("Todo archived.")
}

func (a *App) UnarchiveTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Unarchive(id)
	a.Save()
	fmt.Println("Todo unarchived.")
}

func (a *App) EditTodo(input string) {
	a.Load()
	id, todo := a.getId(input)
	if id == -1 {
		return
	}
	parser := &Parser{}

	if parser.ParseEditTodo(todo, input) {
		a.Save()
		fmt.Println("Todo updated.")
	}
}

func (a *App) ExpandTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	parser := &Parser{}
	if id == -1 {
		return
	}

	commonProject := parser.ExpandProject(input)
	todos := strings.LastIndex(input, ":")
	if commonProject == "" || len(input) <= todos+1 || todos == -1 {
		fmt.Println("I'm expecting a format like \"todolist ex <project>: <todo1>, <todo2>, ...\"")
		return
	}

	newTodos := strings.Split(input[todos+1:], ",")

	for _, todo := range newTodos {
		args := []string{"add ", commonProject, " ", todo}
		a.AddTodo(strings.Join(args, ""))
	}

	a.TodoList.Delete(id)
	a.Save()
	fmt.Println("Todo expanded.")
}

func (a *App) ArchiveCompleted() {
	a.Load()
	for _, todo := range a.TodoList.Todos() {
		if todo.Completed {
			todo.Archive()
		}
	}
	a.Save()
	fmt.Println("All completed todos have been archived.")
}

func (a *App) ListTodos(input string) {
	a.Load()
	filtered := NewFilter(a.TodoList.Todos()).Filter(input)
	grouped := a.getGroups(input, filtered)

	formatter := NewFormatter(grouped)
	formatter.Print()
}

func (a *App) PrioritizeTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Prioritize(id)
	a.Save()
	fmt.Println("Todo prioritized.")
}

func (a *App) UnprioritizeTodo(input string) {
	a.Load()
	id, _ := a.getId(input)
	if id == -1 {
		return
	}
	a.TodoList.Unprioritize(id)
	a.Save()
	fmt.Println("Todo un-prioritized.")
}

func (a *App) getId(input string) (int, *Todo) {
	re, _ := regexp.Compile("\\d+")
	if re.MatchString(input) {
		id, _ := strconv.Atoi(re.FindString(input))
		todo := a.TodoList.FindById(id)
		if todo == nil {
			fmt.Println("No such id.")
			return -1, nil

		}
		return id, todo

	} else {
		fmt.Println("Invalid id.")
		return -1, nil

	}
}

func (a *App) getGroups(input string, todos []*Todo) *GroupedTodos {
	grouper := &Grouper{}
	contextRegex, _ := regexp.Compile(`by c.*$`)
	projectRegex, _ := regexp.Compile(`by p.*$`)

	var grouped *GroupedTodos

	if contextRegex.MatchString(input) {
		grouped = grouper.GroupByContext(todos)
	} else if projectRegex.MatchString(input) {
		grouped = grouper.GroupByProject(todos)
	} else {
		grouped = grouper.GroupByNothing(todos)
	}
	return grouped
}

func (a *App) GarbageCollect() {
	a.Load()
	a.TodoList.GarbageCollect()
	a.Save()
	fmt.Println("Garbage collection complete.")
}

func (a *App) Load() error {
	todos, err := a.TodoStore.Load()
	if err != nil {
		return err
	}
	a.TodoList.Load(todos)
	return nil
}

func (a *App) Save() {
	a.TodoStore.Save(a.TodoList.Data)
}
<|endoftext|>


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

package simplepush

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/goprotobuf/proto"
	"github.com/mozilla-services/heka/message"
	"github.com/mozilla-services/pushgo/id"
)

// A HekaFormat specifies the Heka log message format. The binary Protobuf
// format is more efficient, and should be preferred over the JSON encoding
// when human readability is not a concern.
type HekaFormat int

// Heka message formats.
const (
	HekaProtobuf HekaFormat = iota
	HekaJSON
)

// A LogLevel represents a message log level.
type LogLevel int32

// syslog severity levels.
const (
	EMERGENCY LogLevel = iota
	ALERT
	CRITICAL
	ERROR
	WARNING
	NOTICE
	INFO
	DEBUG
)

var levelNames = map[LogLevel]string{
	EMERGENCY: "EMERGENCY",
	ALERT:     "ALERT",
	CRITICAL:  "CRITICAL",
	ERROR:     "ERROR",
	WARNING:   "WARNING",
	NOTICE:    "NOTICE",
	INFO:      "INFO",
	DEBUG:     "DEBUG",
}

func (l LogLevel) String() string {
	return levelNames[l]
}

const (
	HeaderID      = "X-Request-Id"
	TextLogTime   = "2006-01-02 15:04:05 -0700"
	CommonLogTime = "02/Jan/2006:15:04:05 -0700"
)

// logNames sorts log field names lexicographically.
type logNames []string

func (n logNames) Len() int           { return len(n) }
func (n logNames) Less(i, j int) bool { return n[i] < n[j] }
func (n logNames) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }

type LogFields map[string]string

func (l LogFields) Names() (names logNames) {
	names = make(logNames, len(l))
	i := 0
	for name := range l {
		names[i] = name
		i++
	}
	sort.Sort(names)
	return
}

type Logger interface {
	HasConfigStruct
	Log(level LogLevel, messageType, payload string, fields LogFields) error
	SetFilter(level LogLevel)
	ShouldLog(level LogLevel) bool
}

var AvailableLoggers = make(AvailableExtensions)

type SimpleLogger struct {
	Logger
}

// Error string helper that ignores nil errors
func ErrStr(err error) string {
	if err == nil {
		return ""
	}
	return err.Error()
}

// Attempt to convert an interface to a string, ignore failures
func IStr(i interface{}) (reply string) {
	if i == nil {
		return ""
	}
	if reply, ok := i.(string); ok {
		return reply
	}
	return "Undefined"
}

// SimplePush Logger implementation, utilizes the passed in Logger
func NewLogger(log Logger) (*SimpleLogger, error) {
	return &SimpleLogger{log}, nil
}

// Default logging calls for convenience
func (sl *SimpleLogger) Debug(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(DEBUG, mtype, msg, fields)
}

func (sl *SimpleLogger) Info(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(INFO, mtype, msg, fields)
}

func (sl *SimpleLogger) Notice(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(NOTICE, mtype, msg, fields)
}

func (sl *SimpleLogger) Warn(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(WARNING, mtype, msg, fields)
}

func (sl *SimpleLogger) Error(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(ERROR, mtype, msg, fields)
}

func (sl *SimpleLogger) Critical(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(CRITICAL, mtype, msg, fields)
}

func (sl *SimpleLogger) Alert(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(ALERT, mtype, msg, fields)
}

func (sl *SimpleLogger) Panic(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(EMERGENCY, mtype, msg, fields)
}

// NewHekaLogger creates a logger that writes Protobuf or JSON-encoded log
// messages to standard output.
func NewHekaLogger(format HekaFormat) *HekaLogger {
	return &HekaLogger{format: format, writer: os.Stdout}
}

type HekaLoggerConfig struct {
	Name       string
	EnvVersion string `toml:"env_version"`
	Filter     int32
}

type HekaLogger struct {
	pid        int32
	logName    string
	envVersion string
	hostname   string
	filter     LogLevel
	format     HekaFormat
	writer     io.Writer
}

func (hl *HekaLogger) ConfigStruct() interface{} {
	return &HekaLoggerConfig{
		Name:       fmt.Sprintf("push-%s", VERSION),
		EnvVersion: "1",
		Filter:     0,
	}
}

func (hl *HekaLogger) Init(app *Application, config interface{}) (err error) {
	conf := config.(*HekaLoggerConfig)
	hl.pid = int32(os.Getpid())
	hl.hostname = app.Hostname()
	hl.logName = conf.Name
	hl.envVersion = conf.EnvVersion
	hl.filter = LogLevel(conf.Filter)
	return
}

func (hl *HekaLogger) ShouldLog(level LogLevel) bool {
	return level <= hl.filter
}

func (hl *HekaLogger) SetFilter(level LogLevel) {
	hl.filter = level
}

func (hl *HekaLogger) writeMessage(m *message.Message) (err error) {
	switch hl.format {
	case HekaProtobuf:
		var data []byte
		if data, err = proto.Marshal(m); err != nil {
			return
		}
		_, err = hl.writer.Write(data)

	case HekaJSON:
		encoder := json.NewEncoder(hl.writer)
		err = encoder.Encode(m)
	}
	return
}

func (hl *HekaLogger) Log(level LogLevel, messageType, payload string, fields LogFields) (err error) {
	if !hl.ShouldLog(level) {
		return
	}
	messageID, _ := id.GenerateBytes()
	m := new(message.Message)
	m.SetUuid(messageID)
	m.SetTimestamp(time.Now().UnixNano())
	m.SetType(messageType)
	m.SetLogger(hl.logName)
	m.SetSeverity(int32(level))
	m.SetPayload(payload)
	m.SetEnvVersion(hl.envVersion)
	m.SetPid(hl.pid)
	m.SetHostname(hl.hostname)
	for _, name := range fields.Names() {
		message.NewStringField(m, name, fields[name])
	}
	if err = hl.writeMessage(m); err != nil {
		log.Fatalf("Error writing log message: %s", err)
	}
	return
}

// NewTextLogger creates a logger that writes human-readable log messages to
// standard error.
func NewTextLogger() *TextLogger {
	return &TextLogger{writer: os.Stderr}
}

type TextLoggerConfig struct {
	Filter int32
	Trace  bool
}

// A TextLogger writes human-readable log messages.
type TextLogger struct {
	pid      int32
	hostname string
	filter   LogLevel
	writer   io.Writer
}

func (tl *TextLogger) ConfigStruct() interface{} {
	return &TextLoggerConfig{
		Filter: 0,
		Trace:  false,
	}
}

func (tl *TextLogger) Init(app *Application, config interface{}) (err error) {
	conf := config.(*TextLoggerConfig)
	tl.pid = int32(os.Getpid())
	tl.hostname = app.Hostname()
	tl.filter = LogLevel(conf.Filter)
	return
}

func (tl *TextLogger) ShouldLog(level LogLevel) bool {
	return level <= tl.filter
}

func (tl *TextLogger) SetFilter(level LogLevel) {
	tl.filter = level
}

func (tl *TextLogger) Log(level LogLevel, messageType, payload string, fields LogFields) (err error) {
	// Return ASAP if we shouldn't be logging
	if !tl.ShouldLog(level) {
		return
	}

	reply := new(bytes.Buffer)
	fmt.Fprintf(reply, "%s [% 8s] %s %s", time.Now().Format(TextLogTime),
		level, messageType, strconv.Quote(payload))

	if len(fields) > 0 {
		reply.WriteByte(' ')
		names := fields.Names()
		for i, name := range names {
			fmt.Fprintf(reply, "%s:%s", name, fields[name])
			if i < len(names)-1 {
				reply.WriteString(", ")
			}
		}
	}

	reply.WriteByte('\n')
	_, err = reply.WriteTo(tl.writer)

	return
}

// logResponseWriter wraps an http.ResponseWriter, recording its status code,
// content length, and response time.
type logResponseWriter struct {
	http.ResponseWriter
	wroteHeader   bool
	StatusCode    int
	ContentLength int
	RespondedAt   time.Time
}

// writerOnly hides the optional ReadFrom method of an io.Writer from io.Copy.
// Taken from package net/http, copyright 2009, The Go Authors.
type writerOnly struct {
	io.Writer
}

// ReadFrom calls the ReadFrom method of the underlying ResponseWriter. Defined
// for compatibility with *response.ReadFrom from package net/http.
func (w *logResponseWriter) ReadFrom(r io.Reader) (int64, error) {
	if dest, ok := w.ResponseWriter.(io.ReaderFrom); ok {
		return dest.ReadFrom(r)
	}
	return io.Copy(writerOnly{w}, r)
}

// WriteHeader records the response time and status code, then calls the
// WriteHeader method of the underlying ResponseWriter.
func (w *logResponseWriter) WriteHeader(statusCode int) {
	if !w.wroteHeader {
		w.wroteHeader = true
		w.setStatus(statusCode)
	}
	w.ResponseWriter.WriteHeader(statusCode)
}

// setStatus records the response time and status code.
func (w *logResponseWriter) setStatus(statusCode int) {
	w.RespondedAt = time.Now()
	w.StatusCode = statusCode
}

// Write calls the Write method of the underlying ResponseWriter and records
// the number of bytes written.
func (w *logResponseWriter) Write(data []byte) (n int, err error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	n, err = w.ResponseWriter.Write(data)
	w.ContentLength += len(data)
	return
}

// Hijack calls the Hijack method of the underlying ResponseWriter, allowing a
// custom protocol handler (e.g., WebSockets) to take over the connection.
func (w *logResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if hj, ok := w.ResponseWriter.(http.Hijacker); ok {
		return hj.Hijack()
	}
	return nil, nil, io.EOF
}

// CloseNotify calls the CloseNotify method of the underlying ResponseWriter,
// or returns a nil channel if the operation is not supported.
func (w *logResponseWriter) CloseNotify() <-chan bool {
	if cn, ok := w.ResponseWriter.(http.CloseNotifier); ok {
		return cn.CloseNotify()
	}
	return nil
}

// Flush calls the Flush method of the underlying ResponseWriter, recording a
// successful response if WriteHeader was not called.
func (w *logResponseWriter) Flush() {
	if !w.wroteHeader {
		w.wroteHeader = true
		w.setStatus(http.StatusOK)
	}
	if f, ok := w.ResponseWriter.(http.Flusher); ok {
		f.Flush()
	}
}

// LogHandler logs the result of an HTTP request.
type LogHandler struct {
	http.Handler
	Log *SimpleLogger
}

// formatRequest generates a Common Log Format request line.
func (h *LogHandler) formatRequest(writer *logResponseWriter, req *http.Request, remoteAddrs []string) string {
	remoteAddr := "-"
	if len(remoteAddrs) > 0 {
		remoteAddr = remoteAddrs[0]
	}
	requestInfo := fmt.Sprintf("%s %s %s", req.Method, req.URL.Path, req.Proto)
	return fmt.Sprintf(`%s - - [%s] %s %d %d`, remoteAddr, writer.RespondedAt.Format(CommonLogTime),
		strconv.Quote(requestInfo), writer.StatusCode, writer.ContentLength)
}

// logResponse logs a response to an HTTP request.
func (h *LogHandler) logResponse(writer *logResponseWriter, req *http.Request, requestID string, receivedAt time.Time) {
	if !h.Log.ShouldLog(INFO) {
		return
	}
	forwardedFor := req.Header[http.CanonicalHeaderKey("X-Forwarded-For")]
	remoteAddrs := make([]string, len(forwardedFor)+1)
	copy(remoteAddrs, forwardedFor)
	remoteAddrs[len(remoteAddrs)-1], _, _ = net.SplitHostPort(req.RemoteAddr)
	h.Log.Info("http", h.formatRequest(writer, req, remoteAddrs), LogFields{
		"rid":                requestID,
		"agent":              req.Header.Get("User-Agent"),
		"path":               req.URL.Path,
		"method":             req.Method,
		"code":               strconv.Itoa(writer.StatusCode),
		"remoteAddressChain": fmt.Sprintf("[%s]", strings.Join(remoteAddrs, ", ")),
		"t":                  strconv.FormatInt(int64(writer.RespondedAt.Sub(receivedAt)/time.Millisecond), 10)})
}

// ServeHTTP implements http.Handler.ServeHTTP.
func (h *LogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	receivedAt := time.Now()

	// The `X-Request-Id` header is used by Heroku, restify, etc. to correlate
	// logs for the same request.
	requestID := req.Header.Get(HeaderID)
	if !id.Valid(requestID) {
		requestID, _ = id.Generate()
		req.Header.Set(HeaderID, requestID)
	}

	writer := &logResponseWriter{ResponseWriter: res, StatusCode: http.StatusOK}
	defer h.logResponse(writer, req, requestID, receivedAt)

	h.Handler.ServeHTTP(writer, req)
}

func init() {
	AvailableLoggers["protobuf"] = func() HasConfigStruct { return NewHekaLogger(HekaProtobuf) }
	AvailableLoggers["json"] = func() HasConfigStruct { return NewHekaLogger(HekaJSON) }
	AvailableLoggers["text"] = func() HasConfigStruct { return NewTextLogger() }
	AvailableLoggers["default"] = AvailableLoggers["text"]
}
<commit_msg>`logResponseWriter`: Log hijacked responses.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package simplepush

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"code.google.com/p/goprotobuf/proto"
	"github.com/mozilla-services/heka/message"
	"github.com/mozilla-services/pushgo/id"
)

// A HekaFormat specifies the Heka log message format. The binary Protobuf
// format is more efficient, and should be preferred over the JSON encoding
// when human readability is not a concern.
type HekaFormat int

// Heka message formats.
const (
	HekaProtobuf HekaFormat = iota
	HekaJSON
)

// A LogLevel represents a message log level.
type LogLevel int32

// syslog severity levels.
const (
	EMERGENCY LogLevel = iota
	ALERT
	CRITICAL
	ERROR
	WARNING
	NOTICE
	INFO
	DEBUG
)

var levelNames = map[LogLevel]string{
	EMERGENCY: "EMERGENCY",
	ALERT:     "ALERT",
	CRITICAL:  "CRITICAL",
	ERROR:     "ERROR",
	WARNING:   "WARNING",
	NOTICE:    "NOTICE",
	INFO:      "INFO",
	DEBUG:     "DEBUG",
}

func (l LogLevel) String() string {
	return levelNames[l]
}

const (
	HeaderID      = "X-Request-Id"
	TextLogTime   = "2006-01-02 15:04:05 -0700"
	CommonLogTime = "02/Jan/2006:15:04:05 -0700"
)

// logNames sorts log field names lexicographically.
type logNames []string

func (n logNames) Len() int           { return len(n) }
func (n logNames) Less(i, j int) bool { return n[i] < n[j] }
func (n logNames) Swap(i, j int)      { n[i], n[j] = n[j], n[i] }

type LogFields map[string]string

func (l LogFields) Names() (names logNames) {
	names = make(logNames, len(l))
	i := 0
	for name := range l {
		names[i] = name
		i++
	}
	sort.Sort(names)
	return
}

type Logger interface {
	HasConfigStruct
	Log(level LogLevel, messageType, payload string, fields LogFields) error
	SetFilter(level LogLevel)
	ShouldLog(level LogLevel) bool
}

var AvailableLoggers = make(AvailableExtensions)

type SimpleLogger struct {
	Logger
}

// Error string helper that ignores nil errors
func ErrStr(err error) string {
	if err == nil {
		return ""
	}
	return err.Error()
}

// Attempt to convert an interface to a string, ignore failures
func IStr(i interface{}) (reply string) {
	if i == nil {
		return ""
	}
	if reply, ok := i.(string); ok {
		return reply
	}
	return "Undefined"
}

// SimplePush Logger implementation, utilizes the passed in Logger
func NewLogger(log Logger) (*SimpleLogger, error) {
	return &SimpleLogger{log}, nil
}

// Default logging calls for convenience
func (sl *SimpleLogger) Debug(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(DEBUG, mtype, msg, fields)
}

func (sl *SimpleLogger) Info(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(INFO, mtype, msg, fields)
}

func (sl *SimpleLogger) Notice(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(NOTICE, mtype, msg, fields)
}

func (sl *SimpleLogger) Warn(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(WARNING, mtype, msg, fields)
}

func (sl *SimpleLogger) Error(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(ERROR, mtype, msg, fields)
}

func (sl *SimpleLogger) Critical(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(CRITICAL, mtype, msg, fields)
}

func (sl *SimpleLogger) Alert(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(ALERT, mtype, msg, fields)
}

func (sl *SimpleLogger) Panic(mtype, msg string, fields LogFields) error {
	return sl.Logger.Log(EMERGENCY, mtype, msg, fields)
}

// NewHekaLogger creates a logger that writes Protobuf or JSON-encoded log
// messages to standard output.
func NewHekaLogger(format HekaFormat) *HekaLogger {
	return &HekaLogger{format: format, writer: os.Stdout}
}

type HekaLoggerConfig struct {
	Name       string
	EnvVersion string `toml:"env_version"`
	Filter     int32
}

type HekaLogger struct {
	pid        int32
	logName    string
	envVersion string
	hostname   string
	filter     LogLevel
	format     HekaFormat
	writer     io.Writer
}

func (hl *HekaLogger) ConfigStruct() interface{} {
	return &HekaLoggerConfig{
		Name:       fmt.Sprintf("push-%s", VERSION),
		EnvVersion: "1",
		Filter:     0,
	}
}

func (hl *HekaLogger) Init(app *Application, config interface{}) (err error) {
	conf := config.(*HekaLoggerConfig)
	hl.pid = int32(os.Getpid())
	hl.hostname = app.Hostname()
	hl.logName = conf.Name
	hl.envVersion = conf.EnvVersion
	hl.filter = LogLevel(conf.Filter)
	return
}

func (hl *HekaLogger) ShouldLog(level LogLevel) bool {
	return level <= hl.filter
}

func (hl *HekaLogger) SetFilter(level LogLevel) {
	hl.filter = level
}

func (hl *HekaLogger) writeMessage(m *message.Message) (err error) {
	switch hl.format {
	case HekaProtobuf:
		var data []byte
		if data, err = proto.Marshal(m); err != nil {
			return
		}
		_, err = hl.writer.Write(data)

	case HekaJSON:
		encoder := json.NewEncoder(hl.writer)
		err = encoder.Encode(m)
	}
	return
}

func (hl *HekaLogger) Log(level LogLevel, messageType, payload string, fields LogFields) (err error) {
	if !hl.ShouldLog(level) {
		return
	}
	messageID, _ := id.GenerateBytes()
	m := new(message.Message)
	m.SetUuid(messageID)
	m.SetTimestamp(time.Now().UnixNano())
	m.SetType(messageType)
	m.SetLogger(hl.logName)
	m.SetSeverity(int32(level))
	m.SetPayload(payload)
	m.SetEnvVersion(hl.envVersion)
	m.SetPid(hl.pid)
	m.SetHostname(hl.hostname)
	for _, name := range fields.Names() {
		message.NewStringField(m, name, fields[name])
	}
	if err = hl.writeMessage(m); err != nil {
		log.Fatalf("Error writing log message: %s", err)
	}
	return
}

// NewTextLogger creates a logger that writes human-readable log messages to
// standard error.
func NewTextLogger() *TextLogger {
	return &TextLogger{writer: os.Stderr}
}

type TextLoggerConfig struct {
	Filter int32
	Trace  bool
}

// A TextLogger writes human-readable log messages.
type TextLogger struct {
	pid      int32
	hostname string
	filter   LogLevel
	writer   io.Writer
}

func (tl *TextLogger) ConfigStruct() interface{} {
	return &TextLoggerConfig{
		Filter: 0,
		Trace:  false,
	}
}

func (tl *TextLogger) Init(app *Application, config interface{}) (err error) {
	conf := config.(*TextLoggerConfig)
	tl.pid = int32(os.Getpid())
	tl.hostname = app.Hostname()
	tl.filter = LogLevel(conf.Filter)
	return
}

func (tl *TextLogger) ShouldLog(level LogLevel) bool {
	return level <= tl.filter
}

func (tl *TextLogger) SetFilter(level LogLevel) {
	tl.filter = level
}

func (tl *TextLogger) Log(level LogLevel, messageType, payload string, fields LogFields) (err error) {
	// Return ASAP if we shouldn't be logging
	if !tl.ShouldLog(level) {
		return
	}

	reply := new(bytes.Buffer)
	fmt.Fprintf(reply, "%s [% 8s] %s %s", time.Now().Format(TextLogTime),
		level, messageType, strconv.Quote(payload))

	if len(fields) > 0 {
		reply.WriteByte(' ')
		names := fields.Names()
		for i, name := range names {
			fmt.Fprintf(reply, "%s:%s", name, fields[name])
			if i < len(names)-1 {
				reply.WriteString(", ")
			}
		}
	}

	reply.WriteByte('\n')
	_, err = reply.WriteTo(tl.writer)

	return
}

// logResponseWriter wraps an http.ResponseWriter, recording its status code,
// content length, and response time.
type logResponseWriter struct {
	http.ResponseWriter
	wroteHeader   bool
	StatusCode    int
	ContentLength int
	RespondedAt   time.Time
}

// writerOnly hides the optional ReadFrom method of an io.Writer from io.Copy.
// Taken from package net/http, copyright 2009, The Go Authors.
type writerOnly struct {
	io.Writer
}

// ReadFrom calls the ReadFrom method of the underlying ResponseWriter. Defined
// for compatibility with *response.ReadFrom from package net/http.
func (w *logResponseWriter) ReadFrom(r io.Reader) (int64, error) {
	if dest, ok := w.ResponseWriter.(io.ReaderFrom); ok {
		return dest.ReadFrom(r)
	}
	return io.Copy(writerOnly{w}, r)
}

// WriteHeader records the response time and status code, then calls the
// WriteHeader method of the underlying ResponseWriter.
func (w *logResponseWriter) WriteHeader(statusCode int) {
	if !w.wroteHeader {
		w.wroteHeader = true
		w.setStatus(statusCode)
	}
	w.ResponseWriter.WriteHeader(statusCode)
}

// setStatus records the response time and status code.
func (w *logResponseWriter) setStatus(statusCode int) {
	w.RespondedAt = time.Now()
	w.StatusCode = statusCode
}

// Write calls the Write method of the underlying ResponseWriter and records
// the number of bytes written.
func (w *logResponseWriter) Write(data []byte) (n int, err error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	n, err = w.ResponseWriter.Write(data)
	w.ContentLength += len(data)
	return
}

// Hijack calls the Hijack method of the underlying ResponseWriter, allowing a
// custom protocol handler (e.g., WebSockets) to take over the connection.
func (w *logResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	hj, ok := w.ResponseWriter.(http.Hijacker)
	if !ok {
		return nil, nil, io.EOF
	}
	if !w.wroteHeader {
		w.wroteHeader = true
		w.setStatus(http.StatusSwitchingProtocols)
	}
	return hj.Hijack()
}

// CloseNotify calls the CloseNotify method of the underlying ResponseWriter,
// or returns a nil channel if the operation is not supported.
func (w *logResponseWriter) CloseNotify() <-chan bool {
	if cn, ok := w.ResponseWriter.(http.CloseNotifier); ok {
		return cn.CloseNotify()
	}
	return nil
}

// Flush calls the Flush method of the underlying ResponseWriter, recording a
// successful response if WriteHeader was not called.
func (w *logResponseWriter) Flush() {
	if !w.wroteHeader {
		w.wroteHeader = true
		w.setStatus(http.StatusOK)
	}
	if f, ok := w.ResponseWriter.(http.Flusher); ok {
		f.Flush()
	}
}

// LogHandler logs the result of an HTTP request.
type LogHandler struct {
	http.Handler
	Log *SimpleLogger
}

// formatRequest generates a Common Log Format request line.
func (h *LogHandler) formatRequest(writer *logResponseWriter, req *http.Request, remoteAddrs []string) string {
	remoteAddr := "-"
	if len(remoteAddrs) > 0 {
		remoteAddr = remoteAddrs[0]
	}
	requestInfo := fmt.Sprintf("%s %s %s", req.Method, req.URL.Path, req.Proto)
	return fmt.Sprintf(`%s - - [%s] %s %d %d`, remoteAddr, writer.RespondedAt.Format(CommonLogTime),
		strconv.Quote(requestInfo), writer.StatusCode, writer.ContentLength)
}

// logResponse logs a response to an HTTP request.
func (h *LogHandler) logResponse(writer *logResponseWriter, req *http.Request, requestID string, receivedAt time.Time) {
	if !h.Log.ShouldLog(INFO) {
		return
	}
	forwardedFor := req.Header[http.CanonicalHeaderKey("X-Forwarded-For")]
	remoteAddrs := make([]string, len(forwardedFor)+1)
	copy(remoteAddrs, forwardedFor)
	remoteAddrs[len(remoteAddrs)-1], _, _ = net.SplitHostPort(req.RemoteAddr)
	h.Log.Info("http", h.formatRequest(writer, req, remoteAddrs), LogFields{
		"rid":                requestID,
		"agent":              req.Header.Get("User-Agent"),
		"path":               req.URL.Path,
		"method":             req.Method,
		"code":               strconv.Itoa(writer.StatusCode),
		"remoteAddressChain": fmt.Sprintf("[%s]", strings.Join(remoteAddrs, ", ")),
		"t":                  strconv.FormatInt(int64(writer.RespondedAt.Sub(receivedAt)/time.Millisecond), 10)})
}

// ServeHTTP implements http.Handler.ServeHTTP.
func (h *LogHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
	receivedAt := time.Now()

	// The `X-Request-Id` header is used by Heroku, restify, etc. to correlate
	// logs for the same request.
	requestID := req.Header.Get(HeaderID)
	if !id.Valid(requestID) {
		requestID, _ = id.Generate()
		req.Header.Set(HeaderID, requestID)
	}

	writer := &logResponseWriter{ResponseWriter: res, StatusCode: http.StatusOK}
	defer h.logResponse(writer, req, requestID, receivedAt)

	h.Handler.ServeHTTP(writer, req)
}

func init() {
	AvailableLoggers["protobuf"] = func() HasConfigStruct { return NewHekaLogger(HekaProtobuf) }
	AvailableLoggers["json"] = func() HasConfigStruct { return NewHekaLogger(HekaJSON) }
	AvailableLoggers["text"] = func() HasConfigStruct { return NewTextLogger() }
	AvailableLoggers["default"] = AvailableLoggers["text"]
}
<|endoftext|>


<commit_before>package command

import (
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

// This command encapsulates a sqlite statement.
type ExecuteCommand struct {
	Stmt string `json:"stmt"`
}

// Creates a new write command.
func NewExecuteCommand(stmt string) *ExecuteCommand {
	return &ExecuteCommand{
		Stmt: stmt,
	}
}

// The name of the command in the log.
func (c *ExecuteCommand) CommandName() string {
	return "write"
}

// Executes an sqlite statement.
func (c *ExecuteCommand) Apply(server raft.Server) (interface{}, error) {
	log.Trace("Applying ExecuteCommand: '%s'", c.Stmt)
	db := server.Context().(*db.DB)
	return nil, db.Execute(c.Stmt)
}

// This command encapsulates a set of sqlite statement, which are executed
// within a transaction.
type TransactionExecuteCommandSet struct {
	Stmts []string `json:"stmts"`
}

// Creates a new set of sqlite commands, which execute within a transaction.
func NewTransactionExecuteCommandSet(stmts []string) *TransactionExecuteCommandSet {
	return &TransactionExecuteCommandSet{
		Stmts: stmts,
	}
}

// The name of the command in the log.
func (c *TransactionExecuteCommandSet) CommandName() string {
	return "transaction_execute"
}

// Executes a set of sqlite statements, within a transaction. All statements
// will take effect, or none.
func (c *TransactionExecuteCommandSet) Apply(server raft.Server) (interface{}, error) {
	log.Trace("Applying TransactionExecuteCommandSet of size %d", len(c.Stmts))
	db := server.Context().(*db.DB)

	err := db.StartTransaction()
	if err != nil {
		log.Error("Failed to start transaction:", err.Error())
		return nil, err
	}
	for i := range c.Stmts {
		err = db.Execute(c.Stmts[i])
		if err != nil {
			log.Error("Failed to execute statement within transaction", err.Error())
			err2 := db.RollbackTransaction()
			if err2 != nil {
				log.Error("Failed to rollback transaction:", err2.Error())
			}
			return nil, err
		}
	}
	err = db.CommitTransaction()
	if err != nil {
		log.Error("Failed to commit transaction:", err.Error())
		return nil, err
	}
	return nil, nil
}
<commit_msg>Use 'defer' to rollback transactions<commit_after>package command

import (
	"github.com/otoolep/raft"
	"github.com/otoolep/rqlite/db"

	log "code.google.com/p/log4go"
)

// This command encapsulates a sqlite statement.
type ExecuteCommand struct {
	Stmt string `json:"stmt"`
}

// Creates a new write command.
func NewExecuteCommand(stmt string) *ExecuteCommand {
	return &ExecuteCommand{
		Stmt: stmt,
	}
}

// The name of the command in the log.
func (c *ExecuteCommand) CommandName() string {
	return "write"
}

// Executes an sqlite statement.
func (c *ExecuteCommand) Apply(server raft.Server) (interface{}, error) {
	log.Trace("Applying ExecuteCommand: '%s'", c.Stmt)
	db := server.Context().(*db.DB)
	return nil, db.Execute(c.Stmt)
}

// This command encapsulates a set of sqlite statement, which are executed
// within a transaction.
type TransactionExecuteCommandSet struct {
	Stmts []string `json:"stmts"`
}

// Creates a new set of sqlite commands, which execute within a transaction.
func NewTransactionExecuteCommandSet(stmts []string) *TransactionExecuteCommandSet {
	return &TransactionExecuteCommandSet{
		Stmts: stmts,
	}
}

// The name of the command in the log.
func (c *TransactionExecuteCommandSet) CommandName() string {
	return "transaction_execute"
}

// Executes a set of sqlite statements, within a transaction. All statements
// will take effect, or none.
func (c *TransactionExecuteCommandSet) Apply(server raft.Server) (interface{}, error) {
	log.Trace("Applying TransactionExecuteCommandSet of size %d", len(c.Stmts))

	commitSuccess := false
	db := server.Context().(*db.DB)
	defer func() {
		if !commitSuccess {
			err := db.RollbackTransaction()
			if err != nil {
				log.Error("Failed to rollback transaction: %s", err.Error)
			}
		}
	}()

	err := db.StartTransaction()
	if err != nil {
		log.Error("Failed to start transaction:", err.Error())
		return nil, err
	}
	for i := range c.Stmts {
		err = db.Execute(c.Stmts[i])
		if err != nil {
			log.Error("Failed to execute statement within transaction", err.Error())
			return nil, err
		}
	}
	err = db.CommitTransaction()
	if err != nil {
		log.Error("Failed to commit transaction:", err.Error())
		return nil, err
	} else {
		commitSuccess = true
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package slackboard

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type SlackboardResponse struct {
	Message string `json:"message"`
}

func sendResponse(w http.ResponseWriter, msg string, code int) {
	var (
		respBody       []byte
		respSlackboard SlackboardResponse
	)

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", fmt.Sprintf("slackboard %s", Version))

	respSlackboard.Message = msg
	respBody, err := json.Marshal(respSlackboard)
	if err != nil {
		msg := "Response-body could not be created"
		http.Error(w, msg, http.StatusInternalServerError)
		LogError.Error(msg)
		return
	}

	switch code {
	case http.StatusOK:
		fmt.Fprintf(w, string(respBody))
	default:
		http.Error(w, string(respBody), code)
		LogError.Error(msg)
	}
}
<commit_msg>Return response by Content-Type: applicatin/json.<commit_after>package slackboard

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type SlackboardResponse struct {
	Message string `json:"message"`
}

func sendResponse(w http.ResponseWriter, msg string, code int) {
	var (
		respBody       []byte
		respSlackboard SlackboardResponse
	)

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", fmt.Sprintf("slackboard %s", Version))

	respSlackboard.Message = msg
	respBody, err := json.Marshal(respSlackboard)
	if err != nil {
		msg := "Response-body could not be created"
		http.Error(w, msg, http.StatusInternalServerError)
		LogError.Error(msg)
		return
	}

	switch code {
	case http.StatusOK:
		fmt.Fprintf(w, string(respBody))
	default:
		w.WriteHeader(code)
		w.Write(respBody)
		LogError.Error(msg)
	}
}
<|endoftext|>


<commit_before><commit_msg>tests, windows: Add bridge binding test to validate IP address<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests<commit_after><|endoftext|>


<commit_before>// Copyright 2017-present The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tpl

import (
	"io"

	"text/template/parse"

	"html/template"
	texttemplate "text/template"

	bp "github.com/spf13/hugo/bufferpool"
)

var (
	_ TemplateExecutor = (*TemplateAdapter)(nil)
)

// TemplateHandler manages the collection of templates.
type TemplateHandler interface {
	TemplateFinder
	AddTemplate(name, tpl string) error
	AddLateTemplate(name, tpl string) error
	LoadTemplates(absPath, prefix string)
	PrintErrors()

	MarkReady()
	RebuildClone()
}

// TemplateFinder finds templates.
type TemplateFinder interface {
	Lookup(name string) *TemplateAdapter
}

// Template is the common interface between text/template and html/template.
type Template interface {
	Execute(wr io.Writer, data interface{}) error
	Name() string
}

// TemplateExecutor adds some extras to Template.
type TemplateExecutor interface {
	Template
	ExecuteToString(data interface{}) (string, error)
	Tree() string
}

// TemplateAdapter implements the TemplateExecutor interface.
type TemplateAdapter struct {
	Template
}

// ExecuteToString executes the current template and returns the result as a
// string.
func (t *TemplateAdapter) ExecuteToString(data interface{}) (string, error) {
	b := bp.GetBuffer()
	defer bp.PutBuffer(b)
	if err := t.Execute(b, data); err != nil {
		return "", err
	}
	return b.String(), nil
}

// Tree returns the template Parse tree as a string.
// Note: this isn't safe for parallel execution on the same template
// vs Lookup and Execute.
func (t *TemplateAdapter) Tree() string {
	var tree *parse.Tree
	switch tt := t.Template.(type) {
	case *template.Template:
		tree = tt.Tree
	case *texttemplate.Template:
		tree = tt.Tree
	default:
		panic("Unknown template")
	}

	if tree.Root == nil {
		return ""
	}
	s := tree.Root.String()

	return s
}

// TemplateTestMocker adds a way to override some template funcs during tests.
// The interface is named so it's not used in regular application code.
type TemplateTestMocker interface {
	SetFuncs(funcMap map[string]interface{})
}
<commit_msg>tpl: Fix nil pointer in Tree()<commit_after>// Copyright 2017-present The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tpl

import (
	"io"

	"text/template/parse"

	"html/template"
	texttemplate "text/template"

	bp "github.com/spf13/hugo/bufferpool"
)

var (
	_ TemplateExecutor = (*TemplateAdapter)(nil)
)

// TemplateHandler manages the collection of templates.
type TemplateHandler interface {
	TemplateFinder
	AddTemplate(name, tpl string) error
	AddLateTemplate(name, tpl string) error
	LoadTemplates(absPath, prefix string)
	PrintErrors()

	MarkReady()
	RebuildClone()
}

// TemplateFinder finds templates.
type TemplateFinder interface {
	Lookup(name string) *TemplateAdapter
}

// Template is the common interface between text/template and html/template.
type Template interface {
	Execute(wr io.Writer, data interface{}) error
	Name() string
}

// TemplateExecutor adds some extras to Template.
type TemplateExecutor interface {
	Template
	ExecuteToString(data interface{}) (string, error)
	Tree() string
}

// TemplateAdapter implements the TemplateExecutor interface.
type TemplateAdapter struct {
	Template
}

// ExecuteToString executes the current template and returns the result as a
// string.
func (t *TemplateAdapter) ExecuteToString(data interface{}) (string, error) {
	b := bp.GetBuffer()
	defer bp.PutBuffer(b)
	if err := t.Execute(b, data); err != nil {
		return "", err
	}
	return b.String(), nil
}

// Tree returns the template Parse tree as a string.
// Note: this isn't safe for parallel execution on the same template
// vs Lookup and Execute.
func (t *TemplateAdapter) Tree() string {
	var tree *parse.Tree
	switch tt := t.Template.(type) {
	case *template.Template:
		tree = tt.Tree
	case *texttemplate.Template:
		tree = tt.Tree
	default:
		panic("Unknown template")
	}

	if tree == nil || tree.Root == nil {
		return ""
	}
	s := tree.Root.String()

	return s
}

// TemplateTestMocker adds a way to override some template funcs during tests.
// The interface is named so it's not used in regular application code.
type TemplateTestMocker interface {
	SetFuncs(funcMap map[string]interface{})
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"strconv"

	"github.com/jung-kurt/gofpdf"
)

type PDFFont struct {
	Family string
	Style  string
	Size   float64
}

var (
	stanzaFont  = PDFFont{"Times", "", 18}
	chordFont   = PDFFont{"Helvetica", "B", stanzaFont.Size * 0.85}
	commentFont = PDFFont{"Times", "I", chordFont.Size}
	titleFont   = PDFFont{"Helvetica", "B", stanzaFont.Size * 1.5}
	sectionFont = commentFont
)

var stanzaIndent = stanzaFont.Size
var stanzaNumberIndent = stanzaIndent / 2.0
var chorusIndent = stanzaIndent * 2

//var echoFont = PDFFont{stanzaFont.Family, "", stanzaFont.Size} DARK GREY
//var songNumberFont = PDFFont{"Helvetica", "B", 15}
//var tocFont = PDFFont{"Times", "", 12}
//var tocSectionFont = PDFFont{"Times", "I", 12}

func WriteSongPDF(song *Song) (*bytes.Buffer, error) {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.AddPage()

	stanzaHt := pdf.PointConvert(stanzaFont.Size)
	chordHt := pdf.PointConvert(chordFont.Size)
	commentHt := pdf.PointConvert(commentFont.Size)
	titleHt := pdf.PointConvert(titleFont.Size)
	sectionHt := pdf.PointConvert(sectionFont.Size)

	tr := pdf.UnicodeTranslatorFromDescriptor("")
	_, height := pdf.GetPageSize()
	_, top, _, bot := pdf.GetMargins()

	height -= (top + bot) //Get usable height

	//Print title
	setFont(pdf, titleFont)
	pdf.WriteAligned(0, titleHt, song.Title, "C")
	pdf.Ln(titleHt)
	//Print section
	if len(song.Section) > 0 {
		setFont(pdf, sectionFont)
		pdf.WriteAligned(0, sectionHt, song.Section, "C")
		pdf.Ln(sectionHt)
	}
	println(pdf, tr, "", stanzaFont)

	var w float64
	//Print pre-song comments
	printlnSlice(
		pdf,
		tr,
		song.BeforeComments,
		commentFont)
	pdf.Ln(commentHt)

	for _, stanza := range song.Stanzas {
		if (pdf.GetY() + stanza.getHeight(pdf)) >= height {
			pdf.AddPage()
		}

		pdf.SetX(stanzaIndent)
		pdf.SetLeftMargin(stanzaIndent)

		if stanza.IsChorus {
			pdf.SetLeftMargin(chorusIndent)
			pdf.SetX(chorusIndent)
		}

		//Print pre-stanza comments
		printlnSlice(
			pdf,
			tr,
			stanza.BeforeComments,
			commentFont)

		for ind, line := range stanza.Lines {
			last_pos := 0
			last_chord_w := 0.0
			for _, chord := range line.Chords {

				//Put blank padding
				//to position chords correctly
				if chord.Position > 0 {
					setFont(pdf, stanzaFont)
					w = pdf.GetStringWidth(line.Text[last_pos:chord.Position])
					w -= last_chord_w
					pdf.Cell(w, chordHt, "")
				}

				last_chord_w, _ = print(pdf, tr, chord.Text, chordFont)
				last_pos = chord.Position
			}
			if stanza.HasChords() {
				pdf.Ln(chordHt)
			}

			setFont(pdf, stanzaFont)
			//Print stanza number on the first line
			if song.ShowStanzaNumbers &&
				ind == 0 &&
				stanza.ShowNumber &&
				!stanza.IsChorus {

				num := strconv.Itoa(stanza.Number)
				pdf.SetX(stanzaNumberIndent)
				pdf.Cell(stanzaIndent-stanzaNumberIndent, stanzaHt, tr(num))
			}

			//Do we need to print an echo portion?
			if line.HasEcho() {
				if line.EchoIndex > 0 {
					str := line.Text[0:line.EchoIndex]
					w = pdf.GetStringWidth(str)
					pdf.Cell(w, stanzaHt, tr(str))
				}

				pdf.SetTextColor(128, 128, 128)
				str := line.Text[line.EchoIndex:len(line.Text)]

				fmt.Println(str)
				w = pdf.GetStringWidth(str)
				pdf.Cell(w, stanzaHt, tr(str))
				pdf.SetTextColor(0, 0, 0)
			} else {
				w = pdf.GetStringWidth(line.Text)
				pdf.Cell(w, stanzaHt, tr(line.Text))
			}
			pdf.Ln(stanzaHt)
		}

		//print post-stanza comments
		printlnSlice(
			pdf,
			tr,
			stanza.AfterComments,
			commentFont)
		pdf.Ln(stanzaHt)
	}

	pdf.SetX(stanzaIndent)
	pdf.SetLeftMargin(stanzaIndent)

	//Print post-song comments
	printlnSlice(
		pdf,
		tr,
		song.AfterComments,
		commentFont)

	buf := new(bytes.Buffer)
	err := pdf.Output(buf)

	if err != nil {
		log.Println(err)
	}

	return buf, nil
}

func setFont(pdf *gofpdf.Fpdf, font PDFFont) {
	pdf.SetFont(font.Family, font.Style, font.Size)
}

func print(pdf *gofpdf.Fpdf, tr func(string) string, str string, font PDFFont) (width, height float64) {
	setFont(pdf, font)

	h := pdf.PointConvert(font.Size)
	w := pdf.GetStringWidth(str)
	pdf.Cell(w, h, tr(str))

	return w, h
}

func println(pdf *gofpdf.Fpdf, tr func(string) string, str string, font PDFFont) (width, height float64) {
	w, h := print(pdf, tr, str, font)
	pdf.Ln(h)
	return w, h
}

func printlnSlice(pdf *gofpdf.Fpdf, tr func(string) string, slice []string, font PDFFont) {
	for _, s := range slice {
		println(pdf, tr, s, font)
	}
}

func (song Song) getHeight(pdf *gofpdf.Fpdf) float64 {
	commentHt := pdf.PointConvert(commentFont.Size)
	stanzaHt := pdf.PointConvert(stanzaFont.Size)
	titleHt := pdf.PointConvert(titleFont.Size)
	sectionHt := pdf.PointConvert(sectionFont.Size)

	//title and section
	h := titleHt + stanzaHt
	if len(song.Section) > 0 {
		h += sectionHt
	}

	h += commentHt * (float64)(len(song.BeforeComments)+len(song.AfterComments))
	//before comments also have a blank line after
	if song.HasBeforeComments() {
		h += commentHt
	}

	for _, stanza := range song.Stanzas {
		h += stanza.getHeight(pdf)

		//blank line between stanzas
		h += stanzaHt
	}

	return h
}

func (stanza Stanza) getHeight(pdf *gofpdf.Fpdf) float64 {
	//get font heights
	commentHt := pdf.PointConvert(commentFont.Size)
	chordHt := pdf.PointConvert(chordFont.Size)
	stanzaHt := pdf.PointConvert(stanzaFont.Size)

	h := commentHt * (float64)(len(stanza.BeforeComments)+len(stanza.AfterComments))
	if stanza.HasChords() {
		h += chordHt * (float64)(len(stanza.Lines))
	}
	h += stanzaHt * (float64)(len(stanza.Lines))

	return h
}
<commit_msg>PDF output now prevents chords being placed too close<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"strconv"

	"github.com/jung-kurt/gofpdf"
)

type PDFFont struct {
	Family string
	Style  string
	Size   float64
}

var (
	stanzaFont  = PDFFont{"Times", "", 18}
	chordFont   = PDFFont{"Helvetica", "B", stanzaFont.Size * 0.85}
	commentFont = PDFFont{"Times", "I", chordFont.Size}
	titleFont   = PDFFont{"Helvetica", "B", stanzaFont.Size * 1.5}
	sectionFont = commentFont
)

var stanzaIndent = stanzaFont.Size
var stanzaNumberIndent = stanzaIndent / 2.0
var chorusIndent = stanzaIndent * 2

//var echoFont = PDFFont{stanzaFont.Family, "", stanzaFont.Size} DARK GREY
//var songNumberFont = PDFFont{"Helvetica", "B", 15}
//var tocFont = PDFFont{"Times", "", 12}
//var tocSectionFont = PDFFont{"Times", "I", 12}

func WriteSongPDF(song *Song) (*bytes.Buffer, error) {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.AddPage()

	stanzaHt := pdf.PointConvert(stanzaFont.Size)
	chordHt := pdf.PointConvert(chordFont.Size)
	commentHt := pdf.PointConvert(commentFont.Size)
	titleHt := pdf.PointConvert(titleFont.Size)
	sectionHt := pdf.PointConvert(sectionFont.Size)

	tr := pdf.UnicodeTranslatorFromDescriptor("")
	_, height := pdf.GetPageSize()
	_, top, _, bot := pdf.GetMargins()

	height -= (top + bot) //Get usable height

	//Print title
	setFont(pdf, titleFont)
	pdf.WriteAligned(0, titleHt, song.Title, "C")
	pdf.Ln(titleHt)
	//Print section
	if len(song.Section) > 0 {
		setFont(pdf, sectionFont)
		pdf.WriteAligned(0, sectionHt, song.Section, "C")
		pdf.Ln(sectionHt)
	}
	println(pdf, tr, "", stanzaFont)

	var w float64
	//Print pre-song comments
	printlnSlice(
		pdf,
		tr,
		song.BeforeComments,
		commentFont)
	pdf.Ln(commentHt)

	for _, stanza := range song.Stanzas {
		if (pdf.GetY() + stanza.getHeight(pdf)) >= height {
			pdf.AddPage()
		}

		pdf.SetX(stanzaIndent)
		pdf.SetLeftMargin(stanzaIndent)

		if stanza.IsChorus {
			pdf.SetLeftMargin(chorusIndent)
			pdf.SetX(chorusIndent)
		}

		//Print pre-stanza comments
		printlnSlice(
			pdf,
			tr,
			stanza.BeforeComments,
			commentFont)

		for ind, line := range stanza.Lines {
			last_pos := 0
			last_chord_w := 0.0
			last_chord_x := -1.0
			adjust_w := 0.0

			for _, chord := range line.Chords {

				//Put blank padding
				//to position chords correctly
				if chord.Position > 0 {
					setFont(pdf, stanzaFont)
					w = pdf.GetStringWidth(tr(line.Text[last_pos:chord.Position]))
					w -= last_chord_w
					w -= adjust_w
					pdf.Cell(w, chordHt, "")
				}

				if last_chord_x+last_chord_w > pdf.GetX() {
					setFont(pdf, stanzaFont)
					w = (last_chord_x + pdf.GetStringWidth("-")) - pdf.GetX()
					adjust_w += w

					pdf.Cell(w, chordHt, "")
				}

				last_chord_w, _ = print(pdf, tr, chord.Text, chordFont)
				last_pos = chord.Position
				last_chord_x = pdf.GetX()
			}
			if stanza.HasChords() {
				pdf.Ln(chordHt)
			}

			setFont(pdf, stanzaFont)
			//Print stanza number on the first line
			if song.ShowStanzaNumbers &&
				ind == 0 &&
				stanza.ShowNumber &&
				!stanza.IsChorus {

				num := strconv.Itoa(stanza.Number)
				pdf.SetX(stanzaNumberIndent)
				pdf.Cell(stanzaIndent-stanzaNumberIndent, stanzaHt, tr(num))
			}

			//Do we need to print an echo portion?
			if line.HasEcho() {
				if line.EchoIndex > 0 {
					str := line.Text[0:line.EchoIndex]
					w = pdf.GetStringWidth(str)
					pdf.Cell(w, stanzaHt, tr(str))
				}

				pdf.SetTextColor(128, 128, 128)
				str := line.Text[line.EchoIndex:len(line.Text)]

				fmt.Println(str)
				w = pdf.GetStringWidth(str)
				pdf.Cell(w, stanzaHt, tr(str))
				pdf.SetTextColor(0, 0, 0)
			} else {
				w = pdf.GetStringWidth(line.Text)
				pdf.Cell(w, stanzaHt, tr(line.Text))
			}
			pdf.Ln(stanzaHt)
		}

		//print post-stanza comments
		printlnSlice(
			pdf,
			tr,
			stanza.AfterComments,
			commentFont)
		pdf.Ln(stanzaHt)
	}

	pdf.SetX(stanzaIndent)
	pdf.SetLeftMargin(stanzaIndent)

	//Print post-song comments
	printlnSlice(
		pdf,
		tr,
		song.AfterComments,
		commentFont)

	buf := new(bytes.Buffer)
	err := pdf.Output(buf)

	if err != nil {
		log.Println(err)
	}

	return buf, nil
}

func setFont(pdf *gofpdf.Fpdf, font PDFFont) {
	pdf.SetFont(font.Family, font.Style, font.Size)
}

func print(pdf *gofpdf.Fpdf, tr func(string) string, str string, font PDFFont) (width, height float64) {
	setFont(pdf, font)

	h := pdf.PointConvert(font.Size)
	w := pdf.GetStringWidth(str)
	pdf.Cell(w, h, tr(str))

	return w, h
}

func println(pdf *gofpdf.Fpdf, tr func(string) string, str string, font PDFFont) (width, height float64) {
	w, h := print(pdf, tr, str, font)
	pdf.Ln(h)
	return w, h
}

func printlnSlice(pdf *gofpdf.Fpdf, tr func(string) string, slice []string, font PDFFont) {
	for _, s := range slice {
		println(pdf, tr, s, font)
	}
}

func (song Song) getHeight(pdf *gofpdf.Fpdf) float64 {
	commentHt := pdf.PointConvert(commentFont.Size)
	stanzaHt := pdf.PointConvert(stanzaFont.Size)
	titleHt := pdf.PointConvert(titleFont.Size)
	sectionHt := pdf.PointConvert(sectionFont.Size)

	//title and section
	h := titleHt + stanzaHt
	if len(song.Section) > 0 {
		h += sectionHt
	}

	h += commentHt * (float64)(len(song.BeforeComments)+len(song.AfterComments))
	//before comments also have a blank line after
	if song.HasBeforeComments() {
		h += commentHt
	}

	for _, stanza := range song.Stanzas {
		h += stanza.getHeight(pdf)

		//blank line between stanzas
		h += stanzaHt
	}

	return h
}

func (stanza Stanza) getHeight(pdf *gofpdf.Fpdf) float64 {
	//get font heights
	commentHt := pdf.PointConvert(commentFont.Size)
	chordHt := pdf.PointConvert(chordFont.Size)
	stanzaHt := pdf.PointConvert(stanzaFont.Size)

	h := commentHt * (float64)(len(stanza.BeforeComments)+len(stanza.AfterComments))
	if stanza.HasChords() {
		h += chordHt * (float64)(len(stanza.Lines))
	}
	h += stanzaHt * (float64)(len(stanza.Lines))

	return h
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
)

func main() {
	go dispLower()
	go dispUpper()

	// goroutines exit when main() ends
	// so, delay end of main()
	time.Sleep(500 * time.Millisecond)
	fmt.Println()

	// POSSIBLE OUTPUT (unpredictable):
	// abcAdefghiBjCklmDnEoFpGqHrIstJuKvwLxMyNzOPQRSTUVWXYZ

	// POSSIBLE OUTPUT (unpredictable):
	// aAbcBdCeDfEgFhGHiIjJkKlLmMnNoOPpQqRrSsTtUuVvWwXYxZyz

	// POSSIBLE OUTPUT (unpredictable):
	// abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

}

func dispLower() {
	s := "abcdefghijklmnopqrstuvwxyz"
	for i := 0; i < len(s); i++ {
		fmt.Print(string(s[i]))
	}
}

func dispUpper() {
	s := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	for i := 0; i < len(s); i++ {
		fmt.Print(string(s[i]))
	}
}
<commit_msg>Update lang/concurrency/goroutine.go: add message channel to prevent ending main() prematurely<commit_after>package main

import "fmt"

func main() {

	messages := make(chan string)
	go disp("abcdefghijklmnopqrstuvwxyz", messages, "disp-0-done")
	go disp("ABCDEFGHIJKLMNOPQRSTUVWXYZ", messages, "disp-1-done")
	numTasks := 2

	out := ""
	for i := 0; i < numTasks; i++ {
		out += "\n[" + <-messages + "]"
	}
	fmt.Println(out)

	// POSSIBLE OUTPUT (unpredictable):
	// AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtuUvVwWxXyYzZ
	// [disp-0-done]
	// [disp-1-done]

	// POSSIBLE OUTPUT (unpredictable):
	// ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
	// [disp-1-done]
	// [disp-0-done]
}

func disp(s string, messages chan string, doneMsg string) {
	for i := 0; i < len(s); i++ {
		fmt.Print(string(s[i]))
	}
	messages <- doneMsg
}
<|endoftext|>


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

package sqlgen

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

func Select(obj interface{}, fields ...string) (string, error) {
	var sql string

	t, err := checkType(obj)
	if err != nil {
		return "", err
	}

	if len(fields) == 0 {
		fields = fieldNames(t)
	}

	sql = fmt.Sprintf("select %s from %s", strings.Join(fields, ", "), t.Name())
	return strings.ToLower(sql), nil
}

func Insert(obj interface{}) string {
	t := reflect.TypeOf(obj).Elem()
	fieldNames := fieldNames(t)

	qm := make([]string, len(fieldNames))
	for i := 0; i < len(qm); i++ {
		qm[i] = "?"
	}

	sql := fmt.Sprintf("insert into %s (%s) values (%s)", t.Name(), strings.Join(fieldNames, ", "), strings.Join(qm, ", "))
	return strings.ToLower(sql)
}

func Delete(obj interface{}, filters []string) string {
	t := reflect.TypeOf(obj).Elem()

	filter_array := preparedFields(filters)
	filter_sql := strings.Join(filter_array, " and ")

	sql := fmt.Sprintf("delete from %s where ", t.Name())
	sql = strings.ToLower(sql)
	sql = sql + filter_sql
	return sql
}

// obj is the struct to be updated in the database
// uFields are the fields that are gonna be update
// fFields are the fields that are gonna be used as filter
// to the where clause
func Update(obj interface{}, uFields, fFields []string) string {
	t := reflect.TypeOf(obj).Elem()

	fieldsAndValues := preparedFields(uFields)
	filters := preparedFields(fFields)

	sql := fmt.Sprintf("update %s set %s where %s", strings.ToLower(t.Name()), strings.Join(fieldsAndValues, ", "), strings.Join(filters, " and "))

	return sql
}

func checkType(obj interface{}) (reflect.Type, error) {
	t := reflect.TypeOf(obj)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if t.Kind() == reflect.Struct {
		return t, nil
	}
	return nil, errors.New("Error generating SQL, you must provide a struct value or pointer")
}

func fieldNames(t reflect.Type) []string {
	fieldNames := make([]string, t.NumField())

	for i := 0; i < t.NumField(); i++ {
		fieldNames[i] = t.Field(i).Name
	}

	return fieldNames
}

// preparedFields receives a slice of fields an returns a slice with fields in the
// form of field=? that represents a placeholder to be replace for a value
func preparedFields(fields []string) []string {
	preparedFields := make([]string, len(fields))

	for i, v := range fields {
		preparedFields[i] = fmt.Sprintf(`%s=?`, strings.ToLower(v))
	}

	return preparedFields
}
<commit_msg>sqlgen: added docs for Select<commit_after>// Copyright 2012 Cobrateam members. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sqlgen

import (
	"errors"
	"fmt"
	"reflect"
	"strings"
)

// Select generates a SELECT statement, selecting only "fields" from
// the table given by the name of the struct "obj" lowercased. If the type
// of obj is not a struct, the method returns an empty string and an error.
// Otherwise it returns the SQL instruction and a nil error.
func Select(obj interface{}, fields ...string) (string, error) {
	var sql string

	t, err := checkType(obj)
	if err != nil {
		return "", err
	}

	if len(fields) == 0 {
		fields = fieldNames(t)
	}

	sql = fmt.Sprintf("select %s from %s", strings.Join(fields, ", "), t.Name())
	return strings.ToLower(sql), nil
}

func Insert(obj interface{}) string {
	t := reflect.TypeOf(obj).Elem()
	fieldNames := fieldNames(t)

	qm := make([]string, len(fieldNames))
	for i := 0; i < len(qm); i++ {
		qm[i] = "?"
	}

	sql := fmt.Sprintf("insert into %s (%s) values (%s)", t.Name(), strings.Join(fieldNames, ", "), strings.Join(qm, ", "))
	return strings.ToLower(sql)
}

func Delete(obj interface{}, filters []string) string {
	t := reflect.TypeOf(obj).Elem()

	filter_array := preparedFields(filters)
	filter_sql := strings.Join(filter_array, " and ")

	sql := fmt.Sprintf("delete from %s where ", t.Name())
	sql = strings.ToLower(sql)
	sql = sql + filter_sql
	return sql
}

// obj is the struct to be updated in the database
// uFields are the fields that are gonna be update
// fFields are the fields that are gonna be used as filter
// to the where clause
func Update(obj interface{}, uFields, fFields []string) string {
	t := reflect.TypeOf(obj).Elem()

	fieldsAndValues := preparedFields(uFields)
	filters := preparedFields(fFields)

	sql := fmt.Sprintf("update %s set %s where %s", strings.ToLower(t.Name()), strings.Join(fieldsAndValues, ", "), strings.Join(filters, " and "))

	return sql
}

func checkType(obj interface{}) (reflect.Type, error) {
	t := reflect.TypeOf(obj)
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	if t.Kind() == reflect.Struct {
		return t, nil
	}
	return nil, errors.New("Error generating SQL, you must provide a struct value or pointer")
}

func fieldNames(t reflect.Type) []string {
	fieldNames := make([]string, t.NumField())

	for i := 0; i < t.NumField(); i++ {
		fieldNames[i] = t.Field(i).Name
	}

	return fieldNames
}

// preparedFields receives a slice of fields an returns a slice with fields in the
// form of field=? that represents a placeholder to be replace for a value
func preparedFields(fields []string) []string {
	preparedFields := make([]string, len(fields))

	for i, v := range fields {
		preparedFields[i] = fmt.Sprintf(`%s=?`, strings.ToLower(v))
	}

	return preparedFields
}
<|endoftext|>


<commit_before>package main

import "flag"
import "fmt"
import "os"
import "os/exec"
import "strconv"
import "time"

const DEFAULT_SOUND = "/usr/share/sounds/freedesktop/stereo/complete.oga"

func main() {
    path := flag.String("plik", DEFAULT_SOUND, "ścieżka do pliku z ding")
    flag.Parse()
    args := flag.Args()

    fmt.Println(args)

    cmd := exec.Command("paplay", *path)
    cmd.Start()

    var interval int

    if len(args) >= 1 {
        tmp, err := strconv.Atoi(args[0])
        if err != nil{
            fmt.Println("Podaj prawidłowy argument (liczba)!")
            os.Exit(1)
        }
        interval = tmp
    } else {
        fmt.Println("Podaj prawidłową częstotliwość ding!")
        os.Exit(1)
    }

    counter := 1
    for true {
        fmt.Println("Ding!", counter)
        // check if file exists at given path
        if _, err := os.Stat(*path); err == nil {
            cmd := exec.Command("paplay", *path)
            cmd.Start()
        } else {
            fmt.Println("Nie znaleziono takiego pliku z Ding!")
            os.Exit(1)
        }
        time.Sleep(time.Second * time.Duration(interval))
        counter++
    }
}
<commit_msg>#1: handle errors thrown by sound player<commit_after>package main

import "flag"
import "fmt"
import "os"
import "os/exec"
import "strconv"
import "time"

const DEFAULT_SOUND = "/usr/share/sounds/freedesktop/stereo/complete.oga"

func main() {
    path := flag.String("plik", DEFAULT_SOUND, "ścieżka do pliku z ding")
    flag.Parse()
    args := flag.Args()

    var interval int

    if len(args) >= 1 {
        tmp, err := strconv.Atoi(args[0])
        if err != nil{
            fmt.Println("Podaj prawidłowy argument (liczba)!")
            os.Exit(1)
        }
        interval = tmp
    } else {
        fmt.Println("Podaj prawidłową częstotliwość ding!")
        os.Exit(1)
    }

    counter := 1
    for true {
        fmt.Println("Ding!", counter)
        // check if file exists at given path
        if _, err := os.Stat(*path); err == nil {
            cmd := exec.Command("paplay", *path)
            err := cmd.Run()
            if err != nil {
                fmt.Println("Błąd odtwarzania!:\n" + err.Error())
                os.Exit(1)
            }
        } else {
            fmt.Println("Nie znaleziono takiego pliku z Ding!")
            os.Exit(1)
        }
        time.Sleep(time.Second * time.Duration(interval))
        counter++
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 Yuichi Araki. 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"
    "fmt"
    "os"
    "yall"
)

func prompt() {
    fmt.Print("yall> ")
}

func repl() {
    env := yall.NewEnv()
    for {
        prompt()
        reader := bufio.NewReader(os.Stdin)
        line, _, err := reader.ReadLine()
        if nil != err {
            return
        }
        func() {
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            if result := env.EvalString(string(line)); result != nil {
                fmt.Println(result.String())
            }
        }()
    }
    fmt.Println()
}

func main() {
    repl()
}
<commit_msg>Run script mode by command line arguments.<commit_after>// Copyright 2012 Yuichi Araki. 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"
    "flag"
    "fmt"
    "os"
    "yall"
)

func prompt() {
    fmt.Print("yall> ")
}

func repl() {
    env := yall.NewEnv()
    for {
        prompt()
        reader := bufio.NewReader(os.Stdin)
        line, _, err := reader.ReadLine()
        if nil != err {
            return
        }
        func() {
            defer func() {
                if r := recover(); r != nil {
                    fmt.Println(r)
                }
            }()
            if result := env.EvalString(string(line)); result != nil {
                fmt.Println(result.String())
            }
        }()
    }
    fmt.Println()
}

func loadFiles() {
    env := yall.NewEnv()
    for i := 0; i < flag.NArg(); i++ {
        file, err := os.Open(flag.Arg(i))
        if file == nil {
            fmt.Fprintf(os.Stderr, "Can't open %s: error %s\n",
                flag.Arg(i), err)
            os.Exit(1)
        }
        env.Load(file)
        file.Close()
    }
}

func main() {
    flag.Parse()
    if flag.NArg() == 0 {
        repl()
    } else {
        loadFiles()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strings"

	keys "github.com/coreos/update-ssh-keys/authorized_keys_d"
)

var (
	flagUser     = flag.String("u", "core", "Update the given user's authorized_keys file.")
	flagAdd      = flag.String("a", "", "Add the given keys, using the given name to identify them.")
	flagAddForce = flag.String("A", "", "Add the given keys, even if it was disabled with '-D'.")
	flagDelete   = flag.String("d", "", "Delete keys identified by the given name.")
	flagDisable  = flag.String("D", "", "Disable the given set from being added with '-a'.")
	flagList     = flag.Bool("l", false, "List the names and number of keys currently installed.")
	flagReplace  = flag.Bool("n", true, "When adding, don't replace an existing key with the given name.")
	flagHelp     = flag.Bool("h", false, "This ;-)")
)

func stderr(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stderr, strings.TrimSuffix(out, "\n"))
}

func stdout(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stdout, strings.TrimSuffix(out, "\n"))
}

// printKeys prints all the keys currently managed.
func printKeys(akd *keys.SSHAuthorizedKeysDir) error {
	stdout("All keys for %s", *flagUser)
	return akd.WalkKeys(func(k *keys.SSHAuthorizedKey) error {
		if !k.Disabled {
			cmd := exec.Command("ssh-keygen", "-l", "-f", k.Path)
			out, err := cmd.CombinedOutput()
			if err != nil {
				return err
			}
			stdout("%s: %s", k.Name, string(out))
		}
		return nil
	})
}

// addKeys adds keys to akd as name.
func addKeys(akd *keys.SSHAuthorizedKeysDir, name string, force bool) error {
	k := []byte{}
	files := []*os.File{}

	if flag.NArg() > 0 {
		// read from files
		for _, fp := range flag.Args() {
			f, err := os.Open(fp)
			if err != nil {
				return err
			}
			defer f.Close()
			files = append(files, f)
		}
	} else {
		// read from stdin
		files = append(files, os.Stdin)
	}

	for _, f := range files {
		b, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		k = append(k, b...)
	}

	// TODO(vc): akd.Add() treats keys as opaque objects, so we need to
	// sanity check them ourselves before adding them.
	// update-ssh-keys employs ssh-keygen -l -f for this purpose, can do
	// same here.
	return akd.Add(name, k, *flagReplace, force)
}

func main() {
	flag.Parse()

	if *flagHelp {
		flag.Usage()
		os.Exit(1)
	}

	usr, err := user.Lookup(*flagUser)
	if err != nil {
		stderr("Failed to lookup user: %v", *flagUser)
		os.Exit(2)
	}

	akd, err := keys.Open(usr, true)
	if err != nil {
		stderr("Failed to open: %v", err)
		os.Exit(3)
	}
	defer akd.Close()

	switch {
	case *flagList:
		if err := printKeys(akd); err != nil {
			stderr("Failed to print keys: %v", err)
			os.Exit(4)
		}
	case *flagAdd != "":
		if err := addKeys(akd, *flagAdd, false); err != nil {
			stderr("failed to add keys %q: %v", *flagAdd, err)
			os.Exit(5)
		}
	case *flagAddForce != "":
		if err := addKeys(akd, *flagAddForce, true); err != nil {
			stderr("failed to add keys %q: %v", *flagAddForce, err)
			os.Exit(6)
		}
	case *flagDelete != "":
		if err := akd.Remove(*flagDelete); err != nil {
			stderr("failed to delete key %q: %v", *flagDelete, err)
			os.Exit(7)
		}
	case *flagDisable != "":
		if err := akd.Disable(*flagDisable); err != nil {
			stderr("failed to disable key %q: %v", *flagDisable, err)
			os.Exit(8)
		}
	}

	if err := akd.Sync(); err != nil {
		stderr("Failed sync: %v", err)
		os.Exit(9)
	}
	stdout("Updated %s", usr.Name) // TODO(vc): get the authorized_keys path from akd

	os.Exit(0)
}
<commit_msg>update-ssh-keys: print backing file path on SSHAuthorizedKeysDir.Sync().<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"strings"

	keys "github.com/coreos/update-ssh-keys/authorized_keys_d"
)

var (
	flagUser     = flag.String("u", "core", "Update the given user's authorized_keys file.")
	flagAdd      = flag.String("a", "", "Add the given keys, using the given name to identify them.")
	flagAddForce = flag.String("A", "", "Add the given keys, even if it was disabled with '-D'.")
	flagDelete   = flag.String("d", "", "Delete keys identified by the given name.")
	flagDisable  = flag.String("D", "", "Disable the given set from being added with '-a'.")
	flagList     = flag.Bool("l", false, "List the names and number of keys currently installed.")
	flagReplace  = flag.Bool("n", true, "When adding, don't replace an existing key with the given name.")
	flagHelp     = flag.Bool("h", false, "This ;-)")
)

func stderr(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stderr, strings.TrimSuffix(out, "\n"))
}

func stdout(f string, a ...interface{}) {
	out := fmt.Sprintf(f, a...)
	fmt.Fprintln(os.Stdout, strings.TrimSuffix(out, "\n"))
}

// printKeys prints all the keys currently managed.
func printKeys(akd *keys.SSHAuthorizedKeysDir) error {
	stdout("All keys for %s", *flagUser)
	return akd.WalkKeys(func(k *keys.SSHAuthorizedKey) error {
		if !k.Disabled {
			cmd := exec.Command("ssh-keygen", "-l", "-f", k.Path)
			out, err := cmd.CombinedOutput()
			if err != nil {
				return err
			}
			stdout("%s: %s", k.Name, string(out))
		}
		return nil
	})
}

// addKeys adds keys to akd as name.
func addKeys(akd *keys.SSHAuthorizedKeysDir, name string, force bool) error {
	k := []byte{}
	files := []*os.File{}

	if flag.NArg() > 0 {
		// read from files
		for _, fp := range flag.Args() {
			f, err := os.Open(fp)
			if err != nil {
				return err
			}
			defer f.Close()
			files = append(files, f)
		}
	} else {
		// read from stdin
		files = append(files, os.Stdin)
	}

	for _, f := range files {
		b, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		k = append(k, b...)
	}

	// TODO(vc): akd.Add() treats keys as opaque objects, so we need to
	// sanity check them ourselves before adding them.
	// update-ssh-keys employs ssh-keygen -l -f for this purpose, can do
	// same here.
	return akd.Add(name, k, *flagReplace, force)
}

func main() {
	flag.Parse()

	if *flagHelp {
		flag.Usage()
		os.Exit(1)
	}

	usr, err := user.Lookup(*flagUser)
	if err != nil {
		stderr("Failed to lookup user: %v", *flagUser)
		os.Exit(2)
	}

	akd, err := keys.Open(usr, true)
	if err != nil {
		stderr("Failed to open: %v", err)
		os.Exit(3)
	}
	defer akd.Close()

	switch {
	case *flagList:
		if err := printKeys(akd); err != nil {
			stderr("Failed to print keys: %v", err)
			os.Exit(4)
		}
	case *flagAdd != "":
		if err := addKeys(akd, *flagAdd, false); err != nil {
			stderr("failed to add keys %q: %v", *flagAdd, err)
			os.Exit(5)
		}
	case *flagAddForce != "":
		if err := addKeys(akd, *flagAddForce, true); err != nil {
			stderr("failed to add keys %q: %v", *flagAddForce, err)
			os.Exit(6)
		}
	case *flagDelete != "":
		if err := akd.Remove(*flagDelete); err != nil {
			stderr("failed to delete key %q: %v", *flagDelete, err)
			os.Exit(7)
		}
	case *flagDisable != "":
		if err := akd.Disable(*flagDisable); err != nil {
			stderr("failed to disable key %q: %v", *flagDisable, err)
			os.Exit(8)
		}
	}

	if err := akd.Sync(); err != nil {
		stderr("Failed sync: %v", err)
		os.Exit(9)
	}
	stdout("Updated %s", akd.KeysFilePath())

	os.Exit(0)
}
<|endoftext|>


<commit_before>// leisp
// Copyright 2016 Zongmin Lei <leizongmin@gmail.com>. All rights reserved.
// Under the MIT License

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"leisp/interpreter"
	"os"
	"strings"

	"github.com/peterh/liner"
)

func makeIndentString(n int) string {
	s := ""
	for i := 0; i < n; i++ {
		s += "  "
	}
	return s
}

func printWelcome() {
	fmt.Println(`
##       ######## ####  ######  ########
##       ##        ##  ##    ## ##     ##
##       ##        ##  ##       ##     ##
##       ######    ##   ######  ########
##       ##        ##        ## ##
##       ##        ##  ##    ## ##
######## ######## ####  ######  ##

Welcome to leisp 0.0.1

Copyright (c) 2016 Zongmin Lei <http://ucdok.com>

Type (help) and hit Enter for context help.
Press Ctrl+C to Exit.
	`)
}

func printUsage() {

	fmt.Printf("%s\n", `
Usage: leisp [options] [<file1> <file2> ...]

Options:
	`)

	flag.PrintDefaults()
	os.Exit(0)

}

func main() {

	flag.Usage = printUsage
	flag.Parse()

	printWelcome()

	files := flag.Args()
	for _, f := range files {
		content, err := ioutil.ReadFile(f)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		r := interpreter.Eval(nil, string(content))
		if r.IsError() {
			fmt.Println(r.ToString())
			os.Exit(2)
		}
	}

	startREPL()
}

func createLiner() *liner.State {

	rl := liner.NewLiner()
	rl.SetCtrlCAborts(true)
	rl.SetMultiLineMode(true)

	rl.SetTabCompletionStyle(liner.TabCircular)
	rl.SetWordCompleter(func(line string, pos int) (head string, completions []string, tail string) {
		if pos == 0 {
			head, tail = "(", ")"
			completions = []string{""}
		} else {
			// fmt.Println("")
			// str := line[pos:]
			// fmt.Println(str)
			// for _, n := range interpreter.Scope.Keys() {
			// 	fmt.Print(n, "\t")
			// 	if strings.Index(n, str) == 0 {
			// 		completions = append(completions, n)
			// 	}
			// }
			// fmt.Println("")
		}
		return head, completions, tail
	})

	return rl
}

func startREPL() {

	rl := createLiner()

	brackets := make([]rune, 0)
	isString := false
	buffer := ""

	for {

		prompt := "leisp> "
		if len(brackets) > 0 {
			prompt = "       " + makeIndentString(len(brackets))
		}

		line, err := rl.Prompt(prompt)
		if err != nil {
			if err.Error() == "prompt aborted" {
				break
			}
			fmt.Println(err)
			break
		}

		if line == "" {
			continue
		}

		isEscape := false
		for _, r2 := range line {
			if isString {
				if isEscape {
					isEscape = false
				} else {
					if r2 == '\\' {
						isEscape = true
					} else if r2 == '"' {
						isString = false
					}
				}
			} else {
				if r2 == '{' || r2 == '[' || r2 == '(' {
					brackets = append(brackets, r2)
				} else if r2 == '}' || r2 == ']' || r2 == ')' {
					r := brackets[len(brackets)-1]
					if r == '{' && r2 == '}' {
						brackets = brackets[:len(brackets)-1]
					} else if r == '[' && r2 == ']' {
						brackets = brackets[:len(brackets)-1]
					} else if r == '(' && r2 == ')' {
						brackets = brackets[:len(brackets)-1]
					} else {
						fmt.Printf("Error: %s does not matched %s\n", string(r), string(r2))
					}
				} else if r2 == '"' {
					isString = true
				}
			}
		}

		buffer = strings.TrimSpace(buffer + line + " ")
		if len(brackets) == 0 && !isString {

			a := interpreter.Eval(nil, buffer)
			a.Print()

			rl.AppendHistory(buffer)
			buffer = ""
		}

	}

	rl.Close()
}
<commit_msg>REPL history<commit_after>// leisp
// Copyright 2016 Zongmin Lei <leizongmin@gmail.com>. All rights reserved.
// Under the MIT License

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"leisp/interpreter"
	"os"
	"path/filepath"
	"strings"

	"github.com/peterh/liner"
)

func makeIndentString(n int) string {
	s := ""
	for i := 0; i < n; i++ {
		s += "  "
	}
	return s
}

func printWelcome() {
	fmt.Println(`
##       ######## ####  ######  ########
##       ##        ##  ##    ## ##     ##
##       ##        ##  ##       ##     ##
##       ######    ##   ######  ########
##       ##        ##        ## ##
##       ##        ##  ##    ## ##
######## ######## ####  ######  ##

Welcome to leisp 0.0.1

Copyright (c) 2016 Zongmin Lei <http://ucdok.com>

Type (help) and hit Enter for context help.
Press Ctrl+C to Exit.
	`)
}

func printUsage() {

	fmt.Printf("%s\n", `
Usage: leisp [options] [<file1> <file2> ...]

Options:
	`)

	flag.PrintDefaults()
	os.Exit(0)

}

func main() {

	flag.Usage = printUsage
	flag.Parse()

	printWelcome()

	files := flag.Args()
	for _, f := range files {
		content, err := ioutil.ReadFile(f)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		r := interpreter.Eval(nil, string(content))
		if r.IsError() {
			fmt.Println(r.ToString())
			os.Exit(2)
		}
	}

	startREPL()
}

func createLiner() *liner.State {

	rl := liner.NewLiner()
	rl.SetCtrlCAborts(true)
	rl.SetMultiLineMode(true)

	rl.SetTabCompletionStyle(liner.TabCircular)
	rl.SetWordCompleter(func(line string, pos int) (head string, completions []string, tail string) {

		if line == "" {
			head, tail = "(", ")"
			completions = []string{""}
		} else {
			head = line[0:pos] + " "
			tail = line[pos:]
			completions = []string{"()", "'", "{}", "[]", ""}
		}
		return head, completions, tail
	})

	return rl
}

func startREPL() {

	rl := createLiner()

	historyFileName := filepath.Join(os.TempDir(), ".leisp_history")
	historyFile, err := os.OpenFile(historyFileName, os.O_CREATE|os.O_RDWR, 0644)
	fmt.Println(historyFileName)
	if err != nil {
		fmt.Printf("Warning: cannot open history file: %s\n", err)
	} else {
		if _, err := rl.ReadHistory(historyFile); err != nil {
			fmt.Printf("Warning: cannot open history file: %s\n", err)
		}
	}

	brackets := make([]rune, 0)
	isString := false
	buffer := ""

	for {

		prompt := "leisp> "
		if len(brackets) > 0 {
			prompt = "       " + makeIndentString(len(brackets))
		}

		line, err := rl.Prompt(prompt)
		if err != nil {
			if err.Error() == "prompt aborted" {
				break
			}
			fmt.Println(err)
			break
		}

		if line == "" {
			continue
		}

		isEscape := false
		for _, r2 := range line {
			if isString {
				if isEscape {
					isEscape = false
				} else {
					if r2 == '\\' {
						isEscape = true
					} else if r2 == '"' {
						isString = false
					}
				}
			} else {
				if r2 == '{' || r2 == '[' || r2 == '(' {
					brackets = append(brackets, r2)
				} else if r2 == '}' || r2 == ']' || r2 == ')' {
					r := brackets[len(brackets)-1]
					if r == '{' && r2 == '}' {
						brackets = brackets[:len(brackets)-1]
					} else if r == '[' && r2 == ']' {
						brackets = brackets[:len(brackets)-1]
					} else if r == '(' && r2 == ')' {
						brackets = brackets[:len(brackets)-1]
					} else {
						fmt.Printf("Error: %s does not matched %s\n", string(r), string(r2))
					}
				} else if r2 == '"' {
					isString = true
				}
			}
		}

		buffer = strings.TrimSpace(buffer + line + " ")
		if len(brackets) == 0 && !isString {

			a := interpreter.Eval(nil, buffer)
			a.Print()

			rl.AppendHistory(buffer)
			rl.WriteHistory(historyFile)

			buffer = ""
		}

	}

	rl.Close()
}
<|endoftext|>


<commit_before>package types

import (
	"fmt"
)

type Result struct {
	Code CodeType
	Data []byte
	Log  string // Can be non-deterministic
}

func NewResult(code CodeType, data []byte, log string) Result {
	return Result{
		Code: code,
		Data: data,
		Log:  log,
	}
}

func (res Result) IsOK() bool {
	return res.Code == CodeType_OK
}

func (res Result) Error() string {
	return fmt.Sprintf("TMSP error code:%v, data:%X, log:%v", res.Code, res.Data, res.Log)
}

//----------------------------------------

func NewResultOK(data []byte, log string) Result {
	return Result{
		Code: CodeType_OK,
		Data: data,
		Log:  log,
	}
}
<commit_msg>Add NewError -> Result with no data<commit_after>package types

import (
	"fmt"
)

type Result struct {
	Code CodeType
	Data []byte
	Log  string // Can be non-deterministic
}

func NewResult(code CodeType, data []byte, log string) Result {
	return Result{
		Code: code,
		Data: data,
		Log:  log,
	}
}

func (res Result) IsOK() bool {
	return res.Code == CodeType_OK
}

func (res Result) Error() string {
	return fmt.Sprintf("TMSP error code:%v, data:%X, log:%v", res.Code, res.Data, res.Log)
}

//----------------------------------------

func NewResultOK(data []byte, log string) Result {
	return Result{
		Code: CodeType_OK,
		Data: data,
		Log:  log,
	}
}

func NewError(code CodeType, log string) Result {
	return Result{
		Code: code,
		Log:  log,
	}
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "os"
  "os/exec"
  "syscall"
  "io/ioutil"
  "path/filepath"
  "strings"
  "sort"
  "encoding/json"
  "github.com/Masterminds/semver"
)

import . "github.com/tj/go-debug"

var debug = Debug("nodist:shim")

const pathSep = string(os.PathSeparator)

func main() {
  // Prerequisites

  if "" == os.Getenv("NODIST_PREFIX") {
    fmt.Println("Please set the path to the nodist directory in the NODIST_PREFIX environment variable.")
    os.Exit(40)
  }

  // Determine version spec

  var spec string = ""
  if v := os.Getenv("NODE_VERSION"); v != "" {
    spec = v
    debug("NODE_VERSION found:'%s'", spec)
  } else
  if v = os.Getenv("NODIST_VERSION"); v != "" {
    spec = v
    debug("NODIST_VERSION found:'%s'", spec)
  } else
  if v, err := getTargetEngine(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = v
    debug("Target engine found:'%s'", spec)
  } else
  if v, localFile, err := getLocalVersion(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = string(v)
    debug("Local file found:'%s' @ %s", spec, localFile)
  } else
  if v, err := ioutil.ReadFile(os.Getenv("NODIST_PREFIX")+"\\.node-version"); err == nil {
    spec = string(v)
    debug("Global file found: '%s'", spec)
  }

  spec = strings.Trim(spec, "v \r\n")

  if spec == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Please set a version.")
    os.Exit(41)
  }

  constraint, err := semver.NewConstraint(spec)

  if err != nil {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Malformatted version spec ", spec, " . Please set a new version.")
    os.Exit(43)
  }

  // Find an installed version matching the spec...

  installed, err := getInstalledVersions()

  if err != nil {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't list installed versions.")
    os.Exit(44)
  }

  version := ""

  for _, v := range installed {
    if constraint.Check(v) {
      version = v.String()
      break
    }
  }

  if version == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't find an installed version that matches version spec ", spec)
    os.Exit(45)
  }

  // Determine architecture

  x64 := false

  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }

  // Set up binary path

  var path string
  var nodebin string

  path = os.Getenv("NODIST_PREFIX")+"/v"

  if x64 {
    path += "-x64"
  }

  path = path+"/"+version
  nodebin = path+"/node.exe"

  // Run node!

  cmd := exec.Command(nodebin, os.Args[1:]...)
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  cmd.Stdin = os.Stdin
  err = cmd.Run()

  if err != nil {
    exitError, isExitError := err.(*(exec.ExitError))
    if isExitError {
      // You know it. Black Magic...
      os.Exit(exitError.Sys().(syscall.WaitStatus).ExitStatus())
    } else {
      fmt.Println("Sorry, there's a problem with nodist.")
      fmt.Println("Error: ", err)
      os.Exit(42)
    }
  }
}

func getLocalVersion() (version string, file string, returnedError error) {
  var dir string
  var err error
  if len(os.Args) < 2 {
    dir, err = os.Getwd()
    if err != nil {
      returnedError = err
      return
    }
  }else{
    targetFile := os.Args[1]
    dir = filepath.Dir(targetFile)

    if !filepath.IsAbs(dir) {
      cwd, err := os.Getwd()
      if err != nil {
        returnedError = err
        return
      }
      dir = filepath.Join(cwd, dir)
    }
  }

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file = dir+"\\.node-version"
    v, err := ioutil.ReadFile(file);

    if err == nil {
      version = string(v)
      return
    }

    if !os.IsNotExist(err) {
      returnedError = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  version = ""
  return
}

func getInstalledVersions() (versions []*semver.Version, error error) {
  // Determine architecture
  x64 := false
  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }
  // construct path to version dir
  path := os.Getenv("NODIST_PREFIX")+"/v"
  if x64 {
    path += "-x64"
  }

  dirs, err := ioutil.ReadDir(path)
  if err != nil {
    error = err
    return
  }

  versions = make([]*semver.Version, len(dirs))
  for i, dir := range dirs {
    v, err := semver.NewVersion(dir.Name())
    if err == nil {
      versions[i] = v
    }
  }

  sort.Sort(semver.Collection(versions))

  return
}

func getTargetEngine() (spec string, error error) {
  if len(os.Args) < 2 {
    return
  }

  targetFile := os.Args[1]

  dir := filepath.Dir(targetFile)
  if !filepath.IsAbs(dir) {
    cwd, err := os.Getwd()
    if err != nil {
      error = err
      return
    }
    dir = filepath.Join(cwd, dir)
  }

  debug("getTargetEngine: targetDir: %s", dir)

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  spec = ""

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file := dir+"\\package.json"
    rawPackageJSON, err := ioutil.ReadFile(file);
    debug("getTargetEngine: ReadFile %s", file)
    if err == nil {
      // no error handling for parsing, cause we don't want to use a different package.json if we've already found one
      spec, error = getVerSpecFromPackageJSON(rawPackageJSON)
      return
    }

    if !os.IsNotExist(err) {
      error = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  return
}

func getVerSpecFromPackageJSON(rawPackageJSON []byte) (spec string, err error) {
  type PackageJSON struct {
    Engines struct {
      Node string
    }
  }
  var packageJSON PackageJSON
  err = json.Unmarshal(rawPackageJSON, &packageJSON)

  if err == nil {
    spec = packageJSON.Engines.Node
    debug("getVerSpecFromPackageJSON: %+v", packageJSON)
    return
  }

  debug("getVerSpecFromPackageJSON: error: %s", err.Error())

  // incorrect JSON -- bad luck
  return
}
<commit_msg>Shim: Fix #129: Make it understand `latest`<commit_after>package main

import (
  "fmt"
  "os"
  "os/exec"
  "syscall"
  "io/ioutil"
  "path/filepath"
  "strings"
  "sort"
  "encoding/json"
  "github.com/Masterminds/semver"
)

import . "github.com/tj/go-debug"

var debug = Debug("nodist:shim")

const pathSep = string(os.PathSeparator)

func main() {
  // Prerequisites

  if "" == os.Getenv("NODIST_PREFIX") {
    fmt.Println("Please set the path to the nodist directory in the NODIST_PREFIX environment variable.")
    os.Exit(40)
  }

  // Determine version spec

  var spec string = ""
  if v := os.Getenv("NODE_VERSION"); v != "" {
    spec = v
    debug("NODE_VERSION found:'%s'", spec)
  } else
  if v = os.Getenv("NODIST_VERSION"); v != "" {
    spec = v
    debug("NODIST_VERSION found:'%s'", spec)
  } else
  if v, err := getTargetEngine(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = v
    debug("Target engine found:'%s'", spec)
  } else
  if v, localFile, err := getLocalVersion(); err == nil && strings.Trim(string(v), " \r\n") != "" {
    spec = string(v)
    debug("Local file found:'%s' @ %s", spec, localFile)
  } else
  if v, err := ioutil.ReadFile(os.Getenv("NODIST_PREFIX")+"\\.node-version"); err == nil {
    spec = string(v)
    debug("Global file found: '%s'", spec)
  }

  spec = strings.Trim(spec, "v \r\n")

  if spec == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Please set a version.")
    os.Exit(41)
  }

  var constraint *semver.Constraints

  if spec != "latest" {
    var err error
    constraint, err = semver.NewConstraint(spec)

    if err != nil {
      fmt.Println("Sorry, there's a problem with nodist. Couldn't decide which node version to use. Malformatted version spec ", spec, " . Please set a new version.")
      os.Exit(43)
    }
  }

  // Find an installed version matching the spec...

  installed, err := getInstalledVersions()

  if err != nil {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't list installed versions.")
    os.Exit(44)
  }

  version := ""

  if spec == "latest" {
    version = installed[len(installed)-1].String()
  }else{
    for _, v := range installed {
      if constraint.Check(v) {
	version = v.String()
	break
      }
    }
  }

  if version == "" {
    fmt.Println("Sorry, there's a problem with nodist. Couldn't find an installed version that matches version spec ", spec)
    os.Exit(45)
  }

  // Determine architecture

  x64 := false

  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }

  // Set up binary path

  var path string
  var nodebin string

  path = os.Getenv("NODIST_PREFIX")+"/v"

  if x64 {
    path += "-x64"
  }

  path = path+"/"+version
  nodebin = path+"/node.exe"

  // Run node!

  cmd := exec.Command(nodebin, os.Args[1:]...)
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  cmd.Stdin = os.Stdin
  err = cmd.Run()

  if err != nil {
    exitError, isExitError := err.(*(exec.ExitError))
    if isExitError {
      // You know it. Black Magic...
      os.Exit(exitError.Sys().(syscall.WaitStatus).ExitStatus())
    } else {
      fmt.Println("Sorry, there's a problem with nodist.")
      fmt.Println("Error: ", err)
      os.Exit(42)
    }
  }
}

func getLocalVersion() (version string, file string, returnedError error) {
  var dir string
  var err error
  if len(os.Args) < 2 {
    dir, err = os.Getwd()
    if err != nil {
      returnedError = err
      return
    }
  }else{
    targetFile := os.Args[1]
    dir = filepath.Dir(targetFile)

    if !filepath.IsAbs(dir) {
      cwd, err := os.Getwd()
      if err != nil {
        returnedError = err
        return
      }
      dir = filepath.Join(cwd, dir)
    }
  }

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file = dir+"\\.node-version"
    v, err := ioutil.ReadFile(file);

    if err == nil {
      version = string(v)
      return
    }

    if !os.IsNotExist(err) {
      returnedError = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  version = ""
  return
}

func getInstalledVersions() (versions []*semver.Version, error error) {
  // Determine architecture
  x64 := false
  if wantX64 := os.Getenv("NODIST_X64"); wantX64 != "" {
    x64 = (wantX64 == "1")
  }
  // construct path to version dir
  path := os.Getenv("NODIST_PREFIX")+"/v"
  if x64 {
    path += "-x64"
  }

  dirs, err := ioutil.ReadDir(path)
  if err != nil {
    error = err
    return
  }

  versions = make([]*semver.Version, len(dirs))
  for i, dir := range dirs {
    v, err := semver.NewVersion(dir.Name())
    if err == nil {
      versions[i] = v
    }
  }

  sort.Sort(semver.Collection(versions))

  return
}

func getTargetEngine() (spec string, error error) {
  if len(os.Args) < 2 {
    return
  }

  targetFile := os.Args[1]

  dir := filepath.Dir(targetFile)
  if !filepath.IsAbs(dir) {
    cwd, err := os.Getwd()
    if err != nil {
      error = err
      return
    }
    dir = filepath.Join(cwd, dir)
  }

  debug("getTargetEngine: targetDir: %s", dir)

  dirSlice := strings.Split(dir, pathSep) // D:\Programme\nodist => [D:, Programme, nodist]

  spec = ""

  for len(dirSlice) != 1 {
    dir = strings.Join(dirSlice, pathSep)
    file := dir+"\\package.json"
    rawPackageJSON, err := ioutil.ReadFile(file);
    debug("getTargetEngine: ReadFile %s", file)
    if err == nil {
      // no error handling for parsing, cause we don't want to use a different package.json if we've already found one
      spec, error = getVerSpecFromPackageJSON(rawPackageJSON)
      return
    }

    if !os.IsNotExist(err) {
      error = err // some other error.. bad luck.
      return
    }

    // `$ cd ..`
    dirSlice = dirSlice[:len(dirSlice)-1] // pop the last dir
  }

  return
}

func getVerSpecFromPackageJSON(rawPackageJSON []byte) (spec string, err error) {
  type PackageJSON struct {
    Engines struct {
      Node string
    }
  }
  var packageJSON PackageJSON
  err = json.Unmarshal(rawPackageJSON, &packageJSON)

  if err == nil {
    spec = packageJSON.Engines.Node
    debug("getVerSpecFromPackageJSON: %+v", packageJSON)
    return
  }

  debug("getVerSpecFromPackageJSON: error: %s", err.Error())

  // incorrect JSON -- bad luck
  return
}
<|endoftext|>