<commit_before>// Copyright 2014 The Convention Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Every file starts with a copyright. Gophers tend to use BSD-like licenses.
// "The PackageName Authors" in copyrights along with maintained AUTHORS,
// CONTRIBUTORS, and LICENSE files are idiomatic. Comments are proper English
// sentences, always started with "//", and bound to 80 char line length. Code
// itself is not bound any line length, but long lines are often a code smell.

// Package conventions is an example Go package that is loaded with
// documentation specifically targetting new developers that have done the Go
// Tour and have read the documentation on the "go" binary, but want to know
// more about writing packages and software.
//
// The documentation for an entire package written here; only one of the files
// in a package should have it. Comments are always on the line above the thing
// they are documenting. Package declarations and any exports require comments
// and should be in the form of "Package pkgname ..." and "ExportName ..."
// respectively.
package conventions

// The import and const keywords should always be expanded into their multi-line
// form.
//
// One $GOPATH contains all of the packages on the internet. Whenever something
// is exported, the author is forced to maintain stability of that package's
// API. If the author is a bad citizen, they will break API and those depending
// on the API will have two options: update their code or fork the package.
// Forking comes at a cost: it changes the name of all of the imports.
import (
	// Imports from the Go standard libraries are grouped together at the top.
	"errors"
	"fmt"

	// Third party imports are placed below the standard libraries. Setting up
	// text editor hooks to run gofmt and lint on save is a good idea.
	_ "github.com/golang/lint"

	// Local imports are placed below the third party libraries. Importing a
	// package as _ is useful if you require some side-effect of init() from the
	// package.
	_ "github.com/jzelinskie/conventions/subpkg"
)

// Constants always follow the imports.
const (
	enums = iota
	are
	pretty
	cool
)

// Exported variables are usually in multi-line form, however when defining
// huge literals such as the constants used in cryptographic hashing algorithms,
// it is fine to have repeated var statements.
var (
	// ErrStupidMistake is an example of an exported error type.
	ErrStupidMistake = errors.New("stupid mistakes are the story of my life")
)

// Example is an example of how to define new types.
//
// Fields are one-per-line and grouped together however you think is most
// logical. Don't worry too much about writing struct tags for every encoding
// under the sun. Someone can easily create a wrapper type that implements
// the encoding's marshaler interface (i.e. json.Marshaler).
type Example struct {
	ID          int
	Name        string
	Description string

	irrelevant string
}

// NewExample is an example constructor for the Example type.
//
// Constructors are always the first thing to follow the type declaration.
// Constructors always begin with "New" and can simply be called "New" if the
// name of the type being returned is the same as the package (i.e.
// config.New()). Returning a reference literal is better than allocating with
// the new keyword. Always have a trailing comma on the last item in anything
// multi-line.
func NewExample(id int, name, description string) *Example {
	return &Example{
		ID:          id,
		Name:        name,
		Description: description,
	}
}

// Method is an example method for the Example type.
//
// Methods are always what come after constructors. Godoc will order them
// alphabetically, but it is often more useful to order them logically.
// Receivers should only be pointers if the method modifies the receiver. A
// *Example can still call a method with the receiver (e Example).
func (e Example) Method() (bool, error) {
	var (
		nameLength = len(e.Name)
		result     = nameLength < 10
	)

	// Keep lines between logical groups of statements, including the final
	// return.
	return result, nil
}

// Second to last in a file is an init func. This func enables you to run code
// at package import time.
func init() {
}

// Last in a file should be a main func. This func should only be present in a
// package named main to generate a binary file.
func main() {
	// Break long function calls into its multi-line form. Functions with lots of
	// parameters are often a code smell. The use of := for capturing the result
	// of function calls is preferrable to the use of var because it can handle
	// multiple return values.
	example := NewExample(
		1,
		"conventions",
		"this is getting quite meta",
	)

	_, err := example.Method()
	if err != nil {
		// Panics are used only in situations that inform the programmer that they
		// are doing something wrong. They should not be used like exceptions --
		// error is a builtin type for a reason.
		panic("conventions: example method should always return a nil error.")
	}

	// When a zero-value is desired, use the var keyword. Avoid using := around
	// if statements as variables can accidently become shadowed.
	var multiplier int
	if example.ID > 10 {
		multiplier = 10
	} else {
		multiplier = example.ID
	}
	fmt.Printf("Multiplier: %v", multiplier)
}
<commit_msg>revert var to := and move its comment<commit_after>// Copyright 2014 The Convention Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Every file starts with a copyright. Gophers tend to use BSD-like licenses.
// "The PackageName Authors" in copyrights along with maintained AUTHORS,
// CONTRIBUTORS, and LICENSE files are idiomatic. Comments are proper English
// sentences, always started with "//", and bound to 80 char line length. Code
// itself is not bound any line length, but long lines are often a code smell.

// Package conventions is an example Go package that is loaded with
// documentation specifically targetting new developers that have done the Go
// Tour and have read the documentation on the "go" binary, but want to know
// more about writing packages and software.
//
// The documentation for an entire package written here; only one of the files
// in a package should have it. Comments are always on the line above the thing
// they are documenting. Package declarations and any exports require comments
// and should be in the form of "Package pkgname ..." and "ExportName ..."
// respectively.
package conventions

// The import and const keywords should always be expanded into their multi-line
// form.
//
// One $GOPATH contains all of the packages on the internet. Whenever something
// is exported, the author is forced to maintain stability of that package's
// API. If the author is a bad citizen, they will break API and those depending
// on the API will have two options: update their code or fork the package.
// Forking comes at a cost: it changes the name of all of the imports.
import (
	// Imports from the Go standard libraries are grouped together at the top.
	"errors"
	"fmt"

	// Third party imports are placed below the standard libraries. Setting up
	// text editor hooks to run gofmt and lint on save is a good idea.
	_ "github.com/golang/lint"

	// Local imports are placed below the third party libraries. Importing a
	// package as _ is useful if you require some side-effect of init() from the
	// package.
	_ "github.com/jzelinskie/conventions/subpkg"
)

// Constants always follow the imports.
const (
	enums = iota
	are
	pretty
	cool
)

// Exported variables are usually in multi-line form, however when defining
// huge literals such as the constants used in cryptographic hashing algorithms,
// it is fine to have repeated var statements.
var (
	// ErrStupidMistake is an example of an exported error type.
	ErrStupidMistake = errors.New("stupid mistakes are the story of my life")
)

// Example is an example of how to define new types.
//
// Fields are one-per-line and grouped together however you think is most
// logical. Don't worry too much about writing struct tags for every encoding
// under the sun. Someone can easily create a wrapper type that implements
// the encoding's marshaler interface (i.e. json.Marshaler).
type Example struct {
	ID          int
	Name        string
	Description string

	irrelevant string
}

// NewExample is an example constructor for the Example type.
//
// Constructors are always the first thing to follow the type declaration.
// Constructors always begin with "New" and can simply be called "New" if the
// name of the type being returned is the same as the package (i.e.
// config.New()). Returning a reference literal is better than allocating with
// the new keyword. Always have a trailing comma on the last item in anything
// multi-line.
func NewExample(id int, name, description string) *Example {
	return &Example{
		ID:          id,
		Name:        name,
		Description: description,
	}
}

// Method is an example method for the Example type.
//
// Methods are always what come after constructors. Godoc will order them
// alphabetically, but it is often more useful to order them logically.
// Receivers should only be pointers if the method modifies the receiver. A
// *Example can still call a method with the receiver (e Example).
func (e Example) Method() (bool, error) {
	// The use of := for capturing the result of function calls and expressions
	// is preferrable to the use of var.
	nameLength := len(e.Name)
	result := nameLength < 10

	// Keep lines between logical groups of statements, including the final
	// return.
	return result, nil
}

// Second to last in a file is an init func. This func enables you to run code
// at package import time.
func init() {
}

// Last in a file should be a main func. This func should only be present in a
// package named main to generate a binary file.
func main() {
	// Break long function calls into its multi-line form. Functions with lots of
	// parameters are often a code smell.
	example := NewExample(
		1,
		"conventions",
		"this is getting quite meta",
	)

	_, err := example.Method()
	if err != nil {
		// Panics are used only in situations that inform the programmer that they
		// are doing something wrong. They should not be used like exceptions --
		// error is a builtin type for a reason.
		panic("conventions: example method should always return a nil error.")
	}

	// When a zero-value is desired, use the var keyword. Avoid using := around
	// if statements as variables can accidently become shadowed.
	var multiplier int
	if example.ID > 10 {
		multiplier = 10
	} else {
		multiplier = example.ID
	}
	fmt.Printf("Multiplier: %v", multiplier)
}
<|endoftext|>


<commit_before>package telegram

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

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/scbizu/Astral/getcert"
	"github.com/scbizu/Astral/plugin/hub"
	"github.com/scbizu/Astral/talker"
	"github.com/scbizu/Astral/talker/dce"
	"github.com/sirupsen/logrus"
)

//ListenWebHook is the tg api webhook mode
func ListenWebHook(debug bool) (err error) {
	bot, err := ConnectTG()
	if err != nil {
		return
	}
	if debug {
		bot.Debug = true
		logrus.Infof("bot auth passed as %s", bot.Self.UserName)
	}
	bot.RemoveWebhook()
	cert := getcert.NewDomainCert(tgAPIDomain)
	domainWithToken := fmt.Sprintf("%s%s", cert.GetDomain(), token)
	if _, err = bot.SetWebhook(tgbotapi.NewWebhook(domainWithToken)); err != nil {
		logrus.Infof("notify webhook failed:%s", err.Error())
		return
	}

	info, err := bot.GetWebhookInfo()
	if err != nil {
		return err
	}

	logrus.Info(info.LastErrorMessage, info.LastErrorDate)

	pattern := fmt.Sprintf("/%s", token)
	updatesMsgChannel := bot.ListenForWebhook(pattern)
	logrus.Infof("msg in channel:%d", len(updatesMsgChannel))

	go registDCEServer(bot)

	for update := range updatesMsgChannel {
		logrus.Infof("[raw msg]:%#v\n", update)

		if update.Message == nil {
			continue
		}
		pluginHub := hub.NewTGPluginHub(update.Message)
		msg := pluginHub.RegistTGEnabledPlugins(update.Message)
		if isMsgBadRequest(msg) {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, "Astral服务酱表示不想理你")
		}

		mbNames, ok := isMsgNewMember(update)
		if ok {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("撒花欢迎新基佬(%v)入群", mbNames))
		}

		_, ok = isMsgLeftMember(update)
		if ok {
			// drop the member left message
			continue
		}

		msg.ReplyToMessageID = update.Message.MessageID

		go func() {
			time.Sleep(2 * time.Second)
			bot.Send(msg)
		}()

		bot.Send(msg)

	}

	return
}

func isMsgNewMember(update tgbotapi.Update) ([]string, bool) {
	members := update.Message.NewChatMembers
	if members == nil {
		return nil, false
	}
	if len(*members) == 0 {
		return nil, false
	}
	var mbNames []string
	for _, m := range *members {
		mbNames = append(mbNames, m.String())
	}
	return mbNames, true
}

func isMsgLeftMember(update tgbotapi.Update) (string, bool) {
	if update.Message.LeftChatMember == nil {
		return "", false
	}
	mbName := update.Message.LeftChatMember.String()
	return mbName, true
}

func isMsgBadRequest(msg tgbotapi.MessageConfig) bool {
	if msg.Text == "" || msg.ChatID == 0 {
		return true
	}
	return false
}

func registDCEServer(bot *tgbotapi.BotAPI) {
	dceListenHandler := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			r.ParseForm()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				logrus.Println(err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			defer r.Body.Close()
			dceObj, err := dce.NewDCEObj(string(body))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			noti := talker.NewNotifaction(dceObj.GetRepoName(),
				dceObj.GetStageMap(), dceObj.GetCommitMsg(),
				dceObj.GetBuildDuration())
			respMsg, err := bot.Send(noti.Notify())
			if err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(err.Error()))
				return
			}
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(respMsg.Text))
		} else {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("Astral denied your request"))
		}
	}

	http.HandleFunc("/dce", dceListenHandler)

	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))

	go http.ListenAndServe(port, nil)
}
<commit_msg>Revert "telegram: test delay message"<commit_after>package telegram

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

	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/scbizu/Astral/getcert"
	"github.com/scbizu/Astral/plugin/hub"
	"github.com/scbizu/Astral/talker"
	"github.com/scbizu/Astral/talker/dce"
	"github.com/sirupsen/logrus"
)

//ListenWebHook is the tg api webhook mode
func ListenWebHook(debug bool) (err error) {
	bot, err := ConnectTG()
	if err != nil {
		return
	}
	if debug {
		bot.Debug = true
		logrus.Infof("bot auth passed as %s", bot.Self.UserName)
	}
	bot.RemoveWebhook()
	cert := getcert.NewDomainCert(tgAPIDomain)
	domainWithToken := fmt.Sprintf("%s%s", cert.GetDomain(), token)
	if _, err = bot.SetWebhook(tgbotapi.NewWebhook(domainWithToken)); err != nil {
		logrus.Infof("notify webhook failed:%s", err.Error())
		return
	}

	info, err := bot.GetWebhookInfo()
	if err != nil {
		return err
	}

	logrus.Info(info.LastErrorMessage, info.LastErrorDate)

	pattern := fmt.Sprintf("/%s", token)
	updatesMsgChannel := bot.ListenForWebhook(pattern)
	logrus.Infof("msg in channel:%d", len(updatesMsgChannel))

	registDCEServer(bot)

	for update := range updatesMsgChannel {
		logrus.Infof("[raw msg]:%#v\n", update)

		if update.Message == nil {
			continue
		}
		pluginHub := hub.NewTGPluginHub(update.Message)
		msg := pluginHub.RegistTGEnabledPlugins(update.Message)
		if isMsgBadRequest(msg) {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, "Astral服务酱表示不想理你")
		}

		mbNames, ok := isMsgNewMember(update)
		if ok {
			msg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("撒花欢迎新基佬(%v)入群", mbNames))
		}

		_, ok = isMsgLeftMember(update)
		if ok {
			// drop the member left message
			continue
		}

		msg.ReplyToMessageID = update.Message.MessageID
		bot.Send(msg)
	}

	return
}

func isMsgNewMember(update tgbotapi.Update) ([]string, bool) {
	members := update.Message.NewChatMembers
	if members == nil {
		return nil, false
	}
	if len(*members) == 0 {
		return nil, false
	}
	var mbNames []string
	for _, m := range *members {
		mbNames = append(mbNames, m.String())
	}
	return mbNames, true
}

func isMsgLeftMember(update tgbotapi.Update) (string, bool) {
	if update.Message.LeftChatMember == nil {
		return "", false
	}
	mbName := update.Message.LeftChatMember.String()
	return mbName, true
}

func isMsgBadRequest(msg tgbotapi.MessageConfig) bool {
	if msg.Text == "" || msg.ChatID == 0 {
		return true
	}
	return false
}

func registDCEServer(bot *tgbotapi.BotAPI) {
	dceListenHandler := func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodPost {
			r.ParseForm()
			body, err := ioutil.ReadAll(r.Body)
			if err != nil {
				logrus.Println(err)
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}

			defer r.Body.Close()
			dceObj, err := dce.NewDCEObj(string(body))
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			noti := talker.NewNotifaction(dceObj.GetRepoName(),
				dceObj.GetStageMap(), dceObj.GetCommitMsg(),
				dceObj.GetBuildDuration())
			respMsg, err := bot.Send(noti.Notify())
			if err != nil {
				w.WriteHeader(http.StatusBadRequest)
				w.Write([]byte(err.Error()))
				return
			}
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(respMsg.Text))
		} else {
			w.WriteHeader(http.StatusForbidden)
			w.Write([]byte("Astral denied your request"))
		}
	}

	http.HandleFunc("/dce", dceListenHandler)

	port := fmt.Sprintf(":%s", os.Getenv("LISTENPORT"))

	go http.ListenAndServe(port, nil)
}
<|endoftext|>


<commit_before>package providers

import (
	"fmt"
	"testing"
)

func TestDetect(t *testing.T) {
	providersDetect := []struct {
		Getenv   func(string) string
		Expected string
	}{
		{
			func(name string) string {
				if name == slackEnvVarName {
					return "some token"
				}
				return ""
			},
			"*providers.providerSlack",
		},
	}

	for _, p := range providersDetect {
		gotProvider := Detect(p.Getenv)
		if p.Expected != fmt.Sprintf("%T", gotProvider) {
			t.Errorf("expected: %v. got: %v\n", p.Expected, fmt.Sprintf("%T", gotProvider))
		}
	}
}
<commit_msg>Remove test for provider detection<commit_after><|endoftext|>


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

// Finds tsuru applications which deploys count % 20 == 0 |||| this is wrong! if count is 30 % 20 will be 10 and the app still needs a flatten!
// and flatten their filesystems in order to avoid aufs performance bottlenecks.
package docker

import (
	"bytes"
	"fmt"
	"github.com/dotcloud/docker"
	dcli "github.com/fsouza/go-dockerclient"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"os"
)

func needsFlatten(a provision.App) bool {
	deploys := a.GetDeploys()
	if deploys != 0 && deploys%20 == 0 {
		return true
	}
	return false
}

func flatten(imageID string) error {
	config := docker.Config{
		Image:        imageID,
		Cmd:          []string{"/bin/bash"},
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
	}
	_, c, err := dockerCluster().CreateContainer(&config)
	if err != nil {
		return err
	}
	buf := &bytes.Buffer{}
	if err := dockerCluster().ExportContainer(c.ID, buf); err != nil {
		log.Errorf("Flatten: Caugh error while exporting container %s: %s", c.ID, err)
		return err
	}
	// code to debug import issue
	f, _ := os.Create(fmt.Sprintf("/tmp/container-%s", c.ID))
	f.Write(buf.Bytes())
	f.Close()
	out := &bytes.Buffer{}
	opts := dcli.ImportImageOptions{Repository: imageID, Source: "-"}
	if err := dockerCluster().ImportImage(opts, buf, out); err != nil {
		log.Errorf("Flatten: Caugh error while importing image from container %s: %s", c.ID, err)
		return err
	}
	if err := dockerCluster().RemoveContainer(c.ID); err != nil {
		log.Errorf("Flatten: Caugh error while removing container %s: %s", c.ID, err)
	}
	removeFromRegistry(imageID)
	return nil
}

// Flatten finds the images that need to be flattened and export/import
// them in order to flatten them and logs errors when they happen.
func Flatten(a provision.App) {
	if needsFlatten(a) {
		image := getImage(a)
		log.Debugf("Flatten: attempting to flatten image %s.", image)
		if err := flatten(image); err != nil {
			log.Errorf("Flatten: Caugh error while flattening image %s: %s", image, err)
			return
		}
		log.Debugf("Flatten: successfully flattened image %s.", image)
	}
}
<commit_msg>provision/docker/flatten.go: reading buffer to write on file<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Finds tsuru applications which deploys count % 20 == 0 |||| this is wrong! if count is 30 % 20 will be 10 and the app still needs a flatten!
// and flatten their filesystems in order to avoid aufs performance bottlenecks.
package docker

import (
	"bytes"
	"fmt"
	"github.com/dotcloud/docker"
	dcli "github.com/fsouza/go-dockerclient"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"io/ioutil"
	"os"
)

func needsFlatten(a provision.App) bool {
	deploys := a.GetDeploys()
	if deploys != 0 && deploys%20 == 0 {
		return true
	}
	return false
}

func flatten(imageID string) error {
	config := docker.Config{
		Image:        imageID,
		Cmd:          []string{"/bin/bash"},
		AttachStdin:  false,
		AttachStdout: false,
		AttachStderr: false,
	}
	_, c, err := dockerCluster().CreateContainer(&config)
	if err != nil {
		return err
	}
	buf := &bytes.Buffer{}
	if err := dockerCluster().ExportContainer(c.ID, buf); err != nil {
		log.Errorf("Flatten: Caugh error while exporting container %s: %s", c.ID, err)
		return err
	}
	// code to debug import issue
	r := bytes.NewReader(buf.Bytes())
	f, _ := os.Create(fmt.Sprintf("/tmp/container-%s", c.ID))
	b, err := ioutil.ReadAll(r)
	if err != nil {
		log.Debugf("Error while writing debug file: %s", err.Error())
	}
	f.Write(b)
	f.Close()
	r.Seek(0, 0)
	out := &bytes.Buffer{}
	opts := dcli.ImportImageOptions{Repository: imageID, Source: "-"}
	if err := dockerCluster().ImportImage(opts, r, out); err != nil {
		log.Errorf("Flatten: Caugh error while importing image from container %s: %s", c.ID, err)
		return err
	}
	if err := dockerCluster().RemoveContainer(c.ID); err != nil {
		log.Errorf("Flatten: Caugh error while removing container %s: %s", c.ID, err)
	}
	removeFromRegistry(imageID)
	return nil
}

// Flatten finds the images that need to be flattened and export/import
// them in order to flatten them and logs errors when they happen.
func Flatten(a provision.App) {
	if needsFlatten(a) {
		image := getImage(a)
		log.Debugf("Flatten: attempting to flatten image %s.", image)
		if err := flatten(image); err != nil {
			log.Errorf("Flatten: Caugh error while flattening image %s: %s", image, err)
			return
		}
		log.Debugf("Flatten: successfully flattened image %s.", image)
	}
}
<|endoftext|>


<commit_before>package proxy

import (
	"bufio"
	"bytes"
	"container/list"
	"errors"
	"fmt"
	"net"
	"reflect"
	"sync"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-wire"
	tmsp "github.com/tendermint/tmsp/types"
)

const maxResponseSize = 1048576 // 1MB

// This is goroutine-safe, but users should beware that
// the application in general is not meant to be interfaced
// with concurrent callers.
type remoteAppContext struct {
	QuitService
	sync.Mutex // [EB]: is this even used?

	reqQueue chan *reqRes

	mtx       sync.Mutex
	conn      net.Conn
	bufWriter *bufio.Writer
	err       error
	reqSent   *list.List
	resCb     func(tmsp.Request, tmsp.Response)
}

func NewRemoteAppContext(conn net.Conn, bufferSize int) *remoteAppContext {
	app := &remoteAppContext{
		reqQueue:  make(chan *reqRes, bufferSize),
		conn:      conn,
		bufWriter: bufio.NewWriter(conn),
		reqSent:   list.New(),
		resCb:     nil,
	}
	app.QuitService = *NewQuitService(nil, "remoteAppContext", app)
	return app
}

func (app *remoteAppContext) OnStart() error {
	app.QuitService.OnStart()
	go app.sendRequestsRoutine()
	go app.recvResponseRoutine()
	return nil
}

func (app *remoteAppContext) OnStop() {
	app.QuitService.OnStop()
	app.conn.Close()
}

func (app *remoteAppContext) SetResponseCallback(resCb Callback) {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	app.resCb = resCb
}

func (app *remoteAppContext) StopForError(err error) {
	app.mtx.Lock()
	log.Error("Stopping remoteAppContext for error.", "error", err)
	if app.err == nil {
		app.err = err
	}
	app.mtx.Unlock()
	app.Stop()
}

func (app *remoteAppContext) Error() error {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	return app.err
}

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

func (app *remoteAppContext) sendRequestsRoutine() {
	for {
		var n, n2 int
		var err error
		select {
		case <-app.QuitService.Quit:
			return
		case reqres := <-app.reqQueue:

			app.willSendReq(reqres)

			buf := new(bytes.Buffer)
			wire.WriteBinary(reqres.Request, buf, &n2, &err) // Length prefix
			wire.WriteVarint(buf.Len(), app.bufWriter, &n, &err)
			wire.WriteTo(buf.Bytes(), app.bufWriter, &n, &err)
			if err != nil {
				app.StopForError(err)
				return
			}
			log.Debug("Sent request", "requestType", reflect.TypeOf(reqres.Request), "request", reqres.Request)
			if _, ok := reqres.Request.(tmsp.RequestFlush); ok {
				err = app.bufWriter.Flush()
				if err != nil {
					app.StopForError(err)
					return
				}
			}
		}
	}
}

func (app *remoteAppContext) recvResponseRoutine() {
	r := bufio.NewReader(app.conn) // Buffer reads
	for {
		var res tmsp.Response
		var n, n2 int
		var err error
		size := wire.ReadVarint(r, &n2, &err)
		wire.ReadBinaryPtr(&res, r, maxResponseSize, &n, &err)
		if err != nil {
			app.StopForError(err)
			return
		}
		if size != n {
			app.StopForError(fmt.Errorf("Prefixed length not equal to actual length. %v vs %v", size, n))
		}
		switch res := res.(type) {
		case tmsp.ResponseException:
			app.StopForError(errors.New(res.Error))
		default:
			log.Debug("Received response", "responseType", reflect.TypeOf(res), "response", res)
			err := app.didRecvResponse(res)
			if err != nil {
				app.StopForError(err)
			}
		}
	}
}

func (app *remoteAppContext) willSendReq(reqres *reqRes) {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	app.reqSent.PushBack(reqres)
}

func (app *remoteAppContext) didRecvResponse(res tmsp.Response) error {
	app.mtx.Lock()
	defer app.mtx.Unlock()

	// Special logic for events which have no corresponding requests.
	if _, ok := res.(tmsp.ResponseEvent); ok && app.resCb != nil {
		app.resCb(nil, res)
		return nil
	}

	// Get the first reqRes
	next := app.reqSent.Front()
	if next == nil {
		return fmt.Errorf("Unexpected result type %v when nothing expected", reflect.TypeOf(res))
	}
	reqres := next.Value.(*reqRes)
	if !resMatchesReq(reqres.Request, res) {
		return fmt.Errorf("Unexpected result type %v when response to %v expected",
			reflect.TypeOf(res), reflect.TypeOf(reqres.Request))
	}

	reqres.Response = res    // Set response
	reqres.Done()            // Release waiters
	app.reqSent.Remove(next) // Pop first item from linked list

	// Callback if there is a listener
	if app.resCb != nil {
		app.resCb(reqres.Request, res)
	}

	return nil
}

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

func (app *remoteAppContext) EchoAsync(msg string) {
	app.queueRequest(tmsp.RequestEcho{msg})
}

func (app *remoteAppContext) FlushAsync() {
	app.queueRequest(tmsp.RequestFlush{})
}

func (app *remoteAppContext) SetOptionAsync(key string, value string) {
	app.queueRequest(tmsp.RequestSetOption{key, value})
}

func (app *remoteAppContext) AppendTxAsync(tx []byte) {
	app.queueRequest(tmsp.RequestAppendTx{tx})
}

func (app *remoteAppContext) GetHashAsync() {
	app.queueRequest(tmsp.RequestGetHash{})
}

func (app *remoteAppContext) CommitAsync() {
	app.queueRequest(tmsp.RequestCommit{})
}

func (app *remoteAppContext) RollbackAsync() {
	app.queueRequest(tmsp.RequestRollback{})
}

func (app *remoteAppContext) AddListenerAsync(key string) {
	app.queueRequest(tmsp.RequestAddListener{key})
}

func (app *remoteAppContext) RemListenerAsync(key string) {
	app.queueRequest(tmsp.RequestRemListener{key})
}

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

func (app *remoteAppContext) InfoSync() (info []string, err error) {
	reqres := app.queueRequest(tmsp.RequestInfo{})
	app.FlushSync()
	if app.err != nil {
		return nil, app.err
	}
	return reqres.Response.(tmsp.ResponseInfo).Data, nil
}

func (app *remoteAppContext) FlushSync() error {
	app.queueRequest(tmsp.RequestFlush{}).Wait()
	return app.err
}

func (app *remoteAppContext) GetHashSync() (hash []byte, err error) {
	reqres := app.queueRequest(tmsp.RequestGetHash{})
	app.FlushSync()
	if app.err != nil {
		return nil, app.err
	}
	return reqres.Response.(tmsp.ResponseGetHash).Hash, nil
}

// Commits or error
func (app *remoteAppContext) CommitSync() (err error) {
	app.queueRequest(tmsp.RequestCommit{})
	app.FlushSync()
	return app.err
}

// Rollback or error
// Clears internal buffers
func (app *remoteAppContext) RollbackSync() (err error) {
	app.queueRequest(tmsp.RequestRollback{})
	app.FlushSync()
	return app.err
}

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

func (app *remoteAppContext) queueRequest(req tmsp.Request) *reqRes {
	reqres := NewreqRes(req)
	// TODO: set app.err if reqQueue times out
	app.reqQueue <- reqres
	return reqres
}

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

func resMatchesReq(req tmsp.Request, res tmsp.Response) (ok bool) {
	switch req.(type) {
	case tmsp.RequestEcho:
		_, ok = res.(tmsp.ResponseEcho)
	case tmsp.RequestFlush:
		_, ok = res.(tmsp.ResponseFlush)
	case tmsp.RequestInfo:
		_, ok = res.(tmsp.ResponseInfo)
	case tmsp.RequestSetOption:
		_, ok = res.(tmsp.ResponseSetOption)
	case tmsp.RequestAppendTx:
		_, ok = res.(tmsp.ResponseAppendTx)
	case tmsp.RequestGetHash:
		_, ok = res.(tmsp.ResponseGetHash)
	case tmsp.RequestCommit:
		_, ok = res.(tmsp.ResponseCommit)
	case tmsp.RequestRollback:
		_, ok = res.(tmsp.ResponseRollback)
	case tmsp.RequestAddListener:
		_, ok = res.(tmsp.ResponseAddListener)
	case tmsp.RequestRemListener:
		_, ok = res.(tmsp.ResponseRemListener)
	default:
		return false
	}
	return
}

type reqRes struct {
	tmsp.Request
	*sync.WaitGroup
	tmsp.Response // Not set atomically, so be sure to use WaitGroup.
}

func NewreqRes(req tmsp.Request) *reqRes {
	return &reqRes{
		Request:   req,
		WaitGroup: waitGroup1(),
		Response:  nil,
	}
}

func waitGroup1() (wg *sync.WaitGroup) {
	wg = &sync.WaitGroup{}
	wg.Add(1)
	return
}
<commit_msg>Use go-wire's new Read/Write LengthPrefixed methods<commit_after>package proxy

import (
	"bufio"
	"container/list"
	"errors"
	"fmt"
	"net"
	"reflect"
	"sync"

	. "github.com/tendermint/go-common"
	"github.com/tendermint/go-wire"
	tmsp "github.com/tendermint/tmsp/types"
)

const maxResponseSize = 1048576 // 1MB

// This is goroutine-safe, but users should beware that
// the application in general is not meant to be interfaced
// with concurrent callers.
type remoteAppContext struct {
	QuitService
	sync.Mutex // [EB]: is this even used?

	reqQueue chan *reqRes

	mtx       sync.Mutex
	conn      net.Conn
	bufWriter *bufio.Writer
	err       error
	reqSent   *list.List
	resCb     func(tmsp.Request, tmsp.Response)
}

func NewRemoteAppContext(conn net.Conn, bufferSize int) *remoteAppContext {
	app := &remoteAppContext{
		reqQueue:  make(chan *reqRes, bufferSize),
		conn:      conn,
		bufWriter: bufio.NewWriter(conn),
		reqSent:   list.New(),
		resCb:     nil,
	}
	app.QuitService = *NewQuitService(nil, "remoteAppContext", app)
	return app
}

func (app *remoteAppContext) OnStart() error {
	app.QuitService.OnStart()
	go app.sendRequestsRoutine()
	go app.recvResponseRoutine()
	return nil
}

func (app *remoteAppContext) OnStop() {
	app.QuitService.OnStop()
	app.conn.Close()
}

func (app *remoteAppContext) SetResponseCallback(resCb Callback) {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	app.resCb = resCb
}

func (app *remoteAppContext) StopForError(err error) {
	app.mtx.Lock()
	log.Error("Stopping remoteAppContext for error.", "error", err)
	if app.err == nil {
		app.err = err
	}
	app.mtx.Unlock()
	app.Stop()
}

func (app *remoteAppContext) Error() error {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	return app.err
}

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

func (app *remoteAppContext) sendRequestsRoutine() {
	for {
		var n int
		var err error
		select {
		case <-app.QuitService.Quit:
			return
		case reqres := <-app.reqQueue:

			app.willSendReq(reqres)

			wire.WriteBinaryLengthPrefixed(reqres.Request, app.bufWriter, &n, &err) // Length prefix
			if err != nil {
				app.StopForError(err)
				return
			}
			log.Debug("Sent request", "requestType", reflect.TypeOf(reqres.Request), "request", reqres.Request)
			if _, ok := reqres.Request.(tmsp.RequestFlush); ok {
				err = app.bufWriter.Flush()
				if err != nil {
					app.StopForError(err)
					return
				}
			}
		}
	}
}

func (app *remoteAppContext) recvResponseRoutine() {
	r := bufio.NewReader(app.conn) // Buffer reads
	for {
		var res tmsp.Response
		var n int
		var err error
		wire.ReadBinaryPtrLengthPrefixed(&res, r, maxResponseSize, &n, &err)
		if err != nil {
			app.StopForError(err)
			return
		}
		switch res := res.(type) {
		case tmsp.ResponseException:
			app.StopForError(errors.New(res.Error))
		default:
			log.Debug("Received response", "responseType", reflect.TypeOf(res), "response", res)
			err := app.didRecvResponse(res)
			if err != nil {
				app.StopForError(err)
			}
		}
	}
}

func (app *remoteAppContext) willSendReq(reqres *reqRes) {
	app.mtx.Lock()
	defer app.mtx.Unlock()
	app.reqSent.PushBack(reqres)
}

func (app *remoteAppContext) didRecvResponse(res tmsp.Response) error {
	app.mtx.Lock()
	defer app.mtx.Unlock()

	// Special logic for events which have no corresponding requests.
	if _, ok := res.(tmsp.ResponseEvent); ok && app.resCb != nil {
		app.resCb(nil, res)
		return nil
	}

	// Get the first reqRes
	next := app.reqSent.Front()
	if next == nil {
		return fmt.Errorf("Unexpected result type %v when nothing expected", reflect.TypeOf(res))
	}
	reqres := next.Value.(*reqRes)
	if !resMatchesReq(reqres.Request, res) {
		return fmt.Errorf("Unexpected result type %v when response to %v expected",
			reflect.TypeOf(res), reflect.TypeOf(reqres.Request))
	}

	reqres.Response = res    // Set response
	reqres.Done()            // Release waiters
	app.reqSent.Remove(next) // Pop first item from linked list

	// Callback if there is a listener
	if app.resCb != nil {
		app.resCb(reqres.Request, res)
	}

	return nil
}

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

func (app *remoteAppContext) EchoAsync(msg string) {
	app.queueRequest(tmsp.RequestEcho{msg})
}

func (app *remoteAppContext) FlushAsync() {
	app.queueRequest(tmsp.RequestFlush{})
}

func (app *remoteAppContext) SetOptionAsync(key string, value string) {
	app.queueRequest(tmsp.RequestSetOption{key, value})
}

func (app *remoteAppContext) AppendTxAsync(tx []byte) {
	app.queueRequest(tmsp.RequestAppendTx{tx})
}

func (app *remoteAppContext) GetHashAsync() {
	app.queueRequest(tmsp.RequestGetHash{})
}

func (app *remoteAppContext) CommitAsync() {
	app.queueRequest(tmsp.RequestCommit{})
}

func (app *remoteAppContext) RollbackAsync() {
	app.queueRequest(tmsp.RequestRollback{})
}

func (app *remoteAppContext) AddListenerAsync(key string) {
	app.queueRequest(tmsp.RequestAddListener{key})
}

func (app *remoteAppContext) RemListenerAsync(key string) {
	app.queueRequest(tmsp.RequestRemListener{key})
}

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

