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

package v3_1_experimental

import (
	"testing"

	"github.com/coreos/ignition/v2/config/shared/errors"
	"github.com/coreos/ignition/v2/config/v3_1_experimental/types"
	"github.com/stretchr/testify/assert"
)

func TestParse(t *testing.T) {
	type in struct {
		config []byte
	}
	type out struct {
		config         types.Config
		err            error
		checkOnStrings bool
	}

	tests := []struct {
		in  in
		out out
	}{
		{
			in:  in{config: []byte(`{"ignitionVersion": 1}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "1.0.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.1.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.2.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.3.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.1.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.2.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.3.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.4.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "3.1.0-experimental"}}`)},
			out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0"},}`)},
			out: out{err: errors.ErrInvalid},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "invalid.semver"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte{}},
			out: out{err: errors.ErrEmpty},
		},
	}

	for i, test := range tests {
		config, report, err := Parse(test.in.config)
		if (!test.out.checkOnStrings && test.out.err != err) ||
			(test.out.checkOnStrings && test.out.err.Error() != err.Error()) {
			t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report)
		}
		assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report)
	}
}
<commit_msg>config/v3_1_experimental: add some missing version tests<commit_after>// Copyright 2019 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v3_1_experimental

import (
	"testing"

	"github.com/coreos/ignition/v2/config/shared/errors"
	"github.com/coreos/ignition/v2/config/v3_1_experimental/types"
	"github.com/stretchr/testify/assert"
)

func TestParse(t *testing.T) {
	type in struct {
		config []byte
	}
	type out struct {
		config         types.Config
		err            error
		checkOnStrings bool
	}

	tests := []struct {
		in  in
		out out
	}{
		{
			in:  in{config: []byte(`{"ignitionVersion": 1}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "1.0.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.1.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.2.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.3.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.4.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "3.0.0"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.1.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.2.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.3.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.4.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.5.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "3.0.0-experimental"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "3.1.0-experimental"}}`)},
			out: out{config: types.Config{Ignition: types.Ignition{Version: types.MaxVersion.String()}}},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "2.0.0"},}`)},
			out: out{err: errors.ErrInvalid},
		},
		{
			in:  in{config: []byte(`{"ignition": {"version": "invalid.semver"}}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte(`{}`)},
			out: out{err: errors.ErrUnknownVersion},
		},
		{
			in:  in{config: []byte{}},
			out: out{err: errors.ErrEmpty},
		},
	}

	for i, test := range tests {
		config, report, err := Parse(test.in.config)
		if (!test.out.checkOnStrings && test.out.err != err) ||
			(test.out.checkOnStrings && test.out.err.Error() != err.Error()) {
			t.Errorf("#%d: bad error: want %v, got %v, report: %+v", i, test.out.err, err, report)
		}
		assert.Equal(t, test.out.config, config, "#%d: bad config, report: %+v", i, report)
	}
}
<|endoftext|>


<commit_before>package irc

// freshHandler is a handler for a brand new connection that has not been
// registered yet.
type freshHandler struct {
	state chan state
}

func newFreshHandler(state chan state) handler {
	return &freshHandler{state: state}
}

func (h *freshHandler) handle(conn connection, msg message) handler {
	if msg.command != cmdNick.command {
		return h
	}
	return h.handleNick(conn, msg)
}

func (_ *freshHandler) closed(c connection) {
	c.kill()
}

func (h *freshHandler) handleNick(conn connection, msg message) handler {
	state := <-h.state
	defer func() { h.state <- state }()

	if len(msg.params) < 1 {
		sendNumeric(state, conn, errorNoNicknameGiven)
		return h
	}
	nick := msg.params[0]

	user := state.newUser(nick)
	if user == nil {
		sendNumeric(state, conn, errorNicknameInUse)
		return h
	}
	user.sink = conn

	return &freshUserHandler{state: h.state, user: user}
}

// freshUserHandler is a handler for a brand new connection that is in the
// process of registering and has successfully set a nickname.
type freshUserHandler struct {
	user  *user
	state chan state
}

func (h *freshUserHandler) handle(conn connection, msg message) handler {
	if msg.command != cmdUser.command {
		return h
	}
	return h.handleUser(conn, msg)
}

func (h *freshUserHandler) closed(c connection) {
	state := <-h.state
	defer func() { h.state <- state }()

	state.removeUser(h.user)
	c.kill()
}

func (h *freshUserHandler) handleUser(conn connection, msg message) handler {
	state := <-h.state
	defer func() { h.state <- state }()

	if len(msg.params) < 3 || msg.trailing == "" {
		sendNumeric(state, h.user, errorNeedMoreParams)
		return h
	}

	h.user.user = msg.params[0]
	h.user.host = state.getConfig().SpoofHostName
	h.user.server = state.getConfig().Name
	h.user.realName = msg.trailing

	sendIntro(state, h.user)

	return newUserHandler(h.state, h.user.nick)
}
<commit_msg>Make host name spoofing optional<commit_after>package irc

// freshHandler is a handler for a brand new connection that has not been
// registered yet.
type freshHandler struct {
	state chan state
}

func newFreshHandler(state chan state) handler {
	return &freshHandler{state: state}
}

func (h *freshHandler) handle(conn connection, msg message) handler {
	if msg.command != cmdNick.command {
		return h
	}
	return h.handleNick(conn, msg)
}

func (_ *freshHandler) closed(c connection) {
	c.kill()
}

func (h *freshHandler) handleNick(conn connection, msg message) handler {
	state := <-h.state
	defer func() { h.state <- state }()

	if len(msg.params) < 1 {
		sendNumeric(state, conn, errorNoNicknameGiven)
		return h
	}
	nick := msg.params[0]

	user := state.newUser(nick)
	if user == nil {
		sendNumeric(state, conn, errorNicknameInUse)
		return h
	}
	user.sink = conn

	return &freshUserHandler{state: h.state, user: user}
}

// freshUserHandler is a handler for a brand new connection that is in the
// process of registering and has successfully set a nickname.
type freshUserHandler struct {
	user  *user
	state chan state
}

func (h *freshUserHandler) handle(conn connection, msg message) handler {
	if msg.command != cmdUser.command {
		return h
	}
	return h.handleUser(conn, msg)
}

func (h *freshUserHandler) closed(c connection) {
	state := <-h.state
	defer func() { h.state <- state }()

	state.removeUser(h.user)
	c.kill()
}

func (h *freshUserHandler) handleUser(conn connection, msg message) handler {
	state := <-h.state
	defer func() { h.state <- state }()

	if len(msg.params) < 3 || msg.trailing == "" {
		sendNumeric(state, h.user, errorNeedMoreParams)
		return h
	}

	h.user.user = msg.params[0]
	h.user.host = state.getConfig().SpoofHostName
	if h.user.host == "" {
		h.user.host = msg.params[1]
	}
	h.user.server = state.getConfig().Name
	h.user.realName = msg.trailing

	sendIntro(state, h.user)

	return newUserHandler(h.state, h.user.nick)
}
<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/tealeg/xlsx"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type message struct {
	User, Type, Subtype, Text, Ts string
	Timestamp                     time.Time
}

// Implement the sort interface for type messages
type messages []message

func (m messages) Len() int {
	return len(m)
}

func (m messages) Less(i, j int) bool {
	return m[i].Timestamp.Before(m[j].Timestamp)
}

func (m messages) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

type meta struct {
	ID, Name string
	RealName string `json:"real_name,omitempty"`
}

// Set global CLI vars
var filename, outputDir, timezone string
var metadata = make(map[string][]meta)

func main() {

	app := cli.NewApp()
	app.Usage = "An app for exporting Slack history to CSV"
	app.HideVersion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "name, n",
			Value:       time.Now().Format("2006-Jan-02") + "_SlackExport.xlsx",
			Usage:       "Set the name of the exported spreadsheet",
			Destination: &filename,
		},
		cli.StringFlag{
			Name:        "destination, d",
			Value:       "./",
			Usage:       "Specify the output directory for\n\t  the exported xlsx workbook",
			Destination: &outputDir,
		},
		cli.StringFlag{
			Name:        "timezone, t",
			Value:       "Local",
			Usage:       "Specify an alternate timezone.\n\t  See here for available options https://goo.gl/Tmq0oR",
			Destination: &timezone,
		},
	}

	app.Action = func(c *cli.Context) {
		if len(c.Args()) != 1 {
			fmt.Printf("\n*** Error: The location of the target zip file must be the last and only argument!\n***\n" +
				"*** For additional help, enter \"slackhist help\"\n\n")
			os.Exit(1)
		}

		if suffix := strings.HasSuffix(filename, ".xlsx"); suffix == false {
			filename = filename + ".xlsx"
		}

		messages := processData(c.Args()[0], metadata)
		createWorkbook(messages)
	}

	app.Run(os.Args)
}

func processData(f string, md map[string][]meta) map[string]messages {

	payload := make(map[string]messages)
	var dirname string

	// Open a readable stream from the zip file
	r, err := zip.OpenReader(f)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	// Collect the required meta to process the information HACK
	for _, file := range r.File {
		switch file.FileHeader.Name {
		case "channels.json", "users.json":
			getMeta(file, md)
		}
	}

	// For every item in the entire zip folder (recursive)
	for _, file := range r.File {

		isDirectory := file.FileInfo().IsDir()

		// Switch on file = directory
		switch isDirectory {
		case true:

			// Retreive the current directory's base name
			path, err := filepath.Abs(file.FileHeader.Name)
			if err != nil {
				panic(err)
			}
			dirname = filepath.Base(path)

			// Make the directory's base name (thus, the channel name) the key
			// and instantiate an empty slice within payload for the messages to
			// be stored
			payload[dirname] = make([]message, 0)

		case false:
			var thisJSON []message

			// If the file is one that we've already processed, break
			// from this particular loop cycle
			switch file.FileHeader.Name {
			case "integration_logs.json", "channels.json", "users.json":
				continue
			}

			// Grab the parent directory's name
			dirname = filepath.Base(filepath.Dir(file.FileHeader.Name))

			// Open a readable stream from the current file
			rc, err := file.Open()
			if err != nil {
				panic(err)
			}
			defer rc.Close()

			// Create JSON decoder and decode the readable stream to "thisJSON"
			decoder := json.NewDecoder(rc)
			for decoder.More() {
				if err := decoder.Decode(&thisJSON); err != nil {
					panic(err)
				}
			}

			// After a full file decode, iterate through the decoded JSON for
			// messages or attachments, and parse the timezone according to the
			// current user's local time zone format
			for _, value := range thisJSON {
				if value.Type == "message" && value.Subtype == "" || value.Subtype == "file_share" {

					value.Timestamp = parseTimestamp(value.Ts)
					_, value.User = parseUser(value.User, md)

					re := regexp.MustCompile("(<@[a-zA-Z0-9]{9}(\\p{S}[a-zA-Z0-9]+)?>)")
					if matches := re.FindAllString(value.Text, -1); matches != nil {

						value.Text = re.ReplaceAllStringFunc(value.Text, func(match string) string {
							uid := match[2 : len(match)-1]
							username, _ := parseUser(uid, md)
							return "@" + username
						})

					}

					payload[dirname] = append(payload[dirname], value)
				}
			}

		}

	}

	return payload

}

func createWorkbook(m map[string]messages) {

	var channelNames sort.StringSlice

	workbook := xlsx.NewFile()
	fullPath := filepath.Clean(filepath.Join(outputDir, filename))

	// First, sort the map by channel name
	for channel := range m {
		channelNames = append(channelNames, channel)
	}

	channelNames.Sort()

	for _, channel := range channelNames {
		sheet, err := workbook.AddSheet(channel)
		if err != nil {
			panic(err)
		}

		sort.Sort(m[channel])

		headingRow := sheet.AddRow()
		headingRow.AddCell().SetString("Timestamp")
		headingRow.AddCell().SetString("User")
		headingRow.AddCell().SetString("Message")

		for _, message := range m[channel] {
			messageRow := sheet.AddRow()
			messageRow.AddCell().SetString(message.Timestamp.Format("Jan 02, 2006 | 15:04"))
			messageRow.AddCell().SetString(message.User)
			messageRow.AddCell().SetString(message.Text)
		}

	}

	if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
		panic(err)
	}

	if err := workbook.Save(fullPath); err != nil {
		panic(err)
	}

}

/**************************************************************************
 *                         Utility functions                              *
 **************************************************************************/

func getMeta(f *zip.File, m map[string][]meta) {
	filename := f.FileHeader.Name

	var thisJSON []meta

	rc, err := f.Open()
	if err != nil {
		panic(err)
	}
	defer rc.Close()

	decoder := json.NewDecoder(rc)
	for decoder.More() {
		if err := decoder.Decode(&thisJSON); err != nil {
			panic(err)
		}
	}

	switch filename {
	case "users.json":
		m["users"] = thisJSON
	case "channels.json":
		m["channels"] = thisJSON
	default:
		panic(filename)
	}

}

func parseTimestamp(ts string) time.Time {

	timestring, err := strconv.ParseInt(strings.Split(ts, ".")[0], 10, 64)
	if err != nil {
		panic(err)
	}
	tm := time.Unix(timestring, 0)

	loc, err := time.LoadLocation(timezone)
	if err != nil {
		panic(err)
	}

	return tm.In(loc)
}

func parseUser(uid string, m map[string][]meta) (string, string) {
	var username, realname string
	for _, value := range m["users"] {
		if value.ID == uid {
			username = value.Name
			realname = value.RealName
			break
		}
	}
	return username, realname
}
<commit_msg>Update package description<commit_after>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/tealeg/xlsx"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type message struct {
	User, Type, Subtype, Text, Ts string
	Timestamp                     time.Time
}

// Implement the sort interface for type messages
type messages []message

func (m messages) Len() int {
	return len(m)
}

func (m messages) Less(i, j int) bool {
	return m[i].Timestamp.Before(m[j].Timestamp)
}

func (m messages) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

type meta struct {
	ID, Name string
	RealName string `json:"real_name,omitempty"`
}

// Set global CLI vars
var filename, outputDir, timezone string
var metadata = make(map[string][]meta)

func main() {

	app := cli.NewApp()
	app.Usage = "An app for exporting Slack history to Excel (.xlsx)"
	app.HideVersion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "name, n",
			Value:       time.Now().Format("2006-Jan-02") + "_SlackExport.xlsx",
			Usage:       "Set the name of the exported spreadsheet",
			Destination: &filename,
		},
		cli.StringFlag{
			Name:        "destination, d",
			Value:       "./",
			Usage:       "Specify the output directory for\n\t  the exported xlsx workbook",
			Destination: &outputDir,
		},
		cli.StringFlag{
			Name:        "timezone, t",
			Value:       "Local",
			Usage:       "Specify an alternate timezone.\n\t  See here for available options https://goo.gl/Tmq0oR",
			Destination: &timezone,
		},
	}

	app.Action = func(c *cli.Context) {
		if len(c.Args()) != 1 {
			fmt.Printf("\n*** Error: The location of the target zip file must be the last and only argument!\n***\n" +
				"*** For additional help, enter \"slackhist help\"\n\n")
			os.Exit(1)
		}

		if suffix := strings.HasSuffix(filename, ".xlsx"); suffix == false {
			filename = filename + ".xlsx"
		}

		messages := processData(c.Args()[0], metadata)
		createWorkbook(messages)
	}

	app.Run(os.Args)
}

func processData(f string, md map[string][]meta) map[string]messages {

	payload := make(map[string]messages)
	var dirname string

	// Open a readable stream from the zip file
	r, err := zip.OpenReader(f)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	// Collect the required meta to process the information HACK
	for _, file := range r.File {
		switch file.FileHeader.Name {
		case "channels.json", "users.json":
			getMeta(file, md)
		}
	}

	// For every item in the entire zip folder (recursive)
	for _, file := range r.File {

		isDirectory := file.FileInfo().IsDir()

		// Switch on file = directory
		switch isDirectory {
		case true:

			// Retreive the current directory's base name
			path, err := filepath.Abs(file.FileHeader.Name)
			if err != nil {
				panic(err)
			}
			dirname = filepath.Base(path)

			// Make the directory's base name (thus, the channel name) the key
			// and instantiate an empty slice within payload for the messages to
			// be stored
			payload[dirname] = make([]message, 0)

		case false:
			var thisJSON []message

			// If the file is one that we've already processed, break
			// from this particular loop cycle
			switch file.FileHeader.Name {
			case "integration_logs.json", "channels.json", "users.json":
				continue
			}

			// Grab the parent directory's name
			dirname = filepath.Base(filepath.Dir(file.FileHeader.Name))

			// Open a readable stream from the current file
			rc, err := file.Open()
			if err != nil {
				panic(err)
			}
			defer rc.Close()

			// Create JSON decoder and decode the readable stream to "thisJSON"
			decoder := json.NewDecoder(rc)
			for decoder.More() {
				if err := decoder.Decode(&thisJSON); err != nil {
					panic(err)
				}
			}

			// After a full file decode, iterate through the decoded JSON for
			// messages or attachments, and parse the timezone according to the
			// current user's local time zone format
			for _, value := range thisJSON {
				if value.Type == "message" && value.Subtype == "" || value.Subtype == "file_share" {

					value.Timestamp = parseTimestamp(value.Ts)
					_, value.User = parseUser(value.User, md)

					re := regexp.MustCompile("(<@[a-zA-Z0-9]{9}(\\p{S}[a-zA-Z0-9]+)?>)")
					if matches := re.FindAllString(value.Text, -1); matches != nil {

						value.Text = re.ReplaceAllStringFunc(value.Text, func(match string) string {
							uid := match[2 : len(match)-1]
							username, _ := parseUser(uid, md)
							return "@" + username
						})

					}

					payload[dirname] = append(payload[dirname], value)
				}
			}

		}

	}

	return payload

}

func createWorkbook(m map[string]messages) {

	var channelNames sort.StringSlice

	workbook := xlsx.NewFile()
	fullPath := filepath.Clean(filepath.Join(outputDir, filename))

	// First, sort the map by channel name
	for channel := range m {
		channelNames = append(channelNames, channel)
	}

	channelNames.Sort()

	for _, channel := range channelNames {
		sheet, err := workbook.AddSheet(channel)
		if err != nil {
			panic(err)
		}

		sort.Sort(m[channel])

		headingRow := sheet.AddRow()
		headingRow.AddCell().SetString("Timestamp")
		headingRow.AddCell().SetString("User")
		headingRow.AddCell().SetString("Message")

		for _, message := range m[channel] {
			messageRow := sheet.AddRow()
			messageRow.AddCell().SetString(message.Timestamp.Format("Jan 02, 2006 | 15:04"))
			messageRow.AddCell().SetString(message.User)
			messageRow.AddCell().SetString(message.Text)
		}

	}

	if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
		panic(err)
	}

	if err := workbook.Save(fullPath); err != nil {
		panic(err)
	}

}

/**************************************************************************
 *                         Utility functions                              *
 **************************************************************************/

func getMeta(f *zip.File, m map[string][]meta) {
	filename := f.FileHeader.Name

	var thisJSON []meta

	rc, err := f.Open()
	if err != nil {
		panic(err)
	}
	defer rc.Close()

	decoder := json.NewDecoder(rc)
	for decoder.More() {
		if err := decoder.Decode(&thisJSON); err != nil {
			panic(err)
		}
	}

	switch filename {
	case "users.json":
		m["users"] = thisJSON
	case "channels.json":
		m["channels"] = thisJSON
	default:
		panic(filename)
	}

}

func parseTimestamp(ts string) time.Time {

	timestring, err := strconv.ParseInt(strings.Split(ts, ".")[0], 10, 64)
	if err != nil {
		panic(err)
	}
	tm := time.Unix(timestring, 0)

	loc, err := time.LoadLocation(timezone)
	if err != nil {
		panic(err)
	}

	return tm.In(loc)
}

func parseUser(uid string, m map[string][]meta) (string, string) {
	var username, realname string
	for _, value := range m["users"] {
		if value.ID == uid {
			username = value.Name
			realname = value.RealName
			break
		}
	}
	return username, realname
}
<|endoftext|>


<commit_before>package queue

import (
	"github.com/nathan-osman/go-cannon/util"

	"io"
	"log"
	"time"
)

// Mail queue managing the sending of messages to hosts.
type Queue struct {
	storage    *Storage
	hosts      map[string]*Host
	newMessage *util.NonBlockingChan
	stop       chan bool
}

// Deliver the specified message to the appropriate host queue.
func (q *Queue) deliverMessage(m *Message) {
	if id, err := q.storage.NewMessage(m); err == nil {
		log.Printf("delivering message to %s queue", m.Host)
		if _, ok := q.hosts[m.Host]; !ok {
			q.hosts[m.Host] = NewHost(m.Host, q.storage)
		}
		q.hosts[m.Host].Deliver(id)
	} else {
		log.Print(err)
	}
}

// Check for inactive host queues and shut them down.
func (q *Queue) checkForInactiveQueues() {
	for h := range q.hosts {
		if q.hosts[h].Idle() > time.Minute {
			q.hosts[h].Stop()
			delete(q.hosts, h)
		}
	}
}

// Receive new messages and deliver them to the specified host queue.
func (q *Queue) run() {
	defer close(q.stop)
	ticker := time.NewTicker(time.Minute)
	defer ticker.Stop()
loop:
	for {
		select {
		case i := <-q.newMessage.Recv:
			q.deliverMessage(i.(*Message))
		case <-ticker.C:
			q.checkForInactiveQueues()
		case <-q.stop:
			break loop
		}
	}
	log.Println("shutting down host queues")
	for h := range q.hosts {
		q.hosts[h].Stop()
	}
}

// Create a new message queue. Any undelivered messages on disk will be added
// to the appropriate queue.
func NewQueue(directory string) (*Queue, error) {
	if s, messages, err := NewStorage(directory); err == nil {
		q := &Queue{
			storage:    s,
			hosts:      make(map[string]*Host),
			newMessage: util.NewNonBlockingChan(),
			stop:       make(chan bool),
		}
		for _, m := range messages {
			q.newMessage.Send <- m
		}
		go q.run()
		return q, nil
	} else {
		return nil, err
	}
}

// Create a new message body.
func (q *Queue) NewBody() (io.WriteCloser, string, error) {
	return q.storage.NewBody()
}

// Deliver the specified message to the appropriate host queue.
func (q *Queue) Deliver(m *Message) {
	q.newMessage.Send <- m
}

// Stop all active host queues.
func (q *Queue) Stop() {
	q.stop <- true
	<-q.stop
}
<commit_msg>Fixed a bug with loading messages from storage.<commit_after>package queue

import (
	"github.com/nathan-osman/go-cannon/util"

	"io"
	"log"
	"time"
)

// Mail queue managing the sending of messages to hosts.
type Queue struct {
	storage    *Storage
	hosts      map[string]*Host
	newMessage *util.NonBlockingChan
	stop       chan bool
}

// Deliver the specified message to the appropriate host queue.
func (q *Queue) deliverMessage(host, id string) {
	if _, ok := q.hosts[host]; !ok {
		q.hosts[host] = NewHost(host, q.storage)
	}
	q.hosts[host].Deliver(id)
}

// Check for inactive host queues and shut them down.
func (q *Queue) checkForInactiveQueues() {
	for n, h := range q.hosts {
		if h.Idle() > time.Minute {
			h.Stop()
			delete(q.hosts, n)
		}
	}
}

// Receive new messages and deliver them to the specified host queue.
func (q *Queue) run() {
	defer close(q.stop)
	ticker := time.NewTicker(time.Minute)
	defer ticker.Stop()
loop:
	for {
		select {
		case i := <-q.newMessage.Recv:
			m := i.(*Message)
			if id, err := q.storage.NewMessage(m); err == nil {
				q.deliverMessage(m.Host, id)
			} else {
				log.Print(err)
			}
		case <-ticker.C:
			q.checkForInactiveQueues()
		case <-q.stop:
			break loop
		}
	}
	log.Println("shutting down host queues")
	for h := range q.hosts {
		q.hosts[h].Stop()
	}
}

// Create a new message queue. Any undelivered messages on disk will be added
// to the appropriate queue.
func NewQueue(directory string) (*Queue, error) {
	if s, messages, err := NewStorage(directory); err == nil {
		q := &Queue{
			storage:    s,
			hosts:      make(map[string]*Host),
			newMessage: util.NewNonBlockingChan(),
			stop:       make(chan bool),
		}
		for _, id := range messages {
			if m, err := q.storage.GetMessage(id); err == nil {
				q.deliverMessage(m.Host, id)
			}
		}
		go q.run()
		return q, nil
	} else {
		return nil, err
	}
}

// Create a new message body.
func (q *Queue) NewBody() (io.WriteCloser, string, error) {
	return q.storage.NewBody()
}

// Deliver the specified message to the appropriate host queue.
func (q *Queue) Deliver(m *Message) {
	q.newMessage.Send <- m
}

// Stop all active host queues.
func (q *Queue) Stop() {
	q.stop <- true
	<-q.stop
}
<|endoftext|>


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

package queue

import (
	"sync"

	"tux21b.org/v1/gocql"
)

type QueueItem []byte

type Queue struct {
	id          string
	nextIndex   int
	publishLock sync.Mutex
}

type QueueManagerConfig struct {
	CassandraHosts    []string
	CassandraKeyspace string
}

type QueueManager struct {
	name       string
	config     QueueManagerConfig
	queuesLock sync.RWMutex
	queues     map[string]*Queue
	db         *gocql.Session
}

func NewQueueManager(name string, config QueueManagerConfig) (*QueueManager, error) {
	cassCluster := gocql.NewCluster(config.CassandraHosts...)
	cassCluster.Keyspace = config.CassandraKeyspace
	cassSession, err := cassCluster.CreateSession()

	if err != nil {
		return nil, err
	}

	return &QueueManager{
		name:   name,
		config: config,
		db:     cassSession,
	}, nil
}

func (mgr *QueueManager) getOrCreateQueue(queueID string) (*Queue, error) {
	// Hot path: just get the queue from the map
	mgr.queuesLock.RLock()
	queue, exists := mgr.queues[queueID]
	mgr.queuesLock.RUnlock()

	if exists {
		return queue, nil
	}

	// TODO: try to register as the queue's manager

	mgr.queuesLock.Lock()
	queue, exists = mgr.queues[queueID]

	if !exists {
		queue = &Queue{
			id: queueID,
		}
		mgr.queues[queueID] = queue
	}

	mgr.queuesLock.Unlock()

	return queue, nil
}

func (mgr *QueueManager) LookupQueue(queueID string) (string, error) {
	// TODO: stop pretending we own every queue
	return mgr.name, nil
}

func (mgr *QueueManager) Publish(queueID string, items []QueueItem) (int, error) {
	queue, err := mgr.getOrCreateQueue(queueID)

	if err != nil {
		return 0, err
	}

	queue.publishLock.Lock()
	defer queue.publishLock.Unlock()

	// TODO: batch pending items
	idx := queue.nextIndex

	batch := gocql.NewBatch(gocql.UnloggedBatch)

	for i, item := range items {
		batch.Query(`INSERT INTO ? (queue_id, item_id, item_value) VALUES (?, ?, ?)`, queue.id, idx+i, item)
	}

	err = mgr.db.ExecuteBatch(batch)

	if err != nil {
		return 0, err
	}

	queue.nextIndex = idx + len(items)

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

package queue

import (
	"sync"

	"tux21b.org/v1/gocql"
)

type QueueItem []byte

type Queue struct {
	id          string
	nextIndex   int
	publishLock sync.Mutex
}

type QueueManagerConfig struct {
	CassandraHosts    []string
	CassandraKeyspace string
}

type QueueManager struct {
	name       string
	config     QueueManagerConfig
	queuesLock sync.RWMutex
	queues     map[string]*Queue
	db         *gocql.Session
}

func NewQueueManager(name string, config QueueManagerConfig) (*QueueManager, error) {
	cassCluster := gocql.NewCluster(config.CassandraHosts...)
	cassCluster.Keyspace = config.CassandraKeyspace
	cassSession, err := cassCluster.CreateSession()

	if err != nil {
		return nil, err
	}

	return &QueueManager{
		name:   name,
		config: config,
		queues: make(map[string]*Queue),
		db:     cassSession,
	}, nil
}

func (mgr *QueueManager) getOrCreateQueue(queueID string) (*Queue, error) {
	// Hot path: just get the queue from the map
	mgr.queuesLock.RLock()
	queue, exists := mgr.queues[queueID]
	mgr.queuesLock.RUnlock()

	if exists {
		return queue, nil
	}

	// TODO: try to register as the queue's manager

	mgr.queuesLock.Lock()
	queue, exists = mgr.queues[queueID]

	if !exists {
		queue = &Queue{
			id: queueID,
		}
		mgr.queues[queueID] = queue
	}

	mgr.queuesLock.Unlock()

	return queue, nil
}

func (mgr *QueueManager) LookupQueue(queueID string) (string, error) {
	// TODO: stop pretending we own every queue
	return mgr.name, nil
}

func (mgr *QueueManager) Publish(queueID string, items []QueueItem) (int, error) {
	queue, err := mgr.getOrCreateQueue(queueID)

	if err != nil {
		return 0, err
	}

	queue.publishLock.Lock()
	defer queue.publishLock.Unlock()

	// TODO: batch pending items
	idx := queue.nextIndex

	batch := gocql.NewBatch(gocql.UnloggedBatch)

	for i, item := range items {
		batch.Query(`INSERT INTO queue_items (queue_id, item_id, item_value) VALUES (?, ?, ?)`, queue.id, idx+i, item)
	}

	err = mgr.db.ExecuteBatch(batch)

	if err != nil {
		return 0, err
	}

	queue.nextIndex = idx + len(items)

	return idx, nil
}
<|endoftext|>


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

// Package queue implements a Pub/Sub channel in tsuru. It abstracts
// which server is being used and handles connection pooling and
// data transmiting
package queue

import (
	"sync"
	"time"

	"github.com/pkg/errors"
	"github.com/tsuru/config"
	"github.com/tsuru/monsterqueue"
	"github.com/tsuru/monsterqueue/mongodb"
	"github.com/tsuru/tsuru/api/shutdown"
)

type queueInstanceData struct {
	sync.RWMutex
	instance monsterqueue.Queue
}

func (q *queueInstanceData) Shutdown() {
	q.Lock()
	defer q.Unlock()
	if q.instance != nil {
		q.instance.Stop()
		q.instance = nil
	}
}

func (q *queueInstanceData) String() string {
	return "queued tasks"
}

var queueData queueInstanceData

func ResetQueue() {
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		queueData.instance.Stop()
		queueData.instance.ResetStorage()
		queueData.instance = nil
	}
}

func TestingWaitQueueTasks(n int, timeout time.Duration) error {
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		timeoutCh := time.After(timeout)
		for {
			jobs, _ := queueData.instance.ListJobs()
			runningCount := 0
			for _, j := range jobs {
				if j.Status().State != monsterqueue.JobStateEnqueued {
					runningCount++
				}
			}
			if n <= runningCount {
				break
			}
			select {
			case <-timeoutCh:
				return errors.Errorf("timeout waiting for task after %v", timeout)
			case <-time.After(10 * time.Millisecond):
			}
		}
		queueData.instance.Stop()
		queueData.instance.ResetStorage()
		queueData.instance = nil
	}
	return nil
}

func Queue() (monsterqueue.Queue, error) {
	queueData.RLock()
	if queueData.instance != nil {
		defer queueData.RUnlock()
		return queueData.instance, nil
	}
	queueData.RUnlock()
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		return queueData.instance, nil
	}
	queueMongoUrl, _ := config.GetString("queue:mongo-url")
	if queueMongoUrl == "" {
		queueMongoUrl = "localhost:27017"
	}
	queueMongoDB, _ := config.GetString("queue:mongo-database")
	pollingInterval, _ := config.GetFloat("queue:mongo-polling-interval")
	if pollingInterval == 0.0 {
		pollingInterval = 1.0
	}
	conf := mongodb.QueueConfig{
		CollectionPrefix: "tsuru",
		Url:              queueMongoUrl,
		Database:         queueMongoDB,
		PollingInterval:  time.Duration(pollingInterval * float64(time.Second)),
	}
	var err error
	queueData.instance, err = mongodb.NewQueue(conf)
	if err != nil {
		return nil, errors.Wrap(err, "could not create queue instance, please check queue:mongo-url and queue:mongo-database config entries. error")
	}
	shutdown.Register(&queueData)
	go queueData.instance.ProcessLoop()
	return queueData.instance, nil
}
<commit_msg>lint: transforms queueMongoUrl into queueMongoURL<commit_after>// Copyright 2012 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package queue implements a Pub/Sub channel in tsuru. It abstracts
// which server is being used and handles connection pooling and
// data transmiting
package queue

import (
	"sync"
	"time"

	"github.com/pkg/errors"
	"github.com/tsuru/config"
	"github.com/tsuru/monsterqueue"
	"github.com/tsuru/monsterqueue/mongodb"
	"github.com/tsuru/tsuru/api/shutdown"
)

type queueInstanceData struct {
	sync.RWMutex
	instance monsterqueue.Queue
}

func (q *queueInstanceData) Shutdown() {
	q.Lock()
	defer q.Unlock()
	if q.instance != nil {
		q.instance.Stop()
		q.instance = nil
	}
}

func (q *queueInstanceData) String() string {
	return "queued tasks"
}

var queueData queueInstanceData

func ResetQueue() {
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		queueData.instance.Stop()
		queueData.instance.ResetStorage()
		queueData.instance = nil
	}
}

func TestingWaitQueueTasks(n int, timeout time.Duration) error {
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		timeoutCh := time.After(timeout)
		for {
			jobs, _ := queueData.instance.ListJobs()
			runningCount := 0
			for _, j := range jobs {
				if j.Status().State != monsterqueue.JobStateEnqueued {
					runningCount++
				}
			}
			if n <= runningCount {
				break
			}
			select {
			case <-timeoutCh:
				return errors.Errorf("timeout waiting for task after %v", timeout)
			case <-time.After(10 * time.Millisecond):
			}
		}
		queueData.instance.Stop()
		queueData.instance.ResetStorage()
		queueData.instance = nil
	}
	return nil
}

func Queue() (monsterqueue.Queue, error) {
	queueData.RLock()
	if queueData.instance != nil {
		defer queueData.RUnlock()
		return queueData.instance, nil
	}
	queueData.RUnlock()
	queueData.Lock()
	defer queueData.Unlock()
	if queueData.instance != nil {
		return queueData.instance, nil
	}
	queueMongoURL, _ := config.GetString("queue:mongo-url")
	if queueMongoURL == "" {
		queueMongoURL = "localhost:27017"
	}
	queueMongoDB, _ := config.GetString("queue:mongo-database")
	pollingInterval, _ := config.GetFloat("queue:mongo-polling-interval")
	if pollingInterval == 0.0 {
		pollingInterval = 1.0
	}
	conf := mongodb.QueueConfig{
		CollectionPrefix: "tsuru",
		Url:              queueMongoURL,
		Database:         queueMongoDB,
		PollingInterval:  time.Duration(pollingInterval * float64(time.Second)),
	}
	var err error
	queueData.instance, err = mongodb.NewQueue(conf)
	if err != nil {
		return nil, errors.Wrap(err, "could not create queue instance, please check queue:mongo-url and queue:mongo-database config entries. error")
	}
	shutdown.Register(&queueData)
	go queueData.instance.ProcessLoop()
	return queueData.instance, nil
}
<|endoftext|>


<commit_before>package gofakeit

import (
	"fmt"
	"testing"
)

func ExampleFruit() {
	Seed(11)
	fmt.Println(Fruit())
	// Output: Peach
}

func ExampleFaker_Fruit() {
	f := New(11)
	fmt.Println(f.Fruit())
	// Output: Peach
}

func BenchmarkFruit(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Fruit()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Fruit()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Fruit()
		}
	})
}

func ExampleVegetable() {
	Seed(11)
	fmt.Println(Vegetable())
	// Output: Amaranth Leaves
}

func ExampleFaker_Vegetable() {
	f := New(11)
	fmt.Println(f.Vegetable())
	// Output: Amaranth Leaves
}

func BenchmarkVegetable(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Vegetable()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Vegetable()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Vegetable()
		}
	})
}

func ExampleBreakfast() {
	Seed(11)
	fmt.Println(Breakfast())
	// Output: Blueberry banana happy face pancakes
}

func ExampleFaker_Breakfast() {
	f := New(11)
	fmt.Println(f.Breakfast())
	// Output: Blueberry banana happy face pancakes
}

func BenchmarkBreakfast(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Breakfast()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Breakfast()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Breakfast()
		}
	})
}

func ExampleLunch() {
	Seed(11)
	fmt.Println(Lunch())
	// Output: No bake hersheys bar pie
}

func ExampleFaker_Lunch() {
	f := New(11)
	fmt.Println(f.Lunch())
	// Output: No bake hersheys bar pie
}

func BenchmarkLunch(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Lunch()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Lunch()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Lunch()
		}
	})
}

func ExampleDinner() {
	Seed(11)
	fmt.Println(Dinner())
	// Output: Wild addicting dip
}

func ExampleFaker_Dinner() {
	f := New(11)
	fmt.Println(f.Dinner())
	// Output: Wild addicting dip
}

func BenchmarkDinner(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Dinner()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Dinner()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Dinner()
		}
	})
}

func ExampleDrink() {
	Seed(11)
	fmt.Println(Drink())
	// Output: Water
}

func ExampleFaker_Drink() {
	f := New(11)
	fmt.Println(f.Drink())
	// Output: Water
}

func BenchmarkDrink(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Drink()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Drink()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Drink()
		}
	})
}

func ExampleSnack() {
	Seed(11)
	fmt.Println(Snack())
	// Output: Hoisin marinated wing pieces
}

func ExampleFaker_Snack() {
	f := New(11)
	fmt.Println(f.Snack())
	// Output: Hoisin marinated wing pieces
}

func BenchmarkSnack(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Snack()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Snack()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Snack()
		}
	})
}

func ExampleDessert() {
	Seed(11)
	fmt.Println(Dessert())
	// Output: French napoleons
}

func ExampleFaker_Dessert() {
	f := New(11)
	fmt.Println(f.Dessert())
	// Output: French napoleons
}

func BenchmarkDessert(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Dessert()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Dessert()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Dessert()
		}
	})
}
<commit_msg>food - fix drink output<commit_after>package gofakeit

import (
	"fmt"
	"testing"
)

func ExampleFruit() {
	Seed(11)
	fmt.Println(Fruit())
	// Output: Peach
}

func ExampleFaker_Fruit() {
	f := New(11)
	fmt.Println(f.Fruit())
	// Output: Peach
}

func BenchmarkFruit(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Fruit()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Fruit()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Fruit()
		}
	})
}

func ExampleVegetable() {
	Seed(11)
	fmt.Println(Vegetable())
	// Output: Amaranth Leaves
}

func ExampleFaker_Vegetable() {
	f := New(11)
	fmt.Println(f.Vegetable())
	// Output: Amaranth Leaves
}

func BenchmarkVegetable(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Vegetable()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Vegetable()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Vegetable()
		}
	})
}

func ExampleBreakfast() {
	Seed(11)
	fmt.Println(Breakfast())
	// Output: Blueberry banana happy face pancakes
}

func ExampleFaker_Breakfast() {
	f := New(11)
	fmt.Println(f.Breakfast())
	// Output: Blueberry banana happy face pancakes
}

func BenchmarkBreakfast(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Breakfast()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Breakfast()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Breakfast()
		}
	})
}

func ExampleLunch() {
	Seed(11)
	fmt.Println(Lunch())
	// Output: No bake hersheys bar pie
}

func ExampleFaker_Lunch() {
	f := New(11)
	fmt.Println(f.Lunch())
	// Output: No bake hersheys bar pie
}

func BenchmarkLunch(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Lunch()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Lunch()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Lunch()
		}
	})
}

func ExampleDinner() {
	Seed(11)
	fmt.Println(Dinner())
	// Output: Wild addicting dip
}

func ExampleFaker_Dinner() {
	f := New(11)
	fmt.Println(f.Dinner())
	// Output: Wild addicting dip
}

func BenchmarkDinner(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Dinner()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Dinner()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Dinner()
		}
	})
}

func ExampleDrink() {
	Seed(11)
	fmt.Println(Drink())
	// Output: Juice
}

func ExampleFaker_Drink() {
	f := New(11)
	fmt.Println(f.Drink())
	// Output: Juice
}

func BenchmarkDrink(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Drink()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Drink()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Drink()
		}
	})
}

func ExampleSnack() {
	Seed(11)
	fmt.Println(Snack())
	// Output: Hoisin marinated wing pieces
}

func ExampleFaker_Snack() {
	f := New(11)
	fmt.Println(f.Snack())
	// Output: Hoisin marinated wing pieces
}

func BenchmarkSnack(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Snack()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Snack()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Snack()
		}
	})
}

func ExampleDessert() {
	Seed(11)
	fmt.Println(Dessert())
	// Output: French napoleons
}

func ExampleFaker_Dessert() {
	f := New(11)
	fmt.Println(f.Dessert())
	// Output: French napoleons
}

func BenchmarkDessert(b *testing.B) {
	b.Run("package", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Dessert()
		}
	})

	b.Run("Faker math", func(b *testing.B) {
		f := New(0)

		for i := 0; i < b.N; i++ {
			f.Dessert()
		}
	})

	b.Run("Faker crypto", func(b *testing.B) {
		f := NewCrypto()

		for i := 0; i < b.N; i++ {
			f.Dessert()
		}
	})
}
<|endoftext|>


<commit_before>package textformatter

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/mgutz/ansi"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"
)

type ColorScheme struct {
	InfoLevelStyle  string
	WarnLevelStyle  string
	ErrorLevelStyle string
	FatalLevelStyle string
	PanicLevelStyle string
	DebugLevelStyle string
	PrefixStyle1    string
	PrefixStyle2    string
	TimestampStyle  string
}

type compiledColorScheme struct {
	InfoLevelColor  func(string) string
	WarnLevelColor  func(string) string
	ErrorLevelColor func(string) string
	FatalLevelColor func(string) string
	PanicLevelColor func(string) string
	DebugLevelColor func(string) string
	PrefixColor1    func(string) string
	PrefixColor2    func(string) string
	TimestampColor  func(string) string
}

type Instance struct {
	// Set to true to bypass checking for a TTY before outputting colors.
	ForceColors bool

	// Force disabling colors. For a TTY colors are enabled by default.
	DisableColors bool

	// Force formatted layout, even for non-TTY output.
	ForceFormatting bool

	// Disable timestamp logging. useful when output is redirected to logging
	// system that already adds timestamps.
	DisableTimestamp bool

	// Disable the conversion of the log levels to uppercase
	DisableUppercase bool

	// Enable logging the full timestamp when a TTY is attached instead of just
	// the time passed since beginning of execution.
	FullTimestamp bool

	// Timestamp format to use for display when a full timestamp is printed.
	TimestampFormat string

	// Wrap empty fields in quotes if true.
	QuoteEmptyFields bool

	// Can be set to the override the default quoting character "
	// with something else. For example: ', or `.
	QuoteCharacter string

	// Color scheme to use.
	colorScheme *compiledColorScheme

	// Whether the logger's out is to a terminal.
	isTerminal bool

	sync.Once
}

const defaultTimestampFormat = time.RFC3339Nano

var (
	baseTimestamp      time.Time    = time.Now()
	defaultColorScheme *ColorScheme = &ColorScheme{
		InfoLevelStyle:  "green+h",
		WarnLevelStyle:  "yellow+h",
		ErrorLevelStyle: "red+h",
		FatalLevelStyle: "red+h",
		PanicLevelStyle: "red+h",
		DebugLevelStyle: "black+h",
		PrefixStyle1:    "black+h",
		PrefixStyle2:    "cyan",
		TimestampStyle:  "black+h",
	}
	noColorsColorScheme *compiledColorScheme = &compiledColorScheme{
		InfoLevelColor:  ansi.ColorFunc(""),
		WarnLevelColor:  ansi.ColorFunc(""),
		ErrorLevelColor: ansi.ColorFunc(""),
		FatalLevelColor: ansi.ColorFunc(""),
		PanicLevelColor: ansi.ColorFunc(""),
		DebugLevelColor: ansi.ColorFunc(""),
		PrefixColor1:    ansi.ColorFunc(""),
		PrefixColor2:    ansi.ColorFunc(""),
		TimestampColor:  ansi.ColorFunc(""),
	}
	defaultCompiledColorScheme *compiledColorScheme = compileColorScheme(defaultColorScheme)
)

func miniTS() float64 {
	return time.Since(baseTimestamp).Seconds()
}

func getCompiledColor(main string, fallback string) func(string) string {
	var style string
	if main != "" {
		style = main
	} else {
		style = fallback
	}
	return ansi.ColorFunc(style)
}

func compileColorScheme(s *ColorScheme) *compiledColorScheme {
	return &compiledColorScheme{
		InfoLevelColor:  getCompiledColor(s.InfoLevelStyle, defaultColorScheme.InfoLevelStyle),
		WarnLevelColor:  getCompiledColor(s.WarnLevelStyle, defaultColorScheme.WarnLevelStyle),
		ErrorLevelColor: getCompiledColor(s.ErrorLevelStyle, defaultColorScheme.ErrorLevelStyle),
		FatalLevelColor: getCompiledColor(s.FatalLevelStyle, defaultColorScheme.FatalLevelStyle),
		PanicLevelColor: getCompiledColor(s.PanicLevelStyle, defaultColorScheme.PanicLevelStyle),
		DebugLevelColor: getCompiledColor(s.DebugLevelStyle, defaultColorScheme.DebugLevelStyle),
		PrefixColor1:    getCompiledColor(s.PrefixStyle1, defaultColorScheme.PrefixStyle1),
		PrefixColor2:    getCompiledColor(s.PrefixStyle2, defaultColorScheme.PrefixStyle2),
		TimestampColor:  getCompiledColor(s.TimestampStyle, defaultColorScheme.TimestampStyle),
	}
}

func (f *Instance) init(entry *logrus.Entry) {
	if len(f.QuoteCharacter) == 0 {
		f.QuoteCharacter = "\""
	}
	if entry.Logger != nil {
		f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
	}
}

func (f *Instance) checkIfTerminal(w io.Writer) bool {
	switch v := w.(type) {
	case *os.File:
		return terminal.IsTerminal(int(v.Fd()))
	default:
		return false
	}
}

func (f *Instance) SetColorScheme(colorScheme *ColorScheme) {
	f.colorScheme = compileColorScheme(colorScheme)
}

func (f *Instance) Format(entry *logrus.Entry) ([]byte, error) {
	var buf *bytes.Buffer
	var keys []string = make([]string, 0, len(entry.Data))
	for k := range entry.Data {
		keys = append(keys, k)
	}
	lastKeyIdx := len(keys) - 1

	if entry.Buffer != nil {
		buf = entry.Buffer
	} else {
		buf = &bytes.Buffer{}
	}

	prefixFieldClashes(entry.Data)

	f.Do(func() { f.init(entry) })

	isFormatted := f.ForceFormatting || f.isTerminal

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = defaultTimestampFormat
	}
	if isFormatted {
		isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
		var colorScheme *compiledColorScheme
		if isColored {
			if f.colorScheme == nil {
				colorScheme = defaultCompiledColorScheme
			} else {
				colorScheme = f.colorScheme
			}
		} else {
			colorScheme = noColorsColorScheme
		}
		f.printColored(buf, entry, keys, timestampFormat, colorScheme)
	} else {
		if !f.DisableTimestamp {
			f.appendKeyValue(buf, "time", entry.Time.Format(timestampFormat), true)
		}
		f.appendKeyValue(buf, "level", entry.Level.String(), true)
		if entry.Message != "" {
			f.appendKeyValue(buf, "msg", entry.Message, lastKeyIdx >= 0)
		}
		for i, key := range keys {
			f.appendKeyValue(buf, key, entry.Data[key], lastKeyIdx != i)
		}
	}

	buf.WriteRune('\n')
	return buf.Bytes(), nil
}

func (f *Instance) printColored(buf *bytes.Buffer, entry *logrus.Entry, keys []string, timestampFormat string, colorScheme *compiledColorScheme) {
	var levelColor func(string) string
	var levelText string
	switch entry.Level {
	case logrus.InfoLevel:
		levelColor = colorScheme.InfoLevelColor
	case logrus.WarnLevel:
		levelColor = colorScheme.WarnLevelColor
	case logrus.ErrorLevel:
		levelColor = colorScheme.ErrorLevelColor
	case logrus.FatalLevel:
		levelColor = colorScheme.FatalLevelColor
	case logrus.PanicLevel:
		levelColor = colorScheme.PanicLevelColor
	default:
		levelColor = colorScheme.DebugLevelColor
	}

	if entry.Level != logrus.WarnLevel {
		levelText = entry.Level.String()
	} else {
		levelText = "warn"
	}

	if !f.DisableUppercase {
		levelText = strings.ToUpper(levelText)
	}

	if !f.DisableTimestamp {
		var ts string
		if !f.FullTimestamp {
			ts = fmt.Sprintf("[%f]", miniTS())
		} else {
			ts = entry.Time.Format(timestampFormat)
		}
		fmt.Fprint(buf, colorScheme.TimestampColor(ts), " ")
	}

	fmt.Fprint(buf, levelColor(fmt.Sprintf("%5s", levelText)), " ")

	if v, ok := entry.Data["__t"]; ok {
		fmt.Fprint(buf, colorScheme.PrefixColor1(fmt.Sprintf(":%v:", v)), " ")
	}

	if v, ok := entry.Data["__p"]; ok {
		fmt.Fprint(buf, colorScheme.PrefixColor2(fmt.Sprintf("%v", v)))
	} else {
		fmt.Fprint(buf, colorScheme.PrefixColor2("__p<missing>"))
	}

	if v, ok := entry.Data["__f"]; ok {
		fmt.Fprint(buf, colorScheme.PrefixColor2(fmt.Sprintf(".%v", v)))
	}
	fmt.Fprint(buf, ": ", entry.Message)

	for _, k := range keys {
		if k != "__p" && k != "__f" && k != "__t" {
			v := entry.Data[k]
			fmt.Fprintf(buf, " %s=%+v", colorScheme.PrefixColor2(k), v)
		}
	}
}

func (f *Instance) appendKeyValue(b *bytes.Buffer, key string, value interface{}, appendSpace bool) {
	b.WriteString(key)
	b.WriteByte('=')
	f.appendValue(b, value)

	if appendSpace {
		b.WriteByte(' ')
	}
}

func (f *Instance) appendValue(b *bytes.Buffer, value interface{}) {
	switch value := value.(type) {
	case string:
		b.WriteString(value)
	case error:
		errmsg := value.Error()
		b.WriteString(errmsg)
	default:
		fmt.Fprint(b, value)
	}
}

// This is to not silently overwrite `time`, `msg` and `level` fields when
// dumping it. If this code wasn't there doing:
//
//  logrus.WithField("level", 1).Info("hello")
//
// would just silently drop the user provided level. Instead with this code
// it'll be logged as:
//
//  {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."}
func prefixFieldClashes(data logrus.Fields) {
	if t, ok := data["time"]; ok {
		data["fields.time"] = t
	}

	if m, ok := data["msg"]; ok {
		data["fields.msg"] = m
	}

	if l, ok := data["level"]; ok {
		data["fields.level"] = l
	}
}
<commit_msg>Simplified<commit_after>package textformatter

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/mgutz/ansi"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/ssh/terminal"
)

type ColorScheme struct {
	InfoLevel  string
	WarnLevel  string
	ErrorLevel string
	FatalLevel string
	PanicLevel string
	DebugLevel string
	Tag        string
	Prefix     string
	Timestamp  string
}

type compiledColorScheme struct {
	InfoLevel  func(string) string
	WarnLevel  func(string) string
	ErrorLevel func(string) string
	FatalLevel func(string) string
	PanicLevel func(string) string
	DebugLevel func(string) string
	Tag        func(string) string
	Prefix     func(string) string
	Timestamp  func(string) string
}

type Instance struct {
	// Use colors if TTY detected
	UseColors bool

	// Disable timestamp logging. useful when output is redirected to logging
	// system that already adds timestamps.
	DisableTimestamp bool

	// Print level names in `lowercase` instead of `UPPERCASE`
	LowercaseLevels bool

	// Enable logging the full timestamp when a TTY is attached instead of just
	// the time passed since beginning of execution.
	FullTimestamp bool

	// Timestamp format to use for display when a full timestamp is printed.
	TimestampFormat string

	colorScheme *compiledColorScheme
}

const defaultTimestampFormat = time.RFC3339Nano

var (
	baseTimestamp time.Time    = time.Now()
	defaultColors *ColorScheme = &ColorScheme{
		InfoLevel:  "green+h",
		WarnLevel:  "yellow+h",
		ErrorLevel: "red+h",
		FatalLevel: "red+h",
		PanicLevel: "red+h",
		DebugLevel: "black+h",
		Tag:        "black+h",
		Prefix:     "cyan",
		Timestamp:  "black+h",
	}
	noColors *compiledColorScheme = &compiledColorScheme{
		InfoLevel:  ansi.ColorFunc(""),
		WarnLevel:  ansi.ColorFunc(""),
		ErrorLevel: ansi.ColorFunc(""),
		FatalLevel: ansi.ColorFunc(""),
		PanicLevel: ansi.ColorFunc(""),
		DebugLevel: ansi.ColorFunc(""),
		Tag:        ansi.ColorFunc(""),
		Prefix:     ansi.ColorFunc(""),
		Timestamp:  ansi.ColorFunc(""),
	}
	defaultCompiledColorScheme *compiledColorScheme = compileColorScheme(defaultColors)
)

func miniTS() float64 {
	return time.Since(baseTimestamp).Seconds()
}

func getCompiledColor(main string, fallback string) func(string) string {
	var style string
	if main != "" {
		style = main
	} else {
		style = fallback
	}
	return ansi.ColorFunc(style)
}

func compileColorScheme(s *ColorScheme) *compiledColorScheme {
	return &compiledColorScheme{
		InfoLevel:  getCompiledColor(s.InfoLevel, defaultColors.InfoLevel),
		WarnLevel:  getCompiledColor(s.WarnLevel, defaultColors.WarnLevel),
		ErrorLevel: getCompiledColor(s.ErrorLevel, defaultColors.ErrorLevel),
		FatalLevel: getCompiledColor(s.FatalLevel, defaultColors.FatalLevel),
		PanicLevel: getCompiledColor(s.PanicLevel, defaultColors.PanicLevel),
		DebugLevel: getCompiledColor(s.DebugLevel, defaultColors.DebugLevel),
		Tag:        getCompiledColor(s.Tag, defaultColors.Tag),
		Prefix:     getCompiledColor(s.Prefix, defaultColors.Prefix),
		Timestamp:  getCompiledColor(s.Timestamp, defaultColors.Timestamp),
	}
}

func (f *Instance) checkIfTerminal(w io.Writer) bool {
	switch v := w.(type) {
	case *os.File:
		return terminal.IsTerminal(int(v.Fd()))
	default:
		return false
	}
}

func (f *Instance) SetColorScheme(colorScheme *ColorScheme) {
	f.colorScheme = compileColorScheme(colorScheme)
}

func (f *Instance) Format(entry *logrus.Entry) ([]byte, error) {
	var buf *bytes.Buffer
	if entry.Buffer != nil {
		buf = entry.Buffer
	} else {
		buf = &bytes.Buffer{}
	}

	timestampFormat := f.TimestampFormat
	if timestampFormat == "" {
		timestampFormat = defaultTimestampFormat
	}
	var colors *compiledColorScheme
	if f.UseColors {
		if f.colorScheme == nil {
			f.colorScheme = defaultCompiledColorScheme
		}
		colors = f.colorScheme
	} else {
		colors = noColors
	}
	var levelColor func(string) string
	var levelText string
	switch entry.Level {
	case logrus.InfoLevel:
		levelColor = colors.InfoLevel
	case logrus.WarnLevel:
		levelColor = colors.WarnLevel
	case logrus.ErrorLevel:
		levelColor = colors.ErrorLevel
	case logrus.FatalLevel:
		levelColor = colors.FatalLevel
	case logrus.PanicLevel:
		levelColor = colors.PanicLevel
	default:
		levelColor = colors.DebugLevel
	}

	if entry.Level != logrus.WarnLevel {
		levelText = entry.Level.String()
	} else {
		levelText = "warn"
	}

	if !f.LowercaseLevels {
		levelText = strings.ToUpper(levelText)
	}

	if !f.DisableTimestamp {
		var ts string
		if !f.FullTimestamp {
			ts = fmt.Sprintf("[%f]", miniTS())
		} else {
			ts = entry.Time.Format(timestampFormat)
		}
		fmt.Fprint(buf, colors.Timestamp(ts), " ")
	}

	fmt.Fprint(buf, levelColor(fmt.Sprintf("%5s", levelText)), " ")

	if v, ok := entry.Data["__t"]; ok {
		fmt.Fprint(buf, colors.Tag(fmt.Sprintf(":%v:", v)), " ")
	}

	if v, ok := entry.Data["__p"]; ok {
		fmt.Fprint(buf, colors.Prefix(fmt.Sprintf("%v", v)))
	} else {
		fmt.Fprint(buf, colors.Prefix("__p<missing>"))
	}

	if v, ok := entry.Data["__f"]; ok {
		fmt.Fprint(buf, colors.Prefix(fmt.Sprintf(".%v", v)))
	}
	fmt.Fprint(buf, ": ", entry.Message)

	for k, v := range entry.Data {
		if k != "__p" && k != "__f" && k != "__t" {
			fmt.Fprintf(buf, " %s=%#v", colors.Prefix(k), v)
		}
	}
	buf.WriteRune('\n')
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package pretty

import (
	"fmt"
	"io"
	"reflect"
)

const (
	limit = 50
)

var (
	commaLFBytes     = []byte(",\n")
	curlyBytes       = []byte("{}")
	openCurlyLFBytes = []byte("{\n")
	spacePlusLFBytes = []byte(" +\n")
)

type formatter struct {
	d int
	x interface{}

	omit bool
}

// Formatter makes a wrapper, f, that will format x as go source with line
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
// "#" and " " (space) flags are set, for example:
//
//     fmt.Sprintf("%# v", Formatter(x))
//
// If one of these two flags is not set, or any other verb is used, f will
// format x according to the usual rules of package fmt.
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
func Formatter(x interface{}) (f fmt.Formatter) {
	return formatter{x: x}
}

func (fo formatter) String() string {
	return fmt.Sprint(fo.x) // unwrap it
}

func (fo formatter) passThrough(f fmt.State, c rune) {
	s := "%"
	for i := 0; i < 128; i++ {
		if f.Flag(i) {
			s += string(i)
		}
	}
	if w, ok := f.Width(); ok {
		s += fmt.Sprintf("%d", w)
	}
	if p, ok := f.Precision(); ok {
		s += fmt.Sprintf(".%d", p)
	}
	s += string(c)
	fmt.Fprintf(f, s, fo.x)
}

func (fo formatter) Format(f fmt.State, c rune) {
	if c == 'v' && f.Flag('#') && f.Flag(' ') {
		fo.format(f)
		return
	}
	fo.passThrough(f, c)
}

func (fo formatter) format(w io.Writer) {
	v := reflect.ValueOf(fo.x)
	switch v.Kind() {
	case reflect.String:
		lim := limit - 8*fo.d
		s := v.String()
		z := len(s)
		n := (z + lim - 1) / lim
		if n < 1 {
			n = 1 // empty string still produces output
		}
		sep := append(spacePlusLFBytes, make([]byte, fo.d)...)
		for j := 0; j < fo.d; j++ {
			sep[3+j] = '\t'
		}
		for i := 0; i < n; i++ {
			if i > 0 {
				w.Write(sep)
			}
			l, h := i*lim, (i+1)*lim
			if h > z {
				h = z
			}
			fmt.Fprintf(w, "%#v", s[l:h])
		}
		return
	case reflect.Ptr:
		e := v.Elem()
		if !e.IsValid() {
			fmt.Fprintf(w, "%#v", fo.x)
		} else {
			writeByte(w, '&')
			fmt.Fprintf(w, "%# v", formatter{d: fo.d, x: e.Interface()})
		}
	case reflect.Slice:
		s := fmt.Sprintf("%#v", fo.x)
		if len(s) < limit {
			io.WriteString(w, s)
			return
		}

		t := v.Type()

		io.WriteString(w, reflect.TypeOf(fo.x).String())
		w.Write(openCurlyLFBytes)
		for i := 0; i < v.Len(); i++ {
			for j := 0; j < fo.d+1; j++ {
				writeByte(w, '\t')
			}
			inner := formatter{d: fo.d + 1, x: v.Index(i).Interface(), omit: t.Elem().Kind() != reflect.Interface}
			fmt.Fprintf(w, "%# v", inner)
			w.Write(commaLFBytes)
		}
		for j := 0; j < fo.d; j++ {
			writeByte(w, '\t')
		}
		writeByte(w, '}')
	case reflect.Struct:
		t := v.Type()
		if reflect.DeepEqual(reflect.Zero(t).Interface(), fo.x) {
			if !fo.omit {
				io.WriteString(w, t.String())
			}
			w.Write(curlyBytes)
			return
		}

		s := fmt.Sprintf("%#v", fo.x)
		if fo.omit {
			s = s[len(t.String()):]
		}
		if len(s) < limit {
			io.WriteString(w, s)
			return
		}

		if !fo.omit {
			io.WriteString(w, t.String())
		}
		w.Write(openCurlyLFBytes)
		var max int
		for i := 0; i < v.NumField(); i++ {
			if v := t.Field(i); v.Name != "" {
				if len(v.Name)+2 > max {
					max = len(v.Name) + 2
				}
			}
		}
		for i := 0; i < v.NumField(); i++ {
			if f := t.Field(i); f.Name != "" {
				for j := 0; j < fo.d+1; j++ {
					writeByte(w, '\t')
				}
				io.WriteString(w, f.Name)
				writeByte(w, ':')
				for j := len(f.Name) + 1; j < max; j++ {
					writeByte(w, ' ')
				}
				inner := formatter{d: fo.d + 1, x: v.Field(i).Interface()}
				io.WriteString(w, fmt.Sprintf("%# v", inner))
				w.Write(commaLFBytes)
			}
		}
		for j := 0; j < fo.d; j++ {
			writeByte(w, '\t')
		}
		writeByte(w, '}')
	default:
		fmt.Fprintf(w, "%#v", fo.x)
	}
}

func writeByte(w io.Writer, b byte) {
	w.Write([]byte{b})
}
<commit_msg>Prevent formatter from panic'ing with unexported fields<commit_after>package pretty

import (
	"fmt"
	"io"
	"reflect"
)

const (
	limit = 50
)

var (
	commaLFBytes     = []byte(",\n")
	curlyBytes       = []byte("{}")
	openCurlyLFBytes = []byte("{\n")
	spacePlusLFBytes = []byte(" +\n")
)

type formatter struct {
	d int
	x interface{}

	omit bool
}

// Formatter makes a wrapper, f, that will format x as go source with line
// breaks and tabs. Object f responds to the "%v" formatting verb when both the
// "#" and " " (space) flags are set, for example:
//
//     fmt.Sprintf("%# v", Formatter(x))
//
// If one of these two flags is not set, or any other verb is used, f will
// format x according to the usual rules of package fmt.
// In particular, if x satisfies fmt.Formatter, then x.Format will be called.
func Formatter(x interface{}) (f fmt.Formatter) {
	return formatter{x: x}
}

func (fo formatter) String() string {
	return fmt.Sprint(fo.x) // unwrap it
}

func (fo formatter) passThrough(f fmt.State, c rune) {
	s := "%"
	for i := 0; i < 128; i++ {
		if f.Flag(i) {
			s += string(i)
		}
	}
	if w, ok := f.Width(); ok {
		s += fmt.Sprintf("%d", w)
	}
	if p, ok := f.Precision(); ok {
		s += fmt.Sprintf(".%d", p)
	}
	s += string(c)
	fmt.Fprintf(f, s, fo.x)
}

func (fo formatter) Format(f fmt.State, c rune) {
	if c == 'v' && f.Flag('#') && f.Flag(' ') {
		fo.format(f)
		return
	}
	fo.passThrough(f, c)
}

func (fo formatter) format(w io.Writer) {
	v := reflect.ValueOf(fo.x)
	switch v.Kind() {
	case reflect.String:
		lim := limit - 8*fo.d
		s := v.String()
		z := len(s)
		n := (z + lim - 1) / lim
		if n < 1 {
			n = 1 // empty string still produces output
		}
		sep := append(spacePlusLFBytes, make([]byte, fo.d)...)
		for j := 0; j < fo.d; j++ {
			sep[3+j] = '\t'
		}
		for i := 0; i < n; i++ {
			if i > 0 {
				w.Write(sep)
			}
			l, h := i*lim, (i+1)*lim
			if h > z {
				h = z
			}
			fmt.Fprintf(w, "%#v", s[l:h])
		}
		return
	case reflect.Ptr:
		e := v.Elem()
		if !e.IsValid() {
			fmt.Fprintf(w, "%#v", fo.x)
		} else {
			writeByte(w, '&')
			if e.CanInterface() {
				fmt.Fprintf(w, "%# v", formatter{d: fo.d, x: e.Interface()})
			} else {
				fmt.Fprint(w, e.String())
			}
		}
	case reflect.Slice:
		s := fmt.Sprintf("%#v", fo.x)
		if len(s) < limit {
			io.WriteString(w, s)
			return
		}

		t := v.Type()

		io.WriteString(w, reflect.TypeOf(fo.x).String())
		w.Write(openCurlyLFBytes)
		for i := 0; i < v.Len(); i++ {
			for j := 0; j < fo.d+1; j++ {
				writeByte(w, '\t')
			}
			if v.Index(i).CanInterface() {
				inner := formatter{d: fo.d + 1, x: v.Index(i).Interface(), omit: t.Elem().Kind() != reflect.Interface}
				fmt.Fprintf(w, "%# v", inner)
			} else {
				fmt.Fprint(w, v.Index(i).String())
			}
			w.Write(commaLFBytes)
		}
		for j := 0; j < fo.d; j++ {
			writeByte(w, '\t')
		}
		writeByte(w, '}')
	case reflect.Struct:
		t := v.Type()
		if reflect.DeepEqual(reflect.Zero(t).Interface(), fo.x) {
			if !fo.omit {
				io.WriteString(w, t.String())
			}
			w.Write(curlyBytes)
			return
		}

		s := fmt.Sprintf("%#v", fo.x)
		if fo.omit {
			s = s[len(t.String()):]
		}
		if len(s) < limit {
			io.WriteString(w, s)
			return
		}

		if !fo.omit {
			io.WriteString(w, t.String())
		}
		w.Write(openCurlyLFBytes)
		var max int
		for i := 0; i < v.NumField(); i++ {
			if v := t.Field(i); v.Name != "" {
				if len(v.Name)+2 > max {
					max = len(v.Name) + 2
				}
			}
		}
		for i := 0; i < v.NumField(); i++ {
			if f := t.Field(i); f.Name != "" {
				for j := 0; j < fo.d+1; j++ {
					writeByte(w, '\t')
				}
				io.WriteString(w, f.Name)
				writeByte(w, ':')
				for j := len(f.Name) + 1; j < max; j++ {
					writeByte(w, ' ')
				}
				if v.Field(i).CanInterface() {
					inner := formatter{d: fo.d + 1, x: v.Field(i).Interface()}
					fmt.Fprintf(w, "%# v", inner)
				} else {
					io.WriteString(w, v.Field(i).String())
				}
				w.Write(commaLFBytes)
			}
		}
		for j := 0; j < fo.d; j++ {
			writeByte(w, '\t')
		}
		writeByte(w, '}')
	default:
		fmt.Fprintf(w, "%#v", fo.x)
	}
}

func writeByte(w io.Writer, b byte) {
	w.Write([]byte{b})
}
<|endoftext|>


<commit_before>// stored is a storage server.
//
// Usage:
//
//     stored [--name=<mount>] [--db=<dbName>]
//
//     - <name> is the Veyron mount point name, default /global/vstore/<hostname>/<username>.
//     - <dbName> is the filename in which to store the data.
//
// The Store service has Veyron name, <name>/.store.  Individual values with
// path <path> have name <name>/<path>.
package main

import (
	"flag"
	"log"
	"os"
	"os/user"

	"veyron/services/store/server"

	"veyron2"
	"veyron2/rt"
	"veyron2/security"
)

var (
	mountName string
	dbName    = flag.String("db", "/var/tmp/veyron_store.db", "Metadata database")

	// TODO(jyh): Figure out how to get a real public ID.
	rootPublicID    security.PublicID = security.FakePublicID("root")
	serverPrivateID                   = security.FakePrivateID("store")
)

func init() {
	username := "unknown"
	if u, err := user.Current(); err == nil {
		username = u.Username
	}
	hostname := "unknown"
	if h, err := os.Hostname(); err == nil {
		hostname = h
	}
	dir := "global/vstore/" + hostname + "/" + username
	flag.StringVar(&mountName, "name", dir, "Mount point for media")
}

// Main starts the content service, taking arguments from the command line
// flags.
func main() {
	r := rt.Init()

	// Create a new server instance.
	s, err := r.NewServer(veyron2.LocalID(serverPrivateID))
	if err != nil {
		log.Fatal("r.NewServer() failed: ", err)
	}

	// Create a new StoreService.
	storeService, err := server.New(server.ServerConfig{Admin: rootPublicID, DBName: *dbName})
	if err != nil {
		log.Fatal("server.New() failed: ", err)
	}
	defer storeService.Close()

	// Register the services.
	storeDisp := server.NewStoreDispatcher(storeService)
	objectDisp := server.NewObjectDispatcher(storeService)
	if err := s.Register(".store", storeDisp); err != nil {
		log.Fatal("s.Register(storeDisp) failed: ", err)
	}
	if err := s.Register("", objectDisp); err != nil {
		log.Fatal("s.Register(objectDisp) failed: ", err)
	}

	// Create an endpoint and start listening.
	ep, err := s.Listen("tcp", ":0")
	if err != nil {
		log.Fatal("s.Listen() failed: ", err)
	}

	// Publish the service in the mount table.
	log.Printf("Mounting store on %s, endpoint /%s", mountName, ep)
	if err := s.Publish(mountName); err != nil {
		log.Fatal("s.Publish() failed: ", err)
	}

	// Wait forever.
	done := make(chan struct{})
	<-done
}
<commit_msg>veyron/services/store/stored: Let stored use the default identity.<commit_after>// stored is a storage server.
//
// Usage:
//
//     stored [--name=<mount>] [--db=<dbName>]
//
//     - <name> is the Veyron mount point name, default /global/vstore/<hostname>/<username>.
//     - <dbName> is the filename in which to store the data.
//
// The Store service has Veyron name, <name>/.store.  Individual values with
// path <path> have name <name>/<path>.
package main

import (
	"flag"
	"log"
	"os"
	"os/user"

	"veyron/services/store/server"

	"veyron2/rt"
)

var (
	mountName string
	dbName    = flag.String("db", "/var/tmp/veyron_store.db", "Metadata database")
)

func init() {
	username := "unknown"
	if u, err := user.Current(); err == nil {
		username = u.Username
	}
	hostname := "unknown"
	if h, err := os.Hostname(); err == nil {
		hostname = h
	}
	dir := "global/vstore/" + hostname + "/" + username
	flag.StringVar(&mountName, "name", dir, "Mount point for media")
}

// Main starts the content service, taking arguments from the command line
// flags.
func main() {
	r := rt.Init()

	// Create a new server instance.
	s, err := r.NewServer()
	if err != nil {
		log.Fatal("r.NewServer() failed: ", err)
	}

	// Create a new StoreService.
	storeService, err := server.New(server.ServerConfig{Admin: r.Identity().PublicID(), DBName: *dbName})
	if err != nil {
		log.Fatal("server.New() failed: ", err)
	}
	defer storeService.Close()

	// Register the services.
	storeDisp := server.NewStoreDispatcher(storeService)
	objectDisp := server.NewObjectDispatcher(storeService)
	if err := s.Register(".store", storeDisp); err != nil {
		log.Fatal("s.Register(storeDisp) failed: ", err)
	}
	if err := s.Register("", objectDisp); err != nil {
		log.Fatal("s.Register(objectDisp) failed: ", err)
	}

	// Create an endpoint and start listening.
	ep, err := s.Listen("tcp", ":0")
	if err != nil {
		log.Fatal("s.Listen() failed: ", err)
	}

	// Publish the service in the mount table.
	log.Printf("Mounting store on %s, endpoint /%s", mountName, ep)
	if err := s.Publish(mountName); err != nil {
		log.Fatal("s.Publish() failed: ", err)
	}

	// Wait forever.
	done := make(chan struct{})
	<-done
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/alex023/clock"
	"sync"
	"time"
)

// Session is a large volume session manager that supports TTL
type Session struct {
	sync.Mutex
	cache map[string]tokenjob
	clock *clock.Clock
}
type tokenjob struct {
	token string
	job   clock.Job
}

// NewSession create a Session
func NewSession() *Session {
	return &Session{
		cache: make(map[string]tokenjob),
		clock: clock.NewClock(),
	}
}

// AddToken add token string which can release after seconds
// @interval：	Token of the survival time
// return:
//	@added:		return true if add as new,else return false
//	@error:		if interval==0
func (s *Session) AddToken(token string, timeout time.Duration) (added bool, err error) {
	if timeout == 0 {
		err = errors.New("timeout cannot be zero")
		return
	}
	s.Lock()
	defer s.Unlock()

	item, founded := s.cache[token]
	if founded {
		s.clock.UpdateJobTimeout(item.job, timeout)
		added = false //update token
		fmt.Printf("%v| [updated] token [%v] duration=[%2d] \n", time.Now().Format("15:04:05"), token, int(timeout.Seconds()))

	} else {
		job, _ := s.clock.AddJobWithInterval(timeout, func() { s.RemoveToken(token) })
		item := tokenjob{
			token: token,
			job:   job,
		}
		s.cache[token] = item
		added = true
		//output for example
		fmt.Printf("%v| [ added ] token [%v] duration=[%2d] \n", time.Now().Format("15:04:05"), token, int(timeout.Seconds()))
	}
	return
}

// GetToken determine whether token exists
func (s *Session) GetToken(token string) bool {
	s.Lock()
	defer s.Unlock()
	_, founded := s.cache[token]
	return founded
}

//GetTokenNum return numbers of tokens in Session
func (s *Session) GetTokenNum() int {
	s.Lock()
	defer s.Unlock()

	return len(s.cache)
}

//RemoveToken remove token by name from Session
func (s *Session) RemoveToken(token string) {
	s.Lock()
	defer s.Unlock()
	fmt.Printf("%v| [removed] token [%v] by TTLSession \n", time.Now().Format("15:04:05"), token)
	delete(s.cache, token)
}

func main() {
	session := NewSession()

	token1 := "alex023_1"
	fmt.Println("add token and timeout")
	session.AddToken(token1, time.Second*3)
	for i := 0; i < 5; i++ {
		time.Sleep(time.Second * 1)
		fmt.Printf("%v|[watching] token [%v] founded=%v\n", time.Now().Format("15:04:05"), token1, session.GetToken(token1))
	}
	fmt.Println()

	token2 := "alex023_2"
	fmt.Println("add token and update it before timeout")
	session.AddToken(token2, time.Second*3)
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second * 1)
		if i == 1 {
			session.AddToken(token2, time.Second*5)
		}
		fmt.Printf("%v|[watching] token [%v] founded=%v\n", time.Now().Format("15:04:05"), token2, session.GetToken(token2))
	}
}
<commit_msg>enhance example: RemoveToken method can not release job<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/alex023/clock"
	"sync"
	"time"
)

// Session is a large volume session manager that supports TTL
type Session struct {
	sync.Mutex
	cache map[string]tokenjob
	clock *clock.Clock
}
type tokenjob struct {
	token string
	job   clock.Job
}

// NewSession create a Session
func NewSession() *Session {
	return &Session{
		cache: make(map[string]tokenjob),
		clock: clock.NewClock(),
	}
}

// AddToken add token string which can release after seconds
// @interval：	Token of the survival time
// return:
//	@added:		return true if add as new,else return false
//	@error:		if interval==0
func (s *Session) AddToken(token string, timeout time.Duration) (added bool, err error) {
	if timeout == 0 {
		err = errors.New("timeout cannot be zero")
		return
	}
	s.Lock()
	defer s.Unlock()

	item, founded := s.cache[token]
	if founded {
		s.clock.UpdateJobTimeout(item.job, timeout)
		added = false //update token
		fmt.Printf("%v| [updated] token [%v] duration=[%2d] \n", time.Now().Format("15:04:05"), token, int(timeout.Seconds()))

	} else {
		job, _ := s.clock.AddJobWithInterval(timeout, func() { s.RemoveToken(token) })
		item := tokenjob{
			token: token,
			job:   job,
		}
		s.cache[token] = item
		added = true
		//output for example
		fmt.Printf("%v| [ added ] token [%v] duration=[%2d] \n", time.Now().Format("15:04:05"), token, int(timeout.Seconds()))
	}
	return
}

// GetToken determine whether token exists
func (s *Session) GetToken(token string) bool {
	s.Lock()
	defer s.Unlock()
	_, founded := s.cache[token]
	return founded
}

//GetTokenNum return numbers of tokens in Session
func (s *Session) GetTokenNum() int {
	s.Lock()
	defer s.Unlock()

	return len(s.cache)
}

//RemoveToken remove token by name from Session
func (s *Session) RemoveToken(token string) {
	s.Lock()
	defer s.Unlock()
	fmt.Printf("%v| [removed] token [%v] by TTLSession \n", time.Now().Format("15:04:05"), token)
	if tokenjob,founded:=s.cache[token];founded{
		delete(s.cache, token)
		tokenjob.job.Cancel()
	}
}

func main() {
	session := NewSession()

	token1 := "alex023_1"
	fmt.Println("add token and timeout")
	session.AddToken(token1, time.Second*3)
	for i := 0; i < 5; i++ {
		time.Sleep(time.Second * 1)
		fmt.Printf("%v|[watching] token [%v] founded=%v\n", time.Now().Format("15:04:05"), token1, session.GetToken(token1))
	}
	fmt.Println()

	token2 := "alex023_2"
	fmt.Println("add token and update it before timeout")
	session.AddToken(token2, time.Second*3)
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second * 1)
		if i == 1 {
			session.AddToken(token2, time.Second*5)
		}
		fmt.Printf("%v|[watching] token [%v] founded=%v\n", time.Now().Format("15:04:05"), token2, session.GetToken(token2))
	}
}
<|endoftext|>


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

package functional

import (
	"fmt"
	"io/ioutil"
	"os"
	"syscall"
	"strings"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

// Start three units using ssh tunnel
func TestTunnelScheduleBatchUnits(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	members, err := platform.CreateNClusterMembers(cluster, 1)
	if err != nil {
		t.Fatal(err)
	}
	m0 := members[0]
	_, err = cluster.WaitForNMachines(m0, 1)
	if err != nil {
		t.Fatal(err)
	}

	tmp, err := ioutil.TempFile(os.TempDir(), "known-hosts")
	if err != nil {
		t.Fatal(err)
	}
	tmp.Close()
	defer syscall.Unlink(tmp.Name())

	khFile := tmp.Name()

	// Launch one unit
	if stdout, stderr, err := cluster.FleetctlTunnelWithInput(m0, "yes", "--strict-host-key-checking=true", fmt.Sprintf("--known-hosts-file=%s", khFile), "start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit one unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	} else if strings.Contains(stderr, "Error") {
		t.Fatalf("Failed to correctly submit unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	// Launch a batch of units
	if stdout, stderr, err := cluster.FleetctlTunnel(m0, "--strict-host-key-checking=true", fmt.Sprintf("--known-hosts-file=%s", khFile), "start", "fixtures/units/hello@1.service", "fixtures/units/hello@1.service", "fixtures/units/hello@3.service"); err != nil {
		t.Fatalf("Unable to submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	} else if strings.Contains(stderr, "Error") {
		t.Fatalf("Failed to correctly submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}
}
<commit_msg>tests: updated ssh tests<commit_after>// Copyright 2014 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package functional

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"syscall"
	"testing"

	"github.com/coreos/fleet/functional/platform"
)

// Start three units using ssh tunnel
func TestTunnelScheduleBatchUnits(t *testing.T) {
	cluster, err := platform.NewNspawnCluster("smoke")
	if err != nil {
		t.Fatal(err)
	}
	defer cluster.Destroy()

	members, err := platform.CreateNClusterMembers(cluster, 3)
	if err != nil {
		t.Fatal(err)
	}
	m0 := members[0]
	_, err = cluster.WaitForNMachines(m0, 3)
	if err != nil {
		t.Fatal(err)
	}

	tmp, err := ioutil.TempFile(os.TempDir(), "known-hosts")
	if err != nil {
		t.Fatal(err)
	}
	tmp.Close()
	defer syscall.Unlink(tmp.Name())

	khFile := tmp.Name()

	// Launch one unit
	if stdout, stderr, err := cluster.FleetctlTunnelWithInput(m0, "yes", "--strict-host-key-checking=true", fmt.Sprintf("--known-hosts-file=%s", khFile), "start", "fixtures/units/hello.service"); err != nil {
		t.Fatalf("Unable to submit one unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	} else if strings.Contains(stderr, "Error") {
		t.Fatalf("Failed to correctly submit unit using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	// Launch a batch of units
	if stdout, stderr, err := cluster.FleetctlTunnel(m0, "--strict-host-key-checking=true", fmt.Sprintf("--known-hosts-file=%s", khFile), "start", "fixtures/units/hello@1.service", "fixtures/units/hello@2.service", "fixtures/units/hello@3.service", "fixtures/units/hello@4.service", "fixtures/units/hello@5.service", "fixtures/units/hello@6.service", "fixtures/units/hello@7.service", "fixtures/units/hello@8.service", "fixtures/units/hello@9.service", "fixtures/units/hello@10.service"); err != nil {
		t.Fatalf("Unable to submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	} else if strings.Contains(stderr, "Error") {
		t.Fatalf("Failed to correctly submit batch of units using ssh tunnel: \nstdout: %s\nstderr: %s\nerr: %v", stdout, stderr, err)
	}

	_, err = cluster.WaitForNActiveUnits(m0, 11)
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package sqlx

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
)

type ChunkFunk interface{}

type Chunker struct {
	rows *sql.Rows
}

func NewChunker(r *sql.Rows) *Chunker {
	return &Chunker{r}
}

func (self *Chunker) Chunk(n int, f ChunkFunk) error {
	defer self.rows.Close()

	funcValue := reflect.ValueOf(f)
	funcType := funcValue.Type()

	if funcType.Kind() != reflect.Func {
		return errors.New("sqlx: two parameter not a func")
	}

	if funcType.NumIn() != 1 {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	sliceType := funcType.In(0)

	if sliceType.Kind() != reflect.Slice {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	columns, err := self.rows.Columns()

	if err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	sliceValuePrt := reflect.New(sliceType)
	sliceValue := reflect.Indirect(sliceValuePrt)

	sliceElem := sliceType.Elem()
	structValuePrt := reflect.New(sliceElem)
	structValue := reflect.Indirect(structValuePrt)

	if structValue.Kind() != reflect.Struct {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	structType := structValue.Type()

	count := structType.NumField()
	fieldsMap := make(map[int]string)

	for i := 0; i < count; i++ {
		f := structType.Field(i)
		if f.Anonymous || f.PkgPath != "" {
			continue
		}
		fieldsMap[i] = toSnake(f.Name)
	}

	var found bool = false
	var i int = 1
	for self.rows.Next() {
		structValuePrt := reflect.New(sliceElem)
		structValue := reflect.Indirect(structValuePrt)

		fields := make(map[string]reflect.Value)

		for k, v := range fieldsMap {
			fields[v] = structValue.Field(k)
		}

		values := make([]interface{}, len(columns))

		for i, column := range columns {
			if field, ok := fields[column]; ok {
				values[i] = field.Addr().Interface()
			} else {
				values[i] = &sql.NullString{}
			}
		}

		if err := self.rows.Scan(values...); err != nil {
			return fmt.Errorf("sqlx: %s", err)
		}

		sliceValue.Set(reflect.Append(sliceValue, structValue))

		if i == n {
			funcValue.Call([]reflect.Value{sliceValue})
			sliceValue = reflect.Indirect(reflect.New(sliceType))
			found = true
			i = 1
			continue
		}

		i++
		found = true
	}

	if sliceValue.Len() > 0 {
		funcValue.Call([]reflect.Value{sliceValue})
	}

	if err := self.rows.Err(); err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	if !found {
		return sql.ErrNoRows
	}

	if err := self.rows.Close(); err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	return nil
}
<commit_msg>Update Chanker<commit_after>package sqlx

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
)

type ChunkFunk interface{}

type Chunker struct {
	rows *sql.Rows
}

func NewChunker(r *sql.Rows) *Chunker {
	return &Chunker{r}
}

func (self *Chunker) Chunk(n int, f ChunkFunk) error {
	defer self.rows.Close()

	funcValue := reflect.ValueOf(f)
	funcType := funcValue.Type()

	if funcType.Kind() != reflect.Func {
		return errors.New("sqlx: two parameter not a func")
	}

	if funcType.NumIn() != 1 {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	sliceType := funcType.In(0)

	if sliceType.Kind() != reflect.Slice {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	numOut := funcType.NumOut()

	if numOut > 1 {
		return errors.New("sqlx: return must be bool")
	}

	if numOut == 1 {
		outType := funcType.Out(0)
		if outType.Kind() != reflect.Bool {
			return errors.New("sqlx: return must be bool")
		}
	}

	columns, err := self.rows.Columns()

	if err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	sliceValuePrt := reflect.New(sliceType)
	sliceValue := reflect.Indirect(sliceValuePrt)

	sliceElem := sliceType.Elem()
	structValuePrt := reflect.New(sliceElem)
	structValue := reflect.Indirect(structValuePrt)

	if structValue.Kind() != reflect.Struct {
		return errors.New("sqlx: two parameter must be func([]Struct)")
	}

	structType := structValue.Type()

	count := structType.NumField()
	fieldsMap := make(map[int]string)

	for i := 0; i < count; i++ {
		f := structType.Field(i)
		if f.Anonymous || f.PkgPath != "" {
			continue
		}
		fieldsMap[i] = toSnake(f.Name)
	}

	var found bool = false
	var interrupt bool = false
	var i int = 1
	for self.rows.Next() {
		structValuePrt := reflect.New(sliceElem)
		structValue := reflect.Indirect(structValuePrt)

		fields := make(map[string]reflect.Value)

		for k, v := range fieldsMap {
			fields[v] = structValue.Field(k)
		}

		values := make([]interface{}, len(columns))

		for i, column := range columns {
			if field, ok := fields[column]; ok {
				values[i] = field.Addr().Interface()
			} else {
				values[i] = &sql.NullString{}
			}
		}

		if err := self.rows.Scan(values...); err != nil {
			return fmt.Errorf("sqlx: %s", err)
		}

		sliceValue.Set(reflect.Append(sliceValue, structValue))

		if i == n {
			out := funcValue.Call([]reflect.Value{sliceValue})
			sliceValue = reflect.Indirect(reflect.New(sliceType))
			found = true
			i = 1
			if len(out) > 0 && !out[0].Bool() {
				interrupt = true
				break
			}
			continue
		}

		i++
		found = true
	}

	if !interrupt && sliceValue.Len() > 0 {
		funcValue.Call([]reflect.Value{sliceValue})
	}

	if err := self.rows.Err(); err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	if !found {
		return sql.ErrNoRows
	}

	if err := self.rows.Close(); err != nil {
		return fmt.Errorf("sqlx: %s", err)
	}

	return nil
}
<|endoftext|>