<commit_before>package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"plugin"
	"rais/src/iiif"
	"reflect"
	"sort"
	"strings"

	"github.com/uoregon-libraries/gopkg/logger"
)

var idToPathPlugins []func(iiif.ID) (string, error)
var wrapHandlerPlugins []func(string, http.Handler) (http.Handler, error)
var teardownPlugins []func()
var purgeCachePlugins []func()
var expireCachedImagePlugins []func(iiif.ID)

// pluginsFor returns a list of all plugin files which matched the given
// pattern.  Files are sorted by name.
func pluginsFor(pattern string) ([]string, error) {
	if !filepath.IsAbs(pattern) {
		var dir = filepath.Join(filepath.Dir(os.Args[0]), "plugins")
		pattern = filepath.Join(dir, pattern)
	}

	var files, err = filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("invalid plugin file pattern %q", pattern)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("plugin pattern %q doesn't match any files", pattern)
	}

	sort.Strings(files)
	return files, nil
}

// LoadPlugins searches for any plugins matching the pattern given.  If the
// pattern is not an absolute URL, it is treated as a pattern under the
// binary's dir/plugins.
func LoadPlugins(l *logger.Logger, patterns []string) {
	var plugFiles []string
	var seen = make(map[string]bool)
	for _, pattern := range patterns {
		var matches, err = pluginsFor(pattern)
		if err != nil {
			l.Warnf("Skipping invalid plugin pattern %q: %s", pattern, err)
		}

		// We do a sanity check before actually processing any plugins
		for _, file := range matches {
			if filepath.Ext(file) != ".so" {
				l.Fatalf("Cannot load unknown file %q (plugins must be compiled .so files)", file)
			}
			if seen[file] {
				l.Fatalf("Cannot load the same plugin twice (%q)", file)
			}
			seen[file] = true
		}

		plugFiles = append(plugFiles, matches...)
	}

	for _, file := range plugFiles {
		l.Infof("Loading plugin %q", file)
		var err = loadPlugin(file, l)
		if err != nil {
			l.Errorf("Unable to load %q: %s", file, err)
		}
	}
}

type pluginWrapper struct {
	*plugin.Plugin
	path      string
	functions []string
	errors    []string
}

func newPluginWrapper(path string) (*pluginWrapper, error) {
	var p, err = plugin.Open(path)
	if err != nil {
		return nil, fmt.Errorf("cannot load plugin %q: %s", path, err)
	}
	return &pluginWrapper{Plugin: p, path: path}, nil
}

// loadPluginFn loads the symbol by the given name and attempts to set it to
// the given object via reflection.  If the two aren't the same type, an error
// is added to the pluginWrapper's error list.
func (pw *pluginWrapper) loadPluginFn(name string, obj interface{}) {
	var sym, err = pw.Lookup(name)
	if err != nil {
		return
	}

	var objElem = reflect.ValueOf(obj).Elem()
	var objType = objElem.Type()
	var symV = reflect.ValueOf(sym)

	if !symV.Type().AssignableTo(objType) {
		pw.errors = append(pw.errors, fmt.Sprintf("invalid signature for %s (expecting %s)", name, objType))
		return
	}

	objElem.Set(symV)
	pw.functions = append(pw.functions, name)
}

// loadPlugin attempts to read the given plugin file and extract known symbols.
// If a plugin exposes Initialize or SetLogger, they're called here once we're
// sure the plugin is valid.  IDToPath functions are indexed globally for use
// in the RAIS image serving handler.
func loadPlugin(fullpath string, l *logger.Logger) error {
	var pw, err = newPluginWrapper(fullpath)
	if err != nil {
		return err
	}

	// Set up dummy / no-op functions so we can call these without risk
	var log = func(*logger.Logger) {}
	var initialize = func() {}

	// Simply initialize those functions we only want indexed if they exist
	var idToPath func(iiif.ID) (string, error)
	var teardown func()
	var wrapHandler func(string, http.Handler) (http.Handler, error)
	var prgCache func()
	var expCachedImg func(iiif.ID)

	pw.loadPluginFn("SetLogger", &log)
	pw.loadPluginFn("IDToPath", &idToPath)
	pw.loadPluginFn("Initialize", &initialize)
	pw.loadPluginFn("Teardown", &teardown)
	pw.loadPluginFn("WrapHandler", &wrapHandler)
	pw.loadPluginFn("PurgeCaches", &prgCache)
	pw.loadPluginFn("ExpireCachedImage", &expCachedImg)

	if len(pw.errors) != 0 {
		return errors.New(strings.Join(pw.errors, ", "))
	}
	if len(pw.functions) == 0 {
		return fmt.Errorf("no known functions exposed")
	}

	// We need to call SetLogger and Initialize immediately, as they're never
	// called a second time and they tell us if the plugin is going to be used
	log(l)
	initialize()

	// After initialization, we check if the plugin explicitly set itself to Disabled
	var sym plugin.Symbol
	sym, err = pw.Lookup("Disabled")
	if err == nil {
		var disabled, ok = sym.(*bool)
		if !ok {
			return fmt.Errorf("non-boolean Disabled value exposed")
		}
		if *disabled {
			l.Infof("%q is disabled", fullpath)
			return nil
		}
		l.Debugf("%q is explicitly enabled", fullpath)
	}

	// Index remaining functions
	if idToPath != nil {
		idToPathPlugins = append(idToPathPlugins, idToPath)
	}
	if teardown != nil {
		teardownPlugins = append(teardownPlugins, teardown)
	}
	if wrapHandler != nil {
		wrapHandlerPlugins = append(wrapHandlerPlugins, wrapHandler)
	}
	if prgCache != nil {
		purgeCachePlugins = append(purgeCachePlugins, prgCache)
	}
	if expCachedImg != nil {
		expireCachedImagePlugins = append(expireCachedImagePlugins, expCachedImg)
	}

	// Add info to stats
	stats.Plugins = append(stats.Plugins, plugStats{
		Path:      fullpath,
		Functions: pw.functions,
	})

	return nil
}
<commit_msg>Allow plugins to register decoders<commit_after>package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"plugin"
	"rais/src/iiif"
	"rais/src/img"
	"reflect"
	"sort"
	"strings"

	"github.com/uoregon-libraries/gopkg/logger"
)

var idToPathPlugins []func(iiif.ID) (string, error)
var wrapHandlerPlugins []func(string, http.Handler) (http.Handler, error)
var teardownPlugins []func()
var purgeCachePlugins []func()
var expireCachedImagePlugins []func(iiif.ID)

// pluginsFor returns a list of all plugin files which matched the given
// pattern.  Files are sorted by name.
func pluginsFor(pattern string) ([]string, error) {
	if !filepath.IsAbs(pattern) {
		var dir = filepath.Join(filepath.Dir(os.Args[0]), "plugins")
		pattern = filepath.Join(dir, pattern)
	}

	var files, err = filepath.Glob(pattern)
	if err != nil {
		return nil, fmt.Errorf("invalid plugin file pattern %q", pattern)
	}
	if len(files) == 0 {
		return nil, fmt.Errorf("plugin pattern %q doesn't match any files", pattern)
	}

	sort.Strings(files)
	return files, nil
}

// LoadPlugins searches for any plugins matching the pattern given.  If the
// pattern is not an absolute URL, it is treated as a pattern under the
// binary's dir/plugins.
func LoadPlugins(l *logger.Logger, patterns []string) {
	var plugFiles []string
	var seen = make(map[string]bool)
	for _, pattern := range patterns {
		var matches, err = pluginsFor(pattern)
		if err != nil {
			l.Warnf("Skipping invalid plugin pattern %q: %s", pattern, err)
		}

		// We do a sanity check before actually processing any plugins
		for _, file := range matches {
			if filepath.Ext(file) != ".so" {
				l.Fatalf("Cannot load unknown file %q (plugins must be compiled .so files)", file)
			}
			if seen[file] {
				l.Fatalf("Cannot load the same plugin twice (%q)", file)
			}
			seen[file] = true
		}

		plugFiles = append(plugFiles, matches...)
	}

	for _, file := range plugFiles {
		l.Infof("Loading plugin %q", file)
		var err = loadPlugin(file, l)
		if err != nil {
			l.Errorf("Unable to load %q: %s", file, err)
		}
	}
}

type pluginWrapper struct {
	*plugin.Plugin
	path      string
	functions []string
	errors    []string
}

func newPluginWrapper(path string) (*pluginWrapper, error) {
	var p, err = plugin.Open(path)
	if err != nil {
		return nil, fmt.Errorf("cannot load plugin %q: %s", path, err)
	}
	return &pluginWrapper{Plugin: p, path: path}, nil
}

// loadPluginFn loads the symbol by the given name and attempts to set it to
// the given object via reflection.  If the two aren't the same type, an error
// is added to the pluginWrapper's error list.
func (pw *pluginWrapper) loadPluginFn(name string, obj interface{}) {
	var sym, err = pw.Lookup(name)
	if err != nil {
		return
	}

	var objElem = reflect.ValueOf(obj).Elem()
	var objType = objElem.Type()
	var symV = reflect.ValueOf(sym)

	if !symV.Type().AssignableTo(objType) {
		pw.errors = append(pw.errors, fmt.Sprintf("invalid signature for %s (expecting %s)", name, objType))
		return
	}

	objElem.Set(symV)
	pw.functions = append(pw.functions, name)
}