func (app *remoteAppContext) InfoSync() (info []string, err error) {
	reqres := app.queueRequest(tmsp.RequestInfo{})
	app.FlushSync()
	if app.err != nil {
		return nil, app.err
	}
	return reqres.Response.(tmsp.ResponseInfo).Data, nil
}

func (app *remoteAppContext) FlushSync() error {
	app.queueRequest(tmsp.RequestFlush{}).Wait()
	return app.err
}

func (app *remoteAppContext) GetHashSync() (hash []byte, err error) {
	reqres := app.queueRequest(tmsp.RequestGetHash{})
	app.FlushSync()
	if app.err != nil {
		return nil, app.err
	}
	return reqres.Response.(tmsp.ResponseGetHash).Hash, nil
}

// Commits or error
func (app *remoteAppContext) CommitSync() (err error) {
	app.queueRequest(tmsp.RequestCommit{})
	app.FlushSync()
	return app.err
}

// Rollback or error
// Clears internal buffers
func (app *remoteAppContext) RollbackSync() (err error) {
	app.queueRequest(tmsp.RequestRollback{})
	app.FlushSync()
	return app.err
}

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

func (app *remoteAppContext) queueRequest(req tmsp.Request) *reqRes {
	reqres := NewreqRes(req)
	// TODO: set app.err if reqQueue times out
	app.reqQueue <- reqres
	return reqres
}

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

func resMatchesReq(req tmsp.Request, res tmsp.Response) (ok bool) {
	switch req.(type) {
	case tmsp.RequestEcho:
		_, ok = res.(tmsp.ResponseEcho)
	case tmsp.RequestFlush:
		_, ok = res.(tmsp.ResponseFlush)
	case tmsp.RequestInfo:
		_, ok = res.(tmsp.ResponseInfo)
	case tmsp.RequestSetOption:
		_, ok = res.(tmsp.ResponseSetOption)
	case tmsp.RequestAppendTx:
		_, ok = res.(tmsp.ResponseAppendTx)
	case tmsp.RequestGetHash:
		_, ok = res.(tmsp.ResponseGetHash)
	case tmsp.RequestCommit:
		_, ok = res.(tmsp.ResponseCommit)
	case tmsp.RequestRollback:
		_, ok = res.(tmsp.ResponseRollback)
	case tmsp.RequestAddListener:
		_, ok = res.(tmsp.ResponseAddListener)
	case tmsp.RequestRemListener:
		_, ok = res.(tmsp.ResponseRemListener)
	default:
		return false
	}
	return
}

type reqRes struct {
	tmsp.Request
	*sync.WaitGroup
	tmsp.Response // Not set atomically, so be sure to use WaitGroup.
}

func NewreqRes(req tmsp.Request) *reqRes {
	return &reqRes{
		Request:   req,
		WaitGroup: waitGroup1(),
		Response:  nil,
	}
}

func waitGroup1() (wg *sync.WaitGroup) {
	wg = &sync.WaitGroup{}
	wg.Add(1)
	return
}
<|endoftext|>


<commit_before>package pickett

import (
	"fmt"
	"strings"

	pickett_io "github.com/igneous-systems/pickett/io"
)

//checkExistingNames is a helper to generate an error if the name is already
//in use in this configuration.  Pass true if you are interested in build nodes,
//false for networks.
func (c *Config) checkExistingName(proposed string, wantNode bool) error {
	p := strings.Trim(proposed, " \n")
	if p == "" {
		return fmt.Errorf("can't have an empty name in configuration file")
	}
	if wantNode {
		if c.nameToNode[p] != nil {
			return fmt.Errorf("name %s already in use in this configuration (build node)", p)
		}
	}
	if c.nameToNetwork[p] != nil {
		return fmt.Errorf("network name %s already in use in this configuration", p)
	}
	return nil
}

// checkContainerNodes walks all the "container" nodes defined in the configuration file.
// The edges between the nodes are in place when this function completes.
func (c *Config) checkContainerNodes(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	for _, img := range c.Containers {
		w, err := c.newContainerBuilder(img, helper)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(img.Tag, true); err != nil {
			return err
		}
		node := newNodeImpl(img.Tag, w)
		c.nameToNode[img.Tag] = node
	}
	//make a pass adding edges
	for _, img := range c.Containers {
		dest := c.nameToNode[img.Tag]
		work := dest.implementation().(*containerBuilder)
		for _, source := range img.DependsOn {
			node_source, ok := c.nameToNode[source]
			if !ok {
				return fmt.Errorf("image %s depends on %s, but %s not found",
					img.Tag, source, source)
			}
			node_source.addOut(dest)
			work.inEdges = append(work.inEdges, node_source)
		}
	}
	return nil
}

// checkGoBuildNodes verifies all the "go build" nodes in this pickett file.  Note that
// this should not be called until after the checkSourceNodes() have been
// extracted as it needs data structures built at that stage.
func (c *Config) checkGoBuildNodes(pickett_io.Helper, pickett_io.DockerCli) error {
	for _, build := range c.GoBuilds {
		w, err := c.newGoBuilder(build)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(build.Tag, true); err != nil {
			return err
		}
		r, found := c.nameToNode[build.RunIn]
		if !found {
			return fmt.Errorf("Unable to find %s trying to build %s: maybe you need to 'docker pull' it?",
				build.RunIn, build.Tag)
		}

		//add edges
		w.runIn = r
		node := newNodeImpl(build.Tag, w)
		r.addOut(node)
		c.nameToNode[build.Tag] = node
	}
	return nil
}

//check to see if a given image exists, it could be something we are going to construct
//it might just be in the docker cache or the docker repo
func (c *Config) tagExists(tag string, cli pickett_io.DockerCli) bool {
	_, ok := c.nameToNode[strings.Trim(tag, " \n")]
	if ok {
		return true
	}
	_, err := cli.DecodeInspect(strings.Trim(tag, " \n"))
	return err == nil
}

// checkExtractionNodes verifies all the "extract" nodes in the pickett file.  Note that
// this should not be called until after the checkContainerNodes() and checkGoBuildNodes() have been
// extracted their parts, as it needs data structures built in these functions
// (notably dependencies).
func (c *Config) checkExtractionNodes(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	for _, build := range c.Extractions {
		w, err := c.newExtractionBuilder(build)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(build.Tag, true); err != nil {
			return err
		}
		if !c.tagExists(build.RunIn, cli) {
			return fmt.Errorf("Unable to find '%s' (RunIn) trying to setup for artifact build  '%s': maybe you need to 'docker pull' it?",
				build.RunIn, build.Tag)
		}
		r, found := c.nameToNode[build.RunIn]
		var in nodeOrName
		in.name = build.RunIn
		if found {
			in.isNode = true
			in.node = r
		}
		w.runIn = in

		if !c.tagExists(build.MergeWith, cli) {
			return fmt.Errorf("Unable to find '%s' (MergeWith) trying to setup for artifact '%s': maybe you need to 'docker pull' it?",
				build.MergeWith, build.Tag)
		}
		m, found := c.nameToNode[build.MergeWith]
		var merge nodeOrName
		merge.name = build.MergeWith
		if found {
			merge.isNode = true
			merge.node = m
		}
		//
		// handle dependency edges
		//
		_, ok := r.implementation().(*goBuilder)
		if w.runIn.isNode == false || !ok {
			return fmt.Errorf("Unable to create %s, right now artifacts must be derived from GoBuild nodes (%s is not GoBuild)",
				build.Tag, r.name())
		}
		node := newNodeImpl(build.Tag, w)
		if w.runIn.isNode {
			r.addOut(node)
		}
		if w.mergeWith.isNode {
			m.addOut(node)
		}
		c.nameToNode[strings.Trim(build.Tag, " \n")] = node
	}
	return nil
}

func contains(list []string, candidate string) bool {
	for _, s := range list {
		if candidate == s {
			return true
		}
	}
	return false
}

//checkNetworks verifies all the network setups in this configuration file.
func (c *Config) checkNetworks(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	commiters := make(map[string]*outcomeProxyBuilder)
	//first pass is to establish all the names and do things that don't involve
	//complex deps
	for _, n := range c.Networks {
		if err := c.checkExistingName(n.Name, false); err != nil {
			return err
		}
		w, err := c.newNetworkRunner(n)
		if err != nil {
			return err
		}
		trimmedIn := strings.Trim(n.RunIn, " \n")
		other, ok := c.nameToNode[trimmedIn]
		var in nodeOrName
		in.name = trimmedIn
		if ok {
			in.node = other
			in.isNode = true
		}
		w.runIn = in
		c.nameToNetwork[strings.Trim(n.Name, " \n")] = w
		for input, result := range n.CommitOnExit {
			i := strings.Trim(input, " \n")
			if !contains(n.Consumes, i) {
				return fmt.Errorf("can't commit input %s in '%s' because it's not consumed",
					i, w.name())
			}
			p := &outcomeProxyBuilder{
				net:         w,
				inputName:   i,
				imageResult: result,
			}
			//leave a breadcrump
			commiters[i] = p
			//put in list of nodes
			c.nameToNode[result] = newNodeImpl(result, p)
		}
	}

	//second pass is to introduce edges
	for _, net := range c.Networks {
		r := c.nameToNetwork[strings.Trim(net.Name, " \n")]
		n := r.(*networkRunner)

		//can't do this check until second pass
		if !c.tagExists(net.RunIn, cli) {
			return fmt.Errorf("unable to find image '%s' to run (network) %s in!", net.RunIn, net.Name)
		}

		for _, in := range net.Consumes {
			other, ok := c.nameToNetwork[in]
			if !ok {
				return fmt.Errorf("can't find other network node named %s for %s", in, n.name())
			}
			n.consumes = append(n.consumes, other)
			p, ok := commiters[n.name()]
			if ok {
				p.inputRunner = other
			}
		}
	}

	return nil
}

var policyChoices = []string{
	"BY_HAND", "KEEP_UP", "CONTINUE", "FRESH", "ALWAYS",
}

//newNetworkRunner creates a new networkRunner node from the data supplied. It can fail if
//the config file is bogus; this ignores the issue of dependencies.
func (c *Config) newNetworkRunner(n *Network) (*networkRunner, error) {
	result := &networkRunner{
		n:      n.Name,
		expose: n.Expose,
	}
	foundit := false
	pol := defaultPolicy()
	for _, named := range policyChoices {
		if strings.ToUpper(n.Policy) == named {
			switch named {
			case "BY_HAND":
				pol.startIfNonExistant = false
				pol.stop = NEVER
				pol.rebuildIfOOD = false
			case "KEEP_UP":
				pol.stop = NEVER
			case "CONTINUE":
				pol.stop = NEVER
				pol.start = CONTINUE
			case "FRESH":
				//nothing to do, its all defaults
			case "ALWAYS":
				pol.stop = ALWAYS
			}
			foundit = true
			break
		}
	}
	//we allow an empty string to mean FRESH
	if !foundit {
		if n.Policy != "" {
			return nil, fmt.Errorf("unknown policy %s chosen for %s", n.Policy, n.Name)
		}
	}
	result.policy = pol

	//copy entry point if provided
	result.entry = n.EntryPoint
	return result, nil
}

// newContainerBuilder returns a containerBuilder from the configuration information
// provided in the pickett file.  Note that this does some sanity checking of
// the provided directory so this can fail.  It uses the path to the
// Pickett.json file to construct paths such that the directory is relative
// to the place where the Pickett.json is located.  This ignores the issue
// of edges.
func (c *Config) newContainerBuilder(src *Container, helper pickett_io.Helper) (*containerBuilder, error) {
	node := &containerBuilder{
		tag: src.Tag,
		dir: src.Directory,
	}
	_, err := helper.OpenDockerfileRelative(src.Directory)
	if err != nil {
		return nil, fmt.Errorf("looked for %s/Dockerfile: %v",
			helper.DirectoryRelative(src.Directory), err)
	}
	return node, nil
}

// newGoBuilder returns a goBuilder from the configuration information
// provided in the pickett file. This sanity checks the config file, so it can
// fail.  It ignores dependency edges.
func (c *Config) newGoBuilder(build *GoBuild) (*goBuilder, error) {
	result := &goBuilder{
		tag: build.Tag,
	}
	if len(build.Packages) == 0 {
		return nil, fmt.Errorf("you must define at least one source package for a go build")
	}
	result.pkgs = build.Packages
	if build.Command != "" {
		result.command = build.Command
	} else {
		result.command = "go install"
	}
	if build.TestFile != "" {
		result.testFile = build.TestFile
	}
	if build.Probe != "" {
		result.probe = build.Probe
	} else {
		result.probe = "go install -n"
	}
	return result, nil
}

// newExtractionBuilder returns a worker from the configuration information
// provided in the pickett file. This sanity checks the config file, so it can
// fail. It ignores dependency edges.
func (c *Config) newExtractionBuilder(build *Extraction) (*extractionBuilder, error) {
	if len(build.Artifacts) == 0 {
		return nil, fmt.Errorf("%s must define at least one artifact", build.Tag)
	}
	art := make(map[string]string)
	for k, v := range build.Artifacts {
		s, ok := v.(string)
		if !ok {
			return nil, fmt.Errorf("%v must be a string (in artifacts of %s)!", v, build.Tag)
		}
		art[k] = s
	}
	worker := &extractionBuilder{
		artifacts: art,
		tag:       build.Tag,
	}
	return worker, nil
}
<commit_msg>Refactor policy parsing<commit_after>package pickett

import (
	"fmt"
	"strings"

	pickett_io "github.com/igneous-systems/pickett/io"
)

//checkExistingNames is a helper to generate an error if the name is already
//in use in this configuration.  Pass true if you are interested in build nodes,
//false for networks.
func (c *Config) checkExistingName(proposed string, wantNode bool) error {
	p := strings.Trim(proposed, " \n")
	if p == "" {
		return fmt.Errorf("can't have an empty name in configuration file")
	}
	if wantNode {
		if c.nameToNode[p] != nil {
			return fmt.Errorf("name %s already in use in this configuration (build node)", p)
		}
	}
	if c.nameToNetwork[p] != nil {
		return fmt.Errorf("network name %s already in use in this configuration", p)
	}
	return nil
}

// checkContainerNodes walks all the "container" nodes defined in the configuration file.
// The edges between the nodes are in place when this function completes.
func (c *Config) checkContainerNodes(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	for _, img := range c.Containers {
		w, err := c.newContainerBuilder(img, helper)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(img.Tag, true); err != nil {
			return err
		}
		node := newNodeImpl(img.Tag, w)
		c.nameToNode[img.Tag] = node
	}
	//make a pass adding edges
	for _, img := range c.Containers {
		dest := c.nameToNode[img.Tag]
		work := dest.implementation().(*containerBuilder)
		for _, source := range img.DependsOn {
			node_source, ok := c.nameToNode[source]
			if !ok {
				return fmt.Errorf("image %s depends on %s, but %s not found",
					img.Tag, source, source)
			}
			node_source.addOut(dest)
			work.inEdges = append(work.inEdges, node_source)
		}
	}
	return nil
}

// checkGoBuildNodes verifies all the "go build" nodes in this pickett file.  Note that
// this should not be called until after the checkSourceNodes() have been
// extracted as it needs data structures built at that stage.
func (c *Config) checkGoBuildNodes(pickett_io.Helper, pickett_io.DockerCli) error {
	for _, build := range c.GoBuilds {
		w, err := c.newGoBuilder(build)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(build.Tag, true); err != nil {
			return err
		}
		r, found := c.nameToNode[build.RunIn]
		if !found {
			return fmt.Errorf("Unable to find %s trying to build %s: maybe you need to 'docker pull' it?",
				build.RunIn, build.Tag)
		}

		//add edges
		w.runIn = r
		node := newNodeImpl(build.Tag, w)
		r.addOut(node)
		c.nameToNode[build.Tag] = node
	}
	return nil
}

//check to see if a given image exists, it could be something we are going to construct
//it might just be in the docker cache or the docker repo
func (c *Config) tagExists(tag string, cli pickett_io.DockerCli) bool {
	_, ok := c.nameToNode[strings.Trim(tag, " \n")]
	if ok {
		return true
	}
	_, err := cli.DecodeInspect(strings.Trim(tag, " \n"))
	return err == nil
}

// checkExtractionNodes verifies all the "extract" nodes in the pickett file.  Note that
// this should not be called until after the checkContainerNodes() and checkGoBuildNodes() have been
// extracted their parts, as it needs data structures built in these functions
// (notably dependencies).
func (c *Config) checkExtractionNodes(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	for _, build := range c.Extractions {
		w, err := c.newExtractionBuilder(build)
		if err != nil {
			return err
		}
		if err := c.checkExistingName(build.Tag, true); err != nil {
			return err
		}
		if !c.tagExists(build.RunIn, cli) {
			return fmt.Errorf("Unable to find '%s' (RunIn) trying to setup for artifact build  '%s': maybe you need to 'docker pull' it?",
				build.RunIn, build.Tag)
		}
		r, found := c.nameToNode[build.RunIn]
		var in nodeOrName
		in.name = build.RunIn
		if found {
			in.isNode = true
			in.node = r
		}
		w.runIn = in

		if !c.tagExists(build.MergeWith, cli) {
			return fmt.Errorf("Unable to find '%s' (MergeWith) trying to setup for artifact '%s': maybe you need to 'docker pull' it?",
				build.MergeWith, build.Tag)
		}
		m, found := c.nameToNode[build.MergeWith]
		var merge nodeOrName
		merge.name = build.MergeWith
		if found {
			merge.isNode = true
			merge.node = m
		}
		//
		// handle dependency edges
		//
		_, ok := r.implementation().(*goBuilder)
		if w.runIn.isNode == false || !ok {
			return fmt.Errorf("Unable to create %s, right now artifacts must be derived from GoBuild nodes (%s is not GoBuild)",
				build.Tag, r.name())
		}
		node := newNodeImpl(build.Tag, w)
		if w.runIn.isNode {
			r.addOut(node)
		}
		if w.mergeWith.isNode {
			m.addOut(node)
		}
		c.nameToNode[strings.Trim(build.Tag, " \n")] = node
	}
	return nil
}

func contains(list []string, candidate string) bool {
	for _, s := range list {
		if candidate == s {
			return true
		}
	}
	return false
}

//checkNetworks verifies all the network setups in this configuration file.
func (c *Config) checkNetworks(helper pickett_io.Helper, cli pickett_io.DockerCli) error {
	commiters := make(map[string]*outcomeProxyBuilder)
	//first pass is to establish all the names and do things that don't involve
	//complex deps
	for _, n := range c.Networks {
		if err := c.checkExistingName(n.Name, false); err != nil {
			return err
		}
		w, err := c.newNetworkRunner(n)
		if err != nil {
			return err
		}
		trimmedIn := strings.Trim(n.RunIn, " \n")
		other, ok := c.nameToNode[trimmedIn]
		var in nodeOrName
		in.name = trimmedIn
		if ok {
			in.node = other
			in.isNode = true
		}
		w.runIn = in
		c.nameToNetwork[strings.Trim(n.Name, " \n")] = w
		for input, result := range n.CommitOnExit {
			i := strings.Trim(input, " \n")
			if !contains(n.Consumes, i) {
				return fmt.Errorf("can't commit input %s in '%s' because it's not consumed",
					i, w.name())
			}
			p := &outcomeProxyBuilder{
				net:         w,
				inputName:   i,
				imageResult: result,
			}
			//leave a breadcrump
			commiters[i] = p
			//put in list of nodes
			c.nameToNode[result] = newNodeImpl(result, p)
		}
	}

	//second pass is to introduce edges
	for _, net := range c.Networks {
		r := c.nameToNetwork[strings.Trim(net.Name, " \n")]
		n := r.(*networkRunner)

		//can't do this check until second pass
		if !c.tagExists(net.RunIn, cli) {
			return fmt.Errorf("unable to find image '%s' to run (network) %s in!", net.RunIn, net.Name)
		}

		for _, in := range net.Consumes {
			other, ok := c.nameToNetwork[in]
			if !ok {
				return fmt.Errorf("can't find other network node named %s for %s", in, n.name())
			}
			n.consumes = append(n.consumes, other)
			p, ok := commiters[n.name()]
			if ok {
				p.inputRunner = other
			}
		}
	}

	return nil
}

//newNetworkRunner creates a new networkRunner node from the data supplied. It can fail if
//the config file is bogus; this ignores the issue of dependencies.
func (c *Config) newNetworkRunner(n *Network) (*networkRunner, error) {
	result := &networkRunner{
		n:      n.Name,
		expose: n.Expose,
	}
	pol := defaultPolicy()
	switch strings.ToUpper(n.Policy) {
	case "BY_HAND":
		pol.startIfNonExistant = false
		pol.stop = NEVER
		pol.rebuildIfOOD = false
	case "KEEP_UP":
		pol.stop = NEVER
	case "CONTINUE":
		pol.stop = NEVER
		pol.start = CONTINUE
	case "FRESH", "": //we allow an empty string to mean FRESH
		//nothing to do, its all defaults
	case "ALWAYS":
		pol.stop = ALWAYS
	default:
		return nil, fmt.Errorf("unknown policy %s chosen for %s", n.Policy, n.Name)
	}
	result.policy = pol

	//copy entry point if provided
	result.entry = n.EntryPoint
	return result, nil
}

// newContainerBuilder returns a containerBuilder from the configuration information
// provided in the pickett file.  Note that this does some sanity checking of
// the provided directory so this can fail.  It uses the path to the
// Pickett.json file to construct paths such that the directory is relative
// to the place where the Pickett.json is located.  This ignores the issue
// of edges.
func (c *Config) newContainerBuilder(src *Container, helper pickett_io.Helper) (*containerBuilder, error) {
	node := &containerBuilder{
		tag: src.Tag,
		dir: src.Directory,
	}
	_, err := helper.OpenDockerfileRelative(src.Directory)
	if err != nil {
		return nil, fmt.Errorf("looked for %s/Dockerfile: %v",
			helper.DirectoryRelative(src.Directory), err)
	}
	return node, nil
}

// newGoBuilder returns a goBuilder from the configuration information
// provided in the pickett file. This sanity checks the config file, so it can
// fail.  It ignores dependency edges.
func (c *Config) newGoBuilder(build *GoBuild) (*goBuilder, error) {
	result := &goBuilder{
		tag: build.Tag,
	}
	if len(build.Packages) == 0 {
		return nil, fmt.Errorf("you must define at least one source package for a go build")
	}
	result.pkgs = build.Packages
	if build.Command != "" {
		result.command = build.Command
	} else {
		result.command = "go install"
	}
	if build.TestFile != "" {
		result.testFile = build.TestFile
	}
	if build.Probe != "" {
		result.probe = build.Probe
	} else {
		result.probe = "go install -n"
	}
	return result, nil
}

// newExtractionBuilder returns a worker from the configuration information
// provided in the pickett file. This sanity checks the config file, so it can
// fail. It ignores dependency edges.
func (c *Config) newExtractionBuilder(build *Extraction) (*extractionBuilder, error) {
	if len(build.Artifacts) == 0 {
		return nil, fmt.Errorf("%s must define at least one artifact", build.Tag)
	}
	art := make(map[string]string)
	for k, v := range build.Artifacts {
		s, ok := v.(string)
		if !ok {
			return nil, fmt.Errorf("%v must be a string (in artifacts of %s)!", v, build.Tag)
		}
		art[k] = s
	}
	worker := &extractionBuilder{
		artifacts: art,
		tag:       build.Tag,
	}
	return worker, nil
}
<|endoftext|>


<commit_before>package utils

import (
	"log"
	"os"
)

type LogLevel int

const (
	LEVEL_TRACE LogLevel = iota
	LEVEL_DEBUG
	LEVEL_INFO
	LEVEL_WARN
	LEVEL_ERROR
	LEVEL_OFF
)

type Logger struct {
	*log.Logger

	Level  LogLevel
	Output *os.File
}

func NewLogger(f string, l LogLevel) *Logger {
	file, err := os.OpenFile(f, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}

	logger := &Logger{Output: file, Level: l}
	logger.Logger = log.New(file, "", log.Ldate|log.Ltime)

	return logger
}

func NewLoggerFromConfig() *Logger {
	props := make(map[string]string)
	err := LoadConfig("logging.cfg", props)
	if err != nil {
		log.Fatalf("Error loading config: %v", err)
	}

	var level LogLevel
	switch props["level"] {
	case "TRACE", "trace":
		level = LEVEL_TRACE
	case "DEBUG", "debug":
		level = LEVEL_DEBUG
	case "INFO", "info":
		level = LEVEL_INFO
	case "WARN", "warn":
		level = LEVEL_WARN
	case "ERROR", "error":
		level = LEVEL_ERROR
	case "OFF", "off":
		level = LEVEL_ERROR
	default:
		log.Fatalf("Error loading config: %s is not a valid level", props["level"])
	}

	return NewLogger(props["file"], level)
}

func (logger *Logger) Close() {
	err := logger.Output.Close()
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
}

func (logger *Logger) Trace(v ...interface{}) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println(append([]interface{}{"TRACE:"}, v...)...)
	}
}

func (logger *Logger) Tracef(format string, v ...interface{}) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Printf("TRACE: "+format+"\n", v...)
	}
}

func (logger *Logger) TraceBegin(f string) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println("TRACE: Begin -", f)
	}
}

func (logger *Logger) TraceEnd(f string) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println("TRACE: End -", f)
	}
}

func (logger *Logger) Debug(v ...interface{}) {
	if logger.Level <= LEVEL_DEBUG {
		logger.Logger.Println(append([]interface{}{"DEBUG:"}, v...)...)
	}
}

func (logger *Logger) Debugf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_DEBUG {
		logger.Logger.Printf("DEBUG: "+format+"\n", v...)
	}
}

func (logger *Logger) Info(v ...interface{}) {
	if logger.Level <= LEVEL_INFO {
		logger.Logger.Println(append([]interface{}{"INFO:"}, v...)...)
	}
}

func (logger *Logger) Infof(format string, v ...interface{}) {
	if logger.Level <= LEVEL_INFO {
		logger.Logger.Printf("INFO: "+format+"\n", v...)
	}
}

func (logger *Logger) Warn(v ...interface{}) {
	if logger.Level <= LEVEL_WARN {
		logger.Logger.Println(append([]interface{}{"WARN:"}, v...)...)
	}
}

func (logger *Logger) Warnf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_WARN {
		logger.Logger.Printf("WARN: "+format+"\n", v...)
	}
}

func (logger *Logger) Error(v ...interface{}) {
	if logger.Level <= LEVEL_ERROR {
		logger.Logger.Println(append([]interface{}{"ERROR:"}, v...)...)
	}
}

func (logger *Logger) Errorf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_ERROR {
		logger.Logger.Printf("ERROR: "+format+"\n", v...)
	}
}

func (logger *Logger) Fatal(v ...interface{}) {
	logger.Logger.Println(append([]interface{}{"FATAL:"}, v...)...)
}

func (logger *Logger) Fatalf(format string, v ...interface{}) {
	logger.Logger.Fatalf("FATAL: "+format+"\n", v...)
}
<commit_msg>Fix Fatal to use Fatalln instead of Println<commit_after>package utils

import (
	"log"
	"os"
)

type LogLevel int

const (
	LEVEL_TRACE LogLevel = iota
	LEVEL_DEBUG
	LEVEL_INFO
	LEVEL_WARN
	LEVEL_ERROR
	LEVEL_OFF
)

type Logger struct {
	*log.Logger

	Level  LogLevel
	Output *os.File
}

func NewLogger(f string, l LogLevel) *Logger {
	file, err := os.OpenFile(f, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}

	logger := &Logger{Output: file, Level: l}
	logger.Logger = log.New(file, "", log.Ldate|log.Ltime)

	return logger
}

func NewLoggerFromConfig() *Logger {
	props := make(map[string]string)
	err := LoadConfig("logging.cfg", props)
	if err != nil {
		log.Fatalf("Error loading config: %v", err)
	}

	var level LogLevel
	switch props["level"] {
	case "TRACE", "trace":
		level = LEVEL_TRACE
	case "DEBUG", "debug":
		level = LEVEL_DEBUG
	case "INFO", "info":
		level = LEVEL_INFO
	case "WARN", "warn":
		level = LEVEL_WARN
	case "ERROR", "error":
		level = LEVEL_ERROR
	case "OFF", "off":
		level = LEVEL_ERROR
	default:
		log.Fatalf("Error loading config: %s is not a valid level", props["level"])
	}

	return NewLogger(props["file"], level)
}

func (logger *Logger) Close() {
	err := logger.Output.Close()
	if err != nil {
		log.Fatalf("Error opening file: %v", err)
	}
}

func (logger *Logger) Trace(v ...interface{}) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println(append([]interface{}{"TRACE:"}, v...)...)
	}
}

func (logger *Logger) Tracef(format string, v ...interface{}) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Printf("TRACE: "+format+"\n", v...)
	}
}

func (logger *Logger) TraceBegin(f string) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println("TRACE: Begin -", f)
	}
}

func (logger *Logger) TraceEnd(f string) {
	if logger.Level <= LEVEL_TRACE {
		logger.Logger.Println("TRACE: End -", f)
	}
}

func (logger *Logger) Debug(v ...interface{}) {
	if logger.Level <= LEVEL_DEBUG {
		logger.Logger.Println(append([]interface{}{"DEBUG:"}, v...)...)
	}
}

func (logger *Logger) Debugf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_DEBUG {
		logger.Logger.Printf("DEBUG: "+format+"\n", v...)
	}
}

func (logger *Logger) Info(v ...interface{}) {
	if logger.Level <= LEVEL_INFO {
		logger.Logger.Println(append([]interface{}{"INFO:"}, v...)...)
	}
}

func (logger *Logger) Infof(format string, v ...interface{}) {
	if logger.Level <= LEVEL_INFO {
		logger.Logger.Printf("INFO: "+format+"\n", v...)
	}
}

func (logger *Logger) Warn(v ...interface{}) {
	if logger.Level <= LEVEL_WARN {
		logger.Logger.Println(append([]interface{}{"WARN:"}, v...)...)
	}
}

func (logger *Logger) Warnf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_WARN {
		logger.Logger.Printf("WARN: "+format+"\n", v...)
	}
}

func (logger *Logger) Error(v ...interface{}) {
	if logger.Level <= LEVEL_ERROR {
		logger.Logger.Println(append([]interface{}{"ERROR:"}, v...)...)
	}
}

func (logger *Logger) Errorf(format string, v ...interface{}) {
	if logger.Level <= LEVEL_ERROR {
		logger.Logger.Printf("ERROR: "+format+"\n", v...)
	}
}

func (logger *Logger) Fatal(v ...interface{}) {
	logger.Logger.Fatalln(append([]interface{}{"FATAL:"}, v...)...)
}

func (logger *Logger) Fatalf(format string, v ...interface{}) {
	logger.Logger.Fatalf("FATAL: "+format+"\n", v...)
}
<|endoftext|>


<commit_before>package logger

import (
	"fmt"
	"log"
	"os"
	"path"

	"github.com/mgutz/ansi"
)

const (
	_ = iota
	levelError
	levelWarning
	levelNotice
	levelInfo
	levelDebug

	defaultLevel string = "info"
)

var (
	logger   *log.Logger
	logLevel int

	levelLabels map[int]string
	levelSuffix string

	levelMap = map[string]int{
		"error":   levelError,
		"warning": levelWarning,
		"notice":  levelNotice,
		"info":    levelInfo,
		"debug":   levelDebug,
	}
)

// Init initializes the logging system output path and level.
func Init(logPath, level string) error {
	var (
		logOut *os.File
		ok     bool
		err    error
	)

	// Set default log level if none provided
	if level == "" {
		level = defaultLevel
	}

	logLevel, ok = levelMap[level]
	if !ok {
		return ErrInvalidLevel
	}

	if logPath != "" && logPath != "-" {
		ansi.DisableColors(true)
		levelSuffix = ":"

		// Create parent folders if needed
		dirPath, _ := path.Split(logPath)

		err = os.MkdirAll(dirPath, 0755)
		if err != nil {
			return err
		}

		// Open logging output file
		logOut, err = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			return fmt.Errorf("unable to open log file: %s", err)
		}
		defer logOut.Close()
	} else {
		// Set logging output to 'stderr' and activate color
		logOut = os.Stderr
	}

	logger = log.New(logOut, "", log.LstdFlags|log.Lmicroseconds)

	// Set level labels
	levelLabels = map[int]string{
		levelError:   ansi.Color("ERROR", "red"),
		levelWarning: ansi.Color("WARNING", "yellow"),
		levelNotice:  ansi.Color("NOTICE", "magenta"),
		levelInfo:    ansi.Color("INFO", "blue"),
		levelDebug:   ansi.Color("DEBUG", "cyan"),
	}

	return nil
}

// Logger returns the current logger instance.
func Logger() *log.Logger {
	return logger
}

// Error prints an error message in the logging system.
func Error(context, format string, v ...interface{}) {
	printLog(levelError, context, format, v...)
}

// Warning prints a warning message in the logging system.
func Warning(context, format string, v ...interface{}) {
	printLog(levelWarning, context, format, v...)
}

// Notice prints a notice message in the logging system.
func Notice(context, format string, v ...interface{}) {
	printLog(levelNotice, context, format, v...)
}

// Info prints an information message in the logging system.
func Info(context, format string, v ...interface{}) {
	printLog(levelInfo, context, format, v...)
}

// Debug prints a debug message in the logging system.
func Debug(context, format string, v ...interface{}) {
	printLog(levelDebug, context, format, v...)
}

// printLog prints a message in the logging system.
func printLog(level int, context, format string, v ...interface{}) {
	if level > logLevel {
		return
	}

	logger.Printf("%s%s %s: %s", levelLabels[level], levelSuffix, context, fmt.Sprintf(format, v...))
}
<commit_msg>Refactor package<commit_after>// Package logger is a simple wrapper around log.Logger with usual logging levels "error", "warning", "notice",
// "info" and "debug".
package logger

import (
	"fmt"
	"log"
	"os"
	"path"

	"github.com/mgutz/ansi"
)

// Logger represents a logger instance.
type Logger struct {
	logger  *log.Logger
	level   int
	context string
	out     *os.File
}

const (
	_ = iota
	levelError
	levelWarning
	levelNotice
	levelInfo
	levelDebug

	defaultLevel = "info"
)

var (
	levelLabels map[int]string
	levelMap    = map[string]int{
		"error":   levelError,
		"warning": levelWarning,
		"notice":  levelNotice,
		"info":    levelInfo,
		"debug":   levelDebug,
	}
)

// NewLogger returns a new Logger instance initialized with the logging system output path and level. If logPath is
// either empty or "-", logging will be output to os.Stderr. Log messages with severity higher than level will be
// discarded.
func NewLogger(logPath, level string) (*Logger, error) {
	var (
		err error
		ok  bool
	)

	logger := &Logger{level: levelMap[defaultLevel]}

	if logger.level, ok = levelMap[level]; !ok {
		return nil, ErrInvalidLevel
	}

	if logPath != "" && logPath != "-" {
		// Set logging output to a file
		ansi.DisableColors(true)

		// Create parent folders if needed
		dirPath, _ := path.Split(logPath)

		if err = os.MkdirAll(dirPath, 0755); err != nil {
			return nil, err
		}

		if logger.out, err = os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
			return nil, err
		}
	} else {
		// Set logging output to stderr
		logger.out = os.Stderr
	}

	levelLabels = map[int]string{
		levelError:   ansi.Color("ERROR", "red"),
		levelWarning: ansi.Color("WARNING", "yellow"),
		levelNotice:  ansi.Color("NOTICE", "magenta"),
		levelInfo:    ansi.Color("INFO", "blue"),
		levelDebug:   ansi.Color("DEBUG", "cyan"),
	}

	logger.logger = log.New(logger.out, "", log.LstdFlags|log.Lmicroseconds)

	return logger, nil
}

// Logger returns the underlying log.Logger instance.
func (l *Logger) Logger() *log.Logger {
	return l.logger
}

// Context clones the Logger instance and sets the context to the provided string.
func (l *Logger) Context(context string) *Logger {
	logger := *l
	logger.context = context
	return &logger
}

// Error prints an error message in the logging system.
func (l *Logger) Error(format string, v ...interface{}) *Logger {
	return l.print(levelError, format, v...)
}

// Warning prints a warning message in the logging system.
func (l *Logger) Warning(format string, v ...interface{}) *Logger {
	return l.print(levelWarning, format, v...)
}

// Notice prints a notice message in the logging system.
func (l *Logger) Notice(format string, v ...interface{}) *Logger {
	return l.print(levelNotice, format, v...)
}

// Info prints an information message in the logging system.
func (l *Logger) Info(format string, v ...interface{}) *Logger {
	return l.print(levelInfo, format, v...)
}

// Debug prints a debug message in the logging system.
func (l *Logger) Debug(format string, v ...interface{}) *Logger {
	return l.print(levelDebug, format, v...)
}

// Close closes the logger output file.
func (l *Logger) Close() error {
	if l.out != nil {
		return l.out.Close()
	}

	return nil
}

func (l *Logger) print(level int, format string, v ...interface{}) *Logger {
	if level > l.level {
		return l
	}

	if l.context != "" {
		l.logger.Printf(
			"%s: %s",
			fmt.Sprintf("%s: %s", levelLabels[level], l.context),
			fmt.Sprintf(format, v...),
		)
	} else {
		l.logger.Printf("%s: %s", levelLabels[level], fmt.Sprintf(format, v...))
	}

	return l
}
<|endoftext|>


<commit_before>package events

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"time"
	"unsafe"
)

// DefaultLogger is the default logger used by the Log function. This may be
// overwritten by the program to change the default route for log events.
var DefaultLogger = Logger{
	Handler:     Discard,
	EnablePC:    true,
	EnableDebug: true,
}

// Log emits a log event to the default logger.
func Log(format string, args ...interface{}) {
	DefaultLogger.log(1, format, args...)
}

// Debug emits a debug event to the default logger.
func Debug(format string, args ...interface{}) {
	DefaultLogger.debug(1, format, args...)
}

// A Logger is a wrapper around an event handler which exposes a Log method for
// formatting event messages before sending them to the handler.
//
// The format supported by the Log method is a superset of the fmt-style format,
// where the 'verbs' may include a column-surrounded value representing the name
// of the matching argument.
//
// The Log method also makes a special case when it gets an events.Args as last
// argument, it doesn't use it to format the message and instead simply append
// it to the event's argument list.
//
// Here's an example with the defalut logger:
//
//	events.Log("Hello %:name:!", "Luke", events.Args{
//		{"from", "Han"},
//	})
//
// Which produces an event that looks like this:
//
//	events.Event{
//		Message: "Hello Luke!",
//		Args:    events.Args{{"name", "Luke"}, {"from", "Han"}},
//		...
//	}
//
// Logger instances are safe to use concurrently from multiple goroutines.
type Logger struct {
	// Handler is the event handler receiving events from the logger.
	Handler Handler

	// Args is a list of arguments that get automatically injected into every
	// events produced by the logger.
	Args Args

	// CallDepth is used to adjust which caller the logger should report its
	// events are coming from.
	// Leaving to zero means reporting the direct caller of the logger's
	// methods.
	CallDepth int

	// EnablePC controls whether the logger should report the program counter
	// address of its caller on the events it produces.
	// This has a significant impact on the performance of the logger's Log and
	// Debug method but also provides very important insights, be mindful about
	// turning it on or off.
	EnablePC bool

	// EnableDebug controls whether calls to Debug produces events.
	EnableDebug bool
}

// Log formats an event and sends it to the logger's handler.
func (l *Logger) Log(format string, args ...interface{}) {
	l.log(1, format, args...)
}

func (l *Logger) log(depth int, format string, args ...interface{}) {
	var s = logPool.Get().(*logState)
	var a Args
	var pc [1]uintptr

	if l.EnablePC {
		runtime.Callers(l.CallDepth+depth+2, pc[:])
	}

	if n := len(args); n != 0 {
		if s, ok := args[n-1].(Args); ok {
			a, args = s, args[:n-1]
		}
	}

	s.Args = append(s.Args, l.Args...)
	s.fmt, s.Args = appendFormat(s.fmt, s.Args, format, args)
	s.Args = append(s.Args, a...)

	fmt.Fprintf(s, string(s.fmt), args...)

	if len(s.buf) != 0 {
		s.Message = *(*string)(unsafe.Pointer(&reflect.StringHeader{
			Data: uintptr(unsafe.Pointer(&s.buf[0])),
			Len:  len(s.buf),
		}))
	}

	s.Debug = l.EnableDebug
	s.PC = pc[0]
	s.Time = time.Now()
	l.Handler.HandleEvent(&s.Event)

	s.Message = ""
	s.Args = s.Args[:0]
	s.fmt = s.fmt[:0]
	s.buf = s.buf[:0]

	logPool.Put(s)
	return

}

// Debug is like Log but only produces events if the logger has debugging
// enabled.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.debug(1, format, args...)
}

func (l *Logger) debug(depth int, format string, args ...interface{}) {
	if l.EnableDebug {
		l.log(depth+1, format, args...)
	}
}

// With returns a new Logger which is a copy of l augmented with args.
func (l *Logger) With(args Args) *Logger {
	var newArgs Args
	var newLen = len(l.Args) + len(args)

	if newLen != 0 {
		newArgs = make(Args, 0, newLen)
		newArgs = append(newArgs, l.Args...)
		newArgs = append(newArgs, args...)
	}

	return &Logger{
		Args:        newArgs,
		Handler:     l.Handler,
		EnableDebug: l.EnableDebug,
	}
}

// logState is used to build events produced by Logger instances.
type logState struct {
	Event
	fmt []byte
	buf []byte
}

func (s *logState) Write(b []byte) (n int, err error) {
	s.buf = append(s.buf, b...)
	n = len(b)
	return
}

var logPool = sync.Pool{
	New: func() interface{} {
		return &logState{
			Event: Event{
				Args: make(Args, 0, 8),
			},
			fmt: make([]byte, 0, 512),
			buf: make([]byte, 0, 512),
		}
	},
}

func appendFormat(dstFmt []byte, dstArgs Args, srcFmt string, srcArgs []interface{}) ([]byte, Args) {
	for i, n := 0, len(srcFmt); i != n; {
		off := strings.IndexByte(srcFmt[i:], '%')
		if off < 0 {
			dstFmt = append(dstFmt, srcFmt[i:]...)
			break
		}
		off++
		dstFmt = append(dstFmt, srcFmt[i:i+off]...)

		if i += off; i != n && srcFmt[i] == '%' { // escaped '%'
			dstFmt = append(dstFmt, '%')
			i++
			continue
		}

		var key string
		var val interface{}
	fmtLoop:
		for i != n {
			switch c := srcFmt[i]; c {
			default:
				dstFmt = append(dstFmt, c)
				i++
				if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
					break fmtLoop
				}
				continue

			case ':': // extract the argument name from the format string
				if i++; i == n {
					dstFmt = append(dstFmt, ':')
					i = n
					break fmtLoop
				}

				j := strings.IndexByte(srcFmt[i:], ':')
				if j < 0 {
					dstFmt = append(dstFmt, srcFmt[i-1:]...)
					i = n
					break fmtLoop
				}

				key = srcFmt[i : i+j]
				i += j + 1
			}
		}

		if len(srcArgs) == 0 {
			val = missing
		} else {
			val, srcArgs = srcArgs[0], srcArgs[1:]
		}

		dstArgs = append(dstArgs, Arg{key, val})
	}

	return dstFmt, dstArgs
}

var (
	// Prevents Go from doing a memory allocation when there is a missing argument.
	missing interface{} = "MISSING"
)
<commit_msg>[skip ci] update docs<commit_after>package events

import (
	"fmt"
	"reflect"
	"runtime"
	"strings"
	"sync"
	"time"
	"unsafe"
)

// DefaultLogger is the default logger used by the Log function. This may be
// overwritten by the program to change the default route for log events.
var DefaultLogger = Logger{
	Handler:     Discard,
	EnablePC:    true,
	EnableDebug: true,
}

// Log emits a log event to the default logger.
func Log(format string, args ...interface{}) {
	DefaultLogger.log(1, format, args...)
}

// Debug emits a debug event to the default logger.
func Debug(format string, args ...interface{}) {
	DefaultLogger.debug(1, format, args...)
}

// A Logger is a wrapper around an event handler which exposes a Log method for
// formatting event messages before sending them to the handler.
//
// The format supported by the Log method is a superset of the fmt-style format,
// where the 'verbs' may include a column-surrounded value representing the name
// of the matching argument.
//
// The Log method also makes a special case when it gets an events.Args as last
// argument, it doesn't use it to format the message and instead simply append
// it to the event's argument list.
//
// Here's an example with the defalut logger:
//
//	events.Log("Hello %:name:s!", "Luke", events.Args{
//		{"from", "Han"},
//	})
//
// Which produces an event that looks like this:
//
//	events.Event{
//		Message: "Hello Luke!",
//		Args:    events.Args{{"name", "Luke"}, {"from", "Han"}},
//		...
//	}
//
// Logger instances are safe to use concurrently from multiple goroutines.
type Logger struct {
	// Handler is the event handler receiving events from the logger.
	Handler Handler

	// Args is a list of arguments that get automatically injected into every
	// events produced by the logger.
	Args Args

	// CallDepth is used to adjust which caller the logger should report its
	// events are coming from.
	// Leaving to zero means reporting the direct caller of the logger's
	// methods.
	CallDepth int

	// EnablePC controls whether the logger should report the program counter
	// address of its caller on the events it produces.
	// This has a significant impact on the performance of the logger's Log and
	// Debug method but also provides very important insights, be mindful about
	// turning it on or off.
	EnablePC bool

	// EnableDebug controls whether calls to Debug produces events.
	EnableDebug bool
}

// Log formats an event and sends it to the logger's handler.
func (l *Logger) Log(format string, args ...interface{}) {
	l.log(1, format, args...)
}

func (l *Logger) log(depth int, format string, args ...interface{}) {
	var s = logPool.Get().(*logState)
	var a Args
	var pc [1]uintptr

	if l.EnablePC {
		runtime.Callers(l.CallDepth+depth+2, pc[:])
	}

	if n := len(args); n != 0 {
		if s, ok := args[n-1].(Args); ok {
			a, args = s, args[:n-1]
		}
	}

	s.Args = append(s.Args, l.Args...)
	s.fmt, s.Args = appendFormat(s.fmt, s.Args, format, args)
	s.Args = append(s.Args, a...)

	fmt.Fprintf(s, string(s.fmt), args...)

	if len(s.buf) != 0 {
		s.Message = *(*string)(unsafe.Pointer(&reflect.StringHeader{
			Data: uintptr(unsafe.Pointer(&s.buf[0])),
			Len:  len(s.buf),
		}))
	}

	s.Debug = l.EnableDebug
	s.PC = pc[0]
	s.Time = time.Now()
	l.Handler.HandleEvent(&s.Event)

	s.Message = ""
	s.Args = s.Args[:0]
	s.fmt = s.fmt[:0]
	s.buf = s.buf[:0]

	logPool.Put(s)
	return

}

// Debug is like Log but only produces events if the logger has debugging
// enabled.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.debug(1, format, args...)
}

func (l *Logger) debug(depth int, format string, args ...interface{}) {
	if l.EnableDebug {
		l.log(depth+1, format, args...)
	}
}

// With returns a new Logger which is a copy of l augmented with args.
func (l *Logger) With(args Args) *Logger {
	var newArgs Args
	var newLen = len(l.Args) + len(args)

	if newLen != 0 {
		newArgs = make(Args, 0, newLen)
		newArgs = append(newArgs, l.Args...)
		newArgs = append(newArgs, args...)
	}

	return &Logger{
		Args:        newArgs,
		Handler:     l.Handler,
		EnableDebug: l.EnableDebug,
	}
}

// logState is used to build events produced by Logger instances.
type logState struct {
	Event
	fmt []byte
	buf []byte
}

func (s *logState) Write(b []byte) (n int, err error) {
	s.buf = append(s.buf, b...)
	n = len(b)
	return
}

var logPool = sync.Pool{
	New: func() interface{} {
		return &logState{
			Event: Event{
				Args: make(Args, 0, 8),
			},
			fmt: make([]byte, 0, 512),
			buf: make([]byte, 0, 512),
		}
	},
}

func appendFormat(dstFmt []byte, dstArgs Args, srcFmt string, srcArgs []interface{}) ([]byte, Args) {
	for i, n := 0, len(srcFmt); i != n; {
		off := strings.IndexByte(srcFmt[i:], '%')
		if off < 0 {
			dstFmt = append(dstFmt, srcFmt[i:]...)
			break
		}
		off++
		dstFmt = append(dstFmt, srcFmt[i:i+off]...)

		if i += off; i != n && srcFmt[i] == '%' { // escaped '%'
			dstFmt = append(dstFmt, '%')
			i++
			continue
		}

		var key string
		var val interface{}
	fmtLoop:
		for i != n {
			switch c := srcFmt[i]; c {
			default:
				dstFmt = append(dstFmt, c)
				i++
				if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
					break fmtLoop
				}
				continue

			case ':': // extract the argument name from the format string
				if i++; i == n {
					dstFmt = append(dstFmt, ':')
					i = n
					break fmtLoop
				}

				j := strings.IndexByte(srcFmt[i:], ':')
				if j < 0 {
					dstFmt = append(dstFmt, srcFmt[i-1:]...)
					i = n
					break fmtLoop
				}

				key = srcFmt[i : i+j]
				i += j + 1
			}
		}

		if len(srcArgs) == 0 {
			val = missing
		} else {
			val, srcArgs = srcArgs[0], srcArgs[1:]
		}

		dstArgs = append(dstArgs, Arg{key, val})
	}

	return dstFmt, dstArgs
}

var (
	// Prevents Go from doing a memory allocation when there is a missing argument.
	missing interface{} = "MISSING"
)
<|endoftext|>


<commit_before>package restfulspec

import restful "github.com/emicklei/go-restful"

func asParamType(kind int) string {
	switch {
	case kind == restful.PathParameterKind:
		return "path"
	case kind == restful.QueryParameterKind:
		return "query"
	case kind == restful.BodyParameterKind:
		return "body"
	case kind == restful.HeaderParameterKind:
		return "header"
	case kind == restful.FormParameterKind:
		return "form"
	}
	return ""
}
<commit_msg>fix usage of form instead of formData in "in" field<commit_after>package restfulspec

import restful "github.com/emicklei/go-restful"

func asParamType(kind int) string {
	switch {
	case kind == restful.PathParameterKind:
		return "path"
	case kind == restful.QueryParameterKind:
		return "query"
	case kind == restful.BodyParameterKind:
		return "body"
	case kind == restful.HeaderParameterKind:
		return "header"
	case kind == restful.FormParameterKind:
		return "formData"
	}
	return ""
}
<|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.

// Unix cryptographically secure pseudorandom number
// generator.

package rand

import (
	"crypto/aes"
	"io"
	"os"
	"sync"
	"time"
)

// Easy implementation: read from /dev/urandom.
// This is sufficient on Linux, OS X, and FreeBSD.

func init() { Reader = &devReader{name: "/dev/urandom"} }

// A devReader satisfies reads by reading the file named name.
type devReader struct {
	name string
	f    *os.File
	mu   sync.Mutex
}

func (r *devReader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	if r.f == nil {
		f, err := os.Open(r.name, os.O_RDONLY, 0)
		if f == nil {
			r.mu.Unlock()
			return 0, err
		}
		r.f = f
	}
	r.mu.Unlock()
	return r.f.Read(b)
}

// Alternate pseudo-random implementation for use on
// systems without a reliable /dev/urandom.  So far we
// haven't needed it.

// newReader returns a new pseudorandom generator that
// seeds itself by reading from entropy.  If entropy == nil,
// the generator seeds itself by reading from the system's
// random number generator, typically /dev/random.
// The Read method on the returned reader always returns
// the full amount asked for, or else it returns an error.
//
// The generator uses the X9.31 algorithm with AES-128,
// reseeding after every 1 MB of generated data.
func newReader(entropy io.Reader) io.Reader {
	if entropy == nil {
		entropy = &devReader{name: "/dev/random"}
	}
	return &reader{entropy: entropy}
}

type reader struct {
	mu                   sync.Mutex
	budget               int // number of bytes that can be generated
	cipher               *aes.Cipher
	entropy              io.Reader
	time, seed, dst, key [aes.BlockSize]byte
}

func (r *reader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	n = len(b)

	for len(b) > 0 {
		if r.budget == 0 {
			_, err := io.ReadFull(r.entropy, r.seed[0:])
			if err != nil {
				return n - len(b), err
			}
			_, err = io.ReadFull(r.entropy, r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.cipher, err = aes.NewCipher(r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.budget = 1 << 20 // reseed after generating 1MB
		}
		r.budget -= aes.BlockSize

		// ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
		//
		// single block:
		// t = encrypt(time)
		// dst = encrypt(t^seed)
		// seed = encrypt(t^dst)
		ns := time.Nanoseconds()
		r.time[0] = byte(ns >> 56)
		r.time[1] = byte(ns >> 48)
		r.time[2] = byte(ns >> 40)
		r.time[3] = byte(ns >> 32)
		r.time[4] = byte(ns >> 24)
		r.time[5] = byte(ns >> 16)
		r.time[6] = byte(ns >> 8)
		r.time[7] = byte(ns)
		r.cipher.Encrypt(r.time[0:], r.time[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.dst[i] = r.time[i] ^ r.seed[i]
		}
		r.cipher.Encrypt(r.dst[0:], r.dst[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.seed[i] = r.time[i] ^ r.dst[i]
		}
		r.cipher.Encrypt(r.seed[0:], r.seed[0:])

		m := copy(b, r.dst[0:])
		b = b[m:]
	}

	return n, nil
}
<commit_msg>Use defer to unlock mutex in crypto/rand.<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.

// Unix cryptographically secure pseudorandom number
// generator.

package rand

import (
	"crypto/aes"
	"io"
	"os"
	"sync"
	"time"
)

// Easy implementation: read from /dev/urandom.
// This is sufficient on Linux, OS X, and FreeBSD.

func init() { Reader = &devReader{name: "/dev/urandom"} }

// A devReader satisfies reads by reading the file named name.
type devReader struct {
	name string
	f    *os.File
	mu   sync.Mutex
}

func (r *devReader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	if r.f == nil {
		f, err := os.Open(r.name, os.O_RDONLY, 0)
		if f == nil {
			return 0, err
		}
		r.f = f
	}
	return r.f.Read(b)
}

// Alternate pseudo-random implementation for use on
// systems without a reliable /dev/urandom.  So far we
// haven't needed it.

// newReader returns a new pseudorandom generator that
// seeds itself by reading from entropy.  If entropy == nil,
// the generator seeds itself by reading from the system's
// random number generator, typically /dev/random.
// The Read method on the returned reader always returns
// the full amount asked for, or else it returns an error.
//
// The generator uses the X9.31 algorithm with AES-128,
// reseeding after every 1 MB of generated data.
func newReader(entropy io.Reader) io.Reader {
	if entropy == nil {
		entropy = &devReader{name: "/dev/random"}
	}
	return &reader{entropy: entropy}
}

type reader struct {
	mu                   sync.Mutex
	budget               int // number of bytes that can be generated
	cipher               *aes.Cipher
	entropy              io.Reader
	time, seed, dst, key [aes.BlockSize]byte
}

func (r *reader) Read(b []byte) (n int, err os.Error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	n = len(b)

	for len(b) > 0 {
		if r.budget == 0 {
			_, err := io.ReadFull(r.entropy, r.seed[0:])
			if err != nil {
				return n - len(b), err
			}
			_, err = io.ReadFull(r.entropy, r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.cipher, err = aes.NewCipher(r.key[0:])
			if err != nil {
				return n - len(b), err
			}
			r.budget = 1 << 20 // reseed after generating 1MB
		}
		r.budget -= aes.BlockSize

		// ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
		//
		// single block:
		// t = encrypt(time)
		// dst = encrypt(t^seed)
		// seed = encrypt(t^dst)
		ns := time.Nanoseconds()
		r.time[0] = byte(ns >> 56)
		r.time[1] = byte(ns >> 48)
		r.time[2] = byte(ns >> 40)
		r.time[3] = byte(ns >> 32)
		r.time[4] = byte(ns >> 24)
		r.time[5] = byte(ns >> 16)
		r.time[6] = byte(ns >> 8)
		r.time[7] = byte(ns)
		r.cipher.Encrypt(r.time[0:], r.time[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.dst[i] = r.time[i] ^ r.seed[i]
		}
		r.cipher.Encrypt(r.dst[0:], r.dst[0:])
		for i := 0; i < aes.BlockSize; i++ {
			r.seed[i] = r.time[i] ^ r.dst[i]
		}
		r.cipher.Encrypt(r.seed[0:], r.seed[0:])

		m := copy(b, r.dst[0:])
		b = b[m:]
	}

	return n, nil
}
<|endoftext|>


<commit_before>// Copyright 2009 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 iotest

import (
	"io";
	"log";
	"os";
)

type writeLogger struct {
	prefix	string;
	w	io.Writer;
}

func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
	n, err = l.w.Write(p);
	if err != nil {
		log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
	} else {
		log.Stdoutf("%s %x", l.prefix, p[0:n])
	}
	return;
}

// NewWriteLogger returns a writer that behaves like w except
// that it logs (using log.Stdout) each write to standard output,
// printing the prefix and the hexadecimal data written.
func NewWriteLogger(prefix string, w io.Writer) io.Writer {
	return &writeLogger{prefix, w}
}

type readLogger struct {
	prefix	string;
	r	io.Reader;
}

func (l *readLogger) Read(p []byte) (n int, err os.Error) {
	n, err = l.r.Read(p);
	if err != nil {
		log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
	} else {
		log.Stdoutf("%s %x", l.prefix, p[0:n])
	}
	return;
}

// NewReadLogger returns a writer that behaves like w except
// that it logs (using log.Stdout) each write to standard output,
// printing the prefix and the hexadecimal data written.
func NewReadLogger(prefix string, r io.Reader) io.Reader {
	return &readLogger{prefix, r}
}
<commit_msg>Fix doc striing for NewReadLogger.<commit_after>// Copyright 2009 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 iotest

import (
	"io";
	"log";
	"os";
)

type writeLogger struct {
	prefix	string;
	w	io.Writer;
}

func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
	n, err = l.w.Write(p);
	if err != nil {
		log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
	} else {
		log.Stdoutf("%s %x", l.prefix, p[0:n])
	}
	return;
}

// NewWriteLogger returns a writer that behaves like w except
// that it logs (using log.Stdout) each write to standard output,
// printing the prefix and the hexadecimal data written.
func NewWriteLogger(prefix string, w io.Writer) io.Writer {
	return &writeLogger{prefix, w}
}

type readLogger struct {
	prefix	string;
	r	io.Reader;
}

func (l *readLogger) Read(p []byte) (n int, err os.Error) {
	n, err = l.r.Read(p);
	if err != nil {
		log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
	} else {
		log.Stdoutf("%s %x", l.prefix, p[0:n])
	}
	return;
}

// NewReadLogger returns a reader that behaves like r except
// that it logs (using log.Stdout) each read to standard output,
// printing the prefix and the hexadecimal data written.
func NewReadLogger(prefix string, r io.Reader) io.Reader {
	return &readLogger{prefix, r}
}
<|endoftext|>