<commit_before>package ltsv_test

import (
	"errors"
	"fmt"
	"math"
	"testing"
	"time"

	ltsv "github.com/hnakamur/zap-ltsv"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func TestEncodeEntry(t *testing.T) {
	type subtestCase struct {
		ent    zapcore.Entry
		fields []zapcore.Field
		want   string
	}

	testCases := []struct {
		subtestName string
		cfg         zapcore.EncoderConfig
		cases       []subtestCase
	}{
		{
			subtestName: "no time, level and msg config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				cfg.LevelKey = ""
				cfg.MessageKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Stack("stack"),
					},
					// NOTE: Update this value when you edit the source code.
					want: "stack:go.uber.org/zap.Stack\\n\\t/home/hnakamur/go/src/go.uber.org/zap/field.go:209\\ngithub.com/hnakamur/zap-ltsv_test.TestEncodeEntry\\n\\t/home/hnakamur/go/src/github.com/hnakamur/zap-ltsv/encoder_test.go:40\\ntesting.tRunner\\n\\t/usr/local/go/src/testing/testing.go:657\n",
				},
				{
					ent:  zapcore.Entry{},
					want: "\n",
				},
				{
					ent: zapcore.Entry{
						Message: "hello, ltsv logger",
					},
					want: "\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.String("user", "alice"),
					},
					want: "user:alice\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.String("user", "alice"),
						zap.String("group", "adm"),
					},
					want: "user:alice\tgroup:adm\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Skip(),
					},
					want: "\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Stringer("stringer", new(someStringer)),
					},
					want: "stringer:some\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Strings("users", []string{"alice", "bob"}),
					},
					want: "users:[\"alice\",\"bob\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Time("created_at", time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC)),
					},
					want: fmt.Sprintf("created_at:%s\n", time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC).Local().Format("2006-01-02T15:04:05.000-0700")),
					// NOTE: I would like to time in the specified localation, that is UTC in this case.
					//want: "created_at:2017-05-03T21:09:11.980Z\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Times("period", []time.Time{
							time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC),
							time.Date(2017, 5, 3, 21, 23, 59, 999999999, time.UTC),
						}),
					},
					want: "period:[\"2017-05-03T21:09:11.980Z\",\"2017-05-03T21:23:59.999Z\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint("a", 0),
						zap.Uint("b", 9876),
					},
					want: "a:0\tb:9876\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint16("a", 0),
						zap.Uint16("b", 9876),
					},
					want: "a:0\tb:9876\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint16s("a", []uint16{0, 9876}),
					},
					want: "a:[0,9876]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Any("a", []interface{}{2, "foo"}),
					},
					want: "a:[2,\"foo\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Complex128("a", 1+2i),
					},
					want: "a:\"1+2i\"\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Duration("a", time.Duration(time.Minute+2*time.Second)),
					},
					want: "a:1m2s\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Error(errors.New("error 1")),
					},
					want: "error:error 1\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Errors("errors", []error{errors.New("error 1"), errors.New("error 2")}),
					},
					want: "errors:[{\"error\":\"error 1\"},{\"error\":\"error 2\"}]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Namespace("ns"),
						zap.Int("a", 2),
					},
					want: "a:1\tns:{\"a\":2}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Namespace("ns1"),
						zap.Int("a", 2),
						zap.Namespace("ns2"),
						zap.Int("a", 3),
					},
					want: "a:1\tns1:{\"a\":2,\"ns2\":{\"a\":3}}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Int("b", -1),
						zap.Namespace("ns1"),
						zap.Int("a", 2),
						zap.Int("b", -2),
						zap.Namespace("ns2"),
						zap.Int("a", 3),
						zap.Int("b", -3),
					},
					want: "a:1\tb:-1\tns1:{\"a\":2,\"b\":-2,\"ns2\":{\"a\":3,\"b\":-3}}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.ByteString("a", []byte("hello")),
					},
					want: "a:hello\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.ByteStrings("a", [][]byte{[]byte("hello"), []byte("goodbye")}),
					},
					want: "a:[\"hello\",\"goodbye\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Binary("a", []byte{'\xca', '\xfe'}),
					},
					want: "a:yv4=\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Bool("a", true),
						zap.Bool("b", false),
					},
					want: "a:true\tb:false\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Bools("a", []bool{true, false}),
					},
					want: "a:[true,false]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Float64("a", 2.39),
						zap.Float64("max", math.MaxFloat64),
						zap.Float64("smallestNonZero", math.SmallestNonzeroFloat64),
					},
					want: "a:2.39\tmax:179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\tsmallestNonZero:0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uintptr("a", uintptr(2)),
					},
					want: "a:2\n",
				},
			},
		},
		{
			subtestName: "no time and level config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				cfg.LevelKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent:  zapcore.Entry{},
					want: "msg:\n",
				},
				{
					ent: zapcore.Entry{
						Message: "hello, ltsv logger",
					},
					want: "msg:hello, ltsv logger\n",
				},
			},
		},
		{
			subtestName: "no time config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent: zapcore.Entry{
						Level: zapcore.DebugLevel,
					},
					want: "level:debug\tmsg:\n",
				},
				{
					ent: zapcore.Entry{
						Level:   zapcore.InfoLevel,
						Message: "hello, ltsv logger",
					},
					want: "level:info\tmsg:hello, ltsv logger\n",
				},
			},
		},
		{
			subtestName: "developer config",
			cfg:         ltsv.NewDevelopmentEncoderConfig(),
			cases: []subtestCase{
				{
					ent: zapcore.Entry{
						Level: zapcore.DebugLevel,
						Time:  time.Date(2017, 5, 3, 21, 9, 11, 983000000, time.UTC),
					},
					want: "time:2017-05-03T21:09:11.983Z\tlevel:debug\tmsg:\n",
				},
				{
					ent: zapcore.Entry{
						Level:   zapcore.InfoLevel,
						Time:    time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC),
						Message: "hello, ltsv logger",
					},
					want: "time:2017-05-03T21:09:11.980Z\tlevel:info\tmsg:hello, ltsv logger\n",
				},
			},
		},
	}
	for _, tc := range testCases {
		enc := ltsv.NewLTSVEncoder(tc.cfg)
		t.Run(tc.subtestName, func(t *testing.T) {
			for _, st := range tc.cases {
				buf, err := enc.EncodeEntry(st.ent, st.fields)
				if err != nil {
					t.Fatalf("failed to encode entry; ent=%+v, fields=%+v, err=%+v", st.ent, st.fields, err)
				}
				got := buf.String()
				if got != st.want {
					t.Errorf("got=%q, want=%q, ent=%+v, fields=%+v", got, st.want, st.ent, st.fields)
				}
			}
		})
	}
}

type someStringer struct{}

func (s *someStringer) String() string {
	return "some"
}
<commit_msg>Delete test for Stack since it fails on Travis CI<commit_after>package ltsv_test

import (
	"errors"
	"fmt"
	"math"
	"testing"
	"time"

	ltsv "github.com/hnakamur/zap-ltsv"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

func TestEncodeEntry(t *testing.T) {
	type subtestCase struct {
		ent    zapcore.Entry
		fields []zapcore.Field
		want   string
	}

	testCases := []struct {
		subtestName string
		cfg         zapcore.EncoderConfig
		cases       []subtestCase
	}{
		{
			subtestName: "no time, level and msg config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				cfg.LevelKey = ""
				cfg.MessageKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent:  zapcore.Entry{},
					want: "\n",
				},
				{
					ent: zapcore.Entry{
						Message: "hello, ltsv logger",
					},
					want: "\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.String("user", "alice"),
					},
					want: "user:alice\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.String("user", "alice"),
						zap.String("group", "adm"),
					},
					want: "user:alice\tgroup:adm\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Skip(),
					},
					want: "\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Stringer("stringer", new(someStringer)),
					},
					want: "stringer:some\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Strings("users", []string{"alice", "bob"}),
					},
					want: "users:[\"alice\",\"bob\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Time("created_at", time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC)),
					},
					want: fmt.Sprintf("created_at:%s\n", time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC).Local().Format("2006-01-02T15:04:05.000-0700")),
					// NOTE: I would like to time in the specified localation, that is UTC in this case.
					//want: "created_at:2017-05-03T21:09:11.980Z\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Times("period", []time.Time{
							time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC),
							time.Date(2017, 5, 3, 21, 23, 59, 999999999, time.UTC),
						}),
					},
					want: "period:[\"2017-05-03T21:09:11.980Z\",\"2017-05-03T21:23:59.999Z\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint("a", 0),
						zap.Uint("b", 9876),
					},
					want: "a:0\tb:9876\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint16("a", 0),
						zap.Uint16("b", 9876),
					},
					want: "a:0\tb:9876\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uint16s("a", []uint16{0, 9876}),
					},
					want: "a:[0,9876]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Any("a", []interface{}{2, "foo"}),
					},
					want: "a:[2,\"foo\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Complex128("a", 1+2i),
					},
					want: "a:\"1+2i\"\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Duration("a", time.Duration(time.Minute+2*time.Second)),
					},
					want: "a:1m2s\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Error(errors.New("error 1")),
					},
					want: "error:error 1\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Errors("errors", []error{errors.New("error 1"), errors.New("error 2")}),
					},
					want: "errors:[{\"error\":\"error 1\"},{\"error\":\"error 2\"}]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Namespace("ns"),
						zap.Int("a", 2),
					},
					want: "a:1\tns:{\"a\":2}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Namespace("ns1"),
						zap.Int("a", 2),
						zap.Namespace("ns2"),
						zap.Int("a", 3),
					},
					want: "a:1\tns1:{\"a\":2,\"ns2\":{\"a\":3}}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Int("a", 1),
						zap.Int("b", -1),
						zap.Namespace("ns1"),
						zap.Int("a", 2),
						zap.Int("b", -2),
						zap.Namespace("ns2"),
						zap.Int("a", 3),
						zap.Int("b", -3),
					},
					want: "a:1\tb:-1\tns1:{\"a\":2,\"b\":-2,\"ns2\":{\"a\":3,\"b\":-3}}\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.ByteString("a", []byte("hello")),
					},
					want: "a:hello\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.ByteStrings("a", [][]byte{[]byte("hello"), []byte("goodbye")}),
					},
					want: "a:[\"hello\",\"goodbye\"]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Binary("a", []byte{'\xca', '\xfe'}),
					},
					want: "a:yv4=\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Bool("a", true),
						zap.Bool("b", false),
					},
					want: "a:true\tb:false\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Bools("a", []bool{true, false}),
					},
					want: "a:[true,false]\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Float64("a", 2.39),
						zap.Float64("max", math.MaxFloat64),
						zap.Float64("smallestNonZero", math.SmallestNonzeroFloat64),
					},
					want: "a:2.39\tmax:179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\tsmallestNonZero:0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005\n",
				},
				{
					ent: zapcore.Entry{},
					fields: []zapcore.Field{
						zap.Uintptr("a", uintptr(2)),
					},
					want: "a:2\n",
				},
			},
		},
		{
			subtestName: "no time and level config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				cfg.LevelKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent:  zapcore.Entry{},
					want: "msg:\n",
				},
				{
					ent: zapcore.Entry{
						Message: "hello, ltsv logger",
					},
					want: "msg:hello, ltsv logger\n",
				},
			},
		},
		{
			subtestName: "no time config",
			cfg: func() zapcore.EncoderConfig {
				cfg := ltsv.NewDevelopmentEncoderConfig()
				cfg.TimeKey = ""
				return cfg
			}(),
			cases: []subtestCase{
				{
					ent: zapcore.Entry{
						Level: zapcore.DebugLevel,
					},
					want: "level:debug\tmsg:\n",
				},
				{
					ent: zapcore.Entry{
						Level:   zapcore.InfoLevel,
						Message: "hello, ltsv logger",
					},
					want: "level:info\tmsg:hello, ltsv logger\n",
				},
			},
		},
		{
			subtestName: "developer config",
			cfg:         ltsv.NewDevelopmentEncoderConfig(),
			cases: []subtestCase{
				{
					ent: zapcore.Entry{
						Level: zapcore.DebugLevel,
						Time:  time.Date(2017, 5, 3, 21, 9, 11, 983000000, time.UTC),
					},
					want: "time:2017-05-03T21:09:11.983Z\tlevel:debug\tmsg:\n",
				},
				{
					ent: zapcore.Entry{
						Level:   zapcore.InfoLevel,
						Time:    time.Date(2017, 5, 3, 21, 9, 11, 980000000, time.UTC),
						Message: "hello, ltsv logger",
					},
					want: "time:2017-05-03T21:09:11.980Z\tlevel:info\tmsg:hello, ltsv logger\n",
				},
			},
		},
	}
	for _, tc := range testCases {
		enc := ltsv.NewLTSVEncoder(tc.cfg)
		t.Run(tc.subtestName, func(t *testing.T) {
			for _, st := range tc.cases {
				buf, err := enc.EncodeEntry(st.ent, st.fields)
				if err != nil {
					t.Fatalf("failed to encode entry; ent=%+v, fields=%+v, err=%+v", st.ent, st.fields, err)
				}
				got := buf.String()
				if got != st.want {
					t.Errorf("got=%q, want=%q, ent=%+v, fields=%+v", got, st.want, st.ent, st.fields)
				}
			}
		})
	}
}