// loadPlugin attempts to read the given plugin file and extract known symbols.
// If a plugin exposes Initialize or SetLogger, they're called here once we're
// sure the plugin is valid.  IDToPath functions are indexed globally for use
// in the RAIS image serving handler.
func loadPlugin(fullpath string, l *logger.Logger) error {
	var pw, err = newPluginWrapper(fullpath)
	if err != nil {
		return err
	}

	// Set up dummy / no-op functions so we can call these without risk
	var log = func(*logger.Logger) {}
	var initialize = func() {}

	// Simply initialize those functions we only want indexed if they exist
	var idToPath func(iiif.ID) (string, error)
	var teardown func()
	var wrapHandler func(string, http.Handler) (http.Handler, error)
	var prgCache func()
	var expCachedImg func(iiif.ID)
	var imageDecoders func() []img.DecodeFn

	pw.loadPluginFn("SetLogger", &log)
	pw.loadPluginFn("IDToPath", &idToPath)
	pw.loadPluginFn("Initialize", &initialize)
	pw.loadPluginFn("Teardown", &teardown)
	pw.loadPluginFn("WrapHandler", &wrapHandler)
	pw.loadPluginFn("PurgeCaches", &prgCache)
	pw.loadPluginFn("ExpireCachedImage", &expCachedImg)
	pw.loadPluginFn("ImageDecoders", &imageDecoders)

	if len(pw.errors) != 0 {
		return errors.New(strings.Join(pw.errors, ", "))
	}
	if len(pw.functions) == 0 {
		return fmt.Errorf("no known functions exposed")
	}

	// We need to call SetLogger and Initialize immediately, as they're never
	// called a second time and they tell us if the plugin is going to be used
	log(l)
	initialize()

	// After initialization, we check if the plugin explicitly set itself to Disabled
	var sym plugin.Symbol
	sym, err = pw.Lookup("Disabled")
	if err == nil {
		var disabled, ok = sym.(*bool)
		if !ok {
			return fmt.Errorf("non-boolean Disabled value exposed")
		}
		if *disabled {
			l.Infof("%q is disabled", fullpath)
			return nil
		}
		l.Debugf("%q is explicitly enabled", fullpath)
	}

	// Register image decoder(s) if plugin exposes any
	if imageDecoders != nil {
		for _, fn := range imageDecoders() {
			img.RegisterDecoder(fn)
		}
	}

	// Index remaining functions
	if idToPath != nil {
		idToPathPlugins = append(idToPathPlugins, idToPath)
	}
	if teardown != nil {
		teardownPlugins = append(teardownPlugins, teardown)
	}
	if wrapHandler != nil {
		wrapHandlerPlugins = append(wrapHandlerPlugins, wrapHandler)
	}
	if prgCache != nil {
		purgeCachePlugins = append(purgeCachePlugins, prgCache)
	}
	if expCachedImg != nil {
		expireCachedImagePlugins = append(expireCachedImagePlugins, expCachedImg)
	}

	// Add info to stats
	stats.Plugins = append(stats.Plugins, plugStats{
		Path:      fullpath,
		Functions: pw.functions,
	})

	return nil
}
<|endoftext|>


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

package net

import (
	"errors"
	"time"
)

// A Dialer contains options for connecting to an address.
//
// The zero value for each field is equivalent to dialing
// without that option. Dialing with the zero value of Dialer
// is therefore equivalent to just calling the Dial function.
type Dialer struct {
	// Timeout is the maximum amount of time a dial will wait for
	// a connect to complete. If Deadline is also set, it may fail
	// earlier.
	//
	// The default is no timeout.
	//
	// With or without a timeout, the operating system may impose
	// its own earlier timeout. For instance, TCP timeouts are
	// often around 3 minutes.
	Timeout time.Duration

	// Deadline is the absolute point in time after which dials
	// will fail. If Timeout is set, it may fail earlier.
	// Zero means no deadline, or dependent on the operating system
	// as with the Timeout option.
	Deadline time.Time

	// LocalAddr is the local address to use when dialing an
	// address. The address must be of a compatible type for the
	// network being dialed.
	// If nil, a local address is automatically chosen.
	LocalAddr Addr

	// DualStack allows a single dial to attempt to establish
	// multiple IPv4 and IPv6 connections and to return the first
	// established connection when the network is "tcp" and the
	// destination is a host name that has multiple address family
	// DNS records.
	DualStack bool

	// KeepAlive specifies the keep-alive period for an active
	// network connection.
	// If zero, keep-alives are not enabled. Network protocols
	// that do not support keep-alives ignore this field.
	KeepAlive time.Duration
}

// Return either now+Timeout or Deadline, whichever comes first.
// Or zero, if neither is set.
func (d *Dialer) deadline() time.Time {
	if d.Timeout == 0 {
		return d.Deadline
	}
	timeoutDeadline := time.Now().Add(d.Timeout)
	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
		return timeoutDeadline
	} else {
		return d.Deadline
	}
}

func parseNetwork(net string) (afnet string, proto int, err error) {
	i := last(net, ':')
	if i < 0 { // no colon
		switch net {
		case "tcp", "tcp4", "tcp6":
		case "udp", "udp4", "udp6":
		case "ip", "ip4", "ip6":
		case "unix", "unixgram", "unixpacket":
		default:
			return "", 0, UnknownNetworkError(net)
		}
		return net, 0, nil
	}
	afnet = net[:i]
	switch afnet {
	case "ip", "ip4", "ip6":
		protostr := net[i+1:]
		proto, i, ok := dtoi(protostr, 0)
		if !ok || i != len(protostr) {
			proto, err = lookupProtocol(protostr)
			if err != nil {
				return "", 0, err
			}
		}
		return afnet, proto, nil
	}
	return "", 0, UnknownNetworkError(net)
}

func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
	afnet, _, err := parseNetwork(net)
	if err != nil {
		return nil, err
	}
	if op == "dial" && addr == "" {
		return nil, errMissingAddress
	}
	switch afnet {
	case "unix", "unixgram", "unixpacket":
		return ResolveUnixAddr(afnet, addr)
	}
	return resolveInternetAddr(afnet, addr, deadline)
}

// Dial connects to the address on the named network.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
// "unixpacket".
//
// For TCP and UDP networks, addresses have the form host:port.
// If host is a literal IPv6 address or host name, it must be enclosed
// in square brackets as in "[::1]:80", "[ipv6-host]:http" or
// "[ipv6-host%zone]:80".
// The functions JoinHostPort and SplitHostPort manipulate addresses
// in this form.
//
// Examples:
//	Dial("tcp", "12.34.56.78:80")
//	Dial("tcp", "google.com:http")
//	Dial("tcp", "[2001:db8::1]:http")
//	Dial("tcp", "[fe80::1%lo0]:80")
//
// For IP networks, the network must be "ip", "ip4" or "ip6" followed
// by a colon and a protocol number or name and the addr must be a
// literal IP address.
//
// Examples:
//	Dial("ip4:1", "127.0.0.1")
//	Dial("ip6:ospf", "::1")
//
// For Unix networks, the address must be a file system path.
func Dial(network, address string) (Conn, error) {
	var d Dialer
	return d.Dial(network, address)
}

// DialTimeout acts like Dial but takes a timeout.
// The timeout includes name resolution, if required.
func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
	d := Dialer{Timeout: timeout}
	return d.Dial(network, address)
}

// Dial connects to the address on the named network.
//
// See func Dial for a description of the network and address
// parameters.
func (d *Dialer) Dial(network, address string) (Conn, error) {
	ra, err := resolveAddr("dial", network, address, d.deadline())
	if err != nil {
		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
	}
	dialer := func(deadline time.Time) (Conn, error) {
		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
	}
	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
		dialer = func(deadline time.Time) (Conn, error) {
			return dialMulti(network, address, d.LocalAddr, ras, deadline)
		}
	}
	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
	if d.KeepAlive > 0 && err == nil {
		if tc, ok := c.(*TCPConn); ok {
			tc.SetKeepAlive(true)
			tc.SetKeepAlivePeriod(d.KeepAlive)
			testHookSetKeepAlive()
		}
	}
	return c, err
}

var testHookSetKeepAlive = func() {} // changed by dial_test.go

// dialMulti attempts to establish connections to each destination of
// the list of addresses. It will return the first established
// connection and close the other connections. Otherwise it returns
// error on the last attempt.
func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
	type racer struct {
		Conn
		error
	}
	// Sig controls the flow of dial results on lane. It passes a
	// token to the next racer and also indicates the end of flow
	// by using closed channel.
	sig := make(chan bool, 1)
	lane := make(chan racer, 1)
	for _, ra := range ras {
		go func(ra Addr) {
			c, err := dialSingle(net, addr, la, ra, deadline)
			if _, ok := <-sig; ok {
				lane <- racer{c, err}
			} else if err == nil {
				// We have to return the resources
				// that belong to the other
				// connections here for avoiding
				// unnecessary resource starvation.
				c.Close()
			}
		}(ra.toAddr())
	}
	defer close(sig)
	lastErr := errTimeout
	nracers := len(ras)
	for nracers > 0 {
		sig <- true
		racer := <-lane
		if racer.error == nil {
			return racer.Conn, nil
		}
		lastErr = racer.error
		nracers--
	}
	return nil, lastErr
}

