<commit_before>package container_daemon_test

import (
	"errors"
	"io"
	"os"
	"os/exec"
	"syscall"

	"github.com/cloudfoundry-incubator/garden-linux/container_daemon"
	"github.com/cloudfoundry-incubator/garden-linux/container_daemon/fake_ptyopener"
	"github.com/cloudfoundry-incubator/garden-linux/container_daemon/fake_runner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Spawning", func() {
	var (
		runner    *fake_runner.FakeRunner
		ptyOpener *fake_ptyopener.FakePTYOpener
		spawner   *container_daemon.Spawn

		cmd         *exec.Cmd
		returnedFds []*os.File
		returnedErr error
		withTty     bool
	)

	BeforeEach(func() {
		withTty = false
		runner = new(fake_runner.FakeRunner)
		ptyOpener = new(fake_ptyopener.FakePTYOpener)

		cmd = exec.Command("foo")
		spawner = &container_daemon.Spawn{
			Runner: runner,
			PTY:    ptyOpener,
		}
	})

	JustBeforeEach(func() {
		returnedFds, returnedErr = spawner.Spawn(cmd, withTty)
	})

	Describe("With a TTY", func() {
		BeforeEach(func() {
			withTty = true
		})

		Context("when a pty cannot be opened", func() {
			BeforeEach(func() {
				ptyOpener.OpenReturns(nil, nil, errors.New("an error"))
			})

			It("returns an error", func() {
				Expect(returnedErr).To(HaveOccurred())
			})
		})

		Context("when a pty is opened", func() {
			var theOpenedPTY, theOpenedTTY *os.File

			BeforeEach(func() {
				theOpenedPTY = tmp()
				theOpenedTTY = tmp()
				ptyOpener.OpenReturns(theOpenedPTY, theOpenedTTY, nil)
			})

			It("attaches a tty to the process's stdin, out and error", func() {
				Expect(cmd.Stdin).To(Equal(theOpenedTTY))
				Expect(cmd.Stdout).To(Equal(theOpenedTTY))
				Expect(cmd.Stderr).To(Equal(theOpenedTTY))
			})

			It("returns the pty", func() {
				Expect(returnedFds[0]).To(Equal(theOpenedPTY))
			})

			It("waits for the exit status", func() {
				Eventually(runner.WaitCallCount).Should(Equal(1))
				Expect(runner.WaitArgsForCall(0)).To(Equal(cmd))
			})

			It("tells the command to start with a controlling tty and session id", func() {
				Expect(cmd.SysProcAttr.Setctty).To(Equal(true))
				Expect(cmd.SysProcAttr.Setsid).To(Equal(true))
			})

			Context("when sysprocattr is already set", func() {
				BeforeEach(func() {
					cmd.SysProcAttr = &syscall.SysProcAttr{
						Ptrace: true,
					}
				})

				It("does not clobber it", func() {
					Expect(cmd.SysProcAttr.Ptrace).To(Equal(true))
				})
			})

			Context("after wait returns", func() {
				BeforeEach(func() {
					runner.WaitReturns(42)
				})

				It("sends the exit status returned by wait to the exit status fd", func() {
					Eventually(func() byte {
						exit := make([]byte, 1)
						if n, _ := returnedFds[1].Read(exit); n > 0 {
							return exit[0]
						}

						return 255
					}).Should(Equal(byte(42)))
				})
			})

			Context("when wait does not return", func() {
				var block chan struct{}

				BeforeEach(func() {
					block = make(chan struct{})
					runner.WaitStub = func(*exec.Cmd) byte {
						<-block
						return 0
					}
				})

				It("does not block", func(done Done) {
					spawner.Spawn(exec.Command("foo"), withTty)
					close(block)
					close(done)
				})
			})
		})
	})

	Describe("Non Interactively (without a tty)", func() {
		var (
			cmdStdin io.Reader
		)

		BeforeEach(func() {
			withTty = false
		})

		Context("when starting the process succeeds", func() {
			BeforeEach(func() {
				cmd = exec.Command("foo")
				runner.StartStub = func(cmd *exec.Cmd) error {
					cmd.Stdout.Write([]byte("Banana doo"))
					cmd.Stderr.Write([]byte("Banana goo"))
					cmdStdin = cmd.Stdin

					return nil
				}
			})

			It("returns the streams from the spawned process", func() {
				Expect(checkReaderContent(returnedFds[1], "Banana doo")).To(BeTrue())
				Expect(checkReaderContent(returnedFds[2], "Banana goo")).To(BeTrue())

				returnedFds[0].Write([]byte("the stdin"))
				returnedFds[0].Close()
				Expect(checkReaderContent(cmdStdin, "the stdin")).To(BeTrue())
			})

			It("waits for the exit status", func() {
				Eventually(runner.WaitCallCount).Should(Equal(1))
				Expect(runner.WaitArgsForCall(0)).To(Equal(cmd))
			})

			Context("after wait returns", func() {
				BeforeEach(func() {
					runner.WaitReturns(42)
				})

				It("sends the exit status returned by wait to the exit status fd", func() {
					Eventually(func() byte {
						exit := make([]byte, 1)
						if n, _ := returnedFds[3].Read(exit); n > 0 {
							return exit[0]
						}

						return 255
					}).Should(Equal(byte(42)))
				})
			})
		})

		Context("when wait does not return", func() {
			var block chan struct{}

			BeforeEach(func() {
				block = make(chan struct{})
				runner.WaitStub = func(*exec.Cmd) byte {
					<-block
					return 0
				}
			})

			It("does not block", func(done Done) {
				spawner.Spawn(exec.Command("foo"), withTty)
				close(block)
				close(done)
			})
		})
	})
})

func checkReaderContent(reader io.Reader, content string) bool {
	buffer := make([]byte, len(content))

	_, err := io.ReadFull(reader, buffer)
	if err != nil {
		panic(err)
	}

	return content == string(buffer)
}
<commit_msg>Pend test which causes a data race and a suite failure.<commit_after>package container_daemon_test

import (
	"errors"
	"io"
	"os"
	"os/exec"
	"syscall"

	"github.com/cloudfoundry-incubator/garden-linux/container_daemon"
	"github.com/cloudfoundry-incubator/garden-linux/container_daemon/fake_ptyopener"
	"github.com/cloudfoundry-incubator/garden-linux/container_daemon/fake_runner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Spawning", func() {
	var (
		runner    *fake_runner.FakeRunner
		ptyOpener *fake_ptyopener.FakePTYOpener
		spawner   *container_daemon.Spawn

		cmd         *exec.Cmd
		returnedFds []*os.File
		returnedErr error
		withTty     bool
	)

	BeforeEach(func() {
		withTty = false
		runner = new(fake_runner.FakeRunner)
		ptyOpener = new(fake_ptyopener.FakePTYOpener)

		cmd = exec.Command("foo")
		spawner = &container_daemon.Spawn{
			Runner: runner,
			PTY:    ptyOpener,
		}
	})

	JustBeforeEach(func() {
		returnedFds, returnedErr = spawner.Spawn(cmd, withTty)
	})

	Describe("With a TTY", func() {
		BeforeEach(func() {
			withTty = true
		})

		Context("when a pty cannot be opened", func() {
			BeforeEach(func() {
				ptyOpener.OpenReturns(nil, nil, errors.New("an error"))
			})

			It("returns an error", func() {
				Expect(returnedErr).To(HaveOccurred())
			})
		})

		Context("when a pty is opened", func() {
			var theOpenedPTY, theOpenedTTY *os.File

			BeforeEach(func() {
				theOpenedPTY = tmp()
				theOpenedTTY = tmp()
				ptyOpener.OpenReturns(theOpenedPTY, theOpenedTTY, nil)
			})

			It("attaches a tty to the process's stdin, out and error", func() {
				Expect(cmd.Stdin).To(Equal(theOpenedTTY))
				Expect(cmd.Stdout).To(Equal(theOpenedTTY))
				Expect(cmd.Stderr).To(Equal(theOpenedTTY))
			})

			It("returns the pty", func() {
				Expect(returnedFds[0]).To(Equal(theOpenedPTY))
			})

			It("waits for the exit status", func() {
				Eventually(runner.WaitCallCount).Should(Equal(1))
				Expect(runner.WaitArgsForCall(0)).To(Equal(cmd))
			})

			It("tells the command to start with a controlling tty and session id", func() {
				Expect(cmd.SysProcAttr.Setctty).To(Equal(true))
				Expect(cmd.SysProcAttr.Setsid).To(Equal(true))
			})

			Context("when sysprocattr is already set", func() {
				BeforeEach(func() {
					cmd.SysProcAttr = &syscall.SysProcAttr{
						Ptrace: true,
					}
				})

				It("does not clobber it", func() {
					Expect(cmd.SysProcAttr.Ptrace).To(Equal(true))
				})
			})

			Context("after wait returns", func() {
				BeforeEach(func() {
					runner.WaitReturns(42)
				})

				It("sends the exit status returned by wait to the exit status fd", func() {
					Eventually(func() byte {
						exit := make([]byte, 1)
						if n, _ := returnedFds[1].Read(exit); n > 0 {
							return exit[0]
						}

						return 255
					}).Should(Equal(byte(42)))
				})
			})

			Context("when wait does not return", func() {
				var block chan struct{}

				BeforeEach(func() {
					block = make(chan struct{})
					runner.WaitStub = func(*exec.Cmd) byte {
						<-block
						return 0
					}
				})

				// FIXME: This test is pended because it causes a data race and also makes the suite fail.
				PIt("does not block", func(done Done) {
					spawner.Spawn(exec.Command("foo"), withTty)
					close(block)
					close(done)
				})
			})
		})
	})

	Describe("Non Interactively (without a tty)", func() {
		var (
			cmdStdin io.Reader
		)

		BeforeEach(func() {
			withTty = false
		})

		Context("when starting the process succeeds", func() {
			BeforeEach(func() {
				cmd = exec.Command("foo")
				runner.StartStub = func(cmd *exec.Cmd) error {
					cmd.Stdout.Write([]byte("Banana doo"))
					cmd.Stderr.Write([]byte("Banana goo"))
					cmdStdin = cmd.Stdin

					return nil
				}
			})

			It("returns the streams from the spawned process", func() {
				Expect(checkReaderContent(returnedFds[1], "Banana doo")).To(BeTrue())
				Expect(checkReaderContent(returnedFds[2], "Banana goo")).To(BeTrue())

				returnedFds[0].Write([]byte("the stdin"))
				returnedFds[0].Close()
				Expect(checkReaderContent(cmdStdin, "the stdin")).To(BeTrue())
			})

			It("waits for the exit status", func() {
				Eventually(runner.WaitCallCount).Should(Equal(1))
				Expect(runner.WaitArgsForCall(0)).To(Equal(cmd))
			})

			Context("after wait returns", func() {
				BeforeEach(func() {
					runner.WaitReturns(42)
				})

				It("sends the exit status returned by wait to the exit status fd", func() {
					Eventually(func() byte {
						exit := make([]byte, 1)
						if n, _ := returnedFds[3].Read(exit); n > 0 {
							return exit[0]
						}

						return 255
					}).Should(Equal(byte(42)))
				})
			})
		})

		Context("when wait does not return", func() {
			var block chan struct{}

			BeforeEach(func() {
				block = make(chan struct{})
				runner.WaitStub = func(*exec.Cmd) byte {
					<-block
					return 0
				}
			})

			It("does not block", func(done Done) {
				spawner.Spawn(exec.Command("foo"), withTty)
				close(block)
				close(done)
			})
		})
	})
})

func checkReaderContent(reader io.Reader, content string) bool {
	buffer := make([]byte, len(content))

	_, err := io.ReadFull(reader, buffer)
	if err != nil {
		panic(err)
	}

	return content == string(buffer)
}
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"path"
	"runtime"

	cmds "github.com/ipfs/go-ipfs/commands"
	config "github.com/ipfs/go-ipfs/repo/config"

	manet "gx/ipfs/QmPpRcbNUXauP3zWZ1NJMLWpe4QnmEHrd2ba2D3yqWznw7/go-multiaddr-net"
	sysi "gx/ipfs/QmZRjKbHa6DenStpQJFiaPcEwkZqrx7TH6xTf342LDU3qM/go-sysinfo"
)

var sysDiagCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Prints out system diagnostic information.",
		ShortDescription: `
Prints out information about your computer to aid in easier debugging.
`,
	},
	Run: func(req cmds.Request, res cmds.Response) {
		info := make(map[string]interface{})
		err := runtimeInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = envVarInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = diskSpaceInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = memInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = netInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		info["ipfs_version"] = config.CurrentVersionNumber
		info["ipfs_commit"] = config.CurrentCommit
		res.SetOutput(info)
	},
}

func runtimeInfo(out map[string]interface{}) error {
	rt := make(map[string]interface{})
	rt["os"] = runtime.GOOS
	rt["arch"] = runtime.GOARCH
	rt["compiler"] = runtime.Compiler
	rt["version"] = runtime.Version()
	rt["numcpu"] = runtime.NumCPU()
	rt["gomaxprocs"] = runtime.GOMAXPROCS(0)
	rt["numgoroutines"] = runtime.NumGoroutine()

	out["runtime"] = rt
	return nil
}

func envVarInfo(out map[string]interface{}) error {
	ev := make(map[string]interface{})
	ev["GOPATH"] = os.Getenv("GOPATH")
	ev["IPFS_PATH"] = os.Getenv("IPFS_PATH")

	out["environment"] = ev
	return nil
}

func ipfsPath() string {
	p := os.Getenv("IPFS_PATH")
	if p == "" {
		p = path.Join(os.Getenv("HOME"), ".ipfs")
	}
	return p
}

func diskSpaceInfo(out map[string]interface{}) error {
	di := make(map[string]interface{})
	dinfo, err := sysi.DiskUsage(ipfsPath())
	if err != nil {
		return err
	}

	di["fstype"] = dinfo.FsType
	di["total_space"] = dinfo.Total
	di["free_space"] = dinfo.Free

	out["diskinfo"] = di
	return nil
}

func memInfo(out map[string]interface{}) error {
	m := make(map[string]interface{})

	meminf, err := sysi.MemoryInfo()
	if err != nil {
		return err
	}

	m["swap"] = meminf.Swap
	m["virt"] = meminf.Used
	out["memory"] = m
	return nil
}

func netInfo(out map[string]interface{}) error {
	n := make(map[string]interface{})
	addrs, err := manet.InterfaceMultiaddrs()
	if err != nil {
		return err
	}

	var straddrs []string
	for _, a := range addrs {
		straddrs = append(straddrs, a.String())
	}

	n["interface_addresses"] = straddrs
	out["net"] = n
	return nil
}
<commit_msg>Add net.online to diag sys command<commit_after>package commands

import (
	"os"
	"path"
	"runtime"

	cmds "github.com/ipfs/go-ipfs/commands"
	config "github.com/ipfs/go-ipfs/repo/config"

	manet "gx/ipfs/QmPpRcbNUXauP3zWZ1NJMLWpe4QnmEHrd2ba2D3yqWznw7/go-multiaddr-net"
	sysi "gx/ipfs/QmZRjKbHa6DenStpQJFiaPcEwkZqrx7TH6xTf342LDU3qM/go-sysinfo"
)

var sysDiagCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Prints out system diagnostic information.",
		ShortDescription: `
Prints out information about your computer to aid in easier debugging.
`,
	},
	Run: func(req cmds.Request, res cmds.Response) {
		info := make(map[string]interface{})
		err := runtimeInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = envVarInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = diskSpaceInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = memInfo(info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
		node, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		err = netInfo(node.OnlineMode(), info)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		info["ipfs_version"] = config.CurrentVersionNumber
		info["ipfs_commit"] = config.CurrentCommit
		res.SetOutput(info)
	},
}

func runtimeInfo(out map[string]interface{}) error {
	rt := make(map[string]interface{})
	rt["os"] = runtime.GOOS
	rt["arch"] = runtime.GOARCH
	rt["compiler"] = runtime.Compiler
	rt["version"] = runtime.Version()
	rt["numcpu"] = runtime.NumCPU()
	rt["gomaxprocs"] = runtime.GOMAXPROCS(0)
	rt["numgoroutines"] = runtime.NumGoroutine()

	out["runtime"] = rt
	return nil
}

func envVarInfo(out map[string]interface{}) error {
	ev := make(map[string]interface{})
	ev["GOPATH"] = os.Getenv("GOPATH")
	ev["IPFS_PATH"] = os.Getenv("IPFS_PATH")

	out["environment"] = ev
	return nil
}

func ipfsPath() string {
	p := os.Getenv("IPFS_PATH")
	if p == "" {
		p = path.Join(os.Getenv("HOME"), ".ipfs")
	}
	return p
}

func diskSpaceInfo(out map[string]interface{}) error {
	di := make(map[string]interface{})
	dinfo, err := sysi.DiskUsage(ipfsPath())
	if err != nil {
		return err
	}

	di["fstype"] = dinfo.FsType
	di["total_space"] = dinfo.Total
	di["free_space"] = dinfo.Free

	out["diskinfo"] = di
	return nil
}

func memInfo(out map[string]interface{}) error {
	m := make(map[string]interface{})

	meminf, err := sysi.MemoryInfo()
	if err != nil {
		return err
	}

	m["swap"] = meminf.Swap
	m["virt"] = meminf.Used
	out["memory"] = m
	return nil
}

func netInfo(online bool, out map[string]interface{}) error {
	n := make(map[string]interface{})
	addrs, err := manet.InterfaceMultiaddrs()
	if err != nil {
		return err
	}

	var straddrs []string
	for _, a := range addrs {
		straddrs = append(straddrs, a.String())
	}

	n["interface_addresses"] = straddrs
	n["online"] = online
	out["net"] = n
	return nil
}
<|endoftext|>


<commit_before>package core

import (
	"log"
	"testing"
)

func TestDatasetEvaluator(t *testing.T) {
	eval := NewDatasetEvaluator(ML_SCRIPT, TESTSET)
	val, err := eval.Evaluate(TRAINSET)
	if err != nil {
		log.Println(err)
		t.FailNow()
	}
	if val < 0 {
		log.Println("Wrong conversion")
		t.FailNow()
	}
}
<commit_msg>fixed test case<commit_after>package core

import (
	"log"
	"testing"
)

func TestDatasetEvaluator(t *testing.T) {
	params := map[string]string{"script": ML_SCRIPT, "testset": TESTSET}
	eval, err := NewDatasetEvaluator(ONLINE_EVAL, params)
	if err != nil || eval == nil {
		log.Println(err)
		t.FailNow()
	}
	val, err := eval.Evaluate(TRAINSET)
	if err != nil {
		log.Println(err)
		t.FailNow()
	}
	if val < 0 {
		log.Println("Wrong conversion")
		t.FailNow()
	}
}
<|endoftext|>


<commit_before><commit_msg>multiqueue: fix deadlock when there is no available queue<commit_after><|endoftext|>


<commit_before>package synctest

import "sync"

// Locker is an implementation of sync.Locker that notifies callers when
// locks and unlocks happen. otherwise, it behaves identically as a sync.Mutex
type NotifyingLocker struct {
	unlockChans     []chan struct{}
	unlockChansLock *sync.Mutex
	lockChans       []chan struct{}
	lockChansLock   *sync.Mutex
	lck             *sync.Mutex
}

func NewNotifyingLocker() *NotifyingLocker {
	return &NotifyingLocker{
		unlockChans:     nil,
		unlockChansLock: &sync.Mutex{},
		lockChans:       nil,
		lockChansLock:   &sync.Mutex{},
		lck:             &sync.Mutex{},
	}
}

// NotifyLock returns a channel that will close when n is locked. The channel
// never sends and will be closed immediately if n is already locked
func (n *NotifyingLocker) NotifyLock() <-chan struct{} {
	n.lockChansLock.Lock()
	defer n.lockChansLock.Unlock()
	ch := make(chan struct{})
	n.lockChans = append(n.lockChans, ch)
	return ch
}

// NotifyUnlock returns a channel that will close when n is unlocked. The channel
// never sends and will be closed immediately if n is already unlocked.
func (n *NotifyingLocker) NotifyUnlock() <-chan struct{} {
	n.unlockChansLock.Lock()
	defer n.unlockChansLock.Unlock()
	ch := make(chan struct{})
	n.unlockChans = append(n.unlockChans, ch)
	return ch
}

// Lock locks n and closes all unclosed channels returned previously by NotifyLock
func (n *NotifyingLocker) Lock() {
	n.lck.Lock()
	n.lockChansLock.Lock()
	defer n.lockChansLock.Unlock()
	for _, lck := range n.lockChans {
		close(lck)
	}
	n.lockChans = nil
}

func (n *NotifyingLocker) Unlock() {
	n.lck.Unlock()
	n.unlockChansLock.Lock()
	defer n.unlockChansLock.Unlock()
	for _, lck := range n.unlockChans {
		close(lck)
	}
	n.unlockChans = nil
}
<commit_msg>more docs<commit_after>// package synctest contains utilities for testing code that uses code in the
// sync package
package synctest

import "sync"

// Locker is an implementation of sync.Locker that notifies callers when
// locks and unlocks happen. otherwise, it behaves identically as a sync.Mutex.
//
// Example usage:
//  nl := NewNotifyingLocker()
//  ch := nl.NotifyLock()
//  go func() { nl.Lock() }()
//  <-ch // wait for nl.Lock() to be called
type NotifyingLocker struct {
	unlockChans     []chan struct{}
	unlockChansLock *sync.Mutex
	lockChans       []chan struct{}
	lockChansLock   *sync.Mutex
	lck             *sync.Mutex
}

// NewNotifyingLocker creates a new NotifyingLocker ready for use
func NewNotifyingLocker() *NotifyingLocker {
	return &NotifyingLocker{
		unlockChans:     nil,
		unlockChansLock: &sync.Mutex{},
		lockChans:       nil,
		lockChansLock:   &sync.Mutex{},
		lck:             &sync.Mutex{},
	}
}

// NotifyLock returns a channel that will close when n is locked. The channel
// never sends and will be closed immediately if n is already locked
func (n *NotifyingLocker) NotifyLock() <-chan struct{} {
	n.lockChansLock.Lock()
	defer n.lockChansLock.Unlock()
	ch := make(chan struct{})
	n.lockChans = append(n.lockChans, ch)
	return ch
}

// NotifyUnlock returns a channel that will close when n is unlocked. The channel
// never sends and will be closed immediately if n is already unlocked.
func (n *NotifyingLocker) NotifyUnlock() <-chan struct{} {
	n.unlockChansLock.Lock()
	defer n.unlockChansLock.Unlock()
	ch := make(chan struct{})
	n.unlockChans = append(n.unlockChans, ch)
	return ch
}

// Lock locks n and closes all unclosed channels returned previously by NotifyLock
func (n *NotifyingLocker) Lock() {
	n.lck.Lock()
	n.lockChansLock.Lock()
	defer n.lockChansLock.Unlock()
	for _, lck := range n.lockChans {
		close(lck)
	}
	n.lockChans = nil
}

// Unlock unlocks n and closes all unclosed channels returned previously by NotifyUnlock
func (n *NotifyingLocker) Unlock() {
	n.lck.Unlock()
	n.unlockChansLock.Lock()
	defer n.unlockChansLock.Unlock()
	for _, lck := range n.unlockChans {
		close(lck)
	}
	n.unlockChans = nil
}
<|endoftext|>


<commit_before>package crawlbot

import (
	"bytes"
	"errors"
	"io/ioutil"
	"net/http"
)

var ErrHeaderRejected = errors.New("Header Checker rejected URL")

type worker struct {
	state   bool         // true means busy / unavailable. false means idling and is ready for new work
	url     string       // Current URL being processed
	results chan result  // Channel on which to send results
	crawler *Crawler     // It's parent crawler
	client  *http.Client // The client to be used for HTTP connection
}

type result struct {
	err     error
	url     string
	newurls []string
	owner   *worker
}

// Process a given URL, when finish pass back a new list of URLs to process

func (w *worker) setup(targetURL string) {
	w.state = true
	w.url = targetURL
}

func (w *worker) teardown() {
	w.state = false
	w.url = ""
}

func (w *worker) process() {
	go func() {
		// Do the HTTP GET and create the response object
		var resp Response
		httpresp, err := w.client.Get(w.url)
		if httpresp != nil {
			resp = Response{Response: httpresp}
		} else {
			resp = Response{}
		}
		resp.URL = w.url
		resp.Err = err
		resp.Crawler = w.crawler
		if resp.Err != nil {
			w.crawler.Handler(&resp)
			w.sendResults(nil, resp.Err)
			return
		}

		// Check headers using HeaderCheck
		if !w.crawler.CheckHeader(w.crawler, w.url, resp.StatusCode, resp.Header) {
			resp.Body.Close()
			resp.Err = ErrHeaderRejected
			w.sendResults(nil, resp.Err)
			return
		}

		// Read the body
		resp.bytes, resp.Err = ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if resp.Err != nil {
			w.crawler.Handler(&resp)
			w.sendResults(nil, resp.Err)
			return
		}
		// Replace the body with a readCloser that reads from bytes
		resp.Body = &readCloser{bytes.NewReader(resp.bytes)}

		// Process the handler
		w.crawler.Handler(&resp)

		// Find links and finish
		newurls := w.crawler.LinkFinder(&resp)

		// We're done, return the results
		w.sendResults(newurls, nil)
	}()
}

func (w *worker) sendResults(newurls []string, err error) {
	result := result{
		err:     err,
		url:     w.url,
		newurls: newurls,
		owner:   w,
	}

	w.results <- result
}

// ReadCloser is a dummy type that makes bytes.Reader compatible with ReadCloser so we can use it to replace Body
type readCloser struct {
	*bytes.Reader
}

func (r *readCloser) Close() error {
	return nil
}
<commit_msg>Reset the reader after calling the handler so that the linkFinder has a fresh reader<commit_after>package crawlbot

import (
	"bytes"
	"errors"
	"io/ioutil"
	"net/http"
)

var ErrHeaderRejected = errors.New("Header Checker rejected URL")

type worker struct {
	state   bool         // true means busy / unavailable. false means idling and is ready for new work
	url     string       // Current URL being processed
	results chan result  // Channel on which to send results
	crawler *Crawler     // It's parent crawler
	client  *http.Client // The client to be used for HTTP connection
}

type result struct {
	err     error
	url     string
	newurls []string
	owner   *worker
}

// Process a given URL, when finish pass back a new list of URLs to process

func (w *worker) setup(targetURL string) {
	w.state = true
	w.url = targetURL
}

func (w *worker) teardown() {
	w.state = false
	w.url = ""
}

func (w *worker) process() {
	go func() {
		// Do the HTTP GET and create the response object
		var resp Response
		httpresp, err := w.client.Get(w.url)
		if httpresp != nil {
			resp = Response{Response: httpresp}
		} else {
			resp = Response{}
		}
		resp.URL = w.url
		resp.Err = err
		resp.Crawler = w.crawler
		if resp.Err != nil {
			w.crawler.Handler(&resp)
			w.sendResults(nil, resp.Err)
			return
		}

		// Check headers using HeaderCheck
		if !w.crawler.CheckHeader(w.crawler, w.url, resp.StatusCode, resp.Header) {
			resp.Body.Close()
			resp.Err = ErrHeaderRejected
			w.sendResults(nil, resp.Err)
			return
		}

		// Read the body
		resp.bytes, resp.Err = ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if resp.Err != nil {
			w.crawler.Handler(&resp)
			w.sendResults(nil, resp.Err)
			return
		}
		// Replace the body with a readCloser that reads from bytes
		resp.Body = &readCloser{bytes.NewReader(resp.bytes)}

		// Process the handler
		w.crawler.Handler(&resp)
		resp.Body = &readCloser{bytes.NewReader(resp.bytes)}

		// Find links and finish
		newurls := w.crawler.LinkFinder(&resp)

		// We're done, return the results
		w.sendResults(newurls, nil)
	}()
}

func (w *worker) sendResults(newurls []string, err error) {
	result := result{
		err:     err,
		url:     w.url,
		newurls: newurls,
		owner:   w,
	}

	w.results <- result
}

// ReadCloser is a dummy type that makes bytes.Reader compatible with ReadCloser so we can use it to replace Body
type readCloser struct {
	*bytes.Reader
}

func (r *readCloser) Close() error {
	return nil
}
<|endoftext|>


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

package filestorage

import (
	"io"
	"time"
)

// FileStorage is an abstraction that can be used for the storage of files.
type FileStorage interface {
	// Metadata returns a file's metadata.
	Metadata(id string) (Metadata, error)

	// Get returns a file and its metadata.
	Get(id string) (Metadata, io.ReadCloser, error)

	// List returns the metadata for each stored file.
	List() ([]Metadata, error)

	// Add stores a file and its metadata.
	Add(meta Metadata, archive io.Reader) (string, error)

	// SetFile stores a file for an existing metadata entry.
	SetFile(id string, file io.Reader) error

	// Remove removes a file from storage.
	Remove(id string) error
}

// Document represents a document that can be identified uniquely
// by a string.
type Document interface {
	// ID returns the unique ID of the document.
	ID() string

	// SetID sets the ID of the document.  If the ID is already set,
	// SetID() should return true (false otherwise).
	SetID(id string) (alreadySet bool)
}

// Metadata is the meta information for a stored file.
type Metadata interface {
	Document

	// Size is the size of the file (in bytes).
	Size() int64

	// Checksum is the checksum for the file.
	Checksum() string

	// ChecksumFormat is the kind (and encoding) of checksum.
	ChecksumFormat() string

	// Timestamp records when the file was created.
	Timestamp() time.Time

	// Stored indicates whether or not the file has been stored.
	Stored() bool

	// Doc returns a storable copy of the metadata.
	Doc() interface{}

	// SetFile sets the file info on the metadata.
	SetFile(size int64, checksum, checksumFormat string) error

	// SetStored sets Stored to true on the metadata.
	SetStored()
}

// DocStorage is an abstraction for a system that can store docs (structs).
// The system is expected to generate its own unique ID for each doc.
type DocStorage interface {
	// Doc returns the doc that matches the ID.  If there is no match,
	// an error is returned (see errors.IsNotFound).  Any other problem
	// also results in an error.
	Doc(id string) (Document, error)

	// ListDocs returns a list of all the docs in the storage.
	ListDocs() ([]Document, error)

	// AddDoc adds the doc to the storage.  If successful, the storage-
	// generated ID for the doc is returned.  Otherwise an error is
	// returned.
	AddDoc(doc Document) (string, error)

	// RemoveDoc removes the matching doc from the storage.  If there
	// is no match an error is returned (see errors.IsNotFound).  Any
	// other problem also results in an error.
	RemoveDoc(id string) error
}

// RawFileStorage is an abstraction around a system that can store files.
// The system is expected to rely on the user for unique IDs.
type RawFileStorage interface {
	// File returns the matching file.  If there is no match an error is
	// returned (see errors.IsNotFound).  Any other problem also results
	// in an error.
	File(id string) (io.ReadCloser, error)

	// AddFile adds the file to the storage.  If it fails to do so,
	// it returns an error.  If a file is already stored for the ID,
	// AddFile() fails (see errors.IsAlreadyExists).
	AddFile(id string, file io.Reader, size int64) error

	// RemoveFile removes the matching file from the storage.  It fails
	// if there is no error (see errors.IsNotFound).  Any other problem
	// also results in an error.
	RemoveFile(id string) error
}

// MetadataStorage is an extension of DocStorage adapted to file metadata.
type MetadataStorage interface {
	DocStorage

	// Metadata returns the matching Metadata.  It fails if there is no
	// match (see errors.IsNotFound).  Any other problems likewise
	// results in an error.
	Metadata(id string) (Metadata, error)

	// ListMetadata returns a list of all metadata in the storage.
	ListMetadata() ([]Metadata, error)

	// SetStored updates the stored metadata to indicate that the
	// associated file has been successfully stored in a RawFileStorage
	// system.  It will also call SetStored() on the metadata.  If it
	// does not find a stored metadata with the matching ID, it will
	// return an error (see errors.IsNotFound).  It also returns an
	// error if it fails to update the stored metadata.
	SetStored(meta Metadata) error
}
<commit_msg>Clarify a comment.<commit_after>// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package filestorage

import (
	"io"
	"time"
)

// FileStorage is an abstraction that can be used for the storage of files.
type FileStorage interface {
	// Metadata returns a file's metadata.
	Metadata(id string) (Metadata, error)

	// Get returns a file and its metadata.
	Get(id string) (Metadata, io.ReadCloser, error)

	// List returns the metadata for each stored file.
	List() ([]Metadata, error)

	// Add stores a file and its metadata.
	Add(meta Metadata, archive io.Reader) (string, error)

	// SetFile stores a file for an existing metadata entry.
	SetFile(id string, file io.Reader) error

	// Remove removes a file from storage.
	Remove(id string) error
}

// Document represents a document that can be identified uniquely
// by a string.
type Document interface {
	// ID returns the unique ID of the document.
	ID() string

	// SetID sets the ID of the document.  If the ID is already set,
	// SetID() should return true (false otherwise).
	SetID(id string) (alreadySet bool)
}

// Metadata is the meta information for a stored file.
type Metadata interface {
	Document

	// Size is the size of the file (in bytes).
	Size() int64

	// Checksum is the checksum for the file.
	Checksum() string

	// ChecksumFormat is the kind (and encoding) of checksum.
	ChecksumFormat() string

	// Timestamp records when the file was created.
	Timestamp() time.Time

	// Stored indicates whether or not the file has been stored.
	Stored() bool

	// Doc returns a storable copy of the metadata.
	Doc() interface{}

	// SetFile sets the file info on the metadata.
	SetFile(size int64, checksum, checksumFormat string) error

	// SetStored sets Stored to true on the metadata.
	SetStored()
}

// DocStorage is an abstraction for a system that can store docs (structs).
// The system is expected to generate its own unique ID for each doc.
type DocStorage interface {
	// Doc returns the doc that matches the ID.  If there is no match,
	// an error is returned (see errors.IsNotFound).  Any other problem
	// also results in an error.
	Doc(id string) (Document, error)

	// ListDocs returns a list of all the docs in the storage.
	ListDocs() ([]Document, error)

	// AddDoc adds the doc to the storage.  If successful, the storage-
	// generated ID for the doc is returned.  Otherwise an error is
	// returned.
	AddDoc(doc Document) (string, error)

	// RemoveDoc removes the matching doc from the storage.  If there
	// is no match an error is returned (see errors.IsNotFound).  Any
	// other problem also results in an error.
	RemoveDoc(id string) error
}

// RawFileStorage is an abstraction around a system that can store files.
// The system is expected to rely on the user for unique IDs.
type RawFileStorage interface {
	// File returns the matching file.  If there is no match an error is
	// returned (see errors.IsNotFound).  Any other problem also results
	// in an error.
	File(id string) (io.ReadCloser, error)

	// AddFile adds the file to the storage.  If it fails to do so,
	// it returns an error.  If a file is already stored for the ID,
	// AddFile() fails (see errors.IsAlreadyExists).
	AddFile(id string, file io.Reader, size int64) error

	// RemoveFile removes the matching file from the storage.  It fails
	// if there is no such file (see errors.IsNotFound).  Any other problem
	// also results in an error.
	RemoveFile(id string) error
}

// MetadataStorage is an extension of DocStorage adapted to file metadata.
type MetadataStorage interface {
	DocStorage

	// Metadata returns the matching Metadata.  It fails if there is no
	// match (see errors.IsNotFound).  Any other problems likewise
	// results in an error.
	Metadata(id string) (Metadata, error)

	// ListMetadata returns a list of all metadata in the storage.
	ListMetadata() ([]Metadata, error)

	// SetStored updates the stored metadata to indicate that the
	// associated file has been successfully stored in a RawFileStorage
	// system.  It will also call SetStored() on the metadata.  If it
	// does not find a stored metadata with the matching ID, it will
	// return an error (see errors.IsNotFound).  It also returns an
	// error if it fails to update the stored metadata.
	SetStored(meta Metadata) error
}
<|endoftext|>


<commit_before>package filters

import (
	"fmt"
	"strings"

	d "github.com/appPlant/alpinepass/data"
	"github.com/appPlant/alpinepass/util"
)

//PropertyFilter allows filtering a Config for the content of its properties.
type PropertyFilter struct {
	Slices []string
}

func (p PropertyFilter) filter(data d.Config) d.Config {
	verifyFlags(p.Slices) //TODO verify only once and not for every Config
	//var remove = false
	for i := 0; i < len(p.Slices); i++ {
		filterProperty(p.Slices[i], data)
	}
	return data
}

func filterProperty(property string, data d.Config) {
	var split = strings.Split(property, ":")
	var key = split[0]
	var value = split[1]
	fmt.Println(key + " " + value)
}

func verifyFlags(flags []string) {
	for i := 0; i < len(flags); i++ {
		flag := flags[i]
		if !strings.Contains(flag, ":") {
			util.ThrowError("The filter does not contain ':'!")
		}
		if strings.Count(flag, ":") > 1 {
			util.ThrowError("The filter contains too many ':'!")
		}
	}
}
<commit_msg>Improve filter flag verification<commit_after>package filters

import (
	"strings"

	d "github.com/appPlant/alpinepass/data"
	"github.com/appPlant/alpinepass/util"
	"github.com/fatih/structs"
)

//PropertyFilter allows filtering a Config for the content of its properties.
type PropertyFilter struct {
	Slices []string
}

func (p PropertyFilter) filter(data d.Config) d.Config {
	verifyFlags(p.Slices) //TODO verify only once and not for every Config
	//var remove = false
	for i := 0; i < len(p.Slices); i++ {
		filterProperty(p.Slices[i], data)
	}
	return data
}

func filterProperty(property string, data d.Config) {
	/*
		var split = strings.Split(property, ":")
		var key = split[0]
		var value = split[1]
		fmt.Println(key + " " + value)
	*/
}

func verifyFlags(flags []string) {
	for i := 0; i < len(flags); i++ {
		flag := flags[i]

		if !strings.Contains(flag, ":") {
			util.ThrowError("The filter does not contain ':'! Flag: " + flag)
		}
		if strings.Count(flag, ":") > 1 {
			util.ThrowError("The filter contains too many ':'! Flag: " + flag)
		}

		data := d.Config{}
		fieldNames := structs.Names(data)
		key := strings.ToLower(strings.Split(flag, ":")[0])
		isContained := false
		for j := 0; j < len(fieldNames); j++ {
			if key == strings.ToLower(fieldNames[j]) {
				isContained = true
			}
		}
		if !isContained {
			util.ThrowError("The filter type is not valid! Flag: " + flag)
		}
	}
}
<|endoftext|>


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

package pilosa

import (
	"io"
	"log"
)

// Ensure nopLogger implements interface.
var _ Logger = &nopLogger{}

// Logger represents an interface for a shared logger.
type Logger interface {
	Printf(format string, v ...interface{})
	Debugf(format string, v ...interface{})
}

func init() {
	NopLogger = &nopLogger{}
}

// NopLogger represents a Logger that doesn't do anything.
var NopLogger Logger

type nopLogger struct{}

// Printf is a no-op implementation of the Logger Printf method.
func (n *nopLogger) Printf(format string, v ...interface{}) {}

// Debugf is a no-op implementation of the Logger Debugf method.
func (n *nopLogger) Debugf(format string, v ...interface{}) {}

// StandardLogger is a basic implementation of pilosa.Logger based on log.Logger.
type StandardLogger struct {
	logger *log.Logger
}

func NewStandardLogger(w io.Writer) *StandardLogger {
	return &StandardLogger{
		logger: log.New(w, "", log.LstdFlags),
	}
}

func (s *StandardLogger) Printf(format string, v ...interface{}) {
	s.logger.Printf(format, v...)
}

func (s *StandardLogger) Debugf(format string, v ...interface{}) {}

func (s *StandardLogger) Logger() *log.Logger {
	return s.logger
}

// VerboseLogger is an implementation of pilosa.Logger which includes debug messages.
type VerboseLogger struct {
	logger *log.Logger
}

func NewVerboseLogger(w io.Writer) *VerboseLogger {
	return &VerboseLogger{
		logger: log.New(w, "", log.LstdFlags),
	}
}

func (vb *VerboseLogger) Printf(format string, v ...interface{}) {
	vb.logger.Printf(format, v...)
}

func (vb *VerboseLogger) Debugf(format string, v ...interface{}) {
	vb.logger.Printf(format, v...)
}

func (vb *VerboseLogger) Logger() *log.Logger {
	return vb.logger
}
<commit_msg>Unexport StandardLogger<commit_after>// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pilosa

import (
	"io"
	"log"
)

// Ensure nopLogger implements interface.
var _ Logger = &nopLogger{}

// Logger represents an interface for a shared logger.
type Logger interface {
	Printf(format string, v ...interface{})
	Debugf(format string, v ...interface{})
}

func init() {
	NopLogger = &nopLogger{}
}

// NopLogger represents a Logger that doesn't do anything.
var NopLogger Logger

type nopLogger struct{}

// Printf is a no-op implementation of the Logger Printf method.
func (n *nopLogger) Printf(format string, v ...interface{}) {}

// Debugf is a no-op implementation of the Logger Debugf method.
func (n *nopLogger) Debugf(format string, v ...interface{}) {}

// standardLogger is a basic implementation of pilosa.Logger based on log.Logger.
type standardLogger struct {
	logger *log.Logger
}

func NewStandardLogger(w io.Writer) *standardLogger {
	return &standardLogger{
		logger: log.New(w, "", log.LstdFlags),
	}
}

func (s *standardLogger) Printf(format string, v ...interface{}) {
	s.logger.Printf(format, v...)
}

func (s *standardLogger) Debugf(format string, v ...interface{}) {}

func (s *standardLogger) Logger() *log.Logger {
	return s.logger
}

// VerboseLogger is an implementation of pilosa.Logger which includes debug messages.
type VerboseLogger struct {
	logger *log.Logger
}

func NewVerboseLogger(w io.Writer) *VerboseLogger {
	return &VerboseLogger{
		logger: log.New(w, "", log.LstdFlags),
	}
}

func (vb *VerboseLogger) Printf(format string, v ...interface{}) {
	vb.logger.Printf(format, v...)
}

func (vb *VerboseLogger) Debugf(format string, v ...interface{}) {
	vb.logger.Printf(format, v...)
}

func (vb *VerboseLogger) Logger() *log.Logger {
	return vb.logger
}
<|endoftext|>


<commit_before>package negroni

import (
	"bytes"
	"strings"

	"log"
	"net/http"
	"os"
	"text/template"
	"time"
)

// LoggerEntry is the structure
// passed to the template.
type LoggerEntry struct {
	StartTime string
	Status    int
	Duration  time.Duration
	Hostname  string
	Method    string
	Path      string
	Request   *http.Request
}

// LoggerDefaultFormat is the format
// logged used by the default Logger instance.
var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"

// LoggerDefaultDateFormat is the
// format used for date by the
// default Logger instance.
var LoggerDefaultDateFormat = time.RFC3339

// ALogger interface
type ALogger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
type Logger struct {
	// ALogger implements just enough log.Logger interface to be compatible with other implementations
	ALogger
	dateFormat string
	template   *template.Template
}

// NewLogger returns a new Logger instance
func NewLogger() *Logger {
	logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat}
	logger.SetFormat(LoggerDefaultFormat)
	return logger
}

func (l *Logger) SetFormat(format string) {
	l.template = template.Must(template.New("negroni_parser").Parse(format))
}

func (l *Logger) SetDateFormat(format string) {
	l.dateFormat = format
}

func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()

	next(rw, r)

	res := rw.(ResponseWriter)
	log := LoggerEntry{
		StartTime: start.Format(l.dateFormat),
		Status:    res.Status(),
		Duration:  time.Since(start),
		Hostname:  r.Host,
		Method:    r.Method,
		Path:      strings.Replace(r.URL.Path, "%", "%%", -1),
		Request:   r,
	}

	buff := &bytes.Buffer{}
	l.template.Execute(buff, log)
	l.Printf(buff.String())
}
<commit_msg>Use `Println` statement to fix issue instead<commit_after>package negroni

import (
	"bytes"

	"log"
	"net/http"
	"os"
	"text/template"
	"time"
)

// LoggerEntry is the structure
// passed to the template.
type LoggerEntry struct {
	StartTime string
	Status    int
	Duration  time.Duration
	Hostname  string
	Method    string
	Path      string
	Request   *http.Request
}

// LoggerDefaultFormat is the format
// logged used by the default Logger instance.
var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"

// LoggerDefaultDateFormat is the
// format used for date by the
// default Logger instance.
var LoggerDefaultDateFormat = time.RFC3339

// ALogger interface
type ALogger interface {
	Println(v ...interface{})
	Printf(format string, v ...interface{})
}

// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
type Logger struct {
	// ALogger implements just enough log.Logger interface to be compatible with other implementations
	ALogger
	dateFormat string
	template   *template.Template
}

// NewLogger returns a new Logger instance
func NewLogger() *Logger {
	logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat}
	logger.SetFormat(LoggerDefaultFormat)
	return logger
}

func (l *Logger) SetFormat(format string) {
	l.template = template.Must(template.New("negroni_parser").Parse(format))
}

func (l *Logger) SetDateFormat(format string) {
	l.dateFormat = format
}

func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	start := time.Now()

	next(rw, r)

	res := rw.(ResponseWriter)
	log := LoggerEntry{
		StartTime: start.Format(l.dateFormat),
		Status:    res.Status(),
		Duration:  time.Since(start),
		Hostname:  r.Host,
		Method:    r.Method,
		Path:      r.URL.Path,
		Request:   r,
	}

	buff := &bytes.Buffer{}
	l.template.Execute(buff, log)
	l.Println(buff.String())
}
<|endoftext|>


<commit_before>package golog

import (
	"flag"
)

// Prints everything this level and above. (Set to SILENT to disable).
var flag_minloglevel = flag.Int("vlog.minloglevel", INFO,
	"Log messages at or above this level. The "+
		"numbers of severity levels INFO, WARNING, "+
		"ERROR, and FATAL are 0, 1, 2, and 3, respectively")

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
}

// A FailLogger is a Logger with the addition FailNow() function, which flushes
// the Logger and performs some action. The action performed by FailNow() is
// deliberately unspecified, but could include os.Exit(1) or
// testing.(*T).FailNow().
type FailLogger interface {
	Logger
	FailNow()
}

type loggerImpl struct {
	LogOuter
	// This is a reference type so we can add log writers before having
	// parsed flag_minloglevel.
	minloglevel *int
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= *l.minloglevel {
		l.Output(closure())
	}
}
<commit_msg>Functions to create loggers<commit_after>package golog

import (
	"flag"
	"os"
)

// Prints everything this level and above. (Set to SILENT to disable).
var flag_minloglevel = flag.Int("vlog.minloglevel", INFO,
	"Log messages at or above this level. The "+
		"numbers of severity levels INFO, WARNING, "+
		"ERROR, and FATAL are 0, 1, 2, and 3, respectively")

// Logger.Log uses the level to determine whether or not to output the
// arguments. Logger.Log will output the provided arguments exactly, without
// additional formatting such as adding a prefix etc. In addition, Logger.Log
// must be thread safe.
type Logger interface {
	// If the message is to be logged, evaluates the closure and outputs
	// the result.
	Log(level int, closure func() *LogMessage)
}

// A FailLogger is a Logger with the addition FailNow() function, which flushes
// the Logger and performs some action. The action performed by FailNow() is
// deliberately unspecified, but could include os.Exit(1) or
// testing.(*T).FailNow().
type FailLogger interface {
	Logger
	FailNow()
}

func NewLogger(outer LogOuter, minloglevel int) Logger {
	return NewFailLogger(outer, minloglevel)
}

func NewFailLogger(outer LogOuter, minloglevel int) FailLogger {
	return &loggerImpl{outer, &minloglevel}
}

func NewDefaultFailLogger() FailLogger {
	// TODO Don't create new FailLoggers, use global FailLogger?
	return &loggerImpl{&defaultLogOuters, flag_minloglevel}
}

func NewDefaultLogger() Logger {
	// TODO Don't create new FailLoggers, use global FailLogger?
	return &loggerImpl{&defaultLogOuters, flag_minloglevel}
}

type loggerImpl struct {
	LogOuter
	// This is a reference type so we can add log writers before having
	// parsed flag_minloglevel.
	minloglevel *int
}

func (l *loggerImpl) Log(level int, closure func() *LogMessage) {
	if level >= *l.minloglevel {
		l.Output(closure())
	}
}

func (l *loggerImpl) FailNow() {
	os.Exit(1)
}
<|endoftext|>


<commit_before>package gorm

import (
	"database/sql/driver"
	"fmt"
	"log"
	"os"
	"reflect"
	"regexp"
	"time"
	"unicode"
)

var (
	defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)}
	sqlRegexp     = regexp.MustCompile(`(\$\d+)|\?`)
)

type logger interface {
	Print(v ...interface{})
}

// LogWriter log writer interface
type LogWriter interface {
	Println(v ...interface{})
}

// Logger default logger
type Logger struct {
	LogWriter
}

// Print format & print log
func (logger Logger) Print(values ...interface{}) {
	if len(values) > 1 {
		level := values[0]
		currentTime := "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m"
		source := fmt.Sprintf("\033[35m(%v)\033[0m", values[1])
		messages := []interface{}{source, currentTime}

		if level == "sql" {
			// duration
			messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0))
			// sql
			var sql string
			var formattedValues []string

			for _, value := range values[4].([]interface{}) {
				indirectValue := reflect.Indirect(reflect.ValueOf(value))
				if indirectValue.IsValid() {
					value = indirectValue.Interface()
					if t, ok := value.(time.Time); ok {
						formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format(time.RFC3339)))
					} else if b, ok := value.([]byte); ok {
						if str := string(b); isPrintable(str) {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
						} else {
							formattedValues = append(formattedValues, "'<binary>'")
						}
					} else if r, ok := value.(driver.Valuer); ok {
						if value, err := r.Value(); err == nil && value != nil {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
						} else {
							formattedValues = append(formattedValues, "NULL")
						}
					} else {
						formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
					}
				} else {
					formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
				}
			}

			var formattedValuesLength = len(formattedValues)
			for index, value := range sqlRegexp.Split(values[3].(string), -1) {
				sql += value
				if index < formattedValuesLength {
					sql += formattedValues[index]
				}
			}

			messages = append(messages, sql)
		} else {
			messages = append(messages, "\033[31;1m")
			messages = append(messages, values[2:]...)
			messages = append(messages, "\033[0m")
		}
		logger.Println(messages...)
	}
}

func isPrintable(s string) bool {
	for _, r := range s {
		if !unicode.IsPrint(r) {
			return false
		}
	}
	return true
}
<commit_msg>When using the LogMode(true), the SQL produced during the log message, places the bounded variables in the wrong location, this is due to the fact that the current implementation splits the values with a regex similar to: ($\d+)|?.<commit_after>package gorm

import (
	"database/sql/driver"
	"fmt"
	"log"
	"os"
	"reflect"
	"regexp"
	"time"
	"unicode"
)

var (
	defaultLogger            = Logger{log.New(os.Stdout, "\r\n", 0)}
	sqlRegexp                = regexp.MustCompile(`\?`)
	numericPlaceHolderRegexp = regexp.MustCompile(`\$\d+`)
)

type logger interface {
	Print(v ...interface{})
}

// LogWriter log writer interface
type LogWriter interface {
	Println(v ...interface{})
}

// Logger default logger
type Logger struct {
	LogWriter
}

// Print format & print log
func (logger Logger) Print(values ...interface{}) {
	if len(values) > 1 {
		level := values[0]
		currentTime := "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m"
		source := fmt.Sprintf("\033[35m(%v)\033[0m", values[1])
		messages := []interface{}{source, currentTime}

		if level == "sql" {
			// duration
			messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0))
			// sql
			var sql string
			var formattedValues []string

			for _, value := range values[4].([]interface{}) {
				indirectValue := reflect.Indirect(reflect.ValueOf(value))
				if indirectValue.IsValid() {
					value = indirectValue.Interface()
					if t, ok := value.(time.Time); ok {
						formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format(time.RFC3339)))
					} else if b, ok := value.([]byte); ok {
						if str := string(b); isPrintable(str) {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
						} else {
							formattedValues = append(formattedValues, "'<binary>'")
						}
					} else if r, ok := value.(driver.Valuer); ok {
						if value, err := r.Value(); err == nil && value != nil {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
						} else {
							formattedValues = append(formattedValues, "NULL")
						}
					} else {
						formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
					}
				} else {
					formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
				}
			}

			// differentiate between $n placeholders or else treat like ?
			if numericPlaceHolderRegexp.MatchString(values[3].(string)) {
				sql = values[3].(string)
				for index, value := range formattedValues {
					placeholder := fmt.Sprintf(`\$%d`, index+1)
					subre := regexp.MustCompile(placeholder)
					sql = subre.ReplaceAllString(sql, value)
				}
			} else {
				var formattedValuesLength = len(formattedValues)
				for index, value := range sqlRegexp.Split(values[3].(string), -1) {
					sql += value
					if index < formattedValuesLength {
						sql += formattedValues[index]
					}
				}
			}

			messages = append(messages, sql)
		} else {
			messages = append(messages, "\033[31;1m")
			messages = append(messages, values[2:]...)
			messages = append(messages, "\033[0m")
		}
		logger.Println(messages...)
	}
}

func isPrintable(s string) bool {
	for _, r := range s {
		if !unicode.IsPrint(r) {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

// Package logger provides multiple ways to log information of different level
// of importance. No default logger is created, but Get is provided to get any
// logger at any location. See the provided examples, both in the documentation
// and the _examples directory (for complete examples).
package logger

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"time"
)

// The log operation levels.
const (
	FatalLevel = "FATAL"
	ErrorLevel = "ERROR"
	InfoLevel  = "INFO "
	DebugLevel = "DEBUG"
	ThumbLevel = "THUMB"
)

const (
	defaultStackSize = 4096
	defaultLogsSize  = 1024
)

// MsgWriter takes a msg and writes it to the output.
type MsgWriter interface {
	Write(Msg) error
	Close() error
}

// Collection of all created loggers by name, used by the Get function.
var loggers = map[string]*Logger{}

// The Logger is an logging object which logs to an io.Writer or MsgWriter.
// Each logging operation makes a single call to the Writer's Write method, but
// not necessarily at the same time a Log operation is called. A Logger can be
// used simultaneously from multiple goroutines, it guarantees to serialize
// access to the Writer. Messages (for the io.Writer) will always be in the
// following format (where level is always 5 characters long):
//	YYYY-MM-DD HH:MM:SS [LEVEL] tag1, tag2: message
//
// There are four different log levels (from higher to lower): Fatal, Error,
// Info and Debug, aswell as Thumbstone which is a special case. Thumbstone is
// used for testing if a function is called in production.
//
// Note: Log operations (Fatal, Error etc.) don't instally write to the
// io.Writer, before closing the program call Logger.Close to ensure that all
// log operations are written to the io.Writer or MsgWriter.
type Logger struct {
	Name      string
	ShowDebug bool
	Errors    []error
	mw        MsgWriter
	logs      chan Msg
	closed    chan struct{}
}

// Fatal logs a recovered error which could have killed the program.
func (l *Logger) Fatal(tags Tags, recv interface{}) {
	// Capture the stack trace and drop null bytes (they'll show up as spaces).
	buf := make([]byte, defaultStackSize)
	runtime.Stack(buf, false)
	buf = bytes.Trim(buf, "\x00")

	// Try to make some sense of the recoverd value.
	var item string
	switch v := recv.(type) {
	case string:
		item = v
	case error:
		item = v.Error()
	default:
		item = fmt.Sprintf("%v", recv)
	}

	item += "\n" + string(buf)
	l.logs <- Msg{FatalLevel, item, tags, time.Now()}
}

// Error logs a recoverable error.
func (l *Logger) Error(tags Tags, err error) {
	l.logs <- Msg{ErrorLevel, err.Error(), tags, time.Now()}
}

// Info logs an informational message.
func (l *Logger) Info(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{InfoLevel, fmt.Sprintf(format, v...), tags, time.Now()}
}

// Debug logs the lowest level of information, only usefull when debugging
// the application. Only shows when Logger.ShowDebug is set to true, which
// defaults to false.
func (l *Logger) Debug(tags Tags, format string, v ...interface{}) {
	if l.ShowDebug {
		l.logs <- Msg{DebugLevel, fmt.Sprintf(format, v...), tags, time.Now()}
	}
}

// Thumbstone indicates a function is still used in production. When developing
// software it's possible to introduce dead code with updates and new features.
// If a function is being suspected of being dead (not used) in production, add
// a call to Thumbstone and check the production logs to see if you're right.
func (l *Logger) Thumbstone(item string) {
	l.logs <- Msg{ThumbLevel, item, Tags{"thumbstone"}, time.Now()}
}

// Close blocks until all logs are written to the writer. After all logs are
// written it will call Close() on the message writer.
//
// Note: if a log operation is called after Close is called it will panic.
func (l *Logger) Close() error {
	close(l.logs)
	<-l.closed
	if l.mw != nil {
		return l.mw.Close()
	}
	return nil
}

// New creates a new logger, which starts a go routine which writes to the
// message writer, this way the main thread won't be blocked. Name is the name
// of the logger, used in getting the logger, via Get, from any location within
// your code. The logger is thread same and won't block, unless the message
// channel buffer is full.
//
// Because the logging isn't done on the main thread it's possible that the
// program will close before all the log items are written to the writer. It is
// required to call logger.Close() before closing down the program! Otherwise
// logs might be lost!
//
// After calling logger.Close(), log.Errors can be accessed to check for any
// writing errors from the log operations.
func New(name string, mw MsgWriter) (*Logger, error) {
	log, err := new(name, mw)
	if err != nil {
		return nil, err
	}

	go logWriter(log)
	return log, nil
}

// Get gets a logger by its name.
func Get(name string) (*Logger, error) {
	log, ok := loggers[name]
	if !ok {
		return nil, errors.New("logger: no logger found with name " + name)
	}
	return log, nil
}

func new(name string, mw MsgWriter) (*Logger, error) {
	if _, ok := loggers[name]; ok {
		return nil, errors.New("logger: name " + name + " already taken")
	}

	log := &Logger{
		Name:   name,
		mw:     mw,
		logs:   make(chan Msg, defaultLogsSize),
		closed: make(chan struct{}, 1), // Can't block.
	}
	loggers[name] = log

	return log, nil
}

// Needs to be run in it's own goroutine, it blocks until log.logs is closed.
func logWriter(log *Logger) {
	for msg := range log.logs {
		if err := log.mw.Write(msg); err != nil {
			log.Errors = append(log.Errors, err)
		}
	}

	log.closed <- struct{}{}
}
<commit_msg>Increase the stack trace size to 8192 bytes<commit_after>// Copyright (C) 2015 Thomas de Zeeuw.
//
// Licensed onder the MIT license that can be found in the LICENSE file.

// Package logger provides multiple ways to log information of different level
// of importance. No default logger is created, but Get is provided to get any
// logger at any location. See the provided examples, both in the documentation
// and the _examples directory (for complete examples).
package logger

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"time"
)

// The log operation levels.
const (
	FatalLevel = "FATAL"
	ErrorLevel = "ERROR"
	InfoLevel  = "INFO "
	DebugLevel = "DEBUG"
	ThumbLevel = "THUMB"
)

const (
	defaultStackSize = 8192
	defaultLogsSize  = 1024
)

// MsgWriter takes a msg and writes it to the output.
type MsgWriter interface {
	Write(Msg) error
	Close() error
}

// Collection of all created loggers by name, used by the Get function.
var loggers = map[string]*Logger{}

// The Logger is an logging object which logs to an io.Writer or MsgWriter.
// Each logging operation makes a single call to the Writer's Write method, but
// not necessarily at the same time a Log operation is called. A Logger can be
// used simultaneously from multiple goroutines, it guarantees to serialize
// access to the Writer. Messages (for the io.Writer) will always be in the
// following format (where level is always 5 characters long):
//	YYYY-MM-DD HH:MM:SS [LEVEL] tag1, tag2: message
//
// There are four different log levels (from higher to lower): Fatal, Error,
// Info and Debug, aswell as Thumbstone which is a special case. Thumbstone is
// used for testing if a function is called in production.
//
// Note: Log operations (Fatal, Error etc.) don't instally write to the
// io.Writer, before closing the program call Logger.Close to ensure that all
// log operations are written to the io.Writer or MsgWriter.
type Logger struct {
	Name      string
	ShowDebug bool
	Errors    []error
	mw        MsgWriter
	logs      chan Msg
	closed    chan struct{}
}

// Fatal logs a recovered error which could have killed the program.
func (l *Logger) Fatal(tags Tags, recv interface{}) {
	// Capture the stack trace and drop null bytes (they'll show up as spaces).
	buf := make([]byte, defaultStackSize)
	runtime.Stack(buf, false)
	buf = bytes.Trim(buf, "\x00")

	// Try to make some sense of the recoverd value.
	var item string
	switch v := recv.(type) {
	case string:
		item = v
	case error:
		item = v.Error()
	default:
		item = fmt.Sprintf("%v", recv)
	}

	item += "\n" + string(buf)
	l.logs <- Msg{FatalLevel, item, tags, time.Now()}
}

// Error logs a recoverable error.
func (l *Logger) Error(tags Tags, err error) {
	l.logs <- Msg{ErrorLevel, err.Error(), tags, time.Now()}
}

// Info logs an informational message.
func (l *Logger) Info(tags Tags, format string, v ...interface{}) {
	l.logs <- Msg{InfoLevel, fmt.Sprintf(format, v...), tags, time.Now()}
}

// Debug logs the lowest level of information, only usefull when debugging
// the application. Only shows when Logger.ShowDebug is set to true, which
// defaults to false.
func (l *Logger) Debug(tags Tags, format string, v ...interface{}) {
	if l.ShowDebug {
		l.logs <- Msg{DebugLevel, fmt.Sprintf(format, v...), tags, time.Now()}
	}
}

// Thumbstone indicates a function is still used in production. When developing
// software it's possible to introduce dead code with updates and new features.
// If a function is being suspected of being dead (not used) in production, add
// a call to Thumbstone and check the production logs to see if you're right.
func (l *Logger) Thumbstone(item string) {
	l.logs <- Msg{ThumbLevel, item, Tags{"thumbstone"}, time.Now()}
}

// Close blocks until all logs are written to the writer. After all logs are
// written it will call Close() on the message writer.
//
// Note: if a log operation is called after Close is called it will panic.
func (l *Logger) Close() error {
	close(l.logs)
	<-l.closed
	if l.mw != nil {
		return l.mw.Close()
	}
	return nil
}

// New creates a new logger, which starts a go routine which writes to the
// message writer, this way the main thread won't be blocked. Name is the name
// of the logger, used in getting the logger, via Get, from any location within
// your code. The logger is thread same and won't block, unless the message
// channel buffer is full.
//
// Because the logging isn't done on the main thread it's possible that the
// program will close before all the log items are written to the writer. It is
// required to call logger.Close() before closing down the program! Otherwise
// logs might be lost!
//
// After calling logger.Close(), log.Errors can be accessed to check for any
// writing errors from the log operations.
func New(name string, mw MsgWriter) (*Logger, error) {
	log, err := new(name, mw)
	if err != nil {
		return nil, err
	}

	go logWriter(log)
	return log, nil
}

// Get gets a logger by its name.
func Get(name string) (*Logger, error) {
	log, ok := loggers[name]
	if !ok {
		return nil, errors.New("logger: no logger found with name " + name)
	}
	return log, nil
}

func new(name string, mw MsgWriter) (*Logger, error) {
	if _, ok := loggers[name]; ok {
		return nil, errors.New("logger: name " + name + " already taken")
	}

	log := &Logger{
		Name:   name,
		mw:     mw,
		logs:   make(chan Msg, defaultLogsSize),
		closed: make(chan struct{}, 1), // Can't block.
	}
	loggers[name] = log

	return log, nil
}

// Needs to be run in it's own goroutine, it blocks until log.logs is closed.
func logWriter(log *Logger) {
	for msg := range log.logs {
		if err := log.mw.Write(msg); err != nil {
			log.Errors = append(log.Errors, err)
		}
	}

	log.closed <- struct{}{}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/op/go-logging"
	"os"
)

const (
	LOGALL = 0
	LOGSTD = 1
	LOGSYS = 2
)

var (
	logger *logging.Logger
)

func GetLogger(pos int) *logging.Logger {
	log := logging.MustGetLogger("yubari")
	stdFormat := logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s}%{color:reset} %{message}`,
	)
	stdLogger := logging.NewBackendFormatter(logging.NewLogBackend(os.Stdout, "", 0), stdFormat)
	sysFormat := logging.MustStringFormatter(
		`%{shortfunc} ▶ %{level:.4s} %{message}`,
	)
	_sysLogger, _ := logging.NewSyslogBackend("yubari")
	sysLogger := logging.NewBackendFormatter(_sysLogger, sysFormat)

	switch pos {
	case LOGALL:
		logging.SetBackend(stdLogger, sysLogger)
	case LOGSTD:
		logging.SetBackend(stdLogger)
	case LOGSYS:
		logging.SetBackend(sysLogger)
	default:
	}

	// logging.AddModuleLevel(stdBackend).SetLevel(logging.CRITICAL, "")

	return log
}
<commit_msg>better enum<commit_after>package main

import (
	"github.com/op/go-logging"
	"os"
)

type LogType uint8

const (
	LOGALL LogType = iota
	LOGSTD
	LOGSYS
)

var (
	logger *logging.Logger
)

func GetLogger(pos LogType) *logging.Logger {
	log := logging.MustGetLogger("yubari")
	stdFormat := logging.MustStringFormatter(
		`%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s}%{color:reset} %{message}`,
	)
	stdLogger := logging.NewBackendFormatter(logging.NewLogBackend(os.Stdout, "", 0), stdFormat)
	sysFormat := logging.MustStringFormatter(
		`%{shortfunc} ▶ %{level:.4s} %{message}`,
	)
	_sysLogger, _ := logging.NewSyslogBackend("yubari")
	sysLogger := logging.NewBackendFormatter(_sysLogger, sysFormat)

	switch pos {
	case LOGALL:
		logging.SetBackend(stdLogger, sysLogger)
	case LOGSTD:
		logging.SetBackend(stdLogger)
	case LOGSYS:
		logging.SetBackend(sysLogger)
	default:
	}

	// logging.AddModuleLevel(stdBackend).SetLevel(logging.CRITICAL, "")

	return log
}
<|endoftext|>


<commit_before>package gomail

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/mail"
	"net/smtp"
	"strings"
)

// A Mailer represents an SMTP server.
type Mailer struct {
	addr      string
	host      string
	localhost string
	config    *tls.Config
	auth      smtp.Auth
	send      SendMailFunc
}

// A MailerSetting can be used in a mailer constructor to configure it.
type MailerSetting func(m *Mailer)

// SetSendMail allows to set the email-sending function of a mailer.
//
// Example:
//
//	myFunc := func(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
//		// Implement your email-sending function similar to smtp.SendMail
//	}
//	mailer := gomail.NewMailer("host", "user", "pwd", 465, SetSendMail(myFunc))
func SetSendMail(s SendMailFunc) MailerSetting {
	return func(m *Mailer) {
		m.send = s
	}
}

// SetTLSConfig allows to set the TLS configuration used to connect the SMTP
// server.
func SetTLSConfig(c *tls.Config) MailerSetting {
	return func(m *Mailer) {
		m.config = c
	}
}

// SetLocalHost allows HELO msg to be send with customized string.
func SetLocalHost(h string) MailerSetting {
	return func(m *Mailer) {
		m.localhost = h
	}
}

// A SendMailFunc is a function to send emails with the same signature than
// smtp.SendMail.
type SendMailFunc func(addr string, a smtp.Auth, from string, to []string, msg []byte) error

// NewMailer returns a mailer. The given parameters are used to connect to the
// SMTP server via a PLAIN authentication mechanism.
func NewMailer(host string, username string, password string, port int, settings ...MailerSetting) *Mailer {
	return NewCustomMailer(
		fmt.Sprintf("%s:%d", host, port),
		smtp.PlainAuth("", username, password, host),
		settings...,
	)
}

// NewCustomMailer creates a mailer with the given authentication mechanism.
//
// Example:
//
//	gomail.NewCustomMailer("host:587", smtp.CRAMMD5Auth("username", "secret"))
func NewCustomMailer(addr string, auth smtp.Auth, settings ...MailerSetting) *Mailer {
	// Error is not handled here to preserve backward compatibility
	host, port, _ := net.SplitHostPort(addr)

	m := &Mailer{
		addr: addr,
		host: host,
		auth: auth,
	}

	for _, s := range settings {
		s(m)
	}

	if m.config == nil {
		m.config = &tls.Config{ServerName: host}
	}
	if m.send == nil {
		m.send = m.getSendMailFunc(port == "465")
	}

	return m
}

// Send sends the emails to all the recipients of the message.
func (m *Mailer) Send(msg *Message) error {
	message := msg.Export()

	from, err := getFrom(message)
	if err != nil {
		return err
	}
	recipients, bcc, err := getRecipients(message)
	if err != nil {
		return err
	}

	h := flattenHeader(message, "")
	body, err := ioutil.ReadAll(message.Body)
	if err != nil {
		return err
	}

	mail := append(h, body...)
	if err := m.send(m.addr, m.auth, from, recipients, mail); err != nil {
		return err
	}

	for _, to := range bcc {
		h = flattenHeader(message, to)
		mail = append(h, body...)
		if err := m.send(m.addr, m.auth, from, []string{to}, mail); err != nil {
			return err
		}
	}

	return nil
}

func flattenHeader(msg *mail.Message, bcc string) []byte {
	buf := getBuffer()
	defer putBuffer(buf)

	for field, value := range msg.Header {
		if field != "Bcc" {
			buf.WriteString(field)
			buf.WriteString(": ")
			buf.WriteString(strings.Join(value, ", "))
			buf.WriteString("\r\n")
		} else if bcc != "" {
			for _, to := range value {
				if strings.Contains(to, bcc) {
					buf.WriteString(field)
					buf.WriteString(": ")
					buf.WriteString(to)
					buf.WriteString("\r\n")
				}
			}
		}
	}
	buf.WriteString("\r\n")

	return buf.Bytes()
}

func getFrom(msg *mail.Message) (string, error) {
	from := msg.Header.Get("Sender")
	if from == "" {
		from = msg.Header.Get("From")
		if from == "" {
			return "", errors.New("mailer: invalid message, \"From\" field is absent")
		}
	}

	return parseAddress(from)
}

func getRecipients(msg *mail.Message) (recipients, bcc []string, err error) {
	for _, field := range []string{"Bcc", "To", "Cc"} {
		if addresses, ok := msg.Header[field]; ok {
			for _, addr := range addresses {
				switch field {
				case "Bcc":
					bcc, err = addAdress(bcc, addr)
				default:
					recipients, err = addAdress(recipients, addr)
				}
				if err != nil {
					return recipients, bcc, err
				}
			}
		}
	}

	return recipients, bcc, nil
}

func addAdress(list []string, addr string) ([]string, error) {
	addr, err := parseAddress(addr)
	if err != nil {
		return list, err
	}
	for _, a := range list {
		if addr == a {
			return list, nil
		}
	}

	return append(list, addr), nil
}

func parseAddress(field string) (string, error) {
	a, err := mail.ParseAddress(field)
	if a == nil {
		return "", err
	}

	return a.Address, err
}
<commit_msg>Add return-path detection as MAIL command protocol<commit_after>package gomail

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"net/mail"
	"net/smtp"
	"strings"
)

// A Mailer represents an SMTP server.
type Mailer struct {
	addr      string
	host      string
	localhost string
	config    *tls.Config
	auth      smtp.Auth
	send      SendMailFunc
}

// A MailerSetting can be used in a mailer constructor to configure it.
type MailerSetting func(m *Mailer)

// SetSendMail allows to set the email-sending function of a mailer.
//
// Example:
//
//	myFunc := func(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
//		// Implement your email-sending function similar to smtp.SendMail
//	}
//	mailer := gomail.NewMailer("host", "user", "pwd", 465, SetSendMail(myFunc))
func SetSendMail(s SendMailFunc) MailerSetting {
	return func(m *Mailer) {
		m.send = s
	}
}

// SetTLSConfig allows to set the TLS configuration used to connect the SMTP
// server.
func SetTLSConfig(c *tls.Config) MailerSetting {
	return func(m *Mailer) {
		m.config = c
	}
}

// SetLocalHost allows HELO msg to be send with customized string.
func SetLocalHost(h string) MailerSetting {
	return func(m *Mailer) {
		m.localhost = h
	}
}

// A SendMailFunc is a function to send emails with the same signature than
// smtp.SendMail.
type SendMailFunc func(addr string, a smtp.Auth, from string, to []string, msg []byte) error

// NewMailer returns a mailer. The given parameters are used to connect to the
// SMTP server via a PLAIN authentication mechanism.
func NewMailer(host string, username string, password string, port int, settings ...MailerSetting) *Mailer {
	return NewCustomMailer(
		fmt.Sprintf("%s:%d", host, port),
		smtp.PlainAuth("", username, password, host),
		settings...,
	)
}

// NewCustomMailer creates a mailer with the given authentication mechanism.
//
// Example:
//
//	gomail.NewCustomMailer("host:587", smtp.CRAMMD5Auth("username", "secret"))
func NewCustomMailer(addr string, auth smtp.Auth, settings ...MailerSetting) *Mailer {
	// Error is not handled here to preserve backward compatibility
	host, port, _ := net.SplitHostPort(addr)

	m := &Mailer{
		addr: addr,
		host: host,
		auth: auth,
	}

	for _, s := range settings {
		s(m)
	}

	if m.config == nil {
		m.config = &tls.Config{ServerName: host}
	}
	if m.send == nil {
		m.send = m.getSendMailFunc(port == "465")
	}

	return m
}

// Send sends the emails to all the recipients of the message.
func (m *Mailer) Send(msg *Message) error {
	message := msg.Export()

	from, err := getFrom(message)
	if err != nil {
		return err
	}
	recipients, bcc, err := getRecipients(message)
	if err != nil {
		return err
	}

	h := flattenHeader(message, "")
	body, err := ioutil.ReadAll(message.Body)
	if err != nil {
		return err
	}

	mail := append(h, body...)
	if err := m.send(m.addr, m.auth, from, recipients, mail); err != nil {
		return err
	}

	for _, to := range bcc {
		h = flattenHeader(message, to)
		mail = append(h, body...)
		if err := m.send(m.addr, m.auth, from, []string{to}, mail); err != nil {
			return err
		}
	}

	return nil
}

func flattenHeader(msg *mail.Message, bcc string) []byte {
	buf := getBuffer()
	defer putBuffer(buf)

	for field, value := range msg.Header {
		if field != "Bcc" {
			buf.WriteString(field)
			buf.WriteString(": ")
			buf.WriteString(strings.Join(value, ", "))
			buf.WriteString("\r\n")
		} else if bcc != "" {
			for _, to := range value {
				if strings.Contains(to, bcc) {
					buf.WriteString(field)
					buf.WriteString(": ")
					buf.WriteString(to)
					buf.WriteString("\r\n")
				}
			}
		}
	}
	buf.WriteString("\r\n")

	return buf.Bytes()
}

func getFrom(msg *mail.Message) (string, error) {
	from := msg.Header.Get("Return-Path")
	if from == "" {
		from = msg.Header.Get("Sender")
		if from == "" {
			from = msg.Header.Get("From")
			if from == "" {
				return "", errors.New("mailer: invalid message, \"From\" field is absent")
			}
		}
	}

	return parseAddress(from)
}

func getRecipients(msg *mail.Message) (recipients, bcc []string, err error) {
	for _, field := range []string{"Bcc", "To", "Cc"} {
		if addresses, ok := msg.Header[field]; ok {
			for _, addr := range addresses {
				switch field {
				case "Bcc":
					bcc, err = addAdress(bcc, addr)
				default:
					recipients, err = addAdress(recipients, addr)
				}
				if err != nil {
					return recipients, bcc, err
				}
			}
		}
	}

	return recipients, bcc, nil
}

func addAdress(list []string, addr string) ([]string, error) {
	addr, err := parseAddress(addr)
	if err != nil {
		return list, err
	}
	for _, a := range list {
		if addr == a {
			return list, nil
		}
	}

	return append(list, addr), nil
}

func parseAddress(field string) (string, error) {
	a, err := mail.ParseAddress(field)
	if a == nil {
		return "", err
	}

	return a.Address, err
}
<|endoftext|>


<commit_before>/* Copyright 2020 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package config

import (
	"github.com/spf13/viper"
)

// Tests represent a set of major tests.
type Tests map[string][]Test

// Test represents a single set of inputs and expected outputs.
type Test struct {
	Name       string            `mapstructure:"name"`
	Args       map[string]string `mapstructure:"args"`
	MustFail   bool              `mapstructure:"must_fail"`
	Wait       int               `mapstructure:"wait"`
	Wants      string            `mapstructure:"wants"`
	DoesntWant string            `mapstructure:"doesnt_want"`
	Prompt     []string          `mapstructure:"prompt"`
}

func setDefaults() {
	testCases, order := generateTestCases()
	viper.SetDefault("tests", testCases)
	viper.SetDefault("docker.build", "golang:1.14-alpine")
	viper.SetDefault("docker.runtime", "alpine:latest")
	viper.SetDefault("docker.files", createDockerfiles(testCases))
	viper.SetDefault("order", order)
	viper.SetDefault("files", map[string][]string{
		"gnoi_os": {"os_path", "new_os_path"},
	})

}

func generateTestCases() (Tests, []string) {
	provisionTest := []Test{{
		Name:   "Provision Bootstrapping Target",
		Args:   map[string]string{"op": "provision", "cert_id": "&<cert_id>"},
		Wants:  "Install success",
		Prompt: []string{"cert_id"},
	}}
	certTests := []Test{
		{
			Name:  "Get certs",
			Args:  map[string]string{"op": "get"},
			Wait:  10,
			Wants: `GetCertificates:\n{\w*`,
		},
		{
			Name:   "Install a cert",
			Args:   map[string]string{"op": "install", "cert_id": "&<new_cert_id>"},
			Wants:  "Install success",
			Prompt: []string{"new_cert_id"},
		},
		{
			Name:  "Check if Target Can Generate CSR",
			Args:  map[string]string{"op": "check"},
			Wants: `CanGenerateCSR:\n(true|false)`,
		},
		{
			Name:       "Revoke a cert",
			Args:       map[string]string{"op": "revoke", "cert_id": "&<new_cert_id>"},
			Wants:      `RevokeCertificates:\n{\w*`,
			DoesntWant: "Failed",
		},
		{
			Name:   "Rotate Certificate",
			Args:   map[string]string{"op": "rotate", "cert_id": "&<cert_id>"},
			Wants:  "Rotate success",
			Prompt: []string{"cert_id"},
		},
		{
			Name:     "Rotate Non-Existent Certificate",
			Args:     map[string]string{"op": "rotate", "cert_id": "&<non_existent_cert_id>"},
			MustFail: true,
			Wants:    "Failed Rotate",
			Prompt:   []string{"non_existent_cert_id"},
		},
	}
	resetTests := []Test{
		{
			Name:  "Resetting a Target Successfully",
			Args:  map[string]string{},
			Wants: `Reset Called Successfully!`,
		},
	}
	osTests := []Test{
		{
			Name:   "Compatible OS with Good Hash Install",
			Args:   map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			Wants:  `^$`,
			Prompt: []string{"os_version"},
		},
		{
			Name:     "Install Already Installed OS",
			Args:     map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			MustFail: true,
			Wait:     3,
			Wants:    "OS version &<os_version> is already installed",
		},
		{
			Name:  "Activate Newly Installed OS",
			Args:  map[string]string{"op": "activate", "version": "&<os_version>"},
			Wants: `^$`,
		},
		{
			Name:  "Verify Newly Installed OS",
			Args:  map[string]string{"op": "verify"},
			Wait:  20,
			Wants: "Running OS Version: &<os_version>",
		},
		{
			Name:     "Transfer Already Running OS",
			Args:     map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			MustFail: true,
			Wants:    "Failed Install: InstallError occured: INSTALL_RUN_PACKAGE",
		},
		{
			Name:     "Install another OS",
			Args:     map[string]string{"op": "install", "version": "&<new_os_version>", "os": "&<new_os_path>"},
			MustFail: true,
			Wait:     0,
			Wants:    `^$`,
			Prompt:   []string{"new_os_version"},
		},
		{
			Name:  "Activate Newly Installed OS",
			Args:  map[string]string{"op": "activate", "version": "&<new_os_version>"},
			Wants: `^$`,
		},
		{
			Name:  "Verify Newly Installed OS",
			Args:  map[string]string{"op": "verify"},
			Wait:  20,
			Wants: "Running OS Version: &<new_os_version>",
		},
		{
			Name:   "Activate Non Existent Version",
			Args:   map[string]string{"op": "activate", "version": "&<non_existent_os_version>"},
			Wants:  "Failed Activate: Non existent version: &<non_existent_os_version>",
			Prompt: []string{"non_existent_os_version"},
		},
	}
	return Tests{"gnoi_os": osTests, "gnoi_reset": resetTests, "gnoi_cert": certTests, "provision": provisionTest}, []string{"gnoi_os", "gnoi_cert", "gnoi_reset"}
}
<commit_msg>Fix typos in tests (#198)<commit_after>/* Copyright 2020 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package config

import (
	"github.com/spf13/viper"
)

// Tests represent a set of major tests.
type Tests map[string][]Test

// Test represents a single set of inputs and expected outputs.
type Test struct {
	Name       string            `mapstructure:"name"`
	Args       map[string]string `mapstructure:"args"`
	MustFail   bool              `mapstructure:"must_fail"`
	Wait       int               `mapstructure:"wait"`
	Wants      string            `mapstructure:"wants"`
	DoesntWant string            `mapstructure:"doesnt_want"`
	Prompt     []string          `mapstructure:"prompt"`
}

func setDefaults() {
	testCases, order := generateTestCases()
	viper.SetDefault("tests", testCases)
	viper.SetDefault("docker.build", "golang:1.14-alpine")
	viper.SetDefault("docker.runtime", "alpine:latest")
	viper.SetDefault("docker.files", createDockerfiles(testCases))
	viper.SetDefault("order", order)
	viper.SetDefault("files", map[string][]string{
		"gnoi_os": {"os_path", "new_os_path"},
	})

}

func generateTestCases() (Tests, []string) {
	provisionTest := []Test{{
		Name:   "Provision Bootstrapping Target",
		Args:   map[string]string{"op": "provision", "cert_id": "&<cert_id>"},
		Wants:  "Install success",
		Prompt: []string{"cert_id"},
	}}
	certTests := []Test{
		{
			Name:  "Get certs",
			Args:  map[string]string{"op": "get"},
			Wait:  10,
			Wants: `GetCertificates:\n{\w*`,
		},
		{
			Name:   "Install a cert",
			Args:   map[string]string{"op": "install", "cert_id": "&<new_cert_id>"},
			Wants:  "Install success",
			Prompt: []string{"new_cert_id"},
		},
		{
			Name:  "Check if Target Can Generate CSR",
			Args:  map[string]string{"op": "check"},
			Wants: `CanGenerateCSR:\n(true|false)`,
		},
		{
			Name:       "Revoke a cert",
			Args:       map[string]string{"op": "revoke", "cert_id": "&<new_cert_id>"},
			Wants:      `RevokeCertificates:\n{\w*`,
			DoesntWant: "Failed",
		},
		{
			Name:   "Rotate Certificate",
			Args:   map[string]string{"op": "rotate", "cert_id": "&<cert_id>"},
			Wants:  "Rotate success",
			Prompt: []string{"cert_id"},
		},
		{
			Name:     "Rotate Non-Existent Certificate",
			Args:     map[string]string{"op": "rotate", "cert_id": "&<non_existent_cert_id>"},
			MustFail: true,
			Wants:    "Failed Rotate",
			Prompt:   []string{"non_existent_cert_id"},
		},
	}
	resetTests := []Test{
		{
			Name:  "Resetting a Target Successfully",
			Args:  map[string]string{},
			Wants: `Reset Called Successfully!`,
		},
	}
	osTests := []Test{
		{
			Name:   "Compatible OS with Good Hash Install",
			Args:   map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			Wants:  `^$`,
			Prompt: []string{"os_version"},
		},
		{
			Name:     "Install Already Installed OS",
			Args:     map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			MustFail: true,
			Wait:     3,
			Wants:    "OS version &<os_version> is already installed",
		},
		{
			Name:  "Activate Newly Installed OS",
			Args:  map[string]string{"op": "activate", "version": "&<os_version>"},
			Wants: `^$`,
		},
		{
			Name:  "Verify Newly Installed OS",
			Args:  map[string]string{"op": "verify"},
			Wait:  20,
			Wants: "Running OS version: &<os_version>",
		},
		{
			Name:     "Transfer Already Running OS",
			Args:     map[string]string{"op": "install", "version": "&<os_version>", "os": "&<os_path>"},
			MustFail: true,
			Wants:    "Failed Install: InstallError occurred: INSTALL_RUN_PACKAGE",
		},
		{
			Name:     "Install another OS",
			Args:     map[string]string{"op": "install", "version": "&<new_os_version>", "os": "&<new_os_path>"},
			Wants:    `^$`,
			Prompt:   []string{"new_os_version"},
		},
		{
			Name:  "Activate Newly Installed OS",
			Args:  map[string]string{"op": "activate", "version": "&<new_os_version>"},
			Wants: `^$`,
		},
		{
			Name:  "Verify Newly Installed OS",
			Args:  map[string]string{"op": "verify"},
			Wait:  20,
			Wants: "Running OS version: &<new_os_version>",
		},
		{
			Name:   "Activate Non Existent Version",
			Args:   map[string]string{"op": "activate", "version": "&<non_existent_os_version>"},
			MustFail: true,
			Wants:  "Failed Activate: Non existent version: &<non_existent_os_version>",
			Prompt: []string{"non_existent_os_version"},
		},
	}
	return Tests{"gnoi_os": osTests, "gnoi_reset": resetTests, "gnoi_cert": certTests, "provision": provisionTest}, []string{"gnoi_os", "gnoi_cert", "gnoi_reset"}
}
<|endoftext|>