type someStringer struct{}

func (s *someStringer) String() string {
	return "some"
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The logr Authors.

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 stdr implements github.com/go-logr/logr.Logger in terms of
// Go's standard log package.
package stdr

import (
	"log"
	"os"

	"github.com/go-logr/logr"
	"github.com/go-logr/logr/funcr"
)

// The global verbosity level.  See SetVerbosity().
var globalVerbosity int

// SetVerbosity sets the global level against which all info logs will be
// compared.  If this is greater than or equal to the "V" of the logger, the
// message will be logged.  A higher value here means more logs will be written.
// The previous verbosity value is returned.  This is not concurrent-safe -
// callers must be sure to call it from only one goroutine.
func SetVerbosity(v int) int {
	old := globalVerbosity
	globalVerbosity = v
	return old
}

// New returns a logr.Logger which is implemented by Go's standard log package,
// or something like it.  If std is nil, this will use a default logger
// instead.
//
// Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
func New(std StdLogger) logr.Logger {
	return NewWithOptions(std, Options{})
}

// NewWithOptions returns a logr.Logger which is implemented by Go's standard
// log package, or something like it.  See New for details.
func NewWithOptions(std StdLogger, opts Options) logr.Logger {
	if std == nil {
		// Go's log.Default() is only available in 1.16 and higher.
		std = log.New(os.Stderr, "", log.LstdFlags)
	}

	if opts.Depth < 0 {
		opts.Depth = 0
	}

	fopts := funcr.Options{
		LogCaller: funcr.MessageClass(opts.LogCaller),
	}

	sl := &logger{
		Formatter: funcr.NewFormatter(fopts),
		std:       std,
	}

	// For skipping our own logger.Info/Error.
	sl.Formatter.AddCallDepth(1 + opts.Depth)

	return logr.New(sl)
}

// Options carries parameters which influence the way logs are generated.
type Options struct {
	// Depth biases the assumed number of call frames to the "true" caller.
	// This is useful when the calling code calls a function which then calls
	// stdr (e.g. a logging shim to another API).  Values less than zero will
	// be treated as zero.
	Depth int

	// LogCaller tells stdr to add a "caller" key to some or all log lines.
	// Go's log package has options to log this natively, too.
	LogCaller MessageClass

	// TODO: add an option to log the date/time
}

// MessageClass indicates which category or categories of messages to consider.
type MessageClass int

const (
	// None ignores all message classes.
	None MessageClass = iota
	// All considers all message classes.
	All
	// Info only considers info messages.
	Info
	// Error only considers error messages.
	Error
)

// StdLogger is the subset of the Go stdlib log.Logger API that is needed for
// this adapter.
type StdLogger interface {
	// Output is the same as log.Output and log.Logger.Output.
	Output(calldepth int, logline string) error
}

type logger struct {
	funcr.Formatter
	std StdLogger
}

var _ logr.LogSink = &logger{}
var _ logr.CallDepthLogSink = &logger{}

func (l logger) Enabled(level int) bool {
	return globalVerbosity >= level
}

func (l logger) Info(level int, msg string, kvList ...interface{}) {
	prefix, args := l.FormatInfo(level, msg, kvList)
	if prefix != "" {
		args = prefix + ": " + args
	}
	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}

func (l logger) Error(err error, msg string, kvList ...interface{}) {
	prefix, args := l.FormatError(err, msg, kvList)
	if prefix != "" {
		args = prefix + ": " + args
	}
	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}

func (l logger) WithName(name string) logr.LogSink {
	l.Formatter.AddName(name)
	return &l
}

func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
	l.Formatter.AddValues(kvList)
	return &l
}

func (l logger) WithCallDepth(depth int) logr.LogSink {
	l.Formatter.AddCallDepth(depth)
	return &l
}

// Underlier exposes access to the underlying logging implementation.  Since
// callers only have a logr.Logger, they have to know which implementation is
// in use, so this interface is less of an abstraction and more of way to test
// type conversion.
type Underlier interface {
	GetUnderlying() StdLogger
}