// dialSingle attempts to establish and returns a single connection to
// the destination address.
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
	if la != nil && la.Network() != ra.Network() {
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
	}
	switch ra := ra.(type) {
	case *TCPAddr:
		la, _ := la.(*TCPAddr)
		c, err = dialTCP(net, la, ra, deadline)
	case *UDPAddr:
		la, _ := la.(*UDPAddr)
		c, err = dialUDP(net, la, ra, deadline)
	case *IPAddr:
		la, _ := la.(*IPAddr)
		c, err = dialIP(net, la, ra, deadline)
	case *UnixAddr:
		la, _ := la.(*UnixAddr)
		c, err = dialUnix(net, la, ra, deadline)
	default:
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
	}
	if err != nil {
		return nil, err // c is non-nil interface containing nil pointer
	}
	return c, nil
}

// Listen announces on the local network address laddr.
// The network net must be a stream-oriented network: "tcp", "tcp4",
// "tcp6", "unix" or "unixpacket".
// See Dial for the syntax of laddr.
func Listen(net, laddr string) (Listener, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l Listener
	switch la := la.toAddr().(type) {
	case *TCPAddr:
		l, err = ListenTCP(net, la)
	case *UnixAddr:
		l, err = ListenUnix(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}

// ListenPacket announces on the local network address laddr.
// The network net must be a packet-oriented network: "udp", "udp4",
// "udp6", "ip", "ip4", "ip6" or "unixgram".
// See Dial for the syntax of laddr.
func ListenPacket(net, laddr string) (PacketConn, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l PacketConn
	switch la := la.toAddr().(type) {
	case *UDPAddr:
		l, err = ListenUDP(net, la)
	case *IPAddr:
		l, err = ListenIP(net, la)
	case *UnixAddr:
		l, err = ListenUnixgram(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}
<commit_msg>net: fix Dial comment about IPv6 addresses<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"errors"
	"time"
)

// A Dialer contains options for connecting to an address.
//
// The zero value for each field is equivalent to dialing
// without that option. Dialing with the zero value of Dialer
// is therefore equivalent to just calling the Dial function.
type Dialer struct {
	// Timeout is the maximum amount of time a dial will wait for
	// a connect to complete. If Deadline is also set, it may fail
	// earlier.
	//
	// The default is no timeout.
	//
	// With or without a timeout, the operating system may impose
	// its own earlier timeout. For instance, TCP timeouts are
	// often around 3 minutes.
	Timeout time.Duration

	// Deadline is the absolute point in time after which dials
	// will fail. If Timeout is set, it may fail earlier.
	// Zero means no deadline, or dependent on the operating system
	// as with the Timeout option.
	Deadline time.Time

	// LocalAddr is the local address to use when dialing an
	// address. The address must be of a compatible type for the
	// network being dialed.
	// If nil, a local address is automatically chosen.
	LocalAddr Addr

	// DualStack allows a single dial to attempt to establish
	// multiple IPv4 and IPv6 connections and to return the first
	// established connection when the network is "tcp" and the
	// destination is a host name that has multiple address family
	// DNS records.
	DualStack bool

	// KeepAlive specifies the keep-alive period for an active
	// network connection.
	// If zero, keep-alives are not enabled. Network protocols
	// that do not support keep-alives ignore this field.
	KeepAlive time.Duration
}

// Return either now+Timeout or Deadline, whichever comes first.
// Or zero, if neither is set.
func (d *Dialer) deadline() time.Time {
	if d.Timeout == 0 {
		return d.Deadline
	}
	timeoutDeadline := time.Now().Add(d.Timeout)
	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
		return timeoutDeadline
	} else {
		return d.Deadline
	}
}

func parseNetwork(net string) (afnet string, proto int, err error) {
	i := last(net, ':')
	if i < 0 { // no colon
		switch net {
		case "tcp", "tcp4", "tcp6":
		case "udp", "udp4", "udp6":
		case "ip", "ip4", "ip6":
		case "unix", "unixgram", "unixpacket":
		default:
			return "", 0, UnknownNetworkError(net)
		}
		return net, 0, nil
	}
	afnet = net[:i]
	switch afnet {
	case "ip", "ip4", "ip6":
		protostr := net[i+1:]
		proto, i, ok := dtoi(protostr, 0)
		if !ok || i != len(protostr) {
			proto, err = lookupProtocol(protostr)
			if err != nil {
				return "", 0, err
			}
		}
		return afnet, proto, nil
	}
	return "", 0, UnknownNetworkError(net)
}

func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
	afnet, _, err := parseNetwork(net)
	if err != nil {
		return nil, err
	}
	if op == "dial" && addr == "" {
		return nil, errMissingAddress
	}
	switch afnet {
	case "unix", "unixgram", "unixpacket":
		return ResolveUnixAddr(afnet, addr)
	}
	return resolveInternetAddr(afnet, addr, deadline)
}

// Dial connects to the address on the named network.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
// "unixpacket".
//
// For TCP and UDP networks, addresses have the form host:port.
// If host is a literal IPv6 address it must be enclosed
// in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
// The functions JoinHostPort and SplitHostPort manipulate addresses
// in this form.
//
// Examples:
//	Dial("tcp", "12.34.56.78:80")
//	Dial("tcp", "google.com:http")
//	Dial("tcp", "[2001:db8::1]:http")
//	Dial("tcp", "[fe80::1%lo0]:80")
//
// For IP networks, the network must be "ip", "ip4" or "ip6" followed
// by a colon and a protocol number or name and the addr must be a
// literal IP address.
//
// Examples:
//	Dial("ip4:1", "127.0.0.1")
//	Dial("ip6:ospf", "::1")
//
// For Unix networks, the address must be a file system path.
func Dial(network, address string) (Conn, error) {
	var d Dialer
	return d.Dial(network, address)
}

// DialTimeout acts like Dial but takes a timeout.
// The timeout includes name resolution, if required.
func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
	d := Dialer{Timeout: timeout}
	return d.Dial(network, address)
}

// Dial connects to the address on the named network.
//
// See func Dial for a description of the network and address
// parameters.
func (d *Dialer) Dial(network, address string) (Conn, error) {
	ra, err := resolveAddr("dial", network, address, d.deadline())
	if err != nil {
		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
	}
	dialer := func(deadline time.Time) (Conn, error) {
		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
	}
	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
		dialer = func(deadline time.Time) (Conn, error) {
			return dialMulti(network, address, d.LocalAddr, ras, deadline)
		}
	}
	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
	if d.KeepAlive > 0 && err == nil {
		if tc, ok := c.(*TCPConn); ok {
			tc.SetKeepAlive(true)
			tc.SetKeepAlivePeriod(d.KeepAlive)
			testHookSetKeepAlive()
		}
	}
	return c, err
}

var testHookSetKeepAlive = func() {} // changed by dial_test.go

// dialMulti attempts to establish connections to each destination of
// the list of addresses. It will return the first established
// connection and close the other connections. Otherwise it returns
// error on the last attempt.
func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
	type racer struct {
		Conn
		error
	}
	// Sig controls the flow of dial results on lane. It passes a
	// token to the next racer and also indicates the end of flow
	// by using closed channel.
	sig := make(chan bool, 1)
	lane := make(chan racer, 1)
	for _, ra := range ras {
		go func(ra Addr) {
			c, err := dialSingle(net, addr, la, ra, deadline)
			if _, ok := <-sig; ok {
				lane <- racer{c, err}
			} else if err == nil {
				// We have to return the resources
				// that belong to the other
				// connections here for avoiding
				// unnecessary resource starvation.
				c.Close()
			}
		}(ra.toAddr())
	}
	defer close(sig)
	lastErr := errTimeout
	nracers := len(ras)
	for nracers > 0 {
		sig <- true
		racer := <-lane
		if racer.error == nil {
			return racer.Conn, nil
		}
		lastErr = racer.error
		nracers--
	}
	return nil, lastErr
}

// dialSingle attempts to establish and returns a single connection to
// the destination address.
func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
	if la != nil && la.Network() != ra.Network() {
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
	}
	switch ra := ra.(type) {
	case *TCPAddr:
		la, _ := la.(*TCPAddr)
		c, err = dialTCP(net, la, ra, deadline)
	case *UDPAddr:
		la, _ := la.(*UDPAddr)
		c, err = dialUDP(net, la, ra, deadline)
	case *IPAddr:
		la, _ := la.(*IPAddr)
		c, err = dialIP(net, la, ra, deadline)
	case *UnixAddr:
		la, _ := la.(*UnixAddr)
		c, err = dialUnix(net, la, ra, deadline)
	default:
		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
	}
	if err != nil {
		return nil, err // c is non-nil interface containing nil pointer
	}
	return c, nil
}

// Listen announces on the local network address laddr.
// The network net must be a stream-oriented network: "tcp", "tcp4",
// "tcp6", "unix" or "unixpacket".
// See Dial for the syntax of laddr.
func Listen(net, laddr string) (Listener, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l Listener
	switch la := la.toAddr().(type) {
	case *TCPAddr:
		l, err = ListenTCP(net, la)
	case *UnixAddr:
		l, err = ListenUnix(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}

// ListenPacket announces on the local network address laddr.
// The network net must be a packet-oriented network: "udp", "udp4",
// "udp6", "ip", "ip4", "ip6" or "unixgram".
// See Dial for the syntax of laddr.
func ListenPacket(net, laddr string) (PacketConn, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l PacketConn
	switch la := la.toAddr().(type) {
	case *UDPAddr:
		l, err = ListenUDP(net, la)
	case *IPAddr:
		l, err = ListenIP(net, la)
	case *UnixAddr:
		l, err = ListenUnixgram(net, la)
	default:
		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}
<|endoftext|>


<commit_before>package encoding

import (
	"bytes"
	"io"
	"os"
	"testing"

	"github.com/NebulousLabs/Sia/build"
)

// dummy types to test encoding
type (
	// basic
	test0 struct {
		B bool
		I int32
		U uint16
		S string
	}
	// slice/array
	test1 struct {
		Is []int32
		Bs []byte
		Sa [3]string
		Ba [3]byte
	}
	// nested
	test2 struct {
		T test0
	}
	// embedded
	test3 struct {
		test2
	}
	// pointer
	test4 struct {
		P *test0
	}
	// private field -- need to implement MarshalSia/UnmarshalSia
	test5 struct {
		s string
	}
	// private field with pointer receiver
	test6 struct {
		s string
	}
)

func (t test5) MarshalSia() []byte { return []byte(t.s) }

func (t *test5) UnmarshalSia(b []byte) { t.s = string(b) }

func (t *test6) MarshalSia() []byte { return []byte(t.s) }

func (t *test6) UnmarshalSia(b []byte) { t.s = string(b) }

var testStructs = []interface{}{
	test0{false, 65537, 256, "foo"},
	test1{[]int32{1, 2, 3}, []byte("foo"), [3]string{"foo", "bar", "baz"}, [3]byte{'f', 'o', 'o'}},
	test2{test0{false, 65537, 256, "foo"}},
	test3{test2{test0{false, 65537, 256, "foo"}}},
	test4{&test0{false, 65537, 256, "foo"}},
	test5{"foo"},
	&test6{"foo"},
}

var testEncodings = [][]byte{
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
		0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3,
		0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'r', 3, 0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'z', 'f', 'o', 'o'},
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
}

func TestEncode(t *testing.T) {
	// use Marshal for convenience
	for i := range testStructs {
		b := Marshal(testStructs[i])
		if bytes.Compare(b, testEncodings[i]) != 0 {
			t.Errorf("bad encoding of testStructs[%d]: \nexp:\t%v\ngot:\t%v", i, testEncodings[i], b)
		}
	}

	// badWriter should fail on every encode
	enc := NewEncoder(new(badWriter))
	for i := range testStructs {
		err := enc.Encode(testStructs[i])
		if err != io.ErrShortWrite {
			t.Error("expected ErrShortWrite, got", err)
		}
	}
	// special case, not covered by testStructs
	err := enc.Encode(struct{ U [3]uint16 }{[3]uint16{1, 2, 3}})
	if err != io.ErrShortWrite {
		t.Error("expected ErrShortWrite, got", err)
	}

	// bad type
	defer func() {
		if recover() == nil {
			t.Error("expected panic, got nil")
		}
	}()
	enc.Encode(map[int]int{})
}

func TestDecode(t *testing.T) {
	// use Unmarshal for convenience
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	for i := range testEncodings {
		err := Unmarshal(testEncodings[i], emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}

	// bad boolean
	err := Unmarshal([]byte{3}, new(bool))
	if err == nil {
		t.Error("expected error, got nil")
	}

	// non-pointer
	err = Unmarshal([]byte{1, 2, 3}, "foo")
	if err != ErrBadPointer {
		t.Error("expected ErrBadPointer, got", err)
	}

	// unknown type
	err = Unmarshal([]byte{1, 2, 3}, new(map[int]int))
	if err == nil {
		t.Error("expected error, got nil")
	}

	// badReader should fail on every decode
	dec := NewDecoder(new(badReader))
	for i := range testEncodings {
		err := dec.Decode(emptyStructs[i])
		if err == nil {
			t.Error("expected error, got nil")
		}
	}
	// special case, not covered by testStructs
	err = dec.Decode(new([3]byte))
	if err == nil {
		t.Error("expected error, got nil")
	}

}

func TestMarshalUnmarshal(t *testing.T) {
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	for i := range testStructs {
		b := Marshal(testStructs[i])
		err := Unmarshal(b, emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}
}

func TestEncodeDecode(t *testing.T) {
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	b := new(bytes.Buffer)
	enc := NewEncoder(b)
	dec := NewDecoder(b)
	for i := range testStructs {
		enc.Encode(testStructs[i])
		err := dec.Decode(emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}
}

func TestMarshalAll(t *testing.T) {
	var b []byte
	for i := range testStructs {
		b = append(b, Marshal(testStructs[i])...)
	}

	expected := MarshalAll(testStructs...)
	if bytes.Compare(b, expected) != 0 {
		t.Error("expected %v, got %v", expected, b)
	}
}

func TestReadWriteFile(t *testing.T) {
	// standard
	path := build.TempDir("TestReadWriteFile")
	err := WriteFile(path, testStructs[3])
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(path)

	var obj test4
	err = ReadFile(path, &obj)
	if err != nil {
		t.Error(err)
	}

	// bad paths
	err = WriteFile("/foo/bar", "baz")
	if err == nil {
		t.Error("expected error, got nil")
	}
	err = ReadFile("/foo/bar", nil)
	if err == nil {
		t.Error("expected error, got nil")
	}
}
<commit_msg>fix encoding testdir<commit_after>package encoding

import (
	"bytes"
	"io"
	"os"
	"testing"

	"github.com/NebulousLabs/Sia/build"
)

// dummy types to test encoding
type (
	// basic
	test0 struct {
		B bool
		I int32
		U uint16
		S string
	}
	// slice/array
	test1 struct {
		Is []int32
		Bs []byte
		Sa [3]string
		Ba [3]byte
	}
	// nested
	test2 struct {
		T test0
	}
	// embedded
	test3 struct {
		test2
	}
	// pointer
	test4 struct {
		P *test0
	}
	// private field -- need to implement MarshalSia/UnmarshalSia
	test5 struct {
		s string
	}
	// private field with pointer receiver
	test6 struct {
		s string
	}
)

func (t test5) MarshalSia() []byte { return []byte(t.s) }

func (t *test5) UnmarshalSia(b []byte) { t.s = string(b) }

func (t *test6) MarshalSia() []byte { return []byte(t.s) }

func (t *test6) UnmarshalSia(b []byte) { t.s = string(b) }

var testStructs = []interface{}{
	test0{false, 65537, 256, "foo"},
	test1{[]int32{1, 2, 3}, []byte("foo"), [3]string{"foo", "bar", "baz"}, [3]byte{'f', 'o', 'o'}},
	test2{test0{false, 65537, 256, "foo"}},
	test3{test2{test0{false, 65537, 256, "foo"}}},
	test4{&test0{false, 65537, 256, "foo"}},
	test5{"foo"},
	&test6{"foo"},
}

var testEncodings = [][]byte{
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
		0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o', 3,
		0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'r', 3, 0, 0, 0, 0, 0, 0, 0, 'b', 'a', 'z', 'f', 'o', 'o'},
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
	{3, 0, 0, 0, 0, 0, 0, 0, 'f', 'o', 'o'},
}

func TestEncode(t *testing.T) {
	// use Marshal for convenience
	for i := range testStructs {
		b := Marshal(testStructs[i])
		if bytes.Compare(b, testEncodings[i]) != 0 {
			t.Errorf("bad encoding of testStructs[%d]: \nexp:\t%v\ngot:\t%v", i, testEncodings[i], b)
		}
	}

	// badWriter should fail on every encode
	enc := NewEncoder(new(badWriter))
	for i := range testStructs {
		err := enc.Encode(testStructs[i])
		if err != io.ErrShortWrite {
			t.Error("expected ErrShortWrite, got", err)
		}
	}
	// special case, not covered by testStructs
	err := enc.Encode(struct{ U [3]uint16 }{[3]uint16{1, 2, 3}})
	if err != io.ErrShortWrite {
		t.Error("expected ErrShortWrite, got", err)
	}

	// bad type
	defer func() {
		if recover() == nil {
			t.Error("expected panic, got nil")
		}
	}()
	enc.Encode(map[int]int{})
}

func TestDecode(t *testing.T) {
	// use Unmarshal for convenience
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	for i := range testEncodings {
		err := Unmarshal(testEncodings[i], emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}

	// bad boolean
	err := Unmarshal([]byte{3}, new(bool))
	if err == nil {
		t.Error("expected error, got nil")
	}

	// non-pointer
	err = Unmarshal([]byte{1, 2, 3}, "foo")
	if err != ErrBadPointer {
		t.Error("expected ErrBadPointer, got", err)
	}

	// unknown type
	err = Unmarshal([]byte{1, 2, 3}, new(map[int]int))
	if err == nil {
		t.Error("expected error, got nil")
	}

	// badReader should fail on every decode
	dec := NewDecoder(new(badReader))
	for i := range testEncodings {
		err := dec.Decode(emptyStructs[i])
		if err == nil {
			t.Error("expected error, got nil")
		}
	}
	// special case, not covered by testStructs
	err = dec.Decode(new([3]byte))
	if err == nil {
		t.Error("expected error, got nil")
	}

}

func TestMarshalUnmarshal(t *testing.T) {
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	for i := range testStructs {
		b := Marshal(testStructs[i])
		err := Unmarshal(b, emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}
}

func TestEncodeDecode(t *testing.T) {
	var emptyStructs = []interface{}{&test0{}, &test1{}, &test2{}, &test3{}, &test4{}, &test5{}, &test6{}}
	b := new(bytes.Buffer)
	enc := NewEncoder(b)
	dec := NewDecoder(b)
	for i := range testStructs {
		enc.Encode(testStructs[i])
		err := dec.Decode(emptyStructs[i])
		if err != nil {
			t.Error(err)
		}
	}
}

func TestMarshalAll(t *testing.T) {
	var b []byte
	for i := range testStructs {
		b = append(b, Marshal(testStructs[i])...)
	}

	expected := MarshalAll(testStructs...)
	if bytes.Compare(b, expected) != 0 {
		t.Error("expected %v, got %v", expected, b)
	}
}

func TestReadWriteFile(t *testing.T) {
	// standard
	os.MkdirAll(build.TempDir("encoding"), 0777)
	path := build.TempDir("encoding", "TestReadWriteFile")
	err := WriteFile(path, testStructs[3])
	if err != nil {
		t.Fatal(err)
	}

	var obj test4
	err = ReadFile(path, &obj)
	if err != nil {
		t.Error(err)
	}

	// bad paths
	err = WriteFile("/foo/bar", "baz")
	if err == nil {
		t.Error("expected error, got nil")
	}
	err = ReadFile("/foo/bar", nil)
	if err == nil {
		t.Error("expected error, got nil")
	}
}
<|endoftext|>


<commit_before>package log

/*

Because nobody has been able to develop a proper library for logging in Go up until
the moment I was writing this comment (20:21 02/21/2017), I had to write the following
code, which is quite awful - it's true; it works though.
Maybe one day I will make one; I will keep you up to date.

*/

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/olsdavis/goelan/util"
)

var (
	initialized = false
	DebugLogger *log.Logger
	InfoLogger  *log.Logger
	WarnLogger  *log.Logger
	ErrorLogger *log.Logger
	FatalLogger *log.Logger
)

// Initializes the logger.
func Init() {
	if initialized {
		return
	}

	logFileName := fmt.Sprintf("logs/%v_Server.log", time.Now().Format("2006-01-02-_15-04-05"))

	if val, _ := util.Exists("logs/"); !val {
		os.Mkdir("logs", os.ModePerm)
	}

	if val, _ := util.Exists(logFileName); !val {
		os.Create(logFileName)
	}

	file, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not create log file:", err)
	}

	writer := io.MultiWriter(file, os.Stdout)
	DebugLogger = log.New(os.Stdout, "[DEBU] ", log.Ltime|log.Lshortfile)
	InfoLogger = log.New(writer, "[INFO] ", log.Ltime)
	WarnLogger = log.New(writer, "[WARN] ", log.Ltime)
	ErrorLogger = log.New(writer, "[ERRO] ", log.Ltime|log.Llongfile)
	FatalLogger = log.New(writer, "[FATA] ", log.Ltime)

	initialized = true
}

// Debug prints a debug message to the debugging logger.
func Debug(message ...interface{}) {
	DebugLogger.Println(message)
}

// Info prints an info message to the info logger.
func Info(message ...interface{}) {
	InfoLogger.Println(message)
}

// Warn prints a warning message to the warning logger.
func Warn(message ...interface{}) {
	WarnLogger.Println(message)
}

// Error prints an error message to the error logger.
func Error(message ...interface{}) {
	ErrorLogger.Println(message)
}

// Fatal prints a fatal message to the fatal logger.
func Fatal(message ...interface{}) {
	FatalLogger.Println(message)
}
<commit_msg>:wrench: Removed the log.Lshortfile flag.<commit_after>package log

/*

Because nobody has been able to develop a proper library for logging in Go up until
the moment I was writing this comment (20:21 02/21/2017), I had to write the following
code, which is quite awful - it's true; it works though.
Maybe one day I will make one; I will keep you up to date.

*/

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"github.com/olsdavis/goelan/util"
)

var (
	initialized = false
	DebugLogger *log.Logger
	InfoLogger  *log.Logger
	WarnLogger  *log.Logger
	ErrorLogger *log.Logger
	FatalLogger *log.Logger
)

// Initializes the logger.
func Init() {
	if initialized {
		return
	}

	logFileName := fmt.Sprintf("logs/%v_Server.log", time.Now().Format("2006-01-02-_15-04-05"))

	if val, _ := util.Exists("logs/"); !val {
		os.Mkdir("logs", os.ModePerm)
	}

	if val, _ := util.Exists(logFileName); !val {
		os.Create(logFileName)
	}

	file, err := os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not create log file:", err)
	}

	writer := io.MultiWriter(file, os.Stdout)
	DebugLogger = log.New(os.Stdout, "[DEBU] ", log.Ltime)
	InfoLogger = log.New(writer, "[INFO] ", log.Ltime)
	WarnLogger = log.New(writer, "[WARN] ", log.Ltime)
	ErrorLogger = log.New(writer, "[ERRO] ", log.Ltime)
	FatalLogger = log.New(writer, "[FATA] ", log.Ltime)

	initialized = true
}

// Debug prints a debug message to the debugging logger.
func Debug(message ...interface{}) {
	DebugLogger.Println(message)
}

// Info prints an info message to the info logger.
func Info(message ...interface{}) {
	InfoLogger.Println(message)
}

// Warn prints a warning message to the warning logger.
func Warn(message ...interface{}) {
	WarnLogger.Println(message)
}

// Error prints an error message to the error logger.
func Error(message ...interface{}) {
	ErrorLogger.Println(message)
}

// Fatal prints a fatal message to the fatal logger.
func Fatal(message ...interface{}) {
	FatalLogger.Println(message)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Matthias S. Benkmann

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA  02110-1301, USA.
*/

package util

import (
         "os"
         "log"
         "fmt"
         "time"
       )

// The *log.Logger used by util.Log(). By default it simply prints logged
// messages to Stderr without adding any kind of prefix, time, etc.
var Logger = log.New(os.Stderr, "", 0)

// Only messages with a level <= this number will be printed.
var LogLevel = 0

// Outputs a message to util.Logger formatted as with fmt.Printf().
// The level parameter assigns an importance to the message, where 0
// is the most important (such as fatal errors) and increasing numbers
// mark messages of lesser importance. The idea is that a message of
// level N should only be printed when the program was started with
// N -v (i.e. verbose) switches. So level 0 marks messages that should
// always be logged. Level 1 are informative messages the user may
// not care about. Level 2 and above are typically used for debug
// messages, where level 2 are debug messages that may help the user
// pinpoint a problem and level 3 are debug messages only useful to
// developers. There is usually no need for higher levels.
func Log(level int, format string, args ...interface{}) {
  if (level > LogLevel) { return }
  message := fmt.Sprintf(format, args...)
  t := time.Now()
  output := fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d %v",
      t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), message)
  Logger.Println(output)
}
<commit_msg>Issue #21: support logrotate<commit_after>/*
Copyright (c) 2012 Matthias S. Benkmann

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA  02110-1301, USA.
*/

package util

import (
         "io"
         "os"
         "log"
         "fmt"
         "time"
       )

// The *log.Logger used by util.Log(). By default it simply prints logged
// messages to Stderr without adding any kind of prefix, time, etc.
var Logger = log.New(os.Stderr, "", 0)

// Only messages with a level <= this number will be printed.
var LogLevel = 0

// Outputs a message to util.Logger formatted as with fmt.Printf().
// The level parameter assigns an importance to the message, where 0
// is the most important (such as fatal errors) and increasing numbers
// mark messages of lesser importance. The idea is that a message of
// level N should only be printed when the program was started with
// N -v (i.e. verbose) switches. So level 0 marks messages that should
// always be logged. Level 1 are informative messages the user may
// not care about. Level 2 and above are typically used for debug
// messages, where level 2 are debug messages that may help the user
// pinpoint a problem and level 3 are debug messages only useful to
// developers. There is usually no need for higher levels.
func Log(level int, format string, args ...interface{}) {
  if (level > LogLevel) { return }
  message := fmt.Sprintf(format, args...)
  t := time.Now()
  output := fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d %v",
      t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), message)
  Logger.Println(output)
}

// Returns a io.WriteCloser that appends to the file fpath, checking on each
// write if fpath still exists and if it doesn't creating a new file fpath
// to append to. This behaviour is compatible with log-rotation without
// incurring the overhead of re-opening the file on every write.
//
// NOTE: While closing the returned object will close the underlying file
// if it is open, it will not invalidate the object. The next write will
// open the file again (creating it if necessary) and will append to it.
func LogFile(fpath string) io.WriteCloser {
  return &logFile{path:fpath}
}

type logFile struct {
  path string
  file io.WriteCloser
}

func (f *logFile) Close() error {
  if f.file == nil { return nil }
  err := f.file.Close()
  f.file = nil
  return err
}

func (f *logFile) Write(p []byte) (n int, err error) {
  if f.file != nil { // if we have an open file
    _, err = os.Lstat(f.path)
    if err != nil { // if statting the path failed => close old and create a new one
      f.file.Close()
      f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
      if err != nil { return 0,err }
    }
  } else { // if we don't have an open file => create a new one
    f.file, err = os.OpenFile(f.path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
    if err != nil { return 0,err }
  }

  return f.file.Write(p)
}
<|endoftext|>


<commit_before>// Copyright 2011, 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package log

import (
	"fmt"

	"github.com/juju/loggo"
)

var (
	logger = loggo.GetLogger("juju")
)

// Errorf logs a message using the ERROR priority.
func Errorf(format string, a ...interface{}) error {
	logger.Logf(loggo.ERROR, format, a...)
	return nil
}

// Warningf logs a message using the WARNING priority.
func Warningf(format string, a ...interface{}) error {
	logger.Logf(loggo.WARNING, format, a...)
	return nil
}

// Noticef logs a message using the NOTICE priority.
// Notice doesn't really convert to the loggo priorities...
func Noticef(format string, a ...interface{}) error {
	logger.Logf(loggo.INFO, format, a...)
	return nil
}

// Infof logs a message using the INFO priority.
func Infof(format string, a ...interface{}) error {
	logger.Logf(loggo.INFO, format, a...)
	return nil
}

// Debugf logs a message using the DEBUG priority.
func Debugf(format string, a ...interface{}) (err error) {
	logger.Logf(loggo.DEBUG, format, a...)
	return nil
}

// Log the error and return an error with the same text.
func LoggedErrorf(logger loggo.Logger, format string, a ...interface{}) error {
	logger.Logf(loggo.ERROR, format, a...)
	return fmt.Errorf(format, a...)
}
<commit_msg>Remove old logging.<commit_after>// Copyright 2011-2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package log

import (
	"fmt"

	"github.com/juju/loggo"
)

// Log the error and return an error with the same text.
func LoggedErrorf(logger loggo.Logger, format string, a ...interface{}) error {
	logger.Logf(loggo.ERROR, format, a...)
	return fmt.Errorf(format, a...)
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"io"
	"os"
	"sync"

	"github.com/labstack/gommon/color"
	"github.com/mattn/go-colorable"
	"github.com/mattn/go-isatty"
)

type (
	Logger struct {
		level  Level
		out    io.Writer
		err    io.Writer
		prefix string
		mu     sync.Mutex
	}
	Level uint8
)

const (
	TRACE = iota
	DEBUG
	INFO
	NOTICE
	WARN
	ERROR
	FATAL
	OFF
)

var (
	global = New("-")
	levels []string
)

func New(prefix string) (l *Logger) {
	l = &Logger{
		level:  INFO,
		prefix: prefix,
		out:    colorable.NewColorableStdout(),
		err:    colorable.NewColorableStderr(),
	}
	return
}

func (l *Logger) SetPrefix(p string) {
	l.prefix = p
}

func (l *Logger) SetLevel(v Level) {
	l.level = v
}

func (l *Logger) SetOutput(w io.Writer) {
	l.out = w
	l.err = w

	switch w := w.(type) {
	case *os.File:
		if isatty.IsTerminal(w.Fd()) {
			color.Enable()
		}
	default:
		color.Disable()
	}

	// NOTE: Reintialize levels to reflect color enable/disable call.
	initLevels()
}

func (l *Logger) Print(msg interface{}, args ...interface{}) {
	f := fmt.Sprintf("%s", msg)
	fmt.Fprintf(l.out, f, args...)
}

func (l *Logger) Println(msg interface{}, args ...interface{}) {
	f := fmt.Sprintf("%s\n", msg)
	fmt.Fprintf(l.out, f, args...)
}

func (l *Logger) Trace(msg interface{}, args ...interface{}) {
	l.log(TRACE, l.out, msg, args...)
}

func (l *Logger) Debug(msg interface{}, args ...interface{}) {
	l.log(DEBUG, l.out, msg, args...)
}

func (l *Logger) Info(msg interface{}, args ...interface{}) {
	l.log(INFO, l.out, msg, args...)
}

func (l *Logger) Notice(msg interface{}, args ...interface{}) {
	l.log(NOTICE, l.out, msg, args...)
}

func (l *Logger) Warn(msg interface{}, args ...interface{}) {
	l.log(WARN, l.out, msg, args...)
}

func (l *Logger) Error(msg interface{}, args ...interface{}) {
	l.log(ERROR, l.err, msg, args...)
}

func (l *Logger) Fatal(msg interface{}, args ...interface{}) {
	l.log(FATAL, l.err, msg, args...)
}

func SetPrefix(p string) {
	global.SetPrefix(p)
}

func SetLevel(v Level) {
	global.SetLevel(v)
}

func SetOutput(w io.Writer) {
	global.SetOutput(w)
}

func Print(msg interface{}, args ...interface{}) {
	global.Print(msg, args...)
}

func Println(msg interface{}, args ...interface{}) {
	global.Println(msg, args...)
}

func Trace(msg interface{}, args ...interface{}) {
	global.Trace(msg, args...)
}

func Debug(msg interface{}, args ...interface{}) {
	global.Debug(msg, args...)
}

func Info(msg interface{}, args ...interface{}) {
	global.Info(msg, args...)
}

func Notice(msg interface{}, args ...interface{}) {
	global.Notice(msg, args...)
}

func Warn(msg interface{}, args ...interface{}) {
	global.Warn(msg, args...)
}

func Error(msg interface{}, args ...interface{}) {
	global.Error(msg, args...)
}

func Fatal(msg interface{}, args ...interface{}) {
	global.Fatal(msg, args...)
}

func (l *Logger) log(v Level, w io.Writer, msg interface{}, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()

	if v >= l.level {
		// TODO: Improve performance
		f := fmt.Sprintf("%s|%s|%v\n", levels[v], l.prefix, msg)
		fmt.Fprintf(w, f, args...)
	}
}

func initLevels() {
	levels = []string{
		color.Cyan("TRACE"),
		color.Blue("DEBUG"),
		color.Green("INFO"),
		color.Magenta("NOTICE"),
		color.Yellow("WARN"),
		color.Red("ERROR"),
		color.RedBg("FATAL"),
	}
}

func init() {
	initLevels()
}
<commit_msg>Exit in log.Fatal<commit_after>package log

import (
	"fmt"
	"io"
	"os"
	"sync"

	"github.com/labstack/gommon/color"
	"github.com/mattn/go-colorable"
	"github.com/mattn/go-isatty"
)

type (
	Logger struct {
		level  Level
		out    io.Writer
		err    io.Writer
		prefix string
		mu     sync.Mutex
	}
	Level uint8
)

const (
	TRACE = iota
	DEBUG
	INFO
	NOTICE
	WARN
	ERROR
	FATAL
	OFF
)

var (
	global = New("-")
	levels []string
)

func New(prefix string) (l *Logger) {
	l = &Logger{
		level:  INFO,
		prefix: prefix,
		out:    colorable.NewColorableStdout(),
		err:    colorable.NewColorableStderr(),
	}
	return
}

func (l *Logger) SetPrefix(p string) {
	l.prefix = p
}

func (l *Logger) SetLevel(v Level) {
	l.level = v
}

func (l *Logger) SetOutput(w io.Writer) {
	l.out = w
	l.err = w

	switch w := w.(type) {
	case *os.File:
		if isatty.IsTerminal(w.Fd()) {
			color.Enable()
		}
	default:
		color.Disable()
	}

	// NOTE: Reintialize levels to reflect color enable/disable call.
	initLevels()
}

func (l *Logger) Print(msg interface{}, args ...interface{}) {
	f := fmt.Sprintf("%s", msg)
	fmt.Fprintf(l.out, f, args...)
}

func (l *Logger) Println(msg interface{}, args ...interface{}) {
	f := fmt.Sprintf("%s\n", msg)
	fmt.Fprintf(l.out, f, args...)
}

func (l *Logger) Trace(msg interface{}, args ...interface{}) {
	l.log(TRACE, l.out, msg, args...)
}

func (l *Logger) Debug(msg interface{}, args ...interface{}) {
	l.log(DEBUG, l.out, msg, args...)
}

func (l *Logger) Info(msg interface{}, args ...interface{}) {
	l.log(INFO, l.out, msg, args...)
}

func (l *Logger) Notice(msg interface{}, args ...interface{}) {
	l.log(NOTICE, l.out, msg, args...)
}

func (l *Logger) Warn(msg interface{}, args ...interface{}) {
	l.log(WARN, l.out, msg, args...)
}

func (l *Logger) Error(msg interface{}, args ...interface{}) {
	l.log(ERROR, l.err, msg, args...)
}

func (l *Logger) Fatal(msg interface{}, args ...interface{}) {
	l.log(FATAL, l.err, msg, args...)
	os.Exit(1)
}

func SetPrefix(p string) {
	global.SetPrefix(p)
}

func SetLevel(v Level) {
	global.SetLevel(v)
}

func SetOutput(w io.Writer) {
	global.SetOutput(w)
}

func Print(msg interface{}, args ...interface{}) {
	global.Print(msg, args...)
}

func Println(msg interface{}, args ...interface{}) {
	global.Println(msg, args...)
}

func Trace(msg interface{}, args ...interface{}) {
	global.Trace(msg, args...)
}

func Debug(msg interface{}, args ...interface{}) {
	global.Debug(msg, args...)
}

func Info(msg interface{}, args ...interface{}) {
	global.Info(msg, args...)
}

func Notice(msg interface{}, args ...interface{}) {
	global.Notice(msg, args...)
}

func Warn(msg interface{}, args ...interface{}) {
	global.Warn(msg, args...)
}

func Error(msg interface{}, args ...interface{}) {
	global.Error(msg, args...)
}

func Fatal(msg interface{}, args ...interface{}) {
	global.Fatal(msg, args...)
}

func (l *Logger) log(v Level, w io.Writer, msg interface{}, args ...interface{}) {
	l.mu.Lock()
	defer l.mu.Unlock()

	if v >= l.level {
		// TODO: Improve performance
		f := fmt.Sprintf("%s|%s|%v\n", levels[v], l.prefix, msg)
		fmt.Fprintf(w, f, args...)
	}
}

func initLevels() {
	levels = []string{
		color.Cyan("TRACE"),
		color.Blue("DEBUG"),
		color.Green("INFO"),
		color.Magenta("NOTICE"),
		color.Yellow("WARN"),
		color.Red("ERROR"),
		color.RedBg("FATAL"),
	}
}

func init() {
	initLevels()
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"
	"io"
	"os"
	"time"
)

// Logger ...
type Logger interface {
	Infof(format string, v ...interface{})
	Warnf(format string, v ...interface{})
	Printf(format string, v ...interface{})
	Donef(format string, v ...interface{})
	Debugf(format string, v ...interface{})
	Errorf(format string, v ...interface{})
	TInfof(format string, v ...interface{})
	TWarnf(format string, v ...interface{})
	TPrintf(format string, v ...interface{})
	TDonef(format string, v ...interface{})
	TDebugf(format string, v ...interface{})
	TErrorf(format string, v ...interface{})
	Println()
}

const defaultTimeStampLayout = "15:04:05"

type defaultLogger struct {
	enableDebugLog  bool
	timestampLayout string
	stdout          io.Writer
}

// NewLogger ...
func NewLogger(enableDebugLog bool) Logger {
	return defaultLogger{enableDebugLog: enableDebugLog, timestampLayout: defaultTimeStampLayout, stdout: os.Stdout}
}

// Infof ...
func (l defaultLogger) Infof(format string, v ...interface{}) {
	l.printf(infoSeverity, false, format, v...)
}

// Warnf ...
func (l defaultLogger) Warnf(format string, v ...interface{}) {
	l.printf(warnSeverity, false, format, v...)
}

// Printf ...
func (l defaultLogger) Printf(format string, v ...interface{}) {
	l.printf(normalSeverity, false, format, v...)
}

// Donef ...
func (l defaultLogger) Donef(format string, v ...interface{}) {
	l.printf(doneSeverity, false, format, v...)
}

// Debugf ...
func (l defaultLogger) Debugf(format string, v ...interface{}) {
	if l.enableDebugLog {
		l.printf(debugSeverity, false, format, v...)
	}
}

// Errorf ...
func (l defaultLogger) Errorf(format string, v ...interface{}) {
	l.printf(errorSeverity, false, format, v...)
}

// TInfof ...
func (l defaultLogger) TInfof(format string, v ...interface{}) {
	l.printf(infoSeverity, true, format, v...)
}

// TWarnf ...
func (l defaultLogger) TWarnf(format string, v ...interface{}) {
	l.printf(warnSeverity, true, format, v...)
}

// TPrintf ...
func (l defaultLogger) TPrintf(format string, v ...interface{}) {
	l.printf(normalSeverity, true, format, v...)
}

// TDonef ...
func (l defaultLogger) TDonef(format string, v ...interface{}) {
	l.printf(doneSeverity, true, format, v...)
}

// TDebugf ...
func (l defaultLogger) TDebugf(format string, v ...interface{}) {
	if l.enableDebugLog {
		l.printf(debugSeverity, true, format, v...)
	}
}

// TErrorf ...
func (l defaultLogger) TErrorf(format string, v ...interface{}) {
	l.printf(errorSeverity, true, format, v...)
}

// Println ...
func (l defaultLogger) Println() {
	fmt.Println()
}

func (l defaultLogger) timestampField() string {
	currentTime := time.Now()
	return fmt.Sprintf("[%s]", currentTime.Format(l.timestampLayout))
}

func (l defaultLogger) prefixCurrentTime(message string) string {
	return fmt.Sprintf("%s %s", l.timestampField(), message)
}

func (l defaultLogger) createLogMsg(severity Severity, withTime bool, format string, v ...interface{}) string {
	colorFunc := severityColorFuncMap[severity]
	message := colorFunc(format, v...)
	if withTime {
		message = l.prefixCurrentTime(message)
	}

	return message
}

func (l defaultLogger) printf(severity Severity, withTime bool, format string, v ...interface{}) {
	message := l.createLogMsg(severity, withTime, format, v...)
	if _, err := fmt.Fprintln(l.stdout, message); err != nil {
		fmt.Printf("failed to print message: %s, error: %s\n", message, err)
	}
}

// RInfof ...
func RInfof(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("info", stepID, tag, data, format, v...)
}

// RWarnf ...
func RWarnf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("warn", stepID, tag, data, format, v...)
}

// RErrorf ...
func RErrorf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("error", stepID, tag, data, format, v...)
}

var deprecatedLogger = defaultLogger{stdout: os.Stdout, enableDebugLog: false, timestampLayout: defaultTimeStampLayout}

// SetEnableDebugLog ...
// Deprecated: use Logger instead.
func SetEnableDebugLog(enable bool) {
	deprecatedLogger.enableDebugLog = enable
}

// SetTimestampLayout ...
// Deprecated: use Logger instead.
func SetTimestampLayout(layout string) {
	deprecatedLogger.timestampLayout = layout
}

// SetOutWriter ...
// Deprecated: use Logger for verification instead.
func SetOutWriter(writer io.Writer) {
	deprecatedLogger.stdout = writer
}

// Donef ...
// Deprecated: use Logger instead.
func Donef(format string, v ...interface{}) {
	deprecatedLogger.Donef(format, v...)
}

// Infof ...
// Deprecated: use Logger instead.
func Infof(format string, v ...interface{}) {
	deprecatedLogger.Infof(format, v...)
}

// Printf ...
// Deprecated: use Logger instead.
func Printf(format string, v ...interface{}) {
	deprecatedLogger.Printf(format, v...)
}

// Debugf ...
// Deprecated: use Logger instead.
func Debugf(format string, v ...interface{}) {
	deprecatedLogger.Debugf(format, v...)
}

// Warnf ...
// Deprecated: use Logger instead.
func Warnf(format string, v ...interface{}) {
	deprecatedLogger.Warnf(format, v...)
}

// Errorf ...
// Deprecated: use Logger instead.
func Errorf(format string, v ...interface{}) {
	deprecatedLogger.Errorf(format, v...)
}

// TDonef ...
// Deprecated: use Logger instead.
func TDonef(format string, v ...interface{}) {
	deprecatedLogger.TDonef(format, v...)
}

// TInfof ...
// Deprecated: use Logger instead.
func TInfof(format string, v ...interface{}) {
	deprecatedLogger.TInfof(format, v...)
}

// TPrintf ...
// Deprecated: use Logger instead.
func TPrintf(format string, v ...interface{}) {
	deprecatedLogger.TPrintf(format, v...)
}

// TDebugf ...
// Deprecated: use Logger instead.
func TDebugf(format string, v ...interface{}) {
	deprecatedLogger.TDebugf(format, v...)
}

// TWarnf ...
// Deprecated: use Logger instead.
func TWarnf(format string, v ...interface{}) {
	deprecatedLogger.TWarnf(format, v...)
}

// TErrorf ...
// Deprecated: use Logger instead.
func TErrorf(format string, v ...interface{}) {
	deprecatedLogger.TErrorf(format, v...)
}
<commit_msg>Restore EnableDebugLog on Logger. (#136)<commit_after>package log

import (
	"fmt"
	"io"
	"os"
	"time"
)

// Logger ...
type Logger interface {
	Infof(format string, v ...interface{})
	Warnf(format string, v ...interface{})
	Printf(format string, v ...interface{})
	Donef(format string, v ...interface{})
	Debugf(format string, v ...interface{})
	Errorf(format string, v ...interface{})
	TInfof(format string, v ...interface{})
	TWarnf(format string, v ...interface{})
	TPrintf(format string, v ...interface{})
	TDonef(format string, v ...interface{})
	TDebugf(format string, v ...interface{})
	TErrorf(format string, v ...interface{})
	Println()
	EnableDebugLog(enable bool)
}

const defaultTimeStampLayout = "15:04:05"

type defaultLogger struct {
	enableDebugLog  bool
	timestampLayout string
	stdout          io.Writer
}

// NewLogger ...
func NewLogger() Logger {
	return &defaultLogger{enableDebugLog: false, timestampLayout: defaultTimeStampLayout, stdout: os.Stdout}
}

// EnableDebugLog ...
func (l *defaultLogger) EnableDebugLog(enable bool) {
	l.enableDebugLog = enable
}

// Infof ...
func (l *defaultLogger) Infof(format string, v ...interface{}) {
	l.printf(infoSeverity, false, format, v...)
}

// Warnf ...
func (l *defaultLogger) Warnf(format string, v ...interface{}) {
	l.printf(warnSeverity, false, format, v...)
}

// Printf ...
func (l *defaultLogger) Printf(format string, v ...interface{}) {
	l.printf(normalSeverity, false, format, v...)
}

// Donef ...
func (l *defaultLogger) Donef(format string, v ...interface{}) {
	l.printf(doneSeverity, false, format, v...)
}

// Debugf ...
func (l *defaultLogger) Debugf(format string, v ...interface{}) {
	if l.enableDebugLog {
		l.printf(debugSeverity, false, format, v...)
	}
}

// Errorf ...
func (l *defaultLogger) Errorf(format string, v ...interface{}) {
	l.printf(errorSeverity, false, format, v...)
}

// TInfof ...
func (l *defaultLogger) TInfof(format string, v ...interface{}) {
	l.printf(infoSeverity, true, format, v...)
}

// TWarnf ...
func (l *defaultLogger) TWarnf(format string, v ...interface{}) {
	l.printf(warnSeverity, true, format, v...)
}

// TPrintf ...
func (l *defaultLogger) TPrintf(format string, v ...interface{}) {
	l.printf(normalSeverity, true, format, v...)
}

// TDonef ...
func (l *defaultLogger) TDonef(format string, v ...interface{}) {
	l.printf(doneSeverity, true, format, v...)
}

// TDebugf ...
func (l *defaultLogger) TDebugf(format string, v ...interface{}) {
	if l.enableDebugLog {
		l.printf(debugSeverity, true, format, v...)
	}
}

// TErrorf ...
func (l *defaultLogger) TErrorf(format string, v ...interface{}) {
	l.printf(errorSeverity, true, format, v...)
}

// Println ...
func (l *defaultLogger) Println() {
	fmt.Println()
}

func (l *defaultLogger) timestampField() string {
	currentTime := time.Now()
	return fmt.Sprintf("[%s]", currentTime.Format(l.timestampLayout))
}

func (l *defaultLogger) prefixCurrentTime(message string) string {
	return fmt.Sprintf("%s %s", l.timestampField(), message)
}

func (l *defaultLogger) createLogMsg(severity Severity, withTime bool, format string, v ...interface{}) string {
	colorFunc := severityColorFuncMap[severity]
	message := colorFunc(format, v...)
	if withTime {
		message = l.prefixCurrentTime(message)
	}

	return message
}

func (l *defaultLogger) printf(severity Severity, withTime bool, format string, v ...interface{}) {
	message := l.createLogMsg(severity, withTime, format, v...)
	if _, err := fmt.Fprintln(l.stdout, message); err != nil {
		fmt.Printf("failed to print message: %s, error: %s\n", message, err)
	}
}

// RInfof ...
func RInfof(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("info", stepID, tag, data, format, v...)
}

// RWarnf ...
func RWarnf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("warn", stepID, tag, data, format, v...)
}

// RErrorf ...
func RErrorf(stepID string, tag string, data map[string]interface{}, format string, v ...interface{}) {
	rprintf("error", stepID, tag, data, format, v...)
}

var deprecatedLogger = defaultLogger{stdout: os.Stdout, enableDebugLog: false, timestampLayout: defaultTimeStampLayout}

// SetEnableDebugLog ...
// Deprecated: use Logger instead.
func SetEnableDebugLog(enable bool) {
	deprecatedLogger.enableDebugLog = enable
}

// SetTimestampLayout ...
// Deprecated: use Logger instead.
func SetTimestampLayout(layout string) {
	deprecatedLogger.timestampLayout = layout
}

// SetOutWriter ...
// Deprecated: use Logger for verification instead.
func SetOutWriter(writer io.Writer) {
	deprecatedLogger.stdout = writer
}

// Donef ...
// Deprecated: use Logger instead.
func Donef(format string, v ...interface{}) {
	deprecatedLogger.Donef(format, v...)
}

// Infof ...
// Deprecated: use Logger instead.
func Infof(format string, v ...interface{}) {
	deprecatedLogger.Infof(format, v...)
}

// Printf ...
// Deprecated: use Logger instead.
func Printf(format string, v ...interface{}) {
	deprecatedLogger.Printf(format, v...)
}

// Debugf ...
// Deprecated: use Logger instead.
func Debugf(format string, v ...interface{}) {
	deprecatedLogger.Debugf(format, v...)
}

// Warnf ...
// Deprecated: use Logger instead.
func Warnf(format string, v ...interface{}) {
	deprecatedLogger.Warnf(format, v...)
}

// Errorf ...
// Deprecated: use Logger instead.
func Errorf(format string, v ...interface{}) {
	deprecatedLogger.Errorf(format, v...)
}

// TDonef ...
// Deprecated: use Logger instead.
func TDonef(format string, v ...interface{}) {
	deprecatedLogger.TDonef(format, v...)
}

// TInfof ...
// Deprecated: use Logger instead.
func TInfof(format string, v ...interface{}) {
	deprecatedLogger.TInfof(format, v...)
}

// TPrintf ...
// Deprecated: use Logger instead.
func TPrintf(format string, v ...interface{}) {
	deprecatedLogger.TPrintf(format, v...)
}

// TDebugf ...
// Deprecated: use Logger instead.
func TDebugf(format string, v ...interface{}) {
	deprecatedLogger.TDebugf(format, v...)
}

// TWarnf ...
// Deprecated: use Logger instead.
func TWarnf(format string, v ...interface{}) {
	deprecatedLogger.TWarnf(format, v...)
}

// TErrorf ...
// Deprecated: use Logger instead.
func TErrorf(format string, v ...interface{}) {
	deprecatedLogger.TErrorf(format, v...)
}
<|endoftext|>


<commit_before>package tritium

import (
  "goprotobuf.googlecode.com/hg/proto"
)

func (ins *Instruction) Iterate(itFunc func(*Instruction)) {
	itFunc(ins)
	if ins.Children == nil {
		return
	}
	for _, child := range(ins.Children) {
		child.Iterate(itFunc)
	}
}

func List(instrs ...*Instruction) []*Instruction {
  return append(make([]*Instruction, 0), instrs...)
}

func FoldLeft(funcName string, base *Instruction, seq []*Instruction) (acc *Instruction) {
  for acc = base; len(seq) > 0; seq = seq[1:] {
    acc = MakeFunctionCall(funcName, List(acc, seq[0]), nil, *base.LineNumber)
  }
  return acc
}

func MakeText(text string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_TEXT),
    Value: proto.String(text),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakePosition(pos string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_POSITION),
    Value: proto.String(pos),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeImport(path string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_IMPORT),
    Value: proto.String(path),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeLocalVar(name string, val *Instruction, block []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_LOCAL_VAR),
    Value: proto.String(name),
    Arguments: List(val),
    Children: block,
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeFunctionCall(name string, args []*Instruction, block []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_FUNCTION_CALL),
    Value: proto.String(name),
    Arguments: args,
    Children: block,
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeBlock(children []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_BLOCK),
    Children: children,
    LineNumber: proto.Int32(lineNum),
  }
}

func (ins *Instruction) GetFunction(pkg *Package) (*Function) {
	funId := proto.GetInt32(ins.FunctionId)
	return pkg.Functions[int(funId)]
}

func (instr *Instruction) Append(more ...*Instruction) {
  if instr.Children == nil {
    instr.Children = more
  } else {
    instr.Children = append(instr.Children, more...)
  }
}

func (instr *Instruction) ConcatList(more []*Instruction) {
  instr.Append(more...)
}

func (instr *Instruction) ConcatBlock (more *Instruction) {
  instr.Append(more.Children...)
}<commit_msg>Renaming a function.<commit_after>package tritium

import (
  "goprotobuf.googlecode.com/hg/proto"
)

func (ins *Instruction) Iterate(itFunc func(*Instruction)) {
	itFunc(ins)
	if ins.Children == nil {
		return
	}
	for _, child := range(ins.Children) {
		child.Iterate(itFunc)
	}
}

func ListInstructions(instrs ...*Instruction) []*Instruction {
  return append(make([]*Instruction, 0), instrs...)
}

func FoldLeft(funcName string, base *Instruction, seq []*Instruction) (acc *Instruction) {
  for acc = base; len(seq) > 0; seq = seq[1:] {
    acc = MakeFunctionCall(funcName, ListInstructions(acc, seq[0]), nil, *base.LineNumber)
  }
  return acc
}

func MakeText(text string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_TEXT),
    Value: proto.String(text),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakePosition(pos string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_POSITION),
    Value: proto.String(pos),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeImport(path string, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_IMPORT),
    Value: proto.String(path),
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeLocalVar(name string, val *Instruction, block []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_LOCAL_VAR),
    Value: proto.String(name),
    Arguments: ListInstructions(val),
    Children: block,
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeFunctionCall(name string, args []*Instruction, block []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_FUNCTION_CALL),
    Value: proto.String(name),
    Arguments: args,
    Children: block,
    LineNumber: proto.Int32(lineNum),
  }
}

func MakeBlock(children []*Instruction, lineNum int32) *Instruction {
  return &Instruction {
    Type: NewInstruction_InstructionType(Instruction_BLOCK),
    Children: children,
    LineNumber: proto.Int32(lineNum),
  }
}

func (ins *Instruction) GetFunction(pkg *Package) (*Function) {
	funId := proto.GetInt32(ins.FunctionId)
	return pkg.Functions[int(funId)]
}

func (instr *Instruction) Append(more ...*Instruction) {
  if instr.Children == nil {
    instr.Children = more
  } else {
    instr.Children = append(instr.Children, more...)
  }
}

func (instr *Instruction) ConcatList(more []*Instruction) {
  instr.Append(more...)
}

func (instr *Instruction) ConcatBlock (more *Instruction) {
  instr.Append(more.Children...)
}<|endoftext|>