<commit_before>// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"time"

	rpc "github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcutil"
)

// nodeConfig contains all the args, and data required to launch a btcd process
// and connect the rpc client to it.
type nodeConfig struct {
	rpcUser    string
	rpcPass    string
	listen     string
	rpcListen  string
	rpcConnect string
	dataDir    string
	logDir     string
	profile    string
	debugLevel string
	extra      []string
	prefix     string

	exe          string
	endpoint     string
	certFile     string
	keyFile      string
	certificates []byte
}

// newConfig returns a newConfig with all default values.
func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) {
	btcdPath, err := btcdExecutablePath()
	if err != nil {
		return nil, err
	}

	a := &nodeConfig{
		listen:    "127.0.0.1:18555",
		rpcListen: "127.0.0.1:18556",
		rpcUser:   "user",
		rpcPass:   "pass",
		extra:     extra,
		prefix:    prefix,
		exe:       btcdPath,
		endpoint:  "ws",
		certFile:  certFile,
		keyFile:   keyFile,
	}
	if err := a.setDefaults(); err != nil {
		return nil, err
	}
	return a, nil
}

// setDefaults sets the default values of the config. It also creates the
// temporary data, and log directories which must be cleaned up with a call to
// cleanup().
func (n *nodeConfig) setDefaults() error {
	datadir, err := ioutil.TempDir("", n.prefix+"-data")
	if err != nil {
		return err
	}
	n.dataDir = datadir
	logdir, err := ioutil.TempDir("", n.prefix+"-logs")
	if err != nil {
		return err
	}
	n.logDir = logdir
	cert, err := ioutil.ReadFile(n.certFile)
	if err != nil {
		return err
	}
	n.certificates = cert
	return nil
}

// arguments returns an array of arguments that be used to launch the btcd
// process.
func (n *nodeConfig) arguments() []string {
	args := []string{}
	if n.rpcUser != "" {
		// --rpcuser
		args = append(args, fmt.Sprintf("--rpcuser=%s", n.rpcUser))
	}
	if n.rpcPass != "" {
		// --rpcpass
		args = append(args, fmt.Sprintf("--rpcpass=%s", n.rpcPass))
	}
	if n.listen != "" {
		// --listen
		args = append(args, fmt.Sprintf("--listen=%s", n.listen))
	}
	if n.rpcListen != "" {
		// --rpclisten
		args = append(args, fmt.Sprintf("--rpclisten=%s", n.rpcListen))
	}
	if n.rpcConnect != "" {
		// --rpcconnect
		args = append(args, fmt.Sprintf("--rpcconnect=%s", n.rpcConnect))
	}
	// --rpccert
	args = append(args, fmt.Sprintf("--rpccert=%s", n.certFile))
	// --rpckey
	args = append(args, fmt.Sprintf("--rpckey=%s", n.keyFile))
	// --txindex
	args = append(args, "--txindex")
	// --addrindex
	args = append(args, "--addrindex")
	if n.dataDir != "" {
		// --datadir
		args = append(args, fmt.Sprintf("--datadir=%s", n.dataDir))
	}
	if n.logDir != "" {
		// --logdir
		args = append(args, fmt.Sprintf("--logdir=%s", n.logDir))
	}
	if n.profile != "" {
		// --profile
		args = append(args, fmt.Sprintf("--profile=%s", n.profile))
	}
	if n.debugLevel != "" {
		// --debuglevel
		args = append(args, fmt.Sprintf("--debuglevel=%s", n.debugLevel))
	}
	args = append(args, n.extra...)
	return args
}

// command returns the exec.Cmd which will be used to start the btcd process.
func (n *nodeConfig) command() *exec.Cmd {
	return exec.Command(n.exe, n.arguments()...)
}

// rpcConnConfig returns the rpc connection config that can be used to connect
// to the btcd process that is launched via Start().
func (n *nodeConfig) rpcConnConfig() rpc.ConnConfig {
	return rpc.ConnConfig{
		Host:                 n.rpcListen,
		Endpoint:             n.endpoint,
		User:                 n.rpcUser,
		Pass:                 n.rpcPass,
		Certificates:         n.certificates,
		DisableAutoReconnect: true,
	}
}

// String returns the string representation of this nodeConfig.
func (n *nodeConfig) String() string {
	return n.prefix
}

// cleanup removes the tmp data and log directories.
func (n *nodeConfig) cleanup() error {
	dirs := []string{
		n.logDir,
		n.dataDir,
	}
	var err error
	for _, dir := range dirs {
		if err = os.RemoveAll(dir); err != nil {
			log.Printf("Cannot remove dir %s: %v", dir, err)
		}
	}
	return err
}

// node houses the necessary state required to configure, launch, and manage a
// btcd process.
type node struct {
	config *nodeConfig

	cmd     *exec.Cmd
	pidFile string

	dataDir string
}

// newNode creates a new node instance according to the passed config. dataDir
// will be used to hold a file recording the pid of the launched process, and
// as the base for the log and data directories for btcd.
func newNode(config *nodeConfig, dataDir string) (*node, error) {
	return &node{
		config:  config,
		dataDir: dataDir,
		cmd:     config.command(),
	}, nil
}

// start creates a new btcd process, and writes its pid in a file reserved for
// recording the pid of the launched process. This file can be used to
// terminate the process in case of a hang, or panic. In the case of a failing
// test case, or panic, it is important that the process be stopped via stop(),
// otherwise, it will persist unless explicitly killed.
func (n *node) start() error {
	if err := n.cmd.Start(); err != nil {
		return err
	}

	pid, err := os.Create(filepath.Join(n.dataDir,
		fmt.Sprintf("%s.pid", n.config)))
	if err != nil {
		return err
	}

	n.pidFile = pid.Name()
	if _, err = fmt.Fprintf(pid, "%d\n", n.cmd.Process.Pid); err != nil {
		return err
	}

	if err := pid.Close(); err != nil {
		return err
	}

	return nil
}

// stop interrupts the running btcd process process, and waits until it exits
// properly. On windows, interrupt is not supported, so a kill signal is used
// instead
func (n *node) stop() error {
	if n.cmd == nil || n.cmd.Process == nil {
		// return if not properly initialized
		// or error starting the process
		return nil
	}
	defer n.cmd.Wait()
	if runtime.GOOS == "windows" {
		return n.cmd.Process.Signal(os.Kill)
	}
	return n.cmd.Process.Signal(os.Interrupt)
}

// cleanup cleanups process and args files. The file housing the pid of the
// created process will be deleted, as well as any directories created by the
// process.
func (n *node) cleanup() error {
	if n.pidFile != "" {
		if err := os.Remove(n.pidFile); err != nil {
			log.Printf("unable to remove file %s: %v", n.pidFile,
				err)
		}
	}

	return n.config.cleanup()
}

// shutdown terminates the running btcd process, and cleans up all
// file/directories created by node.
func (n *node) shutdown() error {
	if err := n.stop(); err != nil {
		return err
	}
	if err := n.cleanup(); err != nil {
		return err
	}
	return nil
}

// genCertPair generates a key/cert pair to the paths provided.
func genCertPair(certFile, keyFile string) error {
	org := "rpctest autogenerated cert"
	validUntil := time.Now().Add(10 * 365 * 24 * time.Hour)
	cert, key, err := btcutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return err
	}

	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}

	return nil
}
<commit_msg>integration/rpctest: if unable to build btcd, use one in PATH<commit_after>// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package rpctest

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"time"

	rpc "github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcutil"
)

// nodeConfig contains all the args, and data required to launch a btcd process
// and connect the rpc client to it.
type nodeConfig struct {
	rpcUser    string
	rpcPass    string
	listen     string
	rpcListen  string
	rpcConnect string
	dataDir    string
	logDir     string
	profile    string
	debugLevel string
	extra      []string
	prefix     string

	exe          string
	endpoint     string
	certFile     string
	keyFile      string
	certificates []byte
}

// newConfig returns a newConfig with all default values.
func newConfig(prefix, certFile, keyFile string, extra []string) (*nodeConfig, error) {
	btcdPath, err := btcdExecutablePath()
	if err != nil {
		btcdPath = "btcd"
	}

	a := &nodeConfig{
		listen:    "127.0.0.1:18555",
		rpcListen: "127.0.0.1:18556",
		rpcUser:   "user",
		rpcPass:   "pass",
		extra:     extra,
		prefix:    prefix,
		exe:       btcdPath,
		endpoint:  "ws",
		certFile:  certFile,
		keyFile:   keyFile,
	}
	if err := a.setDefaults(); err != nil {
		return nil, err
	}
	return a, nil
}

// setDefaults sets the default values of the config. It also creates the
// temporary data, and log directories which must be cleaned up with a call to
// cleanup().
func (n *nodeConfig) setDefaults() error {
	datadir, err := ioutil.TempDir("", n.prefix+"-data")
	if err != nil {
		return err
	}
	n.dataDir = datadir
	logdir, err := ioutil.TempDir("", n.prefix+"-logs")
	if err != nil {
		return err
	}
	n.logDir = logdir
	cert, err := ioutil.ReadFile(n.certFile)
	if err != nil {
		return err
	}
	n.certificates = cert
	return nil
}

// arguments returns an array of arguments that be used to launch the btcd
// process.
func (n *nodeConfig) arguments() []string {
	args := []string{}
	if n.rpcUser != "" {
		// --rpcuser
		args = append(args, fmt.Sprintf("--rpcuser=%s", n.rpcUser))
	}
	if n.rpcPass != "" {
		// --rpcpass
		args = append(args, fmt.Sprintf("--rpcpass=%s", n.rpcPass))
	}
	if n.listen != "" {
		// --listen
		args = append(args, fmt.Sprintf("--listen=%s", n.listen))
	}
	if n.rpcListen != "" {
		// --rpclisten
		args = append(args, fmt.Sprintf("--rpclisten=%s", n.rpcListen))
	}
	if n.rpcConnect != "" {
		// --rpcconnect
		args = append(args, fmt.Sprintf("--rpcconnect=%s", n.rpcConnect))
	}
	// --rpccert
	args = append(args, fmt.Sprintf("--rpccert=%s", n.certFile))
	// --rpckey
	args = append(args, fmt.Sprintf("--rpckey=%s", n.keyFile))
	// --txindex
	args = append(args, "--txindex")
	// --addrindex
	args = append(args, "--addrindex")
	if n.dataDir != "" {
		// --datadir
		args = append(args, fmt.Sprintf("--datadir=%s", n.dataDir))
	}
	if n.logDir != "" {
		// --logdir
		args = append(args, fmt.Sprintf("--logdir=%s", n.logDir))
	}
	if n.profile != "" {
		// --profile
		args = append(args, fmt.Sprintf("--profile=%s", n.profile))
	}
	if n.debugLevel != "" {
		// --debuglevel
		args = append(args, fmt.Sprintf("--debuglevel=%s", n.debugLevel))
	}
	args = append(args, n.extra...)
	return args
}

// command returns the exec.Cmd which will be used to start the btcd process.
func (n *nodeConfig) command() *exec.Cmd {
	return exec.Command(n.exe, n.arguments()...)
}

// rpcConnConfig returns the rpc connection config that can be used to connect
// to the btcd process that is launched via Start().
func (n *nodeConfig) rpcConnConfig() rpc.ConnConfig {
	return rpc.ConnConfig{
		Host:                 n.rpcListen,
		Endpoint:             n.endpoint,
		User:                 n.rpcUser,
		Pass:                 n.rpcPass,
		Certificates:         n.certificates,
		DisableAutoReconnect: true,
	}
}

// String returns the string representation of this nodeConfig.
func (n *nodeConfig) String() string {
	return n.prefix
}

// cleanup removes the tmp data and log directories.
func (n *nodeConfig) cleanup() error {
	dirs := []string{
		n.logDir,
		n.dataDir,
	}
	var err error
	for _, dir := range dirs {
		if err = os.RemoveAll(dir); err != nil {
			log.Printf("Cannot remove dir %s: %v", dir, err)
		}
	}
	return err
}

// node houses the necessary state required to configure, launch, and manage a
// btcd process.
type node struct {
	config *nodeConfig

	cmd     *exec.Cmd
	pidFile string

	dataDir string
}

// newNode creates a new node instance according to the passed config. dataDir
// will be used to hold a file recording the pid of the launched process, and
// as the base for the log and data directories for btcd.
func newNode(config *nodeConfig, dataDir string) (*node, error) {
	return &node{
		config:  config,
		dataDir: dataDir,
		cmd:     config.command(),
	}, nil
}

// start creates a new btcd process, and writes its pid in a file reserved for
// recording the pid of the launched process. This file can be used to
// terminate the process in case of a hang, or panic. In the case of a failing
// test case, or panic, it is important that the process be stopped via stop(),
// otherwise, it will persist unless explicitly killed.
func (n *node) start() error {
	if err := n.cmd.Start(); err != nil {
		return err
	}

	pid, err := os.Create(filepath.Join(n.dataDir,
		fmt.Sprintf("%s.pid", n.config)))
	if err != nil {
		return err
	}

	n.pidFile = pid.Name()
	if _, err = fmt.Fprintf(pid, "%d\n", n.cmd.Process.Pid); err != nil {
		return err
	}

	if err := pid.Close(); err != nil {
		return err
	}

	return nil
}

// stop interrupts the running btcd process process, and waits until it exits
// properly. On windows, interrupt is not supported, so a kill signal is used
// instead
func (n *node) stop() error {
	if n.cmd == nil || n.cmd.Process == nil {
		// return if not properly initialized
		// or error starting the process
		return nil
	}
	defer n.cmd.Wait()
	if runtime.GOOS == "windows" {
		return n.cmd.Process.Signal(os.Kill)
	}
	return n.cmd.Process.Signal(os.Interrupt)
}

// cleanup cleanups process and args files. The file housing the pid of the
// created process will be deleted, as well as any directories created by the
// process.
func (n *node) cleanup() error {
	if n.pidFile != "" {
		if err := os.Remove(n.pidFile); err != nil {
			log.Printf("unable to remove file %s: %v", n.pidFile,
				err)
		}
	}

	return n.config.cleanup()
}

// shutdown terminates the running btcd process, and cleans up all
// file/directories created by node.
func (n *node) shutdown() error {
	if err := n.stop(); err != nil {
		return err
	}
	if err := n.cleanup(); err != nil {
		return err
	}
	return nil
}

// genCertPair generates a key/cert pair to the paths provided.
func genCertPair(certFile, keyFile string) error {
	org := "rpctest autogenerated cert"
	validUntil := time.Now().Add(10 * 365 * 24 * time.Hour)
	cert, key, err := btcutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return err
	}

	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package drift

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/jipiboily/forwardlytics/integrations"
)

// Drift integration
type Drift struct {
	api service
}

type service interface {
	request(string, string, []byte) error
}

type driftAPIProduction struct {
	baseUrl string
}

type apiSubscriber struct {
	Attributes map[string]interface{} `json:"attributes"`
	CreatedAt  int64                  `json:"createdAt"`
	UserId     string                 `json:"userId"`
	OrgId      string                 `json:"orgId"`
}

type apiEvent struct {
	OrgId      string                 `json:"orgId"`
	UserId     string                 `json:"userId"`
	Event      string                 `json:"event"`
	CreatedAt  int64                  `json:"createdAt"`
	Attributes map[string]interface{} `json:"attributes"`
}

type apiPage struct {
	OrgId      string                 `json:"orgId"`
	UserId     string                 `json:"userId"`
	Event      string                 `json:"event"`
	Url        string                 `json:"url"`
	CreatedAt  int64                  `json:"createdAt"`
	Attributes map[string]interface{} `json:"attributes"`
}

// Identify forwards and identify call to Drift
func (d Drift) Identify(identification integrations.Identification) (err error) {
	s := apiSubscriber{}
	s.UserId = string(identification.UserID)
	s.CreatedAt = identification.Timestamp
	s.OrgId = orgID()
	// Add custom attributes
	s.Attributes = identification.UserTraits
	s.Attributes["forwardlyticsReceivedAt"] = identification.ReceivedAt
	s.Attributes["forwardlyticsTimestamp"] = identification.Timestamp
	payload, err := json.Marshal(s)

	err = d.api.request("POST", "identify", payload)
	if err != nil {
		logrus.WithError(err).WithField("identify", identification).WithField("payload", payload).Error("Error sending identify to drift")
	}
	return
}

// Track forwards the event to Drift
func (d Drift) Track(event integrations.Event) (err error) {
	e := apiEvent{}
	e.OrgId = orgID()
	e.UserId = event.UserID
	e.Attributes = event.Properties
	event.Properties["forwardlyticsReceivedAt"] = event.ReceivedAt
	e.Event = event.Name
	e.CreatedAt = event.Timestamp
	payload, err := json.Marshal(e)
	if err != nil {
		logrus.WithError(err).WithField("event", event).WithField("payload", payload).Error("Error marshalling drift event to json")
	}
	err = d.api.request("POST", "track", payload)
	if err != nil {
		logrus.WithError(err).WithField("event", event).WithField("payload", payload).Error("Error sending event to drift")
	}
	return
}

// Page forwards the page-events to Drift
func (d Drift) Page(page integrations.Page) (err error) {
	p := apiPage{}
	p.OrgId = orgID()
	p.UserId = page.UserID
	p.Url = page.Url
	page.Properties["forwardlyticsReceivedAt"] = page.ReceivedAt
	page.Properties["name"] = page.Name
	p.Attributes = page.Properties
	p.Event = "page"
	p.CreatedAt = page.Timestamp
	payload, err := json.Marshal(p)
	if err != nil {
		logrus.WithError(err).WithField("page", page).WithField("payload", payload).Error("Error marshalling drift page-event to json")
	}
	err = d.api.request("POST", "track", payload)
	if err != nil {
		logrus.WithError(err).WithField("page", page).WithField("payload", payload).Error("Error sending page-event to drift")
	}
	return
}

// Enabled returns wether or not the Drift integration is enabled/configured
func (Drift) Enabled() bool {
	return orgID() != ""
}

func (api driftAPIProduction) request(method string, endpoint string, payload []byte) (err error) {
	apiUrl := api.baseUrl + endpoint
	req, err := http.NewRequest(method, apiUrl, bytes.NewBuffer(payload))
	req.Header.Add("User-Agent", "forwardlytics")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		logrus.WithError(err).WithFields(
			logrus.Fields{
				"method":   method,
				"apiUrl":   apiUrl,
				"endpoint": endpoint,
				"payload":  payload}).Error("Error sending request to Drift api")
		return
	}
	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logrus.WithError(err).WithFields(
				logrus.Fields{
					"method":     method,
					"apiUrl":     apiUrl,
					"endpoint":   endpoint,
					"payload":    payload,
					"httpstatus": resp.StatusCode}).Error("Error reading Drift response")
			return err
		}
		logrus.WithFields(
			logrus.Fields{
				"response":    string(body),
				"HTTP-status": resp.StatusCode,
				"method":      method,
				"endpoint":    endpoint,
				"payload":     payload}).Error("Drift api returned errors")

	}
	return
}

func orgID() string {
	return os.Getenv("DRIFT_ORG_ID")
}

func init() {
	drift := Drift{}
	drift.api = &driftAPIProduction{baseUrl: "https://event.api.drift.com/"}
	integrations.RegisterIntegration("drift", drift)
}
<commit_msg>force payload logging to be a string instead of a byte[]<commit_after>package drift

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"os"

	"github.com/Sirupsen/logrus"
	"github.com/jipiboily/forwardlytics/integrations"
)

// Drift integration
type Drift struct {
	api service
}

type service interface {
	request(string, string, []byte) error
}

type driftAPIProduction struct {
	baseUrl string
}

type apiSubscriber struct {
	Attributes map[string]interface{} `json:"attributes"`
	CreatedAt  int64                  `json:"createdAt"`
	UserId     string                 `json:"userId"`
	OrgId      string                 `json:"orgId"`
}

type apiEvent struct {
	OrgId      string                 `json:"orgId"`
	UserId     string                 `json:"userId"`
	Event      string                 `json:"event"`
	CreatedAt  int64                  `json:"createdAt"`
	Attributes map[string]interface{} `json:"attributes"`
}

type apiPage struct {
	OrgId      string                 `json:"orgId"`
	UserId     string                 `json:"userId"`
	Event      string                 `json:"event"`
	Url        string                 `json:"url"`
	CreatedAt  int64                  `json:"createdAt"`
	Attributes map[string]interface{} `json:"attributes"`
}

// Identify forwards and identify call to Drift
func (d Drift) Identify(identification integrations.Identification) (err error) {
	s := apiSubscriber{}
	s.UserId = string(identification.UserID)
	s.CreatedAt = identification.Timestamp
	s.OrgId = orgID()
	// Add custom attributes
	s.Attributes = identification.UserTraits
	s.Attributes["forwardlyticsReceivedAt"] = identification.ReceivedAt
	s.Attributes["forwardlyticsTimestamp"] = identification.Timestamp
	payload, err := json.Marshal(s)

	err = d.api.request("POST", "identify", payload)
	if err != nil {
		logrus.WithError(err).WithField("identify", identification).WithField("payload", string(payload[:])).Error("Error sending identify to drift")
	}
	return
}

// Track forwards the event to Drift
func (d Drift) Track(event integrations.Event) (err error) {
	e := apiEvent{}
	e.OrgId = orgID()
	e.UserId = event.UserID
	e.Attributes = event.Properties
	event.Properties["forwardlyticsReceivedAt"] = event.ReceivedAt
	e.Event = event.Name
	e.CreatedAt = event.Timestamp
	payload, err := json.Marshal(e)
	if err != nil {
		logrus.WithError(err).WithField("event", event).WithField("payload", string(payload[:])).Error("Error marshalling drift event to json")
	}
	err = d.api.request("POST", "track", payload)
	if err != nil {
		logrus.WithError(err).WithField("event", event).WithField("payload", string(payload[:])).Error("Error sending event to drift")
	}
	return
}

// Page forwards the page-events to Drift
func (d Drift) Page(page integrations.Page) (err error) {
	p := apiPage{}
	p.OrgId = orgID()
	p.UserId = page.UserID
	p.Url = page.Url
	page.Properties["forwardlyticsReceivedAt"] = page.ReceivedAt
	page.Properties["name"] = page.Name
	p.Attributes = page.Properties
	p.Event = "page"
	p.CreatedAt = page.Timestamp
	payload, err := json.Marshal(p)
	if err != nil {
		logrus.WithError(err).WithField("page", page).WithField("payload", string(payload[:])).Error("Error marshalling drift page-event to json")
	}
	err = d.api.request("POST", "track", payload)
	if err != nil {
		logrus.WithError(err).WithField("page", page).WithField("payload", string(payload[:])).Error("Error sending page-event to drift")
	}
	return
}

// Enabled returns wether or not the Drift integration is enabled/configured
func (Drift) Enabled() bool {
	return orgID() != ""
}

func (api driftAPIProduction) request(method string, endpoint string, payload []byte) (err error) {
	apiUrl := api.baseUrl + endpoint
	req, err := http.NewRequest(method, apiUrl, bytes.NewBuffer(payload))
	req.Header.Add("User-Agent", "forwardlytics")
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		logrus.WithError(err).WithFields(
			logrus.Fields{
				"method":   method,
				"apiUrl":   apiUrl,
				"endpoint": endpoint,
				"payload":  string(payload[:])}).Error("Error sending request to Drift api")
		return
	}
	if resp.StatusCode != http.StatusOK {
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logrus.WithError(err).WithFields(
				logrus.Fields{
					"method":     method,
					"apiUrl":     apiUrl,
					"endpoint":   endpoint,
					"payload":    string(payload[:]),
					"httpstatus": resp.StatusCode}).Error("Error reading Drift response")
			return err
		}
		logrus.WithFields(
			logrus.Fields{
				"response":    string(body),
				"HTTP-status": resp.StatusCode,
				"method":      method,
				"endpoint":    endpoint,
				"payload":     string(payload[:])}).Error("Drift api returned errors")

	}
	return
}

func orgID() string {
	return os.Getenv("DRIFT_ORG_ID")
}

func init() {
	drift := Drift{}
	drift.api = &driftAPIProduction{baseUrl: "https://event.api.drift.com/"}
	integrations.RegisterIntegration("drift", drift)
}
<|endoftext|>


<commit_before>package udpmux

import (
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/peer-calls/peer-calls/server/logger"
)

var DefaultMTU uint32 = 8192

type UDPMux struct {
	params      *Params
	conns       map[string]*muxedConn
	mu          sync.Mutex
	logger      logger.Logger
	debugLogger logger.Logger
	connChan    chan Conn
	closeChan   chan struct{}
	closeOnce   sync.Once
	wg          sync.WaitGroup
}

type Params struct {
	Conn          net.PacketConn
	MTU           uint32
	LoggerFactory logger.LoggerFactory
	ReadChanSize  int
}

func New(params Params) *UDPMux {
	u := &UDPMux{
		params:      &params,
		conns:       map[string]*muxedConn{},
		logger:      params.LoggerFactory.GetLogger("udpmux:info"),
		debugLogger: params.LoggerFactory.GetLogger("udpmux:debug"),
		connChan:    make(chan Conn),
		closeChan:   make(chan struct{}),
	}

	if u.params.MTU == 0 {
		u.params.MTU = DefaultMTU
	}

	u.wg.Add(1)
	go func() {
		defer u.wg.Done()
		u.start()
	}()

	return u
}

func (u *UDPMux) LocalAddr() net.Addr {
	return u.params.Conn.LocalAddr()
}

func (u *UDPMux) AcceptConn() (Conn, error) {
	conn, ok := <-u.connChan
	if !ok {
		return nil, fmt.Errorf("Conn closed")
	}

	u.logger.Printf("%s AcceptConn", conn, conn.RemoteAddr())

	return conn, nil
}

func (u *UDPMux) GetConn(raddr net.Addr) (Conn, error) {
	u.mu.Lock()
	defer u.mu.Unlock()

	select {
	case <-u.closeChan:
		return nil, fmt.Errorf("UDPMux closed")
	default:
	}

	if _, ok := u.conns[raddr.String()]; ok {
		return nil, fmt.Errorf("Connection already exists")
	}

	c := u.createConn(raddr, false)

	u.logger.Printf("%s GetConn", c, raddr)

	return c, nil
}

func (u *UDPMux) start() {
	buf := make([]byte, u.params.MTU)

	for {
		i, raddr, err := u.params.Conn.ReadFrom(buf)

		if err != nil {
			u.logger.Printf("Error reading remote data: %s", err)
			_ = u.params.Conn.Close()
			return
		}

		u.handleRemoteBytes(raddr, buf[:i])
	}
}

func (u *UDPMux) CloseChannel() <-chan struct{} {
	return u.closeChan
}

func (u *UDPMux) Close() error {
	u.logger.Println("Close")

	err := u.params.Conn.Close()

	u.close()

	u.wg.Wait()

	return err
}

func (u *UDPMux) close() {
	u.mu.Lock()
	defer u.mu.Unlock()

	for _, conn := range u.conns {
		u.closeConn(conn)
	}

	u.closeOnce.Do(func() {
		close(u.connChan)
		close(u.closeChan)
	})
}

func (u *UDPMux) handleClose(conn *muxedConn) {
	u.mu.Lock()
	defer u.mu.Unlock()

	u.closeConn(conn)
}

func (u *UDPMux) closeConn(conn *muxedConn) {
	u.logger.Printf("%s closeConn", conn)

	conn.onceClose.Do(func() {
		close(conn.readChan)
		close(conn.closeChan)
	})
	delete(u.conns, conn.RemoteAddr().String())
}

func (u *UDPMux) handleRemoteBytes(raddr net.Addr, buf []byte) {
	u.mu.Lock()
	defer u.mu.Unlock()

	select {
	case <-u.closeChan:
		u.logger.Println("Ignoring remote data because connection has been closed")
		return
	default:
	}

	c := u.getOrCreateConn(raddr, true)
	select {
	case <-c.closeChan:
		u.logger.Println("Ignoring remote data because connection has been closed")
		return
	default:
	}

	c.handleRemoteBytes(buf)
}

func (u *UDPMux) getOrCreateConn(raddr net.Addr, accept bool) *muxedConn {
	c, ok := u.conns[raddr.String()]
	if !ok {
		c = u.createConn(raddr, accept)
	}
	return c
}

func (u *UDPMux) createConn(raddr net.Addr, accept bool) *muxedConn {
	c := &muxedConn{
		debugLogger: u.debugLogger,
		conn:        u.params.Conn,
		laddr:       u.params.Conn.LocalAddr(),
		raddr:       raddr,
		readChan:    make(chan []byte, u.params.ReadChanSize),
		closeChan:   make(chan struct{}),
		onClose:     u.handleClose,
	}
	u.conns[raddr.String()] = c
	if accept {
		u.connChan <- c
	}
	return c
}

type Conn interface {
	net.Conn
	CloseChannel() <-chan struct{}
}

type muxedConn struct {
	conn        net.PacketConn
	laddr       net.Addr
	raddr       net.Addr
	readChan    chan []byte
	closeChan   chan struct{}
	onClose     func(m *muxedConn)
	onceClose   sync.Once
	debugLogger logger.Logger
}

var _ Conn = &muxedConn{}

func (m *muxedConn) Close() error {
	m.onClose(m)
	return nil
}

func (m *muxedConn) handleRemoteBytes(buf []byte) {
	b := make([]byte, len(buf))
	copy(b, buf)
	m.readChan <- b
}

func (m *muxedConn) CloseChannel() <-chan struct{} {
	return m.closeChan
}

func (m *muxedConn) Read(b []byte) (int, error) {
	buf, ok := <-m.readChan
	if !ok {
		return 0, fmt.Errorf("Conn closed")
	}
	copy(b, buf)
	m.debugLogger.Printf("%s recv %v", m, buf)
	return len(buf), nil
}

func (m *muxedConn) Write(b []byte) (int, error) {
	select {
	case <-m.closeChan:
		return 0, fmt.Errorf("Conn is closed")
	default:
		m.debugLogger.Printf("%s send %v", m, b)
		return m.conn.WriteTo(b, m.raddr)
	}
}

func (m *muxedConn) LocalAddr() net.Addr {
	return m.laddr
}

func (m *muxedConn) RemoteAddr() net.Addr {
	return m.raddr
}

func (m *muxedConn) SetDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) SetReadDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) SetWriteDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) String() string {
	if s, ok := m.conn.(stringer); ok {
		return fmt.Sprintf("%s [%s %s]", s.String(), m.laddr, m.raddr)
	}

	return fmt.Sprintf("[%s %s]", m.laddr, m.raddr)
}

var _ net.Conn = &muxedConn{}

type stringer interface {
	String() string
}
<commit_msg>Fix AcceptConn logger in udpmux.go<commit_after>package udpmux

import (
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/peer-calls/peer-calls/server/logger"
)

var DefaultMTU uint32 = 8192

type UDPMux struct {
	params      *Params
	conns       map[string]*muxedConn
	mu          sync.Mutex
	logger      logger.Logger
	debugLogger logger.Logger
	connChan    chan Conn
	closeChan   chan struct{}
	closeOnce   sync.Once
	wg          sync.WaitGroup
}

type Params struct {
	Conn          net.PacketConn
	MTU           uint32
	LoggerFactory logger.LoggerFactory
	ReadChanSize  int
}

func New(params Params) *UDPMux {
	u := &UDPMux{
		params:      &params,
		conns:       map[string]*muxedConn{},
		logger:      params.LoggerFactory.GetLogger("udpmux:info"),
		debugLogger: params.LoggerFactory.GetLogger("udpmux:debug"),
		connChan:    make(chan Conn),
		closeChan:   make(chan struct{}),
	}

	if u.params.MTU == 0 {
		u.params.MTU = DefaultMTU
	}

	u.wg.Add(1)
	go func() {
		defer u.wg.Done()
		u.start()
	}()

	return u
}

func (u *UDPMux) LocalAddr() net.Addr {
	return u.params.Conn.LocalAddr()
}

func (u *UDPMux) AcceptConn() (Conn, error) {
	conn, ok := <-u.connChan
	if !ok {
		return nil, fmt.Errorf("Conn closed")
	}

	u.logger.Printf("%s AcceptConn", conn)

	return conn, nil
}

func (u *UDPMux) GetConn(raddr net.Addr) (Conn, error) {
	u.mu.Lock()
	defer u.mu.Unlock()

	select {
	case <-u.closeChan:
		return nil, fmt.Errorf("UDPMux closed")
	default:
	}

	if _, ok := u.conns[raddr.String()]; ok {
		return nil, fmt.Errorf("Connection already exists")
	}

	c := u.createConn(raddr, false)

	u.logger.Printf("%s GetConn", c, raddr)

	return c, nil
}

func (u *UDPMux) start() {
	buf := make([]byte, u.params.MTU)

	for {
		i, raddr, err := u.params.Conn.ReadFrom(buf)

		if err != nil {
			u.logger.Printf("Error reading remote data: %s", err)
			_ = u.params.Conn.Close()
			return
		}

		u.handleRemoteBytes(raddr, buf[:i])
	}
}

func (u *UDPMux) CloseChannel() <-chan struct{} {
	return u.closeChan
}

func (u *UDPMux) Close() error {
	u.logger.Println("Close")

	err := u.params.Conn.Close()

	u.close()

	u.wg.Wait()

	return err
}

func (u *UDPMux) close() {
	u.mu.Lock()
	defer u.mu.Unlock()

	for _, conn := range u.conns {
		u.closeConn(conn)
	}

	u.closeOnce.Do(func() {
		close(u.connChan)
		close(u.closeChan)
	})
}

func (u *UDPMux) handleClose(conn *muxedConn) {
	u.mu.Lock()
	defer u.mu.Unlock()

	u.closeConn(conn)
}

func (u *UDPMux) closeConn(conn *muxedConn) {
	u.logger.Printf("%s closeConn", conn)

	conn.onceClose.Do(func() {
		close(conn.readChan)
		close(conn.closeChan)
	})
	delete(u.conns, conn.RemoteAddr().String())
}

func (u *UDPMux) handleRemoteBytes(raddr net.Addr, buf []byte) {
	u.mu.Lock()
	defer u.mu.Unlock()

	select {
	case <-u.closeChan:
		u.logger.Println("Ignoring remote data because connection has been closed")
		return
	default:
	}

	c := u.getOrCreateConn(raddr, true)
	select {
	case <-c.closeChan:
		u.logger.Println("Ignoring remote data because connection has been closed")
		return
	default:
	}

	c.handleRemoteBytes(buf)
}

func (u *UDPMux) getOrCreateConn(raddr net.Addr, accept bool) *muxedConn {
	c, ok := u.conns[raddr.String()]
	if !ok {
		c = u.createConn(raddr, accept)
	}
	return c
}

func (u *UDPMux) createConn(raddr net.Addr, accept bool) *muxedConn {
	c := &muxedConn{
		debugLogger: u.debugLogger,
		conn:        u.params.Conn,
		laddr:       u.params.Conn.LocalAddr(),
		raddr:       raddr,
		readChan:    make(chan []byte, u.params.ReadChanSize),
		closeChan:   make(chan struct{}),
		onClose:     u.handleClose,
	}
	u.conns[raddr.String()] = c
	if accept {
		u.connChan <- c
	}
	return c
}

type Conn interface {
	net.Conn
	CloseChannel() <-chan struct{}
}

type muxedConn struct {
	conn        net.PacketConn
	laddr       net.Addr
	raddr       net.Addr
	readChan    chan []byte
	closeChan   chan struct{}
	onClose     func(m *muxedConn)
	onceClose   sync.Once
	debugLogger logger.Logger
}

var _ Conn = &muxedConn{}

func (m *muxedConn) Close() error {
	m.onClose(m)
	return nil
}

func (m *muxedConn) handleRemoteBytes(buf []byte) {
	b := make([]byte, len(buf))
	copy(b, buf)
	m.readChan <- b
}

func (m *muxedConn) CloseChannel() <-chan struct{} {
	return m.closeChan
}

func (m *muxedConn) Read(b []byte) (int, error) {
	buf, ok := <-m.readChan
	if !ok {
		return 0, fmt.Errorf("Conn closed")
	}
	copy(b, buf)
	m.debugLogger.Printf("%s recv %v", m, buf)
	return len(buf), nil
}

func (m *muxedConn) Write(b []byte) (int, error) {
	select {
	case <-m.closeChan:
		return 0, fmt.Errorf("Conn is closed")
	default:
		m.debugLogger.Printf("%s send %v", m, b)
		return m.conn.WriteTo(b, m.raddr)
	}
}

func (m *muxedConn) LocalAddr() net.Addr {
	return m.laddr
}

func (m *muxedConn) RemoteAddr() net.Addr {
	return m.raddr
}

func (m *muxedConn) SetDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) SetReadDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) SetWriteDeadline(t time.Time) error {
	return nil
}

func (m *muxedConn) String() string {
	if s, ok := m.conn.(stringer); ok {
		return fmt.Sprintf("%s [%s %s]", s.String(), m.laddr, m.raddr)
	}

	return fmt.Sprintf("[%s %s]", m.laddr, m.raddr)
}

var _ net.Conn = &muxedConn{}

type stringer interface {
	String() string
}
<|endoftext|>


<commit_before>//@author: Parag Patel
//this is the first version of nequeens, it has not been optimized yet. Hasn't been fully tested.

package main

import (
	"fmt"
	"os"
	"strconv"
)

var boardsize int = 3

func printBoard(board [][]bool) {
	fmt.Println("<==SOLUTION==>")
	for i, _ := range board {
		for j, _ := range board[i] {
			if board[i][j] == false {
				fmt.Printf("B ")
			} else {
				fmt.Printf("Q ")
			}
		}
		fmt.Printf("\n")
	}
}

func validatePosition(board [][]bool, x int, y int) bool {

	//check left

	for i := x - 1; i >= 0; i-- {
		if board[i][y] == true {
			return false
		}
	}

	//check leftdiagonalup
	for i, j := x-1, y-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
		if board[i][j] == true {
			return false
		}
	}

	//check leftdiagonaldown
	for i, j := x-1, y+1; i >= 0 && j < boardsize; i, j = i-1, j+1 {
		if board[i][j] == true {
			return false
		}
	}

	return true
}

func newboard(board [][]bool) [][]bool {
	nboard := make([][]bool, boardsize)
	for i, _ := range nboard {
		nboard[i] = make([]bool, boardsize)
	}

	if board != nil {
		copy(nboard, board)
	}

	return nboard
}

func nxnboardandqueensolution(n int) {
	boardsize = n
	fmt.Println(n, "x", n, " board with ", n, " queens, has the following solutions")
	fmt.Println("total of ", nqueens(newboard(nil), n, 0), " solutions")
}

func nqueens(board [][]bool, n int, startx int) int {
	if n == 0 {
		//printBoard(board)
		return 1
	}

	counter := 0

	for i := startx; i < boardsize; i++ {
		for j := 0; j < boardsize; j++ {
			if board[i][j] == false && validatePosition(board, i, j) {
				board[i][j] = true
				nboard := newboard(board)
				counter += nqueens(nboard, n-1, i+1)
				board[i][j] = false
			}
		}
	}

	return counter
}

func main() {

	n, _ := strconv.Atoi(os.Args[1])

	for i := 1; i <= n; i++ {
		nxnboardandqueensolution(i)
	}

}
<commit_msg>removed print comment<commit_after>//@author: Parag Patel
//this is the first version of nequeens, it has not been optimized yet. Hasn't been fully tested.

package main

import (
	"fmt"
	"os"
	"strconv"
)

var boardsize int = 3

func printBoard(board [][]bool) {
	fmt.Println("<==SOLUTION==>")
	for i, _ := range board {
		for j, _ := range board[i] {
			if board[i][j] == false {
				fmt.Printf("B ")
			} else {
				fmt.Printf("Q ")
			}
		}
		fmt.Printf("\n")
	}
}

func validatePosition(board [][]bool, x int, y int) bool {

	//check left

	for i := x - 1; i >= 0; i-- {
		if board[i][y] == true {
			return false
		}
	}

	//check leftdiagonalup
	for i, j := x-1, y-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
		if board[i][j] == true {
			return false
		}
	}

	//check leftdiagonaldown
	for i, j := x-1, y+1; i >= 0 && j < boardsize; i, j = i-1, j+1 {
		if board[i][j] == true {
			return false
		}
	}

	return true
}

func newboard(board [][]bool) [][]bool {
	nboard := make([][]bool, boardsize)
	for i, _ := range nboard {
		nboard[i] = make([]bool, boardsize)
	}

	if board != nil {
		copy(nboard, board)
	}

	return nboard
}

func nxnboardandqueensolution(n int) {
	boardsize = n
	fmt.Println(n, "x", n, " board with ", n, " queens, has the following solutions")
	fmt.Println("total of ", nqueens(newboard(nil), n, 0), " solutions")
}

func nqueens(board [][]bool, n int, startx int) int {
	if n == 0 {
		return 1
	}

	counter := 0

	for i := startx; i < boardsize; i++ {
		for j := 0; j < boardsize; j++ {
			if board[i][j] == false && validatePosition(board, i, j) {
				board[i][j] = true
				nboard := newboard(board)
				counter += nqueens(nboard, n-1, i+1)
				board[i][j] = false
			}
		}
	}

	return counter
}

func main() {

	n, _ := strconv.Atoi(os.Args[1])

	for i := 1; i <= n; i++ {
		nxnboardandqueensolution(i)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
	nameNet "github.com/coreos/go-namespaces/net"
)

func proxyConn(conn *net.Conn, addr string) {
	rConn, err := net.Dial("tcp", addr)
	if err != nil {
		log.Printf(err.Error())
		(*conn).Close()
		return
	}

	go io.Copy(rConn, *conn)
	go io.Copy(*conn, rConn)
}

func proxy(c *cli.Context) {
	addr := c.String("addr")
	target := c.Int("target")
	if target == 0 {
		fmt.Fprintln(os.Stderr, "error: a target pid is required")
		return
	}

	path := c.String("path")
	if path == "" {
		fmt.Fprintln(os.Stderr, "error: an etcd path is required")
		return
	}

	peers := trimsplit(c.String("peers"), ",")
	client := etcd.NewClient(peers)

	log.Printf("Proxying for keys in %s on host %s in namespace %d", path, addr, target)

	// Keep an eye on the backend path
	b := backends{path: path}
	err := b.Sync(client)
	if err != nil {
		log.Fatal(err)
	}

	go b.Watch(client)

	listener, err := nameNet.ListenNamespace(uintptr(target), "tcp", addr)
	if err != nil {
		panic(err)
	}

	for {
		// Wait for a connection.
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		next := b.Next()
		if next == "" {
			conn.Close()
			log.Printf("No backends! Closing the connection")
			continue
		}

		log.Printf("PROXY: targetPid:%d targetAddr:%v addr:%v\n", target, addr, next)
		go proxyConn(&conn, next)
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "nsproxy"
	app.Usage = "Proxy into a network namespace"
	app.Flags = []cli.Flag{
		cli.IntFlag{"target, t", 0, "target namespace pid", false},
		cli.StringFlag{"path, p", "", "path to a dir", false},
		cli.StringFlag{"addr, a", "127.0.0.1:8080", "target address inside the namespace", false},
		cli.StringFlag{"peers, C", "http://127.0.0.1:4001", "a comma seperated list of machine addresses in the cluster", false},
	}
	app.Action = proxy
	app.Run(os.Args)
}
<commit_msg>added namespace by path support<commit_after>package main

import (
	"fmt"
	"io"
	"log"
	"net"
	"os"

	"github.com/codegangsta/cli"
	"github.com/coreos/go-etcd/etcd"
	nameNet "github.com/coreos/go-namespaces/net"
)

func proxyConn(conn *net.Conn, addr string) {
	rConn, err := net.Dial("tcp", addr)
	if err != nil {
		log.Printf(err.Error())
		(*conn).Close()
		return
	}

	go io.Copy(rConn, *conn)
	go io.Copy(*conn, rConn)
}

func proxy(c *cli.Context) {
	addr := c.String("addr")
	target := c.Int("target")
	namespacePath := c.String("namespace")
	if target == 0 && namespacePath == "" {
		fmt.Fprintln(os.Stderr, "error: a target pid or namespace path is required")
		return
	}

	path := c.String("path")
	if path == "" {
		fmt.Fprintln(os.Stderr, "error: an etcd path is required")
		return
	}

	peers := trimsplit(c.String("peers"), ",")
	client := etcd.NewClient(peers)

	log.Printf("Proxying for keys in %s on host %s", path, addr)

	// Keep an eye on the backend path
	b := backends{path: path}
	err := b.Sync(client)
	if err != nil {
		log.Fatal(err)
	}

	go b.Watch(client)

	var listener net.Listener
	if target != 0 {
		log.Printf("Proxying for keys in %s on host %s in namespace %d", path, addr, target)
		listener, err = nameNet.ListenProcessNamespace(uintptr(target), "tcp", addr)
	} else {
		log.Printf("Proxying for keys in %s on host %s in namespace %d", path, addr, namespacePath)
		listener, err = nameNet.ListenNamespace(namespacePath, "tcp", addr)
	}
	if err != nil {
		panic(err)
	}

	for {
		// Wait for a connection.
		conn, err := listener.Accept()
		if err != nil {
			log.Fatal(err)
		}

		next := b.Next()
		if next == "" {
			conn.Close()
			log.Printf("No backends! Closing the connection")
			continue
		}

		log.Printf("PROXY: targetAddr:%v addr:%v\n", addr, next)
		go proxyConn(&conn, next)
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "nsproxy"
	app.Usage = "Proxy into a network namespace"
	app.Flags = []cli.Flag{
		cli.IntFlag{"target, t", 0, "target namespace pid", false},
		cli.StringFlag{"path, p", "", "path to a dir", false},
		cli.StringFlag{"addr, a", "127.0.0.1:8080", "target address inside the namespace", false},
		cli.StringFlag{"peers, C", "http://127.0.0.1:4001", "a comma seperated list of machine addresses in the cluster", false},
		cli.StringFlag{"namespace, ns", "", "target namespace path", false},
	}
	app.Action = proxy
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package e2etest

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/e2e"
)

func TestInitProviders(t *testing.T) {
	t.Parallel()

	// This test reaches out to releases.hashicorp.com to download the
	// template provider, so it can only run if network access is allowed.
	// We intentionally don't try to stub this here, because there's already
	// a stubbed version of this in the "command" package and so the goal here
	// is to test the interaction with the real repository.
	skipIfCannotAccessNetwork(t)

	fixturePath := filepath.Join("test-fixtures", "template-provider")
	tf := e2e.NewBinary(terraformBin, fixturePath)
	defer tf.Close()

	stdout, stderr, err := tf.Run("init")
	if err != nil {
		t.Errorf("unexpected error: %s", err)
	}

	if stderr != "" {
		t.Errorf("unexpected stderr output:\n%s", stderr)
	}

	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
		t.Errorf("success message is missing from output:\n%s", stdout)
	}

	if !strings.Contains(stdout, "- Downloading plugin for provider \"template\"") {
		t.Errorf("provider download message is missing from output:\n%s", stdout)
		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
	}

	if !strings.Contains(stdout, "* provider.template: version = ") {
		t.Errorf("provider pinning recommendation is missing from output:\n%s", stdout)
	}

}

func TestInitProviders_pluginCache(t *testing.T) {
	t.Parallel()

	// This test reaches out to releases.hashicorp.com to access plugin
	// metadata, and download the null plugin, though the template plugin
	// should come from local cache.
	skipIfCannotAccessNetwork(t)

	fixturePath := filepath.Join("test-fixtures", "plugin-cache")
	tf := e2e.NewBinary(terraformBin, fixturePath)
	defer tf.Close()

	// Our fixture dir has a generic os_arch dir, which we need to customize
	// to the actual OS/arch where this test is running in order to get the
	// desired result.
	fixtMachineDir := tf.Path("cache/os_arch")
	wantMachineDir := tf.Path("cache", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Rename(fixtMachineDir, wantMachineDir)

	cmd := tf.Cmd("init")
	cmd.Env = append(cmd.Env, "TF_PLUGIN_CACHE_DIR=./cache")
	cmd.Stdin = nil
	cmd.Stderr = &bytes.Buffer{}

	err := cmd.Run()
	if err != nil {
		t.Errorf("unexpected error: %s", err)
	}

	stderr := cmd.Stderr.(*bytes.Buffer).String()
	if stderr != "" {
		t.Errorf("unexpected stderr output:\n%s", stderr)
	}

	path := fmt.Sprintf(".terraform/plugins/%s_%s/terraform-provider-template_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)
	content, err := tf.ReadFile(path)
	if err != nil {
		t.Fatalf("failed to read installed plugin from %s: %s", path, err)
	}
	if strings.TrimSpace(string(content)) != "this is not a real plugin" {
		t.Errorf("template plugin was not installed from local cache")
	}

	if !tf.FileExists(fmt.Sprintf(".terraform/plugins/%s_%s/terraform-provider-null_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
		t.Errorf("null plugin was not installed")
	}

	if !tf.FileExists(fmt.Sprintf("cache/%s_%s/terraform-provider-null_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
		t.Errorf("null plugin is not in cache after install")
	}
}
<commit_msg>e2e test for `init -from-module`<commit_after>package e2etest

import (
	"bytes"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/e2e"
)

func TestInitProviders(t *testing.T) {
	t.Parallel()

	// This test reaches out to releases.hashicorp.com to download the
	// template provider, so it can only run if network access is allowed.
	// We intentionally don't try to stub this here, because there's already
	// a stubbed version of this in the "command" package and so the goal here
	// is to test the interaction with the real repository.
	skipIfCannotAccessNetwork(t)

	fixturePath := filepath.Join("test-fixtures", "template-provider")
	tf := e2e.NewBinary(terraformBin, fixturePath)
	defer tf.Close()

	stdout, stderr, err := tf.Run("init")
	if err != nil {
		t.Errorf("unexpected error: %s", err)
	}

	if stderr != "" {
		t.Errorf("unexpected stderr output:\n%s", stderr)
	}

	if !strings.Contains(stdout, "Terraform has been successfully initialized!") {
		t.Errorf("success message is missing from output:\n%s", stdout)
	}

	if !strings.Contains(stdout, "- Downloading plugin for provider \"template\"") {
		t.Errorf("provider download message is missing from output:\n%s", stdout)
		t.Logf("(this can happen if you have a copy of the plugin in one of the global plugin search dirs)")
	}

	if !strings.Contains(stdout, "* provider.template: version = ") {
		t.Errorf("provider pinning recommendation is missing from output:\n%s", stdout)
	}

}

func TestInitProviders_pluginCache(t *testing.T) {
	t.Parallel()

	// This test reaches out to releases.hashicorp.com to access plugin
	// metadata, and download the null plugin, though the template plugin
	// should come from local cache.
	skipIfCannotAccessNetwork(t)

	fixturePath := filepath.Join("test-fixtures", "plugin-cache")
	tf := e2e.NewBinary(terraformBin, fixturePath)
	defer tf.Close()

	// Our fixture dir has a generic os_arch dir, which we need to customize
	// to the actual OS/arch where this test is running in order to get the
	// desired result.
	fixtMachineDir := tf.Path("cache/os_arch")
	wantMachineDir := tf.Path("cache", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Rename(fixtMachineDir, wantMachineDir)

	cmd := tf.Cmd("init")
	cmd.Env = append(cmd.Env, "TF_PLUGIN_CACHE_DIR=./cache")
	cmd.Stdin = nil
	cmd.Stderr = &bytes.Buffer{}

	err := cmd.Run()
	if err != nil {
		t.Errorf("unexpected error: %s", err)
	}

	stderr := cmd.Stderr.(*bytes.Buffer).String()
	if stderr != "" {
		t.Errorf("unexpected stderr output:\n%s", stderr)
	}

	path := fmt.Sprintf(".terraform/plugins/%s_%s/terraform-provider-template_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)
	content, err := tf.ReadFile(path)
	if err != nil {
		t.Fatalf("failed to read installed plugin from %s: %s", path, err)
	}
	if strings.TrimSpace(string(content)) != "this is not a real plugin" {
		t.Errorf("template plugin was not installed from local cache")
	}

	if !tf.FileExists(fmt.Sprintf(".terraform/plugins/%s_%s/terraform-provider-null_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
		t.Errorf("null plugin was not installed")
	}

	if !tf.FileExists(fmt.Sprintf("cache/%s_%s/terraform-provider-null_v0.1.0_x4", runtime.GOOS, runtime.GOARCH)) {
		t.Errorf("null plugin is not in cache after install")
	}
}

func TestInit_fromModule(t *testing.T) {
	t.Parallel()

	// This test reaches out to registry.terraform.io and github.com to lookup
	// and fetch a module.
	skipIfCannotAccessNetwork(t)

	fixturePath := filepath.Join("test-fixtures", "empty")
	tf := e2e.NewBinary(terraformBin, fixturePath)
	defer tf.Close()

	cmd := tf.Cmd("init", "-from-module=hashicorp/vault/aws")
	cmd.Stdin = nil
	cmd.Stderr = &bytes.Buffer{}

	err := cmd.Run()
	if err != nil {
		t.Errorf("unexpected error: %s", err)
	}

	stderr := cmd.Stderr.(*bytes.Buffer).String()
	if stderr != "" {
		t.Errorf("unexpected stderr output:\n%s", stderr)
	}

	content, err := tf.ReadFile("main.tf")
	if err != nil {
		t.Fatalf("failed to read main.tf: %s", err)
	}
	if !bytes.Contains(content, []byte("vault")) {
		t.Fatalf("main.tf doesn't appear to be a vault configuration: \n%s", content)
	}
}
<|endoftext|>


<commit_before>package jetpack

import "bufio"
import "bytes"
import "compress/bzip2"
import "compress/gzip"
import "crypto/sha512"
import "fmt"
import "io"
import "net"
import "os"

import "github.com/appc/spec/aci"
import "github.com/appc/spec/schema/types"
import "github.com/juju/errors"

import "../run"

func untilError(steps ...func() error) error {
	for _, step := range steps {
		if err := step(); err != nil {
			return err
		}
	}
	return nil
}

// FIXME: mostly copy/paste from github.com/appc/spec/actool/validate.go
func DecompressingReader(rd io.Reader) (io.Reader, error) {
	brd := bufio.NewReaderSize(rd, 1024)
	header, err := brd.Peek(768)
	if err != nil {
		return nil, errors.Trace(err)
	}

	typ, err := aci.DetectFileType(bytes.NewReader(header))
	if err != nil {
		return nil, errors.Trace(err)
	}

	var r io.Reader
	switch typ {
	case aci.TypeGzip:
		r, err = gzip.NewReader(brd)
		if err != nil {
			return nil, errors.Trace(err)
		}
	case aci.TypeBzip2:
		r = bzip2.NewReader(brd)
	case aci.TypeXz:
		r = aci.XzReader(brd)
	case aci.TypeTar:
		r = brd
	case aci.TypeUnknown:
		return nil, errors.New("unknown filetype")
	default:
		panic(fmt.Sprintf("bad type returned from DetectFileType: %v", typ))
	}
	return r, nil
}

func UnpackImage(uri, path, saveAmiPath string) (hsh *types.Hash, err error) {
	// use fetch(1) to avoid worrying about protocols, proxies and such
	fetchCmd := run.Command("fetch", "-o", "-", uri)
	fetch, err := fetchCmd.StdoutPipe()
	if err != nil {
		return nil, errors.Trace(err)
	}

	fetchRd := fetch.(io.Reader)

	if saveAmiPath != "" {
		if ami, err := os.OpenFile(saveAmiPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0400); err != nil {
			return nil, errors.Trace(err)
		} else {
			defer ami.Close()
			fetchRd = io.TeeReader(fetch, ami)
		}
	}

	// We trust system's tar, no need to roll our own
	untarCmd := run.Command("tar", "-C", path, "-xf", "-")
	untar, err := untarCmd.StdinPipe()
	if err != nil {
		return nil, errors.Trace(err)
	}

	if err := untarCmd.Start(); err != nil {
		return nil, errors.Trace(err)
	}
	// FIXME: defer killing process if survived

	if err := fetchCmd.Start(); err != nil {
		return nil, errors.Trace(err)
	}
	// FIXME: defer killing process if survived

	aci, err := DecompressingReader(fetchRd)
	if err != nil {
		return nil, errors.Trace(err)
	}

	hash := sha512.New()

	if _, err := io.Copy(hash, io.TeeReader(aci, untar)); err != nil {
		return nil, errors.Trace(err)
	}

	if err := fetch.Close(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := fetchCmd.Wait(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := untar.Close(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := untarCmd.Wait(); err != nil {
		return nil, errors.Trace(err)
	}

	if hash, err := types.NewHash(fmt.Sprintf("sha512-%x", hash.Sum(nil))); err != nil {
		// CAN'T HAPPEN
		return nil, errors.Trace(err)
	} else {
		return hash, nil
	}
}

func ConsoleApp(username string) *types.App {
	return &types.App{
		Exec: []string{"/usr/bin/login", "-f", username},
		User: "root",
	}
}

func nextIP(ip net.IP) net.IP {
	for i := len(ip) - 1; i >= 0; i-- {
		ip[i] += 1
		if ip[i] > 0 {
			return ip
		}
	}
	return nil
}
<commit_msg>Preserve environment when launching console<commit_after>package jetpack

import "bufio"
import "bytes"
import "compress/bzip2"
import "compress/gzip"
import "crypto/sha512"
import "fmt"
import "io"
import "net"
import "os"

import "github.com/appc/spec/aci"
import "github.com/appc/spec/schema/types"
import "github.com/juju/errors"

import "../run"

func untilError(steps ...func() error) error {
	for _, step := range steps {
		if err := step(); err != nil {
			return err
		}
	}
	return nil
}

// FIXME: mostly copy/paste from github.com/appc/spec/actool/validate.go
func DecompressingReader(rd io.Reader) (io.Reader, error) {
	brd := bufio.NewReaderSize(rd, 1024)
	header, err := brd.Peek(768)
	if err != nil {
		return nil, errors.Trace(err)
	}

	typ, err := aci.DetectFileType(bytes.NewReader(header))
	if err != nil {
		return nil, errors.Trace(err)
	}

	var r io.Reader
	switch typ {
	case aci.TypeGzip:
		r, err = gzip.NewReader(brd)
		if err != nil {
			return nil, errors.Trace(err)
		}
	case aci.TypeBzip2:
		r = bzip2.NewReader(brd)
	case aci.TypeXz:
		r = aci.XzReader(brd)
	case aci.TypeTar:
		r = brd
	case aci.TypeUnknown:
		return nil, errors.New("unknown filetype")
	default:
		panic(fmt.Sprintf("bad type returned from DetectFileType: %v", typ))
	}
	return r, nil
}

func UnpackImage(uri, path, saveAmiPath string) (hsh *types.Hash, err error) {
	// use fetch(1) to avoid worrying about protocols, proxies and such
	fetchCmd := run.Command("fetch", "-o", "-", uri)
	fetch, err := fetchCmd.StdoutPipe()
	if err != nil {
		return nil, errors.Trace(err)
	}

	fetchRd := fetch.(io.Reader)

	if saveAmiPath != "" {
		if ami, err := os.OpenFile(saveAmiPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0400); err != nil {
			return nil, errors.Trace(err)
		} else {
			defer ami.Close()
			fetchRd = io.TeeReader(fetch, ami)
		}
	}

	// We trust system's tar, no need to roll our own
	untarCmd := run.Command("tar", "-C", path, "-xf", "-")
	untar, err := untarCmd.StdinPipe()
	if err != nil {
		return nil, errors.Trace(err)
	}

	if err := untarCmd.Start(); err != nil {
		return nil, errors.Trace(err)
	}
	// FIXME: defer killing process if survived

	if err := fetchCmd.Start(); err != nil {
		return nil, errors.Trace(err)
	}
	// FIXME: defer killing process if survived

	aci, err := DecompressingReader(fetchRd)
	if err != nil {
		return nil, errors.Trace(err)
	}

	hash := sha512.New()

	if _, err := io.Copy(hash, io.TeeReader(aci, untar)); err != nil {
		return nil, errors.Trace(err)
	}

	if err := fetch.Close(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := fetchCmd.Wait(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := untar.Close(); err != nil {
		return nil, errors.Trace(err)
	}

	if err := untarCmd.Wait(); err != nil {
		return nil, errors.Trace(err)
	}

	if hash, err := types.NewHash(fmt.Sprintf("sha512-%x", hash.Sum(nil))); err != nil {
		// CAN'T HAPPEN
		return nil, errors.Trace(err)
	} else {
		return hash, nil
	}
}

func ConsoleApp(username string) *types.App {
	return &types.App{
		Exec: []string{"/usr/bin/login", "-fp", username},
		User: "root",
	}
}

func nextIP(ip net.IP) net.IP {
	for i := len(ip) - 1; i >= 0; i-- {
		ip[i] += 1
		if ip[i] > 0 {
			return ip
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package jq

import (
	"testing"
	"time"
)

type TestJob1 struct {
	Ch chan struct{}
}

func (j *TestJob1) Run() error {
	j.Ch <- struct{}{}
	return nil
}

func (j *TestJob1) Result() interface{}{
	return nil
}

type TestJob2 struct {
	Ch chan struct{}
}

func (j *TestJob2) Run() error {
	j.Ch <- struct{}{}
	return nil
}

func (j *TestJob2) Result() interface{} {
	return nil
}

func TestSetConfig(t *testing.T) {
	type testcase struct {
		in     QueueConfig
		expect error
	}
	cases := []testcase{{
		in: QueueConfig{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: nil,
	}, {
		in: QueueConfig{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: ErrQueueIsExist,
	}, {
		in: QueueConfig{
			Name:        "testname2",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: ErrContenerIsNotUnique,
	}}

	for _, v := range cases {
		err := SetConfig(v.in)
		if err != v.expect {
			t.Errorf("expect %s but got %s", v.expect, err)
		}
	}

	// clear
	clearutil()
}

func TestSetConfigList(t *testing.T) {
	type testcase struct {
		in     []QueueConfig
		expect error
	}
	cases := []testcase{{
		in: []QueueConfig{{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		}, {
			Name:        "testname2",
			Concurrency: 1,
			JobContener: &TestJob2{},
		}},
		expect: nil,
	}}

	for _, v := range cases {
		err := SetConfigList(v.in)
		if err != v.expect {
			t.Errorf("expect %s but got %s", v.expect, err)
		}
	}
	// clear
	clearutil()
}

func TestPublish(t *testing.T) {
	// initialize
	SetConfig(QueueConfig{
		Name:        "test1",
		JobContener: &TestJob1{},
		Concurrency: 1,
		Length:      1,
	})

	// returns error if job is not registerd.
	_, err := Publish(&TestJob2{})
	if err != ErrQueueNotFound {
		t.Fail()
	}

	// returns info if job is registerd.
	ch := make(chan struct{}, 0)
	info, err := Publish(&TestJob1{ch})
	if err != nil {
		t.Fail()
	}
	if info == nil {
		t.Fail()
	}

	// returns error if queue is full
	_, err = Publish(&TestJob1{ch})
	if err != ErrJobQueueIsFull {
		t.Fail()
	}

	// must run(1st called job)
	select {
	case <-time.After(10 * time.Second):
		t.Fail()
	case <-ch:
		t.Log("ok")
	}

	Kill("test1")
}

func clearutil() {
	configList = map[string]queueConfig{}
}
<commit_msg>improve test<commit_after>package jq

import (
	"testing"
	"time"
)

type TestJob1 struct {
	Ch chan struct{}
}

func (j *TestJob1) Run() error {
	time.Sleep(100*time.Millisecond)
	j.Ch <- struct{}{}
	return nil
}

func (j *TestJob1) Result() interface{}{
	return nil
}

type TestJob2 struct {
	Ch chan struct{}
}

func (j *TestJob2) Run() error {
	time.Sleep(100*time.Millisecond)
	j.Ch <- struct{}{}
	return nil
}

func (j *TestJob2) Result() interface{} {
	return nil
}

func TestSetConfig(t *testing.T) {
	type testcase struct {
		in     QueueConfig
		expect error
	}
	cases := []testcase{{
		in: QueueConfig{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: nil,
	}, {
		in: QueueConfig{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: ErrQueueIsExist,
	}, {
		in: QueueConfig{
			Name:        "testname2",
			Concurrency: 1,
			JobContener: &TestJob1{},
		},
		expect: ErrContenerIsNotUnique,
	}}

	for _, v := range cases {
		err := SetConfig(v.in)
		if err != v.expect {
			t.Errorf("expect %s but got %s", v.expect, err)
		}
	}

	// clear
	clearutil()
}

func TestSetConfigList(t *testing.T) {
	type testcase struct {
		in     []QueueConfig
		expect error
	}
	cases := []testcase{{
		in: []QueueConfig{{
			Name:        "testname",
			Concurrency: 1,
			JobContener: &TestJob1{},
		}, {
			Name:        "testname2",
			Concurrency: 1,
			JobContener: &TestJob2{},
		}},
		expect: nil,
	}}

	for _, v := range cases {
		err := SetConfigList(v.in)
		if err != v.expect {
			t.Errorf("expect %s but got %s", v.expect, err)
		}
	}
	// clear
	clearutil()
}

func TestPublish(t *testing.T) {
	// initialize
	SetConfig(QueueConfig{
		Name:        "test1",
		JobContener: &TestJob1{},
		Concurrency: 1,
		Length:      1,
	})

	// returns error if job is not registerd.
	_, err := Publish(&TestJob2{})
	if err != ErrQueueNotFound {
		t.Fail()
	}

	// returns info if job is registerd.
	ch := make(chan struct{}, 0)
	info, err := Publish(&TestJob1{ch})
	if err != nil {
		t.Fail()
	}
	if info == nil {
		t.Fail()
	}

	// returns error if queue is full
	_, err = Publish(&TestJob1{ch})
	if err != ErrJobQueueIsFull {
		t.Fail()
	}

	// must run(1st called job)
	select {
	case <-time.After(10 * time.Second):
		t.Fail()
	case <-ch:
		t.Log("ok")
	}

	Kill("test1")
}

func clearutil() {
	configList = map[string]queueConfig{}
}
<|endoftext|>


<commit_before>package formatter

import (
  "github.com/phemmer/sawmill/event"
  "fmt"
)

type ansiColorCodes struct {
	Bold, Normal, Black, BlackBold, Red, RedBold, Green, GreenBold, Yellow, YellowBold, Blue, BlueBold, Magenta, MagentaBold, Cyan, CyanBold, White, WhiteBold, Underline, Reset []byte
}
var colors = ansiColorCodes{
	Bold:        []byte{27, '[', '1', 'm'},
	Normal:      []byte{27, '[', '2', '2', 'm'},
	Black:       []byte{27, '[', '3', '0', 'm'},
	BlackBold:   []byte{27, '[', '3', '0', ';', '1', 'm'},
	Red:         []byte{27, '[', '3', '1', 'm'},
	RedBold:     []byte{27, '[', '3', '1', ';', '1', 'm'},
	Green:       []byte{27, '[', '3', '2', 'm'},
	GreenBold:   []byte{27, '[', '3', '2', ';', '1', 'm'},
	Yellow:      []byte{27, '[', '3', '3', 'm'},
	YellowBold:  []byte{27, '[', '3', '3', ';', '1', 'm'},
	Blue:        []byte{27, '[', '3', '4', 'm'},
	BlueBold:    []byte{27, '[', '3', '4', ';', '1', 'm'},
	Magenta:     []byte{27, '[', '3', '5', 'm'},
	MagentaBold: []byte{27, '[', '3', '5', ';', '1', 'm'},
	Cyan:        []byte{27, '[', '3', '6', 'm'},
	CyanBold:    []byte{27, '[', '3', '6', ';', '1', 'm'},
	White:       []byte{27, '[', '3', '7', 'm'},
	WhiteBold:   []byte{27, '[', '3', '7', ';', '1', 'm'},

	Underline:   []byte{27, '[', '4', 'm'},

	Reset:   []byte{27, '[', '0', 'm'},
}

const (
	SIMPLE_FORMAT = "{{.Message}}{{range $k,$v := .Fields}} {{$k}}={{$v}}{{end}}"
	CONSOLE_COLOR_FORMAT = "{{.Time \"2006-01-02_15:04:05.000\"}} {{.Level | .Color | printf \"%s>\" | .Pad -9}} {{.Message | .Pad -30}}{{range $k,$v := .Fields}} {{$k | $.Color}}={{$v}}{{end}}"
	CONSOLE_NOCOLOR_FORMAT = "{{.Time \"2006-01-02_15:04:05.000\"}} {{.Level | printf \"%s>\" | .Pad -9}} {{.Message | .Pad -30}}{{range $k,$v := .Fields}} {{$k}}={{$v}}{{end}}"
)

type Formatter struct {
	Event *event.Event
}
func EventFormatter(logEvent *event.Event) (*Formatter) {
  return &Formatter{Event: logEvent}
}
func (formatter *Formatter) Time(format string) string {
	return formatter.Event.Time.Format(format)
}
func (formatter *Formatter) Level() string {
	return formatter.Event.LevelName()
}
func (formatter *Formatter) Color(text string) string {
	var levelColor []byte
	if formatter.Event.Level <= event.Error {
		levelColor = colors.Red
	} else if formatter.Event.Level == event.Warning {
		levelColor = colors.Yellow
	} else {
		levelColor = colors.Blue
	}
	return fmt.Sprintf("%s%s%s", levelColor, text, colors.Reset)
}
func (formatter *Formatter) Pad(size int, text string) string {
	return text //TODO
}
func (formatter *Formatter) Message() string {
	return formatter.Event.Message
}
func (formatter *Formatter) Fields() map[string]interface{} {
	return formatter.Event.FlatFields()
}
<commit_msg>add a working `Pad()` to the formatter<commit_after>package formatter

import (
  "github.com/phemmer/sawmill/event"
  "fmt"
  "strings"
)

type ansiColorCodes struct {
	Bold, Normal, Black, BlackBold, Red, RedBold, Green, GreenBold, Yellow, YellowBold, Blue, BlueBold, Magenta, MagentaBold, Cyan, CyanBold, White, WhiteBold, Underline, Reset []byte
}
var colors = ansiColorCodes{
	Bold:        []byte{27, '[', '1', 'm'},
	Normal:      []byte{27, '[', '2', '2', 'm'},
	Black:       []byte{27, '[', '3', '0', 'm'},
	BlackBold:   []byte{27, '[', '3', '0', ';', '1', 'm'},
	Red:         []byte{27, '[', '3', '1', 'm'},
	RedBold:     []byte{27, '[', '3', '1', ';', '1', 'm'},
	Green:       []byte{27, '[', '3', '2', 'm'},
	GreenBold:   []byte{27, '[', '3', '2', ';', '1', 'm'},
	Yellow:      []byte{27, '[', '3', '3', 'm'},
	YellowBold:  []byte{27, '[', '3', '3', ';', '1', 'm'},
	Blue:        []byte{27, '[', '3', '4', 'm'},
	BlueBold:    []byte{27, '[', '3', '4', ';', '1', 'm'},
	Magenta:     []byte{27, '[', '3', '5', 'm'},
	MagentaBold: []byte{27, '[', '3', '5', ';', '1', 'm'},
	Cyan:        []byte{27, '[', '3', '6', 'm'},
	CyanBold:    []byte{27, '[', '3', '6', ';', '1', 'm'},
	White:       []byte{27, '[', '3', '7', 'm'},
	WhiteBold:   []byte{27, '[', '3', '7', ';', '1', 'm'},

	Underline:   []byte{27, '[', '4', 'm'},

	Reset:   []byte{27, '[', '0', 'm'},
}

const (
	SIMPLE_FORMAT = "{{.Message}}{{range $k,$v := .Fields}} {{$k}}={{$v}}{{end}}"
	CONSOLE_COLOR_FORMAT = "{{.Time \"2006-01-02_15:04:05.000\"}} {{.Level | .Color | printf \"%s>\" | .Pad -10}} {{.Message | .Pad -30}}{{range $k,$v := .Fields}} {{$k | $.Color}}={{$v}}{{end}}"
	CONSOLE_NOCOLOR_FORMAT = "{{.Time \"2006-01-02_15:04:05.000\"}} {{.Level | printf \"%s>\" | .Pad -10}} {{.Message | .Pad -30}}{{range $k,$v := .Fields}} {{$k}}={{$v}}{{end}}"
)

type Formatter struct {
	Event *event.Event
}
func EventFormatter(logEvent *event.Event) (*Formatter) {
  return &Formatter{Event: logEvent}
}
func (formatter *Formatter) Time(format string) string {
	return formatter.Event.Time.Format(format)
}
func (formatter *Formatter) Level() string {
	return formatter.Event.LevelName()
}
func (formatter *Formatter) Color(text string) string {
	var levelColor []byte
	if formatter.Event.Level <= event.Error {
		levelColor = colors.Red
	} else if formatter.Event.Level == event.Warning {
		levelColor = colors.Yellow
	} else {
		levelColor = colors.Blue
	}
	return fmt.Sprintf("%s%s%s", levelColor, text, colors.Reset)
}

/*
This pads the provided text to the specified length, while properly handling the color escape codes.
Like the `%-10s` format, negative values mean pad on the right, where as positive values mean pad on the left.
*/
func (formatter *Formatter) Pad(size int, text string) string {
  pos := 0
  colorLen := 0
  for index := strings.Index(text[pos:], "["); index != -1; index = strings.Index(text[pos:], "[") {
    pos = pos + index
    index = strings.Index(text[pos:], "m")
    if index == -1 {
      break
    }
    colorLen = colorLen + index + 1 // + 1 because 'index' is effectively the number of characters before 'm', where we want length including 'm'
    pos = pos + index + 1
  }
  textLen := len(text) - colorLen

  if size < 0 {
    padLen := -size - textLen
    if padLen > 0 {
      return fmt.Sprintf("%s%s", text, strings.Repeat(" ", padLen))
    }
  } else {
    padLen := size - textLen
    if padLen > 0 {
      return fmt.Sprintf("%s%s", strings.Repeat(" ", padLen), text)
    }
  }

	return text
}
func (formatter *Formatter) Message() string {
	return formatter.Event.Message
}
func (formatter *Formatter) Fields() map[string]interface{} {
	return formatter.Event.FlatFields()
}
<|endoftext|>


<commit_before>package log

import (
	"time"
)

type Level uint

const (
	_                = 0
	ErrorLevel Level = 1 << (iota - 1)
	WarnLevel
	InfoLevel
	DebugLevel
	TraceLevel
)

type Logger struct {
	sink   Sink
	fields []Field
}

type Record struct {
	l      Logger
	Meta   Metadata
	Format string
	Args   []interface{}
}

func (r *Record) Fields() []Field {
	return r.l.fields
}

type Field struct {
	Name  string
	Value interface{}
}

type Metadata struct {
	Level Level
	Time  time.Time
	File  string
	Line  uint
}

func newRecord(l Logger, m Metadata, format string, args []interface{}) Record {
	return Record{l: l, Meta: m, Format: format, Args: args}
}

func newMetadata(lvl Level, withTime bool) Metadata {
	if withTime {
		return Metadata{Level: lvl, Time: time.Now()}
	}
	return Metadata{Level: lvl}
}

func (l Logger) IsEnabled(lvl Level) bool {
	m := newMetadata(lvl, false)
	return l.sink.IsEnabled(&m)
}

func (l Logger) Logf(lvl Level, format string, args ...interface{}) {
	if !l.IsEnabled(lvl) {
		return
	}
	r := newRecord(l, newMetadata(lvl, true), format, args)
	l.sink.Log(&r)
}

func (l Logger) Log(lvl Level, message string) {
	l.Logf(lvl, message)
}

func (l Logger) Logv(lvl Level, args ...interface{}) {
	l.Logf(lvl, "", args...)
}

func (l Logger) Info(message string) {
	l.Log(InfoLevel, message)
}

func (l Logger) Warn(message string) {
	l.Log(WarnLevel, message)
}

func (l Logger) Error(message string) {
	l.Log(ErrorLevel, message)
}

func (l Logger) Debug(message string) {
	l.Log(DebugLevel, message)
}

func (l Logger) Trace(message string) {
	l.Log(TraceLevel, message)
}

func (l Logger) Infov(args ...interface{}) {
	l.Logv(InfoLevel, args...)
}

func (l Logger) WarnV(args ...interface{}) {
	l.Logv(WarnLevel, args...)
}

func (l Logger) Errorv(args ...interface{}) {
	l.Logv(ErrorLevel, args...)
}

func (l Logger) Debugv(args ...interface{}) {
	l.Logv(DebugLevel, args...)
}

func (l Logger) Tracev(args ...interface{}) {
	l.Logv(TraceLevel, args...)
}

func (l Logger) Infof(format string, args ...interface{}) {
	l.Logf(InfoLevel, format, args...)
}

func (l Logger) Warnf(format string, args ...interface{}) {
	l.Logf(WarnLevel, format, args...)
}

func (l Logger) Errorf(format string, args ...interface{}) {
	l.Logf(ErrorLevel, format, args...)
}

func (l Logger) Debugf(format string, args ...interface{}) {
	l.Logf(DebugLevel, format, args...)
}

func (l Logger) Tracef(format string, args ...interface{}) {
	l.Logf(TraceLevel, format, args...)
}

func (l Logger) Flush() {
	l.sink.Flush()
}

func (l Logger) With(name string, value interface{}) Logger {
	s := make([]Field, 0, len(l.fields)+1)
	s = append(s, l.fields...)
	s = append(s, Field{name, value})
	return Logger{l.sink, s}
}

func (l Logger) WithFields(fields []Field) Logger {
	s := make([]Field, 0, len(l.fields)+len(fields))
	s = append(s, l.fields...)
	s = append(s, fields...)
	return Logger{l.sink, s}
}

func IsEnabled(lvl Level) bool {
	return g.IsEnabled(lvl)
}

func Logf(lvl Level, format string, args ...interface{}) {
	g.Logf(lvl, format, args...)
}

func Log(lvl Level, message string) {
	g.Log(lvl, message)
}

func Logv(lvl Level, args ...interface{}) {
	g.Logv(lvl, args...)
}

func Info(message string) {
	g.Info(message)
}

func Warn(message string) {
	g.Warn(message)
}

func Error(message string) {
	g.Error(message)
}

func Debug(message string) {
	g.Debug(message)
}

func Trace(message string) {
	g.Trace(message)
}

func Infov(args ...interface{}) {
	g.Infov(args...)
}

func WarnV(args ...interface{}) {
	g.WarnV(args...)
}

func Errorv(args ...interface{}) {
	g.Errorv(args...)
}

func Debugv(args ...interface{}) {
	g.Debugv(args...)
}

func Tracev(args ...interface{}) {
	g.Tracev(args...)
}

func Infof(format string, args ...interface{}) {
	g.Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
	g.Warnf(format, args...)
}

func Errorf(format string, args ...interface{}) {
	g.Errorf(format, args...)
}

func Debugf(format string, args ...interface{}) {
	g.Debugf(format, args...)
}

func Tracef(format string, args ...interface{}) {
	g.Tracef(format, args...)
}

func Flush() {
	g.Flush()
}

func With(name string, val interface{}) Logger {
	return g.With(name, val)
}

func WithFields(fields []Field) Logger {
	return g.WithFields(fields)
}

var (
	g *Logger
)

func init() {
	g = &Logger{sink: NopSink{}}
}

func SetLogger(l *Logger) {
	g = l
}

func GetLogger() *Logger {
	return g
}

func New(sink Sink) *Logger {
	return &Logger{sink, nil}
}

func GetSink(logger *Logger) Sink {
	return logger.sink
}
<commit_msg>change: init to a console by default<commit_after>package log

import (
	"os"
	"time"
)

type Level uint

const (
	_                = 0
	ErrorLevel Level = 1 << (iota - 1)
	WarnLevel
	InfoLevel
	DebugLevel
	TraceLevel
)

type Logger struct {
	sink   Sink
	fields []Field
}

type Record struct {
	l      Logger
	Meta   Metadata
	Format string
	Args   []interface{}
}

func (r *Record) Fields() []Field {
	return r.l.fields
}

type Field struct {
	Name  string
	Value interface{}
}

type Metadata struct {
	Level Level
	Time  time.Time
	File  string
	Line  uint
}

func newRecord(l Logger, m Metadata, format string, args []interface{}) Record {
	return Record{l: l, Meta: m, Format: format, Args: args}
}

func newMetadata(lvl Level, withTime bool) Metadata {
	if withTime {
		return Metadata{Level: lvl, Time: time.Now()}
	}
	return Metadata{Level: lvl}
}

func (l Logger) IsEnabled(lvl Level) bool {
	m := newMetadata(lvl, false)
	return l.sink.IsEnabled(&m)
}

func (l Logger) Logf(lvl Level, format string, args ...interface{}) {
	if !l.IsEnabled(lvl) {
		return
	}
	r := newRecord(l, newMetadata(lvl, true), format, args)
	l.sink.Log(&r)
}

func (l Logger) Log(lvl Level, message string) {
	l.Logf(lvl, message)
}

func (l Logger) Logv(lvl Level, args ...interface{}) {
	l.Logf(lvl, "", args...)
}

func (l Logger) Info(message string) {
	l.Log(InfoLevel, message)
}

func (l Logger) Warn(message string) {
	l.Log(WarnLevel, message)
}

func (l Logger) Error(message string) {
	l.Log(ErrorLevel, message)
}

func (l Logger) Debug(message string) {
	l.Log(DebugLevel, message)
}

func (l Logger) Trace(message string) {
	l.Log(TraceLevel, message)
}

func (l Logger) Infov(args ...interface{}) {
	l.Logv(InfoLevel, args...)
}

func (l Logger) WarnV(args ...interface{}) {
	l.Logv(WarnLevel, args...)
}

func (l Logger) Errorv(args ...interface{}) {
	l.Logv(ErrorLevel, args...)
}

func (l Logger) Debugv(args ...interface{}) {
	l.Logv(DebugLevel, args...)
}

func (l Logger) Tracev(args ...interface{}) {
	l.Logv(TraceLevel, args...)
}

func (l Logger) Infof(format string, args ...interface{}) {
	l.Logf(InfoLevel, format, args...)
}

func (l Logger) Warnf(format string, args ...interface{}) {
	l.Logf(WarnLevel, format, args...)
}

func (l Logger) Errorf(format string, args ...interface{}) {
	l.Logf(ErrorLevel, format, args...)
}

func (l Logger) Debugf(format string, args ...interface{}) {
	l.Logf(DebugLevel, format, args...)
}

func (l Logger) Tracef(format string, args ...interface{}) {
	l.Logf(TraceLevel, format, args...)
}

func (l Logger) Flush() {
	l.sink.Flush()
}

func (l Logger) With(name string, value interface{}) Logger {
	s := make([]Field, 0, len(l.fields)+1)
	s = append(s, l.fields...)
	s = append(s, Field{name, value})
	return Logger{l.sink, s}
}

func (l Logger) WithFields(fields []Field) Logger {
	s := make([]Field, 0, len(l.fields)+len(fields))
	s = append(s, l.fields...)
	s = append(s, fields...)
	return Logger{l.sink, s}
}

func IsEnabled(lvl Level) bool {
	return g.IsEnabled(lvl)
}

func Logf(lvl Level, format string, args ...interface{}) {
	g.Logf(lvl, format, args...)
}

func Log(lvl Level, message string) {
	g.Log(lvl, message)
}

func Logv(lvl Level, args ...interface{}) {
	g.Logv(lvl, args...)
}

func Info(message string) {
	g.Info(message)
}

func Warn(message string) {
	g.Warn(message)
}

func Error(message string) {
	g.Error(message)
}

func Debug(message string) {
	g.Debug(message)
}

func Trace(message string) {
	g.Trace(message)
}

func Infov(args ...interface{}) {
	g.Infov(args...)
}

func WarnV(args ...interface{}) {
	g.WarnV(args...)
}

func Errorv(args ...interface{}) {
	g.Errorv(args...)
}

func Debugv(args ...interface{}) {
	g.Debugv(args...)
}

func Tracev(args ...interface{}) {
	g.Tracev(args...)
}

func Infof(format string, args ...interface{}) {
	g.Infof(format, args...)
}

func Warnf(format string, args ...interface{}) {
	g.Warnf(format, args...)
}

func Errorf(format string, args ...interface{}) {
	g.Errorf(format, args...)
}

func Debugf(format string, args ...interface{}) {
	g.Debugf(format, args...)
}

func Tracef(format string, args ...interface{}) {
	g.Tracef(format, args...)
}

func Flush() {
	g.Flush()
}

func With(name string, val interface{}) Logger {
	return g.With(name, val)
}

func WithFields(fields []Field) Logger {
	return g.WithFields(fields)
}

var (
	g *Logger
)

func init() {
	g = &Logger{sink: &LeveledSink{
		MaxLevel: ErrorLevel,
		Inner: &StreamSink {
			Stream: os.Stderr,
			Formatter: DefaultColorTextFormatterForHuman,
		},
	}}
}

func SetLogger(l *Logger) {
	g = l
}

func GetLogger() *Logger {
	return g
}

func New(sink Sink) *Logger {
	return &Logger{sink, nil}
}

func GetSink(logger *Logger) Sink {
	return logger.sink
}
<|endoftext|>


<commit_before>package log

import (
	"fmt"

	"github.com/davecgh/go-spew/spew"
	"github.com/eyecuelab/kit/goenv"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)

var (
	//Print is an alias for log.Print in logrus
	Print = log.Print

	//Fatalf is an alias for log.Fatalf in logrus
	Fatalf = log.Fatalf

	//Fatal is an alias for log.Fatal in logrus
	Fatal = log.Fatal

	//Println is an alias for log.Println in logrus
	Println = log.Println

	//Info is an alias for log.Info in logrus
	Info = log.Info

	//Warn is an alias for log.Warn in logrus
	Warn = log.Warn

	//Warnf is an alias for log.Warnf in logrus
	Warnf = log.Warnf
)

func FatalWrap(err error, msg string) {
	log.Fatalf("%+v", errors.Wrap(err, msg))
}

func Infof(format string, args ...interface{}) {
	s := spew.Sprintf(format, args...)
	log.Infof(s)
}

func Infofln(format string, args ...interface{}) {

	Infof(format, args...)
}

func ErrorWrap(err error, msg string) {
	log.Errorf("%+v", errors.Wrap(err, msg))
}

//Check calls Fatal on an error if it is non-nil.
func Check(err error) {
	if err != nil {
		Fatal(err)
	}
}

var Logger = log.StandardLogger()

func init() {
	if goenv.Prod {
		log.SetFormatter(&log.JSONFormatter{})
	}
}
<commit_msg>remove unnecessary import from log<commit_after>package log

import (
	"github.com/davecgh/go-spew/spew"
	"github.com/eyecuelab/kit/goenv"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)

var (
	//Print is an alias for log.Print in logrus
	Print = log.Print

	//Fatalf is an alias for log.Fatalf in logrus
	Fatalf = log.Fatalf

	//Fatal is an alias for log.Fatal in logrus
	Fatal = log.Fatal

	//Println is an alias for log.Println in logrus
	Println = log.Println

	//Info is an alias for log.Info in logrus
	Info = log.Info

	//Warn is an alias for log.Warn in logrus
	Warn = log.Warn

	//Warnf is an alias for log.Warnf in logrus
	Warnf = log.Warnf
)

func FatalWrap(err error, msg string) {
	log.Fatalf("%+v", errors.Wrap(err, msg))
}

func Infof(format string, args ...interface{}) {
	s := spew.Sprintf(format, args...)
	log.Infof(s)
}

func Infofln(format string, args ...interface{}) {

	Infof(format, args...)
}

func ErrorWrap(err error, msg string) {
	log.Errorf("%+v", errors.Wrap(err, msg))
}

//Check calls Fatal on an error if it is non-nil.
func Check(err error) {
	if err != nil {
		Fatal(err)
	}
}

var Logger = log.StandardLogger()

func init() {
	if goenv.Prod {
		log.SetFormatter(&log.JSONFormatter{})
	}
}
<|endoftext|>


<commit_before><commit_msg>Add `Delta`.<commit_after><|endoftext|>


<commit_before>package api

import (
	"fmt"
	"testing"

	"github.com/kylelemons/godebug/pretty"

	"github.com/turnage/graw/internal/data"
	"github.com/turnage/graw/internal/reap"
)

func TestListing(t *testing.T) {
	h := reap.Harvest{
		Comments: []*data.Comment{
			&data.Comment{
				Body: "text",
			},
		},
	}
	l := NewLurker(reaperWhich(h, nil))

	actual, err := l.Listing("/messages", "")
	if err != nil {
		t.Errorf("error lurking listing: %v")
	}

	if diff := pretty.Compare(&h, &actual); diff != "" {
		t.Errorf("harvest unexpected; diff: %s", diff)
	}
}

func TestThread(t *testing.T) {
	h := reap.Harvest{
		Posts: []*data.Post{
			&data.Post{
				SelfText: "hello",
			},
		},
	}
	l := NewLurker(reaperWhich(h, nil))

	post, err := l.Thread("")
	if err != nil {
		t.Errorf("error pulling thread: %v", err)
	}

	if diff := pretty.Compare(post, h.Posts[0]); diff != "" {
		t.Errorf("post incorrect; diff: %s", diff)
	}
}

func TestThreadReturnsEmpty(t *testing.T) {
	l := NewLurker(reaperWhich(reap.Harvest{}, nil))
	_, err := l.Thread("")
	if err != DoesNotExistErr {
		t.Errorf("err unexpected; wanted DoesNotExistErr; got %v", err)
	}
}

func TestExists(t *testing.T) {
	empty := reap.Harvest{}
	post := reap.Harvest{Posts: []*data.Post{&data.Post{}}}
	comment := reap.Harvest{Comments: []*data.Comment{&data.Comment{}}}
	message := reap.Harvest{Messages: []*data.Message{&data.Message{}}}
	fail := fmt.Errorf("a failure")

	for _, test := range []struct {
		input string
		h     reap.Harvest
		err   error

		exists bool
		path   string
	}{
		{"t1_ffjdkdf", empty, nil, false, "/api/info.json"},
		{"t4_ffjdkdf", empty, nil, false, "/message/messages/ffjdkdf"},
		{"t2_fffjsdj", post, nil, true, "/api/info.json"},
		{"t4_fffjsdj", message, nil, true, "/message/messages/fffjsdj"},
		{"t1_fffjsdj", comment, nil, true, "/api/info.json"},
		{"t1_fffjsdj", comment, fail, false, "/api/info.json"},
	} {
		r := reaperWhich(test.h, test.err)
		l := NewLurker(r)
		exists, err := l.Exists(test.input)
		if err != test.err {
			t.Errorf("got err %v; wanted %v", err, test.err)
		}

		if exists != test.exists {
			t.Errorf(
				"got existence result %v; wanted %v",
				exists,
				test.exists,
			)
		}

		if r.path != test.path {
			t.Errorf("got path %s; wanted %s", r.path, test.path)
		}
	}
}
<commit_msg>Include missing argument in fmt (ty, go vet).<commit_after>package api

import (
	"fmt"
	"testing"

	"github.com/kylelemons/godebug/pretty"

	"github.com/turnage/graw/internal/data"
	"github.com/turnage/graw/internal/reap"
)

func TestListing(t *testing.T) {
	h := reap.Harvest{
		Comments: []*data.Comment{
			&data.Comment{
				Body: "text",
			},
		},
	}
	l := NewLurker(reaperWhich(h, nil))

	actual, err := l.Listing("/messages", "")
	if err != nil {
		t.Errorf("error lurking listing: %v", err)
	}

	if diff := pretty.Compare(&h, &actual); diff != "" {
		t.Errorf("harvest unexpected; diff: %s", diff)
	}
}

func TestThread(t *testing.T) {
	h := reap.Harvest{
		Posts: []*data.Post{
			&data.Post{
				SelfText: "hello",
			},
		},
	}
	l := NewLurker(reaperWhich(h, nil))

	post, err := l.Thread("")
	if err != nil {
		t.Errorf("error pulling thread: %v", err)
	}

	if diff := pretty.Compare(post, h.Posts[0]); diff != "" {
		t.Errorf("post incorrect; diff: %s", diff)
	}
}

func TestThreadReturnsEmpty(t *testing.T) {
	l := NewLurker(reaperWhich(reap.Harvest{}, nil))
	_, err := l.Thread("")
	if err != DoesNotExistErr {
		t.Errorf("err unexpected; wanted DoesNotExistErr; got %v", err)
	}
}

func TestExists(t *testing.T) {
	empty := reap.Harvest{}
	post := reap.Harvest{Posts: []*data.Post{&data.Post{}}}
	comment := reap.Harvest{Comments: []*data.Comment{&data.Comment{}}}
	message := reap.Harvest{Messages: []*data.Message{&data.Message{}}}
	fail := fmt.Errorf("a failure")

	for _, test := range []struct {
		input string
		h     reap.Harvest
		err   error

		exists bool
		path   string
	}{
		{"t1_ffjdkdf", empty, nil, false, "/api/info.json"},
		{"t4_ffjdkdf", empty, nil, false, "/message/messages/ffjdkdf"},
		{"t2_fffjsdj", post, nil, true, "/api/info.json"},
		{"t4_fffjsdj", message, nil, true, "/message/messages/fffjsdj"},
		{"t1_fffjsdj", comment, nil, true, "/api/info.json"},
		{"t1_fffjsdj", comment, fail, false, "/api/info.json"},
	} {
		r := reaperWhich(test.h, test.err)
		l := NewLurker(r)
		exists, err := l.Exists(test.input)
		if err != test.err {
			t.Errorf("got err %v; wanted %v", err, test.err)
		}

		if exists != test.exists {
			t.Errorf(
				"got existence result %v; wanted %v",
				exists,
				test.exists,
			)
		}

		if r.path != test.path {
			t.Errorf("got path %s; wanted %s", r.path, test.path)
		}
	}
}
<|endoftext|>


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

package buildgo

import (
	"context"
	"errors"
	"fmt"
	"log"
	"path"
	"sort"
	"strings"
	"time"

	"golang.org/x/build/dashboard"
	compute "google.golang.org/api/compute/v1"
)

// MakeBasepinDisks looks at the list of all the project's VM images
// and creates (if needed) a disk for each one, named with the prefix
// "basepin-". The purpose of these "basepin" disks is to speed up GCE
// VM creations. When GCE creates a new disk for a new VM, it takes a
// fast path when creating the disk if there's another disk in the
// same zone for that image, and makes the new disk a thin
// Copy-on-Write shadow over the basepin disk. GCE also does this if
// there's been a VM created within the past N minutes of that type,
// but we want VMs to always create quickly.
func (c *Client) MakeBasepinDisks(ctx context.Context) error {
	currentImage := map[string]bool{}
	for _, hc := range dashboard.Hosts {
		if hc.VMImage != "" {
			currentImage[hc.VMImage] = true
		}
	}

	// Try to find it by name.
	svc := c.Compute()
	imList, err := svc.Images.List(c.Env.ProjectName).Do()
	if err != nil {
		return fmt.Errorf("Error listing images for %s: %v", c.Env.ProjectName, err)
	}
	if imList.NextPageToken != "" {
		return errors.New("too many images; pagination not supported")
	}

	getNeedMap := func() map[string]*compute.Image {
		need := make(map[string]*compute.Image) // keys like "https://www.googleapis.com/compute/v1/projects/symbolic-datum-552/global/images/linux-buildlet-arm"
		for _, im := range imList.Items {
			imBase := path.Base(im.SelfLink)
			if strings.Contains(im.SelfLink, "-debug") {
				continue
			}
			if !currentImage[imBase] {
				continue
			}
			need[im.SelfLink] = im
		}
		return need
	}

	for _, zone := range c.Env.VMZones {
		diskList, err := svc.Disks.List(c.Env.ProjectName, zone).Do()
		if err != nil {
			return fmt.Errorf("error listing disks in zone %v: %v", zone, err)
		}
		if diskList.NextPageToken != "" {
			return fmt.Errorf("too many disks in %v; pagination not supported (yet?)", zone)
		}

		need := getNeedMap()

		for _, d := range diskList.Items {
			if !strings.HasPrefix(d.Name, "basepin-") {
				continue
			}
			if si, ok := need[d.SourceImage]; ok && d.SourceImageId == fmt.Sprint(si.Id) {
				if c.Verbose {
					log.Printf("basepin: have %s: %s (%v)\n", d.Name, d.SourceImage, d.SourceImageId)
				}
				delete(need, d.SourceImage)
				continue
			}
			if zone != c.Env.KubeBuild.Zone {
				log.Printf("basepin: deleting unnecessary disk %v in zone %v", d.Name, zone)
				op, err := svc.Disks.Delete(c.Env.ProjectName, zone, d.Name).Do()
				if err != nil {
					log.Printf("basepin: failed to delete disk %v in zone %v: %v", d.Name, zone, err)
					continue
				}
				if err := c.AwaitOp(ctx, op); err != nil {
					log.Printf("basepin: failed to delete disk %v in zone %v: %v", d.Name, zone, err)
					continue
				}
			}
		}

		var needed []string
		for imageName := range need {
			needed = append(needed, imageName)
		}
		sort.Strings(needed)
		for _, n := range needed {
			log.Printf("basepin: need %v disk in %v", n, zone)
		}
		for i, imName := range needed {
			im := need[imName]
			log.Printf("basepin: (%d/%d) creating %s ...", i+1, len(needed), im.Name)
			op, err := svc.Disks.Insert(c.Env.ProjectName, zone, &compute.Disk{
				Description:   "zone-cached basepin image of " + im.Name,
				Name:          "basepin-" + im.Name + "-" + fmt.Sprint(im.Id),
				SizeGb:        im.DiskSizeGb,
				SourceImage:   im.SelfLink,
				SourceImageId: fmt.Sprint(im.Id),
				Type:          "https://www.googleapis.com/compute/v1/projects/" + c.Env.ProjectName + "/zones/" + zone + "/diskTypes/pd-ssd",
			}).Do()
			if err != nil {
				return err
			}
			if err := c.AwaitOp(ctx, op); err != nil {
				return fmt.Errorf("basepin: failed to create: %v", err)
			}
		}
		log.Printf("basepin: created %d images in %v", len(needed), zone)
	}
	return nil
}

// AwaitOp waits for op to finish. It returns nil if the operating
// finished successfully.
func (c *Client) AwaitOp(ctx context.Context, op *compute.Operation) error {
	// TODO: clean this up with respect to status updates & logging.
	svc := c.Compute()
	opName := op.Name
	// TODO: move logging to Client c.logger. and add Client.WithLogger shallow copier.
	log.Printf("Waiting on operation %v (in %q)", opName, op.Zone)
	for {
		time.Sleep(2 * time.Second)
		op, err := svc.ZoneOperations.Get(c.Env.ProjectName, path.Base(op.Zone), opName).Do()
		if err != nil {
			return fmt.Errorf("Failed to get op %s: %v", opName, err)
		}
		switch op.Status {
		case "PENDING", "RUNNING":
			log.Printf("Waiting on operation %v", opName)
			continue
		case "DONE":
			if op.Error != nil {
				var last error
				for _, operr := range op.Error.Errors {
					log.Printf("Error: %+v", operr)
					last = fmt.Errorf("%v", operr)
				}
				return last
			}
			return nil
		default:
			return fmt.Errorf("Unknown status %q: %+v", op.Status, op)
		}
	}
}
<commit_msg>internal/buildgo: handle greater quantity of disks<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package buildgo

import (
	"context"
	"errors"
	"fmt"
	"log"
	"path"
	"sort"
	"strings"
	"time"

	"golang.org/x/build/dashboard"
	"google.golang.org/api/compute/v1"
)

// diskPrefix is the name prefix of GCE disks used by MakeBasepinDisks.
const diskPrefix = "basepin-"

// MakeBasepinDisks looks at the list of all the project's VM images
// and creates (if needed) a disk for each one, named with the prefix
// "basepin-". The purpose of these "basepin" disks is to speed up GCE
// VM creations. When GCE creates a new disk for a new VM, it takes a
// fast path when creating the disk if there's another disk in the
// same zone for that image, and makes the new disk a thin
// Copy-on-Write shadow over the basepin disk. GCE also does this if
// there's been a VM created within the past N minutes of that type,
// but we want VMs to always create quickly.
func (c *Client) MakeBasepinDisks(ctx context.Context) error {
	currentImage := map[string]bool{}
	for _, hc := range dashboard.Hosts {
		if hc.VMImage != "" {
			currentImage[hc.VMImage] = true
		}
	}

	// Try to find it by name.
	svc := c.Compute()
	imList, err := svc.Images.List(c.Env.ProjectName).Do()
	if err != nil {
		return fmt.Errorf("Error listing images for %s: %v", c.Env.ProjectName, err)
	}
	if imList.NextPageToken != "" {
		return errors.New("too many images; pagination not supported")
	}

	getNeedMap := func() map[string]*compute.Image {
		need := make(map[string]*compute.Image) // keys like "https://www.googleapis.com/compute/v1/projects/symbolic-datum-552/global/images/linux-buildlet-arm"
		for _, im := range imList.Items {
			imBase := path.Base(im.SelfLink)
			if strings.Contains(im.SelfLink, "-debug") {
				continue
			}
			if !currentImage[imBase] {
				continue
			}
			need[im.SelfLink] = im
		}
		return need
	}

	for _, zone := range c.Env.VMZones {
		diskList, err := svc.Disks.List(c.Env.ProjectName, zone).Filter(fmt.Sprintf(`name="%s*"`, diskPrefix)).Do()
		if err != nil {
			return fmt.Errorf("error listing disks in zone %v: %v", zone, err)
		}
		if diskList.NextPageToken != "" {
			return fmt.Errorf("too many disks in %v; pagination not supported (yet?)", zone)
		}

		need := getNeedMap()

		for _, d := range diskList.Items {
			if si, ok := need[d.SourceImage]; ok && d.SourceImageId == fmt.Sprint(si.Id) {
				if c.Verbose {
					log.Printf("basepin: have %s: %s (%v)\n", d.Name, d.SourceImage, d.SourceImageId)
				}
				delete(need, d.SourceImage)
				continue
			}
			if zone != c.Env.KubeBuild.Zone {
				log.Printf("basepin: deleting unnecessary disk %v in zone %v", d.Name, zone)
				op, err := svc.Disks.Delete(c.Env.ProjectName, zone, d.Name).Do()
				if err != nil {
					log.Printf("basepin: failed to delete disk %v in zone %v: %v", d.Name, zone, err)
					continue
				}
				if err := c.AwaitOp(ctx, op); err != nil {
					log.Printf("basepin: failed to delete disk %v in zone %v: %v", d.Name, zone, err)
					continue
				}
			}
		}

		var needed []string
		for imageName := range need {
			needed = append(needed, imageName)
		}
		sort.Strings(needed)
		for _, n := range needed {
			log.Printf("basepin: need %v disk in %v", n, zone)
		}
		for i, imName := range needed {
			im := need[imName]
			log.Printf("basepin: (%d/%d) creating %s ...", i+1, len(needed), im.Name)
			op, err := svc.Disks.Insert(c.Env.ProjectName, zone, &compute.Disk{
				Description:   "zone-cached basepin image of " + im.Name,
				Name:          diskPrefix + im.Name + "-" + fmt.Sprint(im.Id),
				SizeGb:        im.DiskSizeGb,
				SourceImage:   im.SelfLink,
				SourceImageId: fmt.Sprint(im.Id),
				Type:          "https://www.googleapis.com/compute/v1/projects/" + c.Env.ProjectName + "/zones/" + zone + "/diskTypes/pd-ssd",
			}).Do()
			if err != nil {
				return err
			}
			if err := c.AwaitOp(ctx, op); err != nil {
				return fmt.Errorf("basepin: failed to create: %v", err)
			}
		}
		log.Printf("basepin: created %d images in %v", len(needed), zone)
	}
	return nil
}

// AwaitOp waits for op to finish. It returns nil if the operating
// finished successfully.
func (c *Client) AwaitOp(ctx context.Context, op *compute.Operation) error {
	// TODO: clean this up with respect to status updates & logging.
	svc := c.Compute()
	opName := op.Name
	// TODO: move logging to Client c.logger. and add Client.WithLogger shallow copier.
	log.Printf("Waiting on operation %v (in %q)", opName, op.Zone)
	for {
		time.Sleep(2 * time.Second)
		op, err := svc.ZoneOperations.Get(c.Env.ProjectName, path.Base(op.Zone), opName).Do()
		if err != nil {
			return fmt.Errorf("Failed to get op %s: %v", opName, err)
		}
		switch op.Status {
		case "PENDING", "RUNNING":
			log.Printf("Waiting on operation %v", opName)
			continue
		case "DONE":
			if op.Error != nil {
				var last error
				for _, operr := range op.Error.Errors {
					log.Printf("Error: %+v", operr)
					last = fmt.Errorf("%v", operr)
				}
				return last
			}
			return nil
		default:
			return fmt.Errorf("Unknown status %q: %+v", op.Status, op)
		}
	}
}
<|endoftext|>


<commit_before>package discord

import (
	"fmt"
	"strings"

	"github.com/bwmarrin/discordgo"
	"github.com/scbizu/Astral/internal/config"
)

type Bot struct {
	session *discordgo.Session
}

func NewBot() (*Bot, error) {
	bot, err := discordgo.New(config.GetDiscordClientID())
	if err != nil {
		return nil, err
	}
	return &Bot{session: bot}, nil
}

func (b *Bot) ResolveMessage(msgs []string) string {
	return fmt.Sprintf("%s\n\n", strings.Join(msgs, "\n\n"))
}

func (b *Bot) Send(msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	if _, err := b.session.ChannelMessageSend(
		config.DiscordCNSC2ChannelID,
		msg,
	); err != nil {
		return err
	}

	return nil
}

func (b *Bot) SendToChannel(channelID string, msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageSend(
		channelID,
		msg,
	); err != nil {
		return err
	}

	return nil
}
<commit_msg>internal/discord: close open ws<commit_after>package discord

import (
	"fmt"
	"strings"

	"github.com/bwmarrin/discordgo"
	"github.com/scbizu/Astral/internal/config"
)

type Bot struct {
	session *discordgo.Session
}

func NewBot() (*Bot, error) {
	bot, err := discordgo.New(config.GetDiscordClientID())
	if err != nil {
		return nil, err
	}
	return &Bot{session: bot}, nil
}

func (b *Bot) ResolveMessage(msgs []string) string {
	return fmt.Sprintf("%s\n\n", strings.Join(msgs, "\n\n"))
}

func (b *Bot) Send(msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageSend(
		config.DiscordCNSC2ChannelID,
		msg,
	); err != nil {
		return err
	}

	return nil
}

func (b *Bot) SendToChannel(channelID string, msg string) error {
	if err := b.session.Open(); err != nil {
		return err
	}
	defer b.session.Close()
	if _, err := b.session.ChannelMessageSend(
		channelID,
		msg,
	); err != nil {
		return err
	}

	return nil
}
<|endoftext|>