// GetUnderlying returns the StdLogger underneath this logger.  Since StdLogger
// is itself an interface, the result may or may not be a Go log.Logger.
func (l logger) GetUnderlying() StdLogger {
	return l.std
}
<commit_msg>Adds option to use non-global verbosity per logger.<commit_after>/*
Copyright 2019 The logr Authors.

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 stdr implements github.com/go-logr/logr.Logger in terms of
// Go's standard log package.
package stdr

import (
	"log"
	"os"

	"github.com/go-logr/logr"
	"github.com/go-logr/logr/funcr"
)

// The global verbosity level.  See SetVerbosity().
var globalVerbosity int

// SetVerbosity sets the global level against which all info logs will be
// compared.  If this is greater than or equal to the "V" of the logger, the
// message will be logged.  A higher value here means more logs will be written.
// The previous verbosity value is returned.  This is not concurrent-safe -
// callers must be sure to call it from only one goroutine.
func SetVerbosity(v int) int {
	old := globalVerbosity
	globalVerbosity = v
	return old
}

// New returns a logr.Logger which is implemented by Go's standard log package,
// or something like it.  If std is nil, this will use a default logger
// instead.
//
// Example: stdr.New(log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile)))
func New(std StdLogger) logr.Logger {
	return NewWithOptions(std, Options{})
}

// NewWithOptions returns a logr.Logger which is implemented by Go's standard
// log package, or something like it.  See New for details.
func NewWithOptions(std StdLogger, opts Options) logr.Logger {
	if std == nil {
		// Go's log.Default() is only available in 1.16 and higher.
		std = log.New(os.Stderr, "", log.LstdFlags)
	}

	if opts.Depth < 0 {
		opts.Depth = 0
	}

	fopts := funcr.Options{
		LogCaller: funcr.MessageClass(opts.LogCaller),
	}

	sl := &logger{
		Formatter: funcr.NewFormatter(fopts),
		std:       std,
		verbosity: opts.Verbosity,
	}

	// For skipping our own logger.Info/Error.
	sl.Formatter.AddCallDepth(1 + opts.Depth)

	return logr.New(sl)
}

// Options carries parameters which influence the way logs are generated.
type Options struct {
	// Depth biases the assumed number of call frames to the "true" caller.
	// This is useful when the calling code calls a function which then calls
	// stdr (e.g. a logging shim to another API).  Values less than zero will
	// be treated as zero.
	Depth int

	// LogCaller tells stdr to add a "caller" key to some or all log lines.
	// Go's log package has options to log this natively, too.
	LogCaller MessageClass

	// Verbosity tells the logger which V logs to write. Higher values enable more logs.
	// If nil, the global value set by SetVerbosity will be used. A pointer is used to provide
	// nil as the default value.
	Verbosity *int

	// TODO: add an option to log the date/time
}

// MessageClass indicates which category or categories of messages to consider.
type MessageClass int

const (
	// None ignores all message classes.
	None MessageClass = iota
	// All considers all message classes.
	All
	// Info only considers info messages.
	Info
	// Error only considers error messages.
	Error
)

// StdLogger is the subset of the Go stdlib log.Logger API that is needed for
// this adapter.
type StdLogger interface {
	// Output is the same as log.Output and log.Logger.Output.
	Output(calldepth int, logline string) error
}

type logger struct {
	funcr.Formatter
	std       StdLogger
	verbosity *int
}

var _ logr.LogSink = &logger{}
var _ logr.CallDepthLogSink = &logger{}

func (l logger) Enabled(level int) bool {
	if l.verbosity != nil {
		return *l.verbosity >= level
	}
	return globalVerbosity >= level
}

func (l logger) Info(level int, msg string, kvList ...interface{}) {
	prefix, args := l.FormatInfo(level, msg, kvList)
	if prefix != "" {
		args = prefix + ": " + args
	}
	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}

func (l logger) Error(err error, msg string, kvList ...interface{}) {
	prefix, args := l.FormatError(err, msg, kvList)
	if prefix != "" {
		args = prefix + ": " + args
	}
	_ = l.std.Output(l.Formatter.GetDepth()+1, args)
}

func (l logger) WithName(name string) logr.LogSink {
	l.Formatter.AddName(name)
	return &l
}

func (l logger) WithValues(kvList ...interface{}) logr.LogSink {
	l.Formatter.AddValues(kvList)
	return &l
}

func (l logger) WithCallDepth(depth int) logr.LogSink {
	l.Formatter.AddCallDepth(depth)
	return &l
}

// Underlier exposes access to the underlying logging implementation.  Since
// callers only have a logr.Logger, they have to know which implementation is
// in use, so this interface is less of an abstraction and more of way to test
// type conversion.
type Underlier interface {
	GetUnderlying() StdLogger
}

// GetUnderlying returns the StdLogger underneath this logger.  Since StdLogger
// is itself an interface, the result may or may not be a Go log.Logger.
func (l logger) GetUnderlying() StdLogger {
	return l.std
}
<|endoftext|>


<commit_before>package rados

// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"

import (
	"unsafe"
)

// MonCommand sends a command to one of the monitors
func (c *Conn) MonCommand(args []byte) ([]byte, string, error) {
	return c.monCommand(args, nil)
}

// MonCommandWithInputBuffer sends a command to one of the monitors, with an input buffer
func (c *Conn) MonCommandWithInputBuffer(args, inputBuffer []byte) ([]byte, string, error) {
	return c.monCommand(args, inputBuffer)
}

func (c *Conn) monCommand(args, inputBuffer []byte) ([]byte, string, error) {
	argv := C.CString(string(args))
	defer C.free(unsafe.Pointer(argv))

	var (
		info               string
		buffer             []byte
		outs, outbuf       *C.char
		outslen, outbuflen C.size_t
	)
	inbuf := C.CString(string(inputBuffer))
	inbufLen := len(inputBuffer)
	defer C.free(unsafe.Pointer(inbuf))

	ret := C.rados_mon_command(c.cluster,
		&argv, 1,
		inbuf,              // bulk input (e.g. crush map)
		C.size_t(inbufLen), // length inbuf
		&outbuf,            // buffer
		&outbuflen,         // buffer length
		&outs,              // status string
		&outslen)

	if outslen > 0 {
		info = C.GoStringN(outs, C.int(outslen))
		C.free(unsafe.Pointer(outs))
	}
	if outbuflen > 0 {
		buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
		C.free(unsafe.Pointer(outbuf))
	}
	if ret != 0 {
		err := getError(ret)
		return nil, info, err
	}

	return buffer, info, nil
}

// PGCommand sends a command to one of the PGs
//
// Implements:
//  int rados_pg_command(rados_t cluster, const char *pgstr,
//                       const char **cmd, size_t cmdlen,
//                       const char *inbuf, size_t inbuflen,
//                       char **outbuf, size_t *outbuflen,
//                       char **outs, size_t *outslen);
func (c *Conn) PGCommand(pgid []byte, args [][]byte) ([]byte, string, error) {
	return c.pgCommand(pgid, args, nil)
}

// PGCommandWithInputBuffer sends a command to one of the PGs, with an input buffer
//
// Implements:
//  int rados_pg_command(rados_t cluster, const char *pgstr,
//                       const char **cmd, size_t cmdlen,
//                       const char *inbuf, size_t inbuflen,
//                       char **outbuf, size_t *outbuflen,
//                       char **outs, size_t *outslen);
func (c *Conn) PGCommandWithInputBuffer(pgid []byte, args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	return c.pgCommand(pgid, args, inputBuffer)
}

func (c *Conn) pgCommand(pgid []byte, args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	name := C.CString(string(pgid))
	defer C.free(unsafe.Pointer(name))

	argc := len(args)
	argv := make([]*C.char, argc)

	for i, arg := range args {
		argv[i] = C.CString(string(arg))
		defer C.free(unsafe.Pointer(argv[i]))
	}

	var (
		info               string
		buffer             []byte
		outs, outbuf       *C.char
		outslen, outbuflen C.size_t
	)
	inbuf := C.CString(string(inputBuffer))
	inbufLen := len(inputBuffer)
	defer C.free(unsafe.Pointer(inbuf))

	ret := C.rados_pg_command(c.cluster,
		name,
		&argv[0],
		C.size_t(argc),
		inbuf,              // bulk input
		C.size_t(inbufLen), // length inbuf
		&outbuf,            // buffer
		&outbuflen,         // buffer length
		&outs,              // status string
		&outslen)

	if outslen > 0 {
		info = C.GoStringN(outs, C.int(outslen))
		C.free(unsafe.Pointer(outs))
	}
	if outbuflen > 0 {
		buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
		C.free(unsafe.Pointer(outbuf))
	}
	if ret != 0 {
		err := getError(ret)
		return nil, info, err
	}

	return buffer, info, nil
}

// MgrCommand sends a command to a ceph-mgr.
func (c *Conn) MgrCommand(args [][]byte) ([]byte, string, error) {
	return c.mgrCommand(args, nil)
}

// MgrCommandWithInputBuffer sends a command, with an input buffer, to a ceph-mgr.
func (c *Conn) MgrCommandWithInputBuffer(args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	return c.mgrCommand(args, inputBuffer)
}

// Implements:
//  int rados_mgr_command(rados_t cluster, const char **cmd,
//                         size_t cmdlen, const char *inbuf,
//                         size_t inbuflen, char **outbuf,
//                         size_t *outbuflen, char **outs,
//                          size_t *outslen);
func (c *Conn) mgrCommand(args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	argc := len(args)
	argv := make([]*C.char, argc)

	for i, arg := range args {
		argv[i] = C.CString(string(arg))
		defer C.free(unsafe.Pointer(argv[i]))
	}

	var (
		info               string
		buffer             []byte
		outs, outbuf       *C.char
		outslen, outbuflen C.size_t
	)
	inbuf := C.CString(string(inputBuffer))
	inbufLen := len(inputBuffer)
	defer C.free(unsafe.Pointer(inbuf))

	ret := C.rados_mgr_command(
		c.cluster,
		&argv[0],
		C.size_t(argc),
		inbuf,
		C.size_t(inbufLen),
		&outbuf,
		&outbuflen,
		&outs,
		&outslen)

	if outslen > 0 {
		info = C.GoStringN(outs, C.int(outslen))
		C.free(unsafe.Pointer(outs))
	}
	if outbuflen > 0 {
		buffer = C.GoBytes(unsafe.Pointer(outbuf), C.int(outbuflen))
		C.free(unsafe.Pointer(outbuf))
	}
	if ret != 0 {
		err := getError(ret)
		return nil, info, err
	}

	return buffer, info, nil
}
<commit_msg>rados: replace copy-n-paste *_command functions argument handling<commit_after>package rados

// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"

import (
	"unsafe"

	"github.com/ceph/go-ceph/internal/cutil"
)

// MonCommand sends a command to one of the monitors
func (c *Conn) MonCommand(args []byte) ([]byte, string, error) {
	return c.monCommand(args, nil)
}

// MonCommandWithInputBuffer sends a command to one of the monitors, with an input buffer
func (c *Conn) MonCommandWithInputBuffer(args, inputBuffer []byte) ([]byte, string, error) {
	return c.monCommand(args, inputBuffer)
}

func (c *Conn) monCommand(args, inputBuffer []byte) ([]byte, string, error) {
	ci := cutil.NewCommandInput([][]byte{args}, inputBuffer)
	defer ci.Free()
	co := cutil.NewCommandOutput()
	defer co.Free()

	ret := C.rados_mon_command(
		c.cluster,
		(**C.char)(ci.Cmd()),
		C.size_t(ci.CmdLen()),
		(*C.char)(ci.InBuf()),
		C.size_t(ci.InBufLen()),
		(**C.char)(co.OutBuf()),
		(*C.size_t)(co.OutBufLen()),
		(**C.char)(co.Outs()),
		(*C.size_t)(co.OutsLen()))
	buf, status := co.GoValues()
	return buf, status, getError(ret)
}

// PGCommand sends a command to one of the PGs
//
// Implements:
//  int rados_pg_command(rados_t cluster, const char *pgstr,
//                       const char **cmd, size_t cmdlen,
//                       const char *inbuf, size_t inbuflen,
//                       char **outbuf, size_t *outbuflen,
//                       char **outs, size_t *outslen);
func (c *Conn) PGCommand(pgid []byte, args [][]byte) ([]byte, string, error) {
	return c.pgCommand(pgid, args, nil)
}

// PGCommandWithInputBuffer sends a command to one of the PGs, with an input buffer
//
// Implements:
//  int rados_pg_command(rados_t cluster, const char *pgstr,
//                       const char **cmd, size_t cmdlen,
//                       const char *inbuf, size_t inbuflen,
//                       char **outbuf, size_t *outbuflen,
//                       char **outs, size_t *outslen);
func (c *Conn) PGCommandWithInputBuffer(pgid []byte, args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	return c.pgCommand(pgid, args, inputBuffer)
}

func (c *Conn) pgCommand(pgid []byte, args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	name := C.CString(string(pgid))
	defer C.free(unsafe.Pointer(name))
	ci := cutil.NewCommandInput(args, inputBuffer)
	defer ci.Free()
	co := cutil.NewCommandOutput()
	defer co.Free()

	ret := C.rados_pg_command(
		c.cluster,
		name,
		(**C.char)(ci.Cmd()),
		C.size_t(ci.CmdLen()),
		(*C.char)(ci.InBuf()),
		C.size_t(ci.InBufLen()),
		(**C.char)(co.OutBuf()),
		(*C.size_t)(co.OutBufLen()),
		(**C.char)(co.Outs()),
		(*C.size_t)(co.OutsLen()))
	buf, status := co.GoValues()
	return buf, status, getError(ret)
}

// MgrCommand sends a command to a ceph-mgr.
func (c *Conn) MgrCommand(args [][]byte) ([]byte, string, error) {
	return c.mgrCommand(args, nil)
}

// MgrCommandWithInputBuffer sends a command, with an input buffer, to a ceph-mgr.
func (c *Conn) MgrCommandWithInputBuffer(args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	return c.mgrCommand(args, inputBuffer)
}

// Implements:
//  int rados_mgr_command(rados_t cluster, const char **cmd,
//                         size_t cmdlen, const char *inbuf,
//                         size_t inbuflen, char **outbuf,
//                         size_t *outbuflen, char **outs,
//                          size_t *outslen);
func (c *Conn) mgrCommand(args [][]byte, inputBuffer []byte) ([]byte, string, error) {
	ci := cutil.NewCommandInput(args, inputBuffer)
	defer ci.Free()
	co := cutil.NewCommandOutput()
	defer co.Free()

	ret := C.rados_mgr_command(
		c.cluster,
		(**C.char)(ci.Cmd()),
		C.size_t(ci.CmdLen()),
		(*C.char)(ci.InBuf()),
		C.size_t(ci.InBufLen()),
		(**C.char)(co.OutBuf()),
		(*C.size_t)(co.OutBufLen()),
		(**C.char)(co.Outs()),
		(*C.size_t)(co.OutsLen()))
	buf, status := co.GoValues()
	return buf, status, getError(ret)
}
<|endoftext|>


<commit_before>package get

import (
	"compress/gzip"
	"encoding/xml"
	"io"
	"log"
	"sort"
)

// common

// Location maps a <location> tag in repodata/repomd.xml or repodata/<ID>-primary.xml.gz
type Location struct {
	Href string `xml:"href,attr"`
}

// repodata/repomd.xml

// Repomd maps a <repomd> tag in repodata/repomd.xml
type Repomd struct {
	Data []Data `xml:"data"`
}

// Data maps a <data> tag in repodata/repomd.xml
type Data struct {
	Type     string   `xml:"type,attr"`
	Location Location `xml:"location"`
}

// repodata/<ID>-primary.xml.gz

// Metadata maps a <metadata> tag in repodata/<ID>-primary.xml.gz
type Metadata struct {
	Packages []Package `xml:"package"`
}

// Package maps a <package> tag in repodata/<ID>-primary.xml.gz
type Package struct {
	Arch     string   `xml:"arch"`
	Location Location `xml:"location"`
}

const repomdPath = "/repodata/repomd.xml"

// Stores a repo
func StoreRepo(url string, storage *Storage, archs map[string]bool) (err error) {
	packagePaths, err := processMetadata(url, storage, archs)
	if err != nil {
		return
	}

	log.Printf("Downloading %v packages...\n", len(packagePaths))
	for i := 0; i < len(packagePaths); i++ {
		packagePath := packagePaths[i]
		log.Printf("...%v\n", packagePath)
		err = Store(url+"/"+packagePath, storage, packagePath)
		if err != nil {
			return
		}
	}
	return
}

// processMetadata stores the repo metadata and returns a list of package file
// paths to download
func processMetadata(url string, storage *Storage, archs map[string]bool) (packagePaths []string, err error) {
	_, err = ApplyStoring(func(r io.ReadCloser) (result interface{}, err error) {
		decoder := xml.NewDecoder(r)
		var repomd Repomd
		err = decoder.Decode(&repomd)
		if err != nil {
			return
		}

		data := repomd.Data
		for i := 0; i < len(data); i++ {
			metadataPath := data[i].Location.Href
			metadataUrl := url + "/" + metadataPath
			if data[i].Type == "primary" {
				packagePaths, err = processPrimary(metadataUrl, storage, metadataPath, archs)
			} else {
				err = Store(metadataUrl, storage, metadataPath)
			}
			if err != nil {
				return
			}
		}
		return
	}, url+repomdPath, storage, repomdPath)
	return
}

// processPrimary stores the primary XML metadata file and returns a list of
// package file paths to download
func processPrimary(url string, storage *Storage, path string, archs map[string]bool) (packagePaths []string, err error) {
	_, err = ApplyStoring(func(r io.ReadCloser) (result interface{}, err error) {
		gzReader, err := gzip.NewReader(r)
		if err != nil {
			return
		}
		defer gzReader.Close()

		decoder := xml.NewDecoder(gzReader)
		var primary Metadata
		err = decoder.Decode(&primary)
		if err != nil {
			return
		}

		archCount := len(archs)
		for _, pack := range primary.Packages {
			if archCount == 0 || archs[pack.Arch] {
				packagePaths = append(packagePaths, pack.Location.Href)
			}
		}
		sort.Strings(packagePaths)
		return
	}, url, storage, path)
	return
}
<commit_msg>Refactoring: isolate xml mapping types<commit_after>package get

import (
	"compress/gzip"
	"encoding/xml"
	"io"
	"log"
	"sort"
)

// common

// XmlLocation maps a <location> tag in repodata/repomd.xml or repodata/<ID>-primary.xml.gz
type XmlLocation struct {
	Href string `xml:"href,attr"`
}

// repodata/repomd.xml

// XmlRepomd maps a <repomd> tag in repodata/repomd.xml
type XmlRepomd struct {
	Data []XmlData `xml:"data"`
}

// XmlData maps a <data> tag in repodata/repomd.xml
type XmlData struct {
	Type     string   `xml:"type,attr"`
	Location XmlLocation `xml:"location"`
}

// repodata/<ID>-primary.xml.gz

// XmlMetadata maps a <metadata> tag in repodata/<ID>-primary.xml.gz
type XmlMetadata struct {
	Packages []XmlPackage `xml:"package"`
}

// XmlPackage maps a <package> tag in repodata/<ID>-primary.xml.gz
type XmlPackage struct {
	Arch     string   `xml:"arch"`
	Location XmlLocation `xml:"location"`
}

const repomdPath = "/repodata/repomd.xml"

// Stores a repo
func StoreRepo(url string, storage *Storage, archs map[string]bool) (err error) {
	packagePaths, err := processMetadata(url, storage, archs)
	if err != nil {
		return
	}

	log.Printf("Downloading %v packages...\n", len(packagePaths))
	for i := 0; i < len(packagePaths); i++ {
		packagePath := packagePaths[i]
		log.Printf("...%v\n", packagePath)
		err = Store(url+"/"+packagePath, storage, packagePath)
		if err != nil {
			return
		}
	}
	return
}

// processMetadata stores the repo metadata and returns a list of package file
// paths to download
func processMetadata(url string, storage *Storage, archs map[string]bool) (packagePaths []string, err error) {
	_, err = ApplyStoring(func(r io.ReadCloser) (result interface{}, err error) {
		decoder := xml.NewDecoder(r)
		var repomd XmlRepomd
		err = decoder.Decode(&repomd)
		if err != nil {
			return
		}

		data := repomd.Data
		for i := 0; i < len(data); i++ {
			metadataPath := data[i].Location.Href
			metadataUrl := url + "/" + metadataPath
			if data[i].Type == "primary" {
				packagePaths, err = processPrimary(metadataUrl, storage, metadataPath, archs)
			} else {
				err = Store(metadataUrl, storage, metadataPath)
			}
			if err != nil {
				return
			}
		}
		return
	}, url+repomdPath, storage, repomdPath)
	return
}

// processPrimary stores the primary XML metadata file and returns a list of
// package file paths to download
func processPrimary(url string, storage *Storage, path string, archs map[string]bool) (packagePaths []string, err error) {
	_, err = ApplyStoring(func(r io.ReadCloser) (result interface{}, err error) {
		gzReader, err := gzip.NewReader(r)
		if err != nil {
			return
		}
		defer gzReader.Close()

		decoder := xml.NewDecoder(gzReader)
		var primary XmlMetadata
		err = decoder.Decode(&primary)
		if err != nil {
			return
		}

		archCount := len(archs)
		for _, pack := range primary.Packages {
			if archCount == 0 || archs[pack.Arch] {
				packagePaths = append(packagePaths, pack.Location.Href)
			}
		}
		sort.Strings(packagePaths)
		return
	}, url, storage, path)
	return
}
<|endoftext|>


<commit_before>package git

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// A file represents a file (or directory) relative to os.Getwd()
type File string

// Determines if the file exists on the filesystem.
func (f File) Exists() bool {
	if _, err := os.Stat(string(f)); os.IsNotExist(err) {
		return false
	}
	return true
}

// Appends the value val to the end of the file f.
// Not that f must already exist.
func (f File) Append(val string) error {
	if !f.Exists() {
		return fmt.Errorf("File %s does not exist", f)
	}
	fi, err := os.OpenFile(f.String(), os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}
	defer fi.Close()
	fmt.Fprintf(fi, "%s", val)
	return nil
}

func (f File) String() string {
	return string(f)
}

// Normalizes the file name that's relative to the current working directory
// to be relative to the workdir root. Ie. convert it from a file system
// path to an index path.
func (f File) IndexPath(c *Client) (IndexPath, error) {
	p, err := filepath.Abs(f.String())
	if err != nil {
		return "", err
	}
	// BUG(driusan): This should verify that there is a prefix and return
	// an error if it's outside of the tree.
	return IndexPath(strings.TrimPrefix(p, string(c.WorkDir)+"/")), nil
}

// Returns stat information for the given file.
func (f File) Stat() (os.FileInfo, error) {
	return os.Stat(f.String())
}

func (f File) Create() error {
	fi, err := os.Create(f.String())
	fi.Close()
	return err
}

// Reads the entire contents of file and return as a string. Note
// that this should only be used for very small files (like refspecs)
//
func (f File) ReadAll() (string, error) {
	val, err := ioutil.ReadFile(f.String())
	if err != nil {
		return "", err
	}
	return string(val), nil
}

// Reads the first line of File. (This is primarily to extract commit message
// lines for reflogs)
func (f File) ReadFirstLine() (string, error) {
	if !f.Exists() {
		return "", fmt.Errorf("File %s does not exist", f)
	}
	fi, err := os.Open(f.String())
	if err != nil {
		return "", err
	}
	defer fi.Close()
	scanner := bufio.NewScanner(fi)
	scanner.Scan()
	if err := scanner.Err(); err != nil {
		return "", err
	}
	return scanner.Text(), nil
}

func (f File) Remove() error {
	return os.Remove(f.String())
}
<commit_msg>Fix bug where file.Create() would fail if directory didn't exist.<commit_after>package git

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// A file represents a file (or directory) relative to os.Getwd()
type File string

// Determines if the file exists on the filesystem.
func (f File) Exists() bool {
	if _, err := os.Stat(string(f)); os.IsNotExist(err) {
		return false
	}
	return true
}

// Appends the value val to the end of the file f.
// Not that f must already exist.
func (f File) Append(val string) error {
	if !f.Exists() {
		return fmt.Errorf("File %s does not exist", f)
	}
	fi, err := os.OpenFile(f.String(), os.O_RDWR|os.O_APPEND, 0660)
	if err != nil {
		return err
	}
	defer fi.Close()
	fmt.Fprintf(fi, "%s", val)
	return nil
}

func (f File) String() string {
	return string(f)
}

// Normalizes the file name that's relative to the current working directory
// to be relative to the workdir root. Ie. convert it from a file system
// path to an index path.
func (f File) IndexPath(c *Client) (IndexPath, error) {
	p, err := filepath.Abs(f.String())
	if err != nil {
		return "", err
	}
	// BUG(driusan): This should verify that there is a prefix and return
	// an error if it's outside of the tree.
	return IndexPath(strings.TrimPrefix(p, string(c.WorkDir)+"/")), nil
}

// Returns stat information for the given file.
func (f File) Stat() (os.FileInfo, error) {
	return os.Stat(f.String())
}

func (f File) Create() error {
	dir := File(filepath.Dir(f.String()))
	if !dir.Exists() {
		if err := os.MkdirAll(dir.String(), 0755); err != nil {
			return err
		}
	}

	fi, err := os.Create(f.String())
	fi.Close()
	return err
}

// Reads the entire contents of file and return as a string. Note
// that this should only be used for very small files (like refspecs)
//
func (f File) ReadAll() (string, error) {
	val, err := ioutil.ReadFile(f.String())
	if err != nil {
		return "", err
	}
	return string(val), nil
}

// Reads the first line of File. (This is primarily to extract commit message
// lines for reflogs)
func (f File) ReadFirstLine() (string, error) {
	if !f.Exists() {
		return "", fmt.Errorf("File %s does not exist", f)
	}
	fi, err := os.Open(f.String())
	if err != nil {
		return "", err
	}
	defer fi.Close()
	scanner := bufio.NewScanner(fi)
	scanner.Scan()
	if err := scanner.Err(); err != nil {
		return "", err
	}
	return scanner.Text(), nil
}

func (f File) Remove() error {
	return os.Remove(f.String())
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "hash/crc32"
  "io"
    "io/ioutil"
  "log"
  "net/http"
  "net/url"
  "os"
  "os/exec"
  "time"

  "github.com/getsentry/raven-go"
)

var sentryDSN string = "<SENTRY DSN GOES HERE>"

func main() {

  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Go Drone")
  })

  http.HandleFunc("/query/", hiveQuery)

  //go testQueryEndpoint()
  log.Fatal(http.ListenAndServe(":5000", nil))

}

func logSentry(err error, r *http.Request) {
  sentryClient, serr := raven.NewClient(sentryDSN, nil)
  if serr != nil {
    log.Printf("Sentry encoutered error: %s", serr)
  }

  trace := raven.NewStacktrace(0, 2, nil)
  packet := raven.NewPacket(err.Error(), raven.NewException(err, trace), raven.NewHttp(r))
  eventID, ch := sentryClient.Capture(packet, nil)
  if cerr := <-ch; cerr != nil {
    log.Printf("Sentry Channel encountered error: %s", cerr)
  }
  message := fmt.Sprintf("Captured error with id %s: %q", eventID, err)
  log.Println(message)
}

func hiveQuery(w http.ResponseWriter, r *http.Request) {

  err := r.ParseForm()
  if err != nil {
    log.Fatal(err)
  }

  query := r.Form["query"][0]
  out, err := runHive(query, r)
  if err != nil {
    log.Println("Hive failed, retrying in 30 seconds")
    time.Sleep(time.Duration(30) * time.Second)
    out, _ = runHive(query, r)
  }
  fmt.Fprintf(w, "%s", out)
}

func crc32String(s string) string {
  return string(crc32.ChecksumIEEE([]byte(s)))
}

func runHive(query string, r *http.Request) (result []byte, err error) {
  log.Printf("Hive Query: %s\n", query)
  cmd := exec.Command("hive", "-e", query)
  result, err := cmd.Output()
  if err != nil {
    logSentry(err, r)
  }
  return
}

func runHiveWithStderr(query string, r *http.Request) (result []byte, err error) {
  log.Printf("Hive Query: %s\n", query)
  cmd := exec.Command("hive", "-e", query)
  stdout, err := cmd.StdoutPipe()
  if err != nil {
    logSentry(err, r)
  }
  stderr, err := cmd.StderrPipe()
  if err != nil {
    logSentry(err, r)
  }
  if err := cmd.Start(); err != nil {
    logSentry(err, r)
  }
  result, err = ioutil.ReadAll(stdout)
  if err != nil {
    logSentry(err, r)
  }

  dstName := crc32String(query)
  dst, err := os.Create(dstName)
  if err != nil {
    logSentry(err, r)
  }
  defer dst.Close()

  _, err = io.Copy(dst, stderr)
  if err != nil {
    logSentry(err, r)
  }

  if err := cmd.Wait(); err != nil {
    logSentry(err, r)
  }
  return
}

func testQueryEndpoint() {
  resp, err := http.PostForm("http://127.0.0.1:5000/query/", url.Values{"query": {"show tables"}})
  if err != nil {
    log.Fatal()
  }

  resp.Body.Close()
}

<commit_msg>format code<commit_after>package main

import (
	"fmt"
	"hash/crc32"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"time"

	"github.com/getsentry/raven-go"
)

var sentryDSN string = "<SENTRY DSN GOES HERE>"

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Go Drone")
	})

	http.HandleFunc("/query/", hiveQuery)

	//go testQueryEndpoint()
	log.Fatal(http.ListenAndServe(":5000", nil))

}

func logSentry(err error, r *http.Request) {
	sentryClient, serr := raven.NewClient(sentryDSN, nil)
	if serr != nil {
		log.Printf("Sentry encoutered error: %s", serr)
	}

	trace := raven.NewStacktrace(0, 2, nil)
	packet := raven.NewPacket(err.Error(), raven.NewException(err, trace), raven.NewHttp(r))
	eventID, ch := sentryClient.Capture(packet, nil)
	if cerr := <-ch; cerr != nil {
		log.Printf("Sentry Channel encountered error: %s", cerr)
	}
	message := fmt.Sprintf("Captured error with id %s: %q", eventID, err)
	log.Println(message)
}

func hiveQuery(w http.ResponseWriter, r *http.Request) {

	err := r.ParseForm()
	if err != nil {
		log.Fatal(err)
	}

	query := r.Form["query"][0]
	out, err := runHive(query, r)
	if err != nil {
		log.Println("Hive failed, retrying in 30 seconds")
		time.Sleep(time.Duration(30) * time.Second)
		out, _ = runHive(query, r)
	}
	fmt.Fprintf(w, "%s", out)
}

func crc32String(s string) string {
	return string(crc32.ChecksumIEEE([]byte(s)))
}

func runHive(query string, r *http.Request) (result []byte, err error) {
	log.Printf("Hive Query: %s\n", query)
	cmd := exec.Command("hive", "-e", query)
	result, err := cmd.Output()
	if err != nil {
		logSentry(err, r)
	}
	return
}

func runHiveWithStderr(query string, r *http.Request) (result []byte, err error) {
	log.Printf("Hive Query: %s\n", query)
	cmd := exec.Command("hive", "-e", query)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		logSentry(err, r)
	}
	stderr, err := cmd.StderrPipe()
	if err != nil {
		logSentry(err, r)
	}
	if err := cmd.Start(); err != nil {
		logSentry(err, r)
	}
	result, err = ioutil.ReadAll(stdout)
	if err != nil {
		logSentry(err, r)
	}

	dstName := crc32String(query)
	dst, err := os.Create(dstName)
	if err != nil {
		logSentry(err, r)
	}
	defer dst.Close()

	_, err = io.Copy(dst, stderr)
	if err != nil {
		logSentry(err, r)
	}

	if err := cmd.Wait(); err != nil {
		logSentry(err, r)
	}
	return
}

func testQueryEndpoint() {
	resp, err := http.PostForm("http://127.0.0.1:5000/query/", url.Values{"query": {"show tables"}})
	if err != nil {
		log.Fatal()
	}

	resp.Body.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	goopt "github.com/droundy/goopt"
	"net"
	"net/http"
	"net/url"
	"runtime"
	"sort"
	"strings"
	"time"
)

var Author = "Alexander Solovyov"
var Version = "0.2"
var Summary = "gofigure [OPTS] URL\n"

var reqs = goopt.Int([]string{"-n", "--requests"}, 1,
	"number of requests to make")
var concurrency = goopt.Int([]string{"-c", "--concurrency"}, 1,
	"concurrency level")
var timeout = goopt.Int([]string{"-t", "--timeout"}, 1000,
	"timeout of each request in milliseconds")
var cpus = goopt.Int([]string{"-p", "--cpus"}, 0,
	"how many processes to run (0 - default)")

type someError struct {
	what string
	str  string
}

func (e *someError) Error() string {
	return fmt.Sprintf(e.what, e.str)
}

type result struct {
	time time.Duration
	err  error
}

type Int64Array []int64

func (p Int64Array) Len() int           { return len(p) }
func (p Int64Array) Less(i, j int) bool { return p[i] < p[j] }
func (p Int64Array) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	if *concurrency > *reqs {
		fmt.Printf("You can't have concurrency higher than number of requests\n")
		return
	}

	url, err := getURL(goopt.Args[0])
	if err != nil {
		fmt.Printf("url is invalid: %s\n", err)
		return
	}

	runtime.GOMAXPROCS(*cpus)

	fmt.Printf("Statistics for requests to %s\n", goopt.Args[0])
	results, total := start(url, *reqs, *concurrency)
	printStats(results, total)
}

func start(url *url.URL, requests int, concurrency int) ([]result, time.Duration) {
	results := make([]result, requests)
	queue := make(chan int, requests)
	out := make(chan result, concurrency)
	const fmtCompleted = "\rCompleted %d from %d requests"

	for i := 0; i < requests; i++ {
		queue <- i
	}

	now := time.Now()

	for i := 0; i < concurrency; i++ {
		go sender(url, queue, out)
	}

	for i := 0; i < requests; i++ {
		results[i] = <-out

		if i > 0 && i%100 == 0 {
			fmt.Printf(fmtCompleted, i, requests)
		}
	}

	// erase 'Completed ...' line
	fmt.Printf("\r%*s", len(fmtCompleted)+10, " ")
	return results, time.Now().Sub(now)
}

func printStats(results []result, workTime time.Duration) {
	times := make(Int64Array, 0)
	total := int64(0)

	for _, r := range results {
		if r.err == nil {
			times = append(times, r.time.Nanoseconds())
			total += r.time.Nanoseconds()
		}
	}
	sort.Sort(times)

	average, median := int64(0), int64(0)
	if len(times) > 0 {
		average = total / int64(len(times))
		median = times[len(times)/2]
	} else {
		average = 0
		median = 0
	}

	fmt.Printf(`
Total requests performed:       %d
Total failures:                 %d
Time taken for tests:           %.3f ms
Average request takes:          %.3f ms
Median request time:            %.3f ms
Average time between responses: %.3f ms
Average requests per second:    %.3f
`,
		*reqs,
		*reqs-len(times),
		ms(workTime.Nanoseconds()),
		ms(average),
		ms(median),
		ms(workTime.Nanoseconds() / int64(*reqs)),
		(float64(*reqs) / (ms(workTime.Nanoseconds()) / 1000)))
}

func ms(x int64) float64 {
    return float64(x) / 1000000
}

func hasPort(s string) bool {
	return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

func getURL(rawurl string) (*url.URL, error) {
	URL, err := url.Parse(rawurl)
	if err != nil {
		return nil, err
	}

	if URL.Scheme != "http" && URL.Scheme != "https" {
		return nil, &someError{"unsupported protocol scheme: %s", URL.Scheme}
	}

	if !hasPort(URL.Host) {
		URL.Host += ":http"
	}

	return URL, nil
}

func sender(url *url.URL, queue chan int, out chan result) {
	for _ = range queue {
		out <- send(url)
	}
}

type respErr struct {
	resp *http.Response
	err  error
}

func send(url *url.URL) result {
	var req http.Request
	req.URL = url

	now := time.Now()
	conn, err := net.Dial("tcp", req.URL.Host)
	if err != nil {
		return result{0, err}
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return result{0, err}
	}

	ch := make(chan respErr, 1)
	go func() {
		reader := bufio.NewReader(conn)
		response, err := http.ReadResponse(reader, &req)
		ch <- respErr{response, err}
	}()

	var res result

	select {
	case <-time.After(time.Duration(*timeout * 1e6)):
		res = result{time.Now().Sub(now), errors.New("Timeout!")}
	case rerr := <-ch:
		res = result{time.Now().Sub(now), rerr.err}
		conn.Close()
		rerr.resp.Body.Close()
	}

	return res
}
<commit_msg>switch to using time.Duration and its stringification capabilities<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	goopt "github.com/droundy/goopt"
	"net"
	"net/http"
	"net/url"
	"runtime"
	"sort"
	"strings"
	"time"
)

var Author = "Alexander Solovyov"
var Version = "0.2"
var Summary = "gofigure [OPTS] URL\n"

var reqs = goopt.Int([]string{"-n", "--requests"}, 1,
	"number of requests to make")
var concurrency = goopt.Int([]string{"-c", "--concurrency"}, 1,
	"concurrency level")
var timeout = goopt.Int([]string{"-t", "--timeout"}, 1000,
	"timeout of each request in milliseconds")
var cpus = goopt.Int([]string{"-p", "--cpus"}, 0,
	"how many processes to run (0 - default)")

type someError struct {
	what string
	str  string
}

func (e *someError) Error() string {
	return fmt.Sprintf(e.what, e.str)
}

type result struct {
	time time.Duration
	err  error
}

type DurationArray []time.Duration

func (p DurationArray) Len() int {
	return len(p)
}
func (p DurationArray) Less(i, j int) bool {
	return p[i].Nanoseconds() < p[j].Nanoseconds()
}
func (p DurationArray) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

func main() {
	goopt.Author = Author
	goopt.Version = Version
	goopt.Summary = Summary
	goopt.Parse(nil)

	if len(goopt.Args) == 0 {
		println(goopt.Usage())
		return
	}

	if *concurrency > *reqs {
		fmt.Printf("You can't have concurrency higher than number of requests\n")
		return
	}

	url, err := getURL(goopt.Args[0])
	if err != nil {
		fmt.Printf("url is invalid: %s\n", err)
		return
	}

	runtime.GOMAXPROCS(*cpus)

	fmt.Printf("Statistics for requests to %s\n", goopt.Args[0])
	results, total := start(url, *reqs, *concurrency)
	printStats(results, total)
}

func start(url *url.URL, requests int, concurrency int) ([]result, time.Duration) {
	results := make([]result, requests)
	queue := make(chan int, requests)
	out := make(chan result, concurrency)
	const fmtCompleted = "\rCompleted %d from %d requests"

	for i := 0; i < requests; i++ {
		queue <- i
	}

	now := time.Now()

	for i := 0; i < concurrency; i++ {
		go sender(url, queue, out)
	}

	for i := 0; i < requests; i++ {
		results[i] = <-out

		if i > 0 && i%100 == 0 {
			fmt.Printf(fmtCompleted, i, requests)
		}
	}

	// erase 'Completed ...' line
	fmt.Printf("\r%*s", len(fmtCompleted)+10, " ")
	return results, time.Now().Sub(now)
}

func printStats(results []result, workTime time.Duration) {
	times := make(DurationArray, 0)
	total := time.Duration(0)

	for _, r := range results {
		if r.err == nil {
			times = append(times, r.time)
			total += r.time
		}
	}
	sort.Sort(times)

	average := time.Duration(0)
	median := time.Duration(0)
	if len(times) > 0 {
		average = time.Duration(total.Nanoseconds() / int64(len(times)))
		median = times[len(times) / 2]
	}

	fmt.Printf(`
Total requests performed:       %d
Total failures:                 %d
Time taken for tests:           %s
Average request takes:          %s
Median request time:            %s
Average time between responses: %s
Average requests per second:    %.3f
`,
		*reqs,
		*reqs-len(times),
		workTime,
		average,
		median,
		time.Duration(workTime.Nanoseconds() / int64(*reqs)),
		(float64(*reqs) / workTime.Seconds()))
}

func hasPort(s string) bool {
	return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
}

func getURL(rawurl string) (*url.URL, error) {
	URL, err := url.Parse(rawurl)
	if err != nil {
		return nil, err
	}

	if URL.Scheme != "http" && URL.Scheme != "https" {
		return nil, &someError{"unsupported protocol scheme: %s", URL.Scheme}
	}

	if !hasPort(URL.Host) {
		URL.Host += ":http"
	}

	return URL, nil
}

func sender(url *url.URL, queue chan int, out chan result) {
	for _ = range queue {
		out <- send(url)
	}
}

type respErr struct {
	resp *http.Response
	err  error
}

func send(url *url.URL) result {
	var req http.Request
	req.URL = url

	now := time.Now()
	conn, err := net.Dial("tcp", req.URL.Host)
	if err != nil {
		return result{0, err}
	}

	err = req.Write(conn)
	if err != nil {
		conn.Close()
		return result{0, err}
	}

	ch := make(chan respErr, 1)
	go func() {
		reader := bufio.NewReader(conn)
		response, err := http.ReadResponse(reader, &req)
		ch <- respErr{response, err}
	}()

	var res result

	select {
	case <-time.After(time.Duration(*timeout * 1e6)):
		res = result{time.Now().Sub(now), errors.New("Timeout!")}
	case rerr := <-ch:
		res = result{time.Now().Sub(now), rerr.err}
		conn.Close()
		rerr.resp.Body.Close()
	}

	return res
}
<|endoftext|>


<commit_before>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// GoRewind is an event store server written in Go that talks ZeroMQ.
package main

import (
	"flag"
	"log"
	"os"
	"github.com/jensrantil/gorewind/server"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

var (
	eventStorePath = flag.String("datadir", "data",
	"directory path where incoming events will be stored. Created"+
	" if non-existent.")
	commandSocketZPath = flag.String("commandsocket",
	"tcp://127.0.0.1:9002", "Command socket. Handles new eventsand"+
	" queries.")
	eventPublishZPath = flag.String("evpubsocket",
	"tcp://127.0.0.1:9003", "ZeroMQ event publishing socket.")
)

// Main method. Will panic if things are so bad that the application
// will not start.
func main() {
	flag.Parse()

	log.Println("Event store to use:", *eventStorePath)
	log.Println("Command socket path:", *commandSocketZPath)
	log.Println("Event publishing socket path:", *eventPublishZPath)
	log.Println()

	stor, err := storage.OpenFile(*eventStorePath)
	if err != nil {
		log.Panicln("could not create DB storage")
	}
	defer stor.Close()

	estore, err := server.NewEventStore(stor)
	if err != nil {
		log.Panicln(os.Stderr, "could not create event store")
	}
	defer estore.Close()

	initParams := server.InitParams{
		Store: estore,
		CommandSocketZPath: commandSocketZPath,
		EvPubSocketZPath: eventPublishZPath,
	}
	serv, err := server.New(&initParams)
	if err != nil {
		panic(err.Error())
	}

	// FIXME: Handle SIGINT correctly and smoothly.

	serv.Run()
}
<commit_msg>Bugfix: Fix broken import<commit_after>// gorewind is an event store server written in Python that talks ZeroMQ.
// Copyright (C) 2013  Jens Rantil
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// GoRewind is an event store server written in Go that talks ZeroMQ.
package main

import (
	"flag"
	"log"
	"os"
	"./server"
	"github.com/syndtr/goleveldb/leveldb/storage"
)

var (
	eventStorePath = flag.String("datadir", "data",
	"directory path where incoming events will be stored. Created"+
	" if non-existent.")
	commandSocketZPath = flag.String("commandsocket",
	"tcp://127.0.0.1:9002", "Command socket. Handles new eventsand"+
	" queries.")
	eventPublishZPath = flag.String("evpubsocket",
	"tcp://127.0.0.1:9003", "ZeroMQ event publishing socket.")
)

// Main method. Will panic if things are so bad that the application
// will not start.
func main() {
	flag.Parse()

	log.Println("Event store to use:", *eventStorePath)
	log.Println("Command socket path:", *commandSocketZPath)
	log.Println("Event publishing socket path:", *eventPublishZPath)
	log.Println()

	stor, err := storage.OpenFile(*eventStorePath)
	if err != nil {
		log.Panicln("could not create DB storage")
	}
	defer stor.Close()

	estore, err := server.NewEventStore(stor)
	if err != nil {
		log.Panicln(os.Stderr, "could not create event store")
	}
	defer estore.Close()

	initParams := server.InitParams{
		Store: estore,
		CommandSocketZPath: commandSocketZPath,
		EvPubSocketZPath: eventPublishZPath,
	}
	serv, err := server.New(&initParams)
	if err != nil {
		panic(err.Error())
	}

	// FIXME: Handle SIGINT correctly and smoothly.

	serv.Run()
}
<|endoftext|>


<commit_before>package tegola

import (
	"fmt"
	"math"

	"github.com/terranodo/tegola/maths/webmercator"
)

const (
	DefaultEpislon            = 10.0
	DefaultExtent             = 4096
	DefaultTileBuffer float64 = 64
	MaxZ                      = 22
)

var UnknownConversionError = fmt.Errorf("do not know how to convert value to requested value")

//Tile slippy map tilenames
//	http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
type Tile struct {
	Z         int
	X         int
	Y         int
	Lat       float64
	Long      float64
	Tolerance float64
	Extent    float64
	Buffer    float64

	// These values are cached
	cached bool
	// The width and height of the region.
	xspan float64
	yspan float64
	// This is the computed bounding box.
	extent  [2][2]float64
	bufpext [2][2]float64
}

// NewTile will return a non-nil tile object.
func NewTile(z, x, y int) (t *Tile) {
	t = &Tile{
		Z:         z,
		X:         x,
		Y:         y,
		Buffer:    DefaultTileBuffer,
		Extent:    DefaultExtent,
		Tolerance: DefaultEpislon,
	}
	t.Lat, t.Long = t.Num2Deg()
	t.Init()
	return t
}

// NewTileLatLong will return a non-nil tile object.
func NewTileLatLong(z int, lat, lon float64) (t *Tile) {
	t = &Tile{
		Z:         z,
		Lat:       lat,
		Long:      lon,
		Buffer:    DefaultTileBuffer,
		Extent:    DefaultExtent,
		Tolerance: DefaultEpislon,
	}
	t.X, t.Y = t.Deg2Num()
	t.Init()
	return t
}

func (t *Tile) Init() {
	max := 20037508.34

	//	resolution
	res := (max * 2) / math.Exp2(float64(t.Z))
	t.cached = true
	t.extent = [2][2]float64{
		{
			-max + (float64(t.X) * res), // MinX
			max - (float64(t.Y) * res),  // Miny
		},
		{
			-max + (float64(t.X) * res) + res, // MaxX
			max - (float64(t.Y) * res) - res,  // MaxY

		},
	}
	t.xspan = t.extent[1][0] - t.extent[0][0]
	t.yspan = t.extent[1][1] - t.extent[0][1]
	/*
		// This is how we can calculate it. But, it will always be a constant.
		// So, we just return that constant.
		bounds, err = t.PixelBounds()
		if err != nil {
			return bounds, err
		}
		bounds[0][0] -= t.Buffer
		bounds[0][1] -= t.Buffer
		bounds[1][0] += t.Buffer
		bounds[1][1] += t.Buffer
	*/
	t.bufpext = [2][2]float64{{0 - t.Buffer, 0 - t.Buffer}, {t.Extent + t.Buffer, t.Extent + t.Buffer}}

}

func (t *Tile) Deg2Num() (x, y int) {
	x = int(math.Floor((t.Long + 180.0) / 360.0 * (math.Exp2(float64(t.Z)))))
	y = int(math.Floor((1.0 - math.Log(math.Tan(t.Lat*math.Pi/180.0)+1.0/math.Cos(t.Lat*math.Pi/180.0))/math.Pi) / 2.0 * (math.Exp2(float64(t.Z)))))

	return x, y
}

func (t *Tile) Num2Deg() (lat, lng float64) {
	n := math.Pi - 2.0*math.Pi*float64(t.Y)/math.Exp2(float64(t.Z))

	lat = 180.0 / math.Pi * math.Atan(0.5*(math.Exp(n)-math.Exp(-n)))
	lng = float64(t.X)/math.Exp2(float64(t.Z))*360.0 - 180.0

	return lat, lng
}

func toWebMercator(srid int, pt [2]float64) (npt [2]float64, err error) {
	switch srid {
	default:
		return npt, UnknownConversionError
	case WebMercator:
		return pt, nil
	case WGS84:
		tnpt, err := webmercator.PToXY(pt[0], pt[1])
		if err != nil {
			return npt, err
		}
		return [2]float64{tnpt[0], tnpt[1]}, nil
	}
}

func fromWebMercator(srid int, pt [2]float64) (npt [2]float64, err error) {
	switch srid {
	default:
		return npt, UnknownConversionError
	case WebMercator:
		return pt, nil
	case WGS84:
		tnpt, err := webmercator.PToLonLat(pt[0], pt[1])
		if err != nil {
			return npt, err
		}
		return [2]float64{tnpt[0], tnpt[1]}, nil
	}
}

func (t *Tile) ToPixel(srid int, pt [2]float64) (npt [2]float64, err error) {
	spt, err := toWebMercator(srid, pt)
	if err != nil {
		return npt, err
	}

	nx := int64((spt[0] - t.extent[0][0]) * t.Extent / t.xspan)
	ny := int64((spt[1] - t.extent[0][1]) * t.Extent / t.yspan)
	return [2]float64{float64(nx), float64(ny)}, nil
}
func (t *Tile) FromPixel(srid int, pt [2]float64) (npt [2]float64, err error) {

	x := float64(int64(pt[0]))
	y := float64(int64(pt[1]))

	wmx := (x * t.xspan / t.Extent) + t.extent[0][0]
	wmy := (y * t.yspan / t.Extent) + t.extent[0][1]
	return fromWebMercator(srid, [2]float64{wmx, wmy})

}

//BoundingBox returns the bound box coordinates for upper left (ulx, uly) and lower right (lrx, lry)
// in web mercator projection
// ported from: https://raw.githubusercontent.com/mapbox/postgis-vt-util/master/postgis-vt-util.sql
func (t *Tile) BoundingBox() BoundingBox {
	return BoundingBox{
		Minx:    t.extent[0][0],
		Miny:    t.extent[0][1],
		Maxx:    t.extent[1][0],
		Maxy:    t.extent[1][1],
		Epsilon: t.ZEpislon(),
		HasXYZ:  true,
		X:       t.X,
		Y:       t.Y,
		Z:       t.Z,
	}
}

func (t *Tile) BufferedBoundingBox() (BoundingBox, error) {

	pbounds, err := t.PixelBufferedBounds()
	if err != nil {
		return BoundingBox{}, err
	}

	min, err := t.FromPixel(WebMercator, pbounds[0])
	if err != nil {
		return BoundingBox{}, err
	}
	max, err := t.FromPixel(WebMercator, pbounds[1])
	if err != nil {
		return BoundingBox{}, err
	}

	return BoundingBox{
		Minx:    min[0],
		Miny:    min[1],
		Maxx:    max[0],
		Maxy:    max[1],
		Epsilon: t.ZEpislon(),
		HasXYZ:  true,
		X:       t.X,
		Y:       t.Y,
		Z:       t.Z,
	}, nil
}

func (t *Tile) PixelBounds() (bounds [2][2]float64, err error) {
	/*
		// This is how we can calculate it. But, it will always be a constant.
		// So, we just return that constant.
		bounds[0], err = t.ToPixel(WebMercator, t.extent[0])
		if err != nil {
			return bounds, err
		}
		bounds[1], err = t.ToPixel(WebMercator, t.extent[1])
		if err != nil {
			return bounds, err
		}
	*/
	return [2][2]float64{{0.0, 0.0}, {t.Extent, t.Extent}}, nil
}

func (t *Tile) PixelBufferedBounds() (bounds [2][2]float64, err error) {
	return t.bufpext, nil
}

//ZRes takes a web mercator zoom level and returns the pixel resolution for that
//	scale, assuming 256x256 pixel tiles. Non-integer zoom levels are accepted.
//	ported from: https://raw.githubusercontent.com/mapbox/postgis-vt-util/master/postgis-vt-util.sql
// TODO: gdey — I'm pretty sure we should be using the extent instead of 256 here. But I don't know what the magic number 40075016.6855785 is used for.
// 40075016.6855785 is close to 2*webmercator.MaxXExtent or 2*webmercator.MaxYExtent
func (t *Tile) ZRes() float64 {
	return 40075016.6855785 / (256 * math.Exp2(float64(t.Z)))
}

// This is from Leafty
func (t *Tile) ZEpislon() float64 {

	if t.Z == MaxZ {
		return 0
	}
	epi := t.Tolerance
	if epi <= 0 {
		return 0
	}
	ext := t.Extent

	denom := (math.Exp2(float64(t.Z)) * ext)

	e := epi / denom
	return e
}
<commit_msg>minor type format change. #107<commit_after>package tegola

import (
	"fmt"
	"math"

	"github.com/terranodo/tegola/maths/webmercator"
)

const (
	DefaultEpislon    = 10.0
	DefaultExtent     = 4096
	DefaultTileBuffer = 64.0
	MaxZ              = 22
)

var UnknownConversionError = fmt.Errorf("do not know how to convert value to requested value")

//Tile slippy map tilenames
//	http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
type Tile struct {
	Z         int
	X         int
	Y         int
	Lat       float64
	Long      float64
	Tolerance float64
	Extent    float64
	Buffer    float64

	// These values are cached
	cached bool
	// The width and height of the region.
	xspan float64
	yspan float64
	// This is the computed bounding box.
	extent  [2][2]float64
	bufpext [2][2]float64
}

// NewTile will return a non-nil tile object.
func NewTile(z, x, y int) (t *Tile) {
	t = &Tile{
		Z:         z,
		X:         x,
		Y:         y,
		Buffer:    DefaultTileBuffer,
		Extent:    DefaultExtent,
		Tolerance: DefaultEpislon,
	}
	t.Lat, t.Long = t.Num2Deg()
	t.Init()
	return t
}

// NewTileLatLong will return a non-nil tile object.
func NewTileLatLong(z int, lat, lon float64) (t *Tile) {
	t = &Tile{
		Z:         z,
		Lat:       lat,
		Long:      lon,
		Buffer:    DefaultTileBuffer,
		Extent:    DefaultExtent,
		Tolerance: DefaultEpislon,
	}
	t.X, t.Y = t.Deg2Num()
	t.Init()
	return t
}

func (t *Tile) Init() {
	max := 20037508.34

	//	resolution
	res := (max * 2) / math.Exp2(float64(t.Z))
	t.cached = true
	t.extent = [2][2]float64{
		{
			-max + (float64(t.X) * res), // MinX
			max - (float64(t.Y) * res),  // Miny
		},
		{
			-max + (float64(t.X) * res) + res, // MaxX
			max - (float64(t.Y) * res) - res,  // MaxY

		},
	}
	t.xspan = t.extent[1][0] - t.extent[0][0]
	t.yspan = t.extent[1][1] - t.extent[0][1]
	/*
		// This is how we can calculate it. But, it will always be a constant.
		// So, we just return that constant.
		bounds, err = t.PixelBounds()
		if err != nil {
			return bounds, err
		}
		bounds[0][0] -= t.Buffer
		bounds[0][1] -= t.Buffer
		bounds[1][0] += t.Buffer
		bounds[1][1] += t.Buffer
	*/
	t.bufpext = [2][2]float64{{0 - t.Buffer, 0 - t.Buffer}, {t.Extent + t.Buffer, t.Extent + t.Buffer}}

}

func (t *Tile) Deg2Num() (x, y int) {
	x = int(math.Floor((t.Long + 180.0) / 360.0 * (math.Exp2(float64(t.Z)))))
	y = int(math.Floor((1.0 - math.Log(math.Tan(t.Lat*math.Pi/180.0)+1.0/math.Cos(t.Lat*math.Pi/180.0))/math.Pi) / 2.0 * (math.Exp2(float64(t.Z)))))

	return x, y
}

func (t *Tile) Num2Deg() (lat, lng float64) {
	n := math.Pi - 2.0*math.Pi*float64(t.Y)/math.Exp2(float64(t.Z))

	lat = 180.0 / math.Pi * math.Atan(0.5*(math.Exp(n)-math.Exp(-n)))
	lng = float64(t.X)/math.Exp2(float64(t.Z))*360.0 - 180.0

	return lat, lng
}

func toWebMercator(srid int, pt [2]float64) (npt [2]float64, err error) {
	switch srid {
	default:
		return npt, UnknownConversionError
	case WebMercator:
		return pt, nil
	case WGS84:
		tnpt, err := webmercator.PToXY(pt[0], pt[1])
		if err != nil {
			return npt, err
		}
		return [2]float64{tnpt[0], tnpt[1]}, nil
	}
}

func fromWebMercator(srid int, pt [2]float64) (npt [2]float64, err error) {
	switch srid {
	default:
		return npt, UnknownConversionError
	case WebMercator:
		return pt, nil
	case WGS84:
		tnpt, err := webmercator.PToLonLat(pt[0], pt[1])
		if err != nil {
			return npt, err
		}
		return [2]float64{tnpt[0], tnpt[1]}, nil
	}
}

func (t *Tile) ToPixel(srid int, pt [2]float64) (npt [2]float64, err error) {
	spt, err := toWebMercator(srid, pt)
	if err != nil {
		return npt, err
	}

	nx := int64((spt[0] - t.extent[0][0]) * t.Extent / t.xspan)
	ny := int64((spt[1] - t.extent[0][1]) * t.Extent / t.yspan)
	return [2]float64{float64(nx), float64(ny)}, nil
}
func (t *Tile) FromPixel(srid int, pt [2]float64) (npt [2]float64, err error) {

	x := float64(int64(pt[0]))
	y := float64(int64(pt[1]))

	wmx := (x * t.xspan / t.Extent) + t.extent[0][0]
	wmy := (y * t.yspan / t.Extent) + t.extent[0][1]
	return fromWebMercator(srid, [2]float64{wmx, wmy})

}

//BoundingBox returns the bound box coordinates for upper left (ulx, uly) and lower right (lrx, lry)
// in web mercator projection
// ported from: https://raw.githubusercontent.com/mapbox/postgis-vt-util/master/postgis-vt-util.sql
func (t *Tile) BoundingBox() BoundingBox {
	return BoundingBox{
		Minx:    t.extent[0][0],
		Miny:    t.extent[0][1],
		Maxx:    t.extent[1][0],
		Maxy:    t.extent[1][1],
		Epsilon: t.ZEpislon(),
		HasXYZ:  true,
		X:       t.X,
		Y:       t.Y,
		Z:       t.Z,
	}
}

func (t *Tile) BufferedBoundingBox() (BoundingBox, error) {

	pbounds, err := t.PixelBufferedBounds()
	if err != nil {
		return BoundingBox{}, err
	}

	min, err := t.FromPixel(WebMercator, pbounds[0])
	if err != nil {
		return BoundingBox{}, err
	}
	max, err := t.FromPixel(WebMercator, pbounds[1])
	if err != nil {
		return BoundingBox{}, err
	}

	return BoundingBox{
		Minx:    min[0],
		Miny:    min[1],
		Maxx:    max[0],
		Maxy:    max[1],
		Epsilon: t.ZEpislon(),
		HasXYZ:  true,
		X:       t.X,
		Y:       t.Y,
		Z:       t.Z,
	}, nil
}

func (t *Tile) PixelBounds() (bounds [2][2]float64, err error) {
	/*
		// This is how we can calculate it. But, it will always be a constant.
		// So, we just return that constant.
		bounds[0], err = t.ToPixel(WebMercator, t.extent[0])
		if err != nil {
			return bounds, err
		}
		bounds[1], err = t.ToPixel(WebMercator, t.extent[1])
		if err != nil {
			return bounds, err
		}
	*/
	return [2][2]float64{{0.0, 0.0}, {t.Extent, t.Extent}}, nil
}

func (t *Tile) PixelBufferedBounds() (bounds [2][2]float64, err error) {
	return t.bufpext, nil
}

//ZRes takes a web mercator zoom level and returns the pixel resolution for that
//	scale, assuming 256x256 pixel tiles. Non-integer zoom levels are accepted.
//	ported from: https://raw.githubusercontent.com/mapbox/postgis-vt-util/master/postgis-vt-util.sql
// TODO: gdey — I'm pretty sure we should be using the extent instead of 256 here. But I don't know what the magic number 40075016.6855785 is used for.
// 40075016.6855785 is close to 2*webmercator.MaxXExtent or 2*webmercator.MaxYExtent
func (t *Tile) ZRes() float64 {
	return 40075016.6855785 / (256 * math.Exp2(float64(t.Z)))
}

// This is from Leafty
func (t *Tile) ZEpislon() float64 {

	if t.Z == MaxZ {
		return 0
	}
	epi := t.Tolerance
	if epi <= 0 {
		return 0
	}
	ext := t.Extent

	denom := (math.Exp2(float64(t.Z)) * ext)

	e := epi / denom
	return e
}
<|endoftext|>


<commit_before>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"

	"github.com/mailru/easyjson/jlexer"
	"github.com/mailru/easyjson/jwriter"
)

func init() {
	dt := DateTime{}
	Default.Add("datetime", &dt, IsDateTime)
}

// IsDateTime returns true when the string is a valid date-time
func IsDateTime(str string) bool {
	if len(str) < 4 {
		return false
	}
	s := strings.Split(strings.ToLower(str), "t")
	if len(s) < 2 || !IsDate(s[0]) {
		return false
	}

	matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
	if len(matches) == 0 || len(matches[0]) == 0 {
		return false
	}
	m := matches[0]
	res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
	return res
}

const (
	// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
	RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
	// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
	DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)

var (
	dateTimeFormats = []string{RFC3339Millis, time.RFC3339, time.RFC3339Nano}
	rxDateTime      = regexp.MustCompile(DateTimePattern)
	MarshalFormat   = RFC3339Millis
)

// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
func ParseDateTime(data string) (DateTime, error) {
	if data == "" {
		return NewDateTime(), nil
	}
	var lastError error
	for _, layout := range dateTimeFormats {
		dd, err := time.Parse(layout, data)
		if err != nil {
			lastError = err
			continue
		}
		lastError = nil
		return DateTime(dd), nil
	}
	return DateTime{}, lastError
}

// DateTime is a time but it serializes to ISO8601 format with millis
// It knows how to read 3 different variations of a RFC3339 date time.
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
//
// swagger:strfmt date-time
type DateTime time.Time

// NewDateTime is a representation of zero value for DateTime type
func NewDateTime() DateTime {
	return DateTime(time.Unix(0, 0).UTC())
}

func (t DateTime) String() string {
	return time.Time(t).Format(MarshalFormat)
}

// MarshalText implements the text marshaller interface
func (t DateTime) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalText implements the text unmarshaller interface
func (t *DateTime) UnmarshalText(text []byte) error {
	tt, err := ParseDateTime(string(text))
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// Scan scans a DateTime value from database driver type.
func (t *DateTime) Scan(raw interface{}) error {
	// TODO: case int64: and case float64: ?
	switch v := raw.(type) {
	case []byte:
		return t.UnmarshalText(v)
	case string:
		return t.UnmarshalText([]byte(v))
	case time.Time:
		*t = DateTime(v)
	case nil:
		*t = DateTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
	}

	return nil
}

// Value converts DateTime to a primitive value ready to written to a database.
func (t DateTime) Value() (driver.Value, error) {
	return driver.Value(t.String()), nil
}

func (t DateTime) MarshalJSON() ([]byte, error) {
	var w jwriter.Writer
	t.MarshalEasyJSON(&w)
	return w.BuildBytes()
}

func (t DateTime) MarshalEasyJSON(w *jwriter.Writer) {
	w.String(time.Time(t).Format(MarshalFormat))
}

func (t *DateTime) UnmarshalJSON(data []byte) error {
	l := jlexer.Lexer{Data: data}
	t.UnmarshalEasyJSON(&l)
	return l.Error()
}

func (t *DateTime) UnmarshalEasyJSON(in *jlexer.Lexer) {
	if data := in.String(); in.Ok() {
		tt, err := ParseDateTime(data)
		if err != nil {
			in.AddError(err)
			return
		}
		*t = tt
	}
}

func (t *DateTime) GetBSON() (interface{}, error) {
	return bson.M{"data": t.String()}, nil
}

func (t *DateTime) SetBSON(raw bson.Raw) error {
	var m bson.M
	if err := raw.Unmarshal(&m); err != nil {
		return err
	}

	if data, ok := m["data"].(string); ok {
		var err error
		*t, err = ParseDateTime(data)
		return err
	}

	return errors.New("couldn't unmarshal bson raw value as Duration")
}
<commit_msg>Add RFC3339 format with microsecond precision<commit_after>// Copyright 2015 go-swagger maintainers
//
// 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 strfmt

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"regexp"
	"strings"
	"time"

	"gopkg.in/mgo.v2/bson"

	"github.com/mailru/easyjson/jlexer"
	"github.com/mailru/easyjson/jwriter"
)

func init() {
	dt := DateTime{}
	Default.Add("datetime", &dt, IsDateTime)
}

// IsDateTime returns true when the string is a valid date-time
func IsDateTime(str string) bool {
	if len(str) < 4 {
		return false
	}
	s := strings.Split(strings.ToLower(str), "t")
	if len(s) < 2 || !IsDate(s[0]) {
		return false
	}

	matches := rxDateTime.FindAllStringSubmatch(s[1], -1)
	if len(matches) == 0 || len(matches[0]) == 0 {
		return false
	}
	m := matches[0]
	res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59"
	return res
}

const (
	// RFC3339Millis represents a ISO8601 format to millis instead of to nanos
	RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
	// RFC3339Micro represents a ISO8601 format to micro instead of to nano
	RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
	// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
	DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)

var (
	dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano}
	rxDateTime      = regexp.MustCompile(DateTimePattern)
	MarshalFormat   = RFC3339Millis
)

// ParseDateTime parses a string that represents an ISO8601 time or a unix epoch
func ParseDateTime(data string) (DateTime, error) {
	if data == "" {
		return NewDateTime(), nil
	}
	var lastError error
	for _, layout := range dateTimeFormats {
		dd, err := time.Parse(layout, data)
		if err != nil {
			lastError = err
			continue
		}
		lastError = nil
		return DateTime(dd), nil
	}
	return DateTime{}, lastError
}

// DateTime is a time but it serializes to ISO8601 format with millis
// It knows how to read 3 different variations of a RFC3339 date time.
// Most APIs we encounter want either millisecond or second precision times.
// This just tries to make it worry-free.
//
// swagger:strfmt date-time
type DateTime time.Time

// NewDateTime is a representation of zero value for DateTime type
func NewDateTime() DateTime {
	return DateTime(time.Unix(0, 0).UTC())
}

func (t DateTime) String() string {
	return time.Time(t).Format(MarshalFormat)
}

// MarshalText implements the text marshaller interface
func (t DateTime) MarshalText() ([]byte, error) {
	return []byte(t.String()), nil
}

// UnmarshalText implements the text unmarshaller interface
func (t *DateTime) UnmarshalText(text []byte) error {
	tt, err := ParseDateTime(string(text))
	if err != nil {
		return err
	}
	*t = tt
	return nil
}

// Scan scans a DateTime value from database driver type.
func (t *DateTime) Scan(raw interface{}) error {
	// TODO: case int64: and case float64: ?
	switch v := raw.(type) {
	case []byte:
		return t.UnmarshalText(v)
	case string:
		return t.UnmarshalText([]byte(v))
	case time.Time:
		*t = DateTime(v)
	case nil:
		*t = DateTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v)
	}

	return nil
}

// Value converts DateTime to a primitive value ready to written to a database.
func (t DateTime) Value() (driver.Value, error) {
	return driver.Value(t.String()), nil
}

func (t DateTime) MarshalJSON() ([]byte, error) {
	var w jwriter.Writer
	t.MarshalEasyJSON(&w)
	return w.BuildBytes()
}

func (t DateTime) MarshalEasyJSON(w *jwriter.Writer) {
	w.String(time.Time(t).Format(MarshalFormat))
}

func (t *DateTime) UnmarshalJSON(data []byte) error {
	l := jlexer.Lexer{Data: data}
	t.UnmarshalEasyJSON(&l)
	return l.Error()
}

func (t *DateTime) UnmarshalEasyJSON(in *jlexer.Lexer) {
	if data := in.String(); in.Ok() {
		tt, err := ParseDateTime(data)
		if err != nil {
			in.AddError(err)
			return
		}
		*t = tt
	}
}

func (t *DateTime) GetBSON() (interface{}, error) {
	return bson.M{"data": t.String()}, nil
}

func (t *DateTime) SetBSON(raw bson.Raw) error {
	var m bson.M
	if err := raw.Unmarshal(&m); err != nil {
		return err
	}

	if data, ok := m["data"].(string); ok {
		var err error
		*t, err = ParseDateTime(data)
		return err
	}

	return errors.New("couldn't unmarshal bson raw value as Duration")
}
<|endoftext